C# 玩转 YOLOv8 目标检测:ONNX Runtime + DirectML 推理 DLL,图片、视频、RTSP、摄像头全打通
文章目录前言先上效果整体架构接口设计这次不用 JSON用结构体数组C# 集成实战1. P/Invoke 声明2. 图片检测五行代码3. 视频检测统一接口三种输入4. 批量处理与循环测速性能实测与调优建议测试环境性能数据调优建议常见问题与解决方案1. 模型加载失败2. GPU 加速未生效3. 视频流卡顿4. 内存泄漏总结 下载与使用资源下载前言上一篇聊OCR 推理 DLL这篇轮到另一个高频需求目标检测。YOLOv8 的官方生态是 PythonUltralytics但做 Windows 桌面软件的朋友都懂给客户交付一个带 Python 环境的检测工具部署就是噩梦。所以我的做法和 OCR 系列一脉相承C 把 YOLOv8 推理、NMS 后处理、视频解码全部封进一个 DLLC# 只面对一组干净的 C 接口。先列成果图片检测一行调用结果直接返回结构体数组不是 JSON零解析开销视频检测本地视频、RTSP 网络流、USB 摄像头同一个接口GPU 加速DirectML 后端NVIDIA / AMD / Intel 核显通吃失败自动回退 CPU程序永远不崩录像功能检测框实时画到帧上直接写出 MP4三段耗时预处理 / 推理 / 后处理分开统计性能瓶颈一目了然配套 WinForm 测试程序单图、批量文件夹、视频、摄像头四种模式 循环测速。先上效果软件界面长这样——左侧模型加载、推理参数、四种检测模式右侧预览区 结果列表用经典的 bus.jpg 实测一把yolov8n置信度 0.25NMS 0.45检测到5 个目标4 个 person 1 个 bus状态栏直接给出三段耗时检测到 5 个目标, 总耗时 87 ms (预处理 2.7 / 推理 77.5 / 后处理 0.5 ms)结果列表同步输出每个框的类别、置信度和坐标类别置信度位置 (x, y) w×hperson0.890(670, 380) 139x439person0.883(221, 407) 132x448person0.878(55, 397) 192x408bus0.543(21, 229) 806x685person0.436(0, 549) 57x210注意右边缘那个只露出半个人、置信度 0.436 的 person 也框出来了——NMS 和置信度阈值调得合适召回就有保障。耗时数据为测试机实测界面已勾选 GPU 加速不同机器、不同分辨率会有差异建议用自己的业务图跑界面上的循环测速功能取平均值。视频模式同样实测通过本地 MP4 逐帧检测 实时画框预览 录像写出一段带检测框的成品视频直接生成中途不需要任何额外工具。逐帧检测会根据视频帧率自动调整整体架构┌─────────────────────────────────────────────┐ │ C# 应用层WinForm / 控制台 / 服务 │ │ - 图片/视频/摄像头/RTSP 四种输入模式 │ │ - 检测框绘制、结果列表、CSV 导出、录像 │ │ - 批量处理、循环测速 │ └──────────────┬──────────────────────────────┘ │ P/Invoke一组 Yolo* C 接口 ┌──────────────▼──────────────────────────────┐ │ 原生 YOLO 推理 DLLCx64 Release │ │ - ONNX RuntimeYOLOv8 推理 │ │ - DirectMLGPU 加速失败自动回退 CPU │ │ - 预处理 / NMS 后处理 / 三段耗时统计 │ │ - 视频解码本地文件 / RTSP / 摄像头 │ │ - 带框录像写出 │ └──────────────┬──────────────────────────────┘ │ ┌──────────────▼──────────────────────────────┐ │ 模型yolov8n.onnxCOCO 80 类 │ │ 输入 [1,3,640,640] → 输出 [1,84,8400] │ └─────────────────────────────────────────────┘接口设计这次不用 JSON用结构体数组OCR 项目里结果是像素进、JSON 出。但目标检测的场景不同视频流 30 FPS每帧几十上百个框如果每帧都走一遍 JSON 序列化 反序列化纯属浪费。所以这个 DLL 换了个思路结果直接返回可 blit 的结构体数组P/Invoke 一层内存拷贝直达 C#零解析、零分配[StructLayout(LayoutKind.Sequential)]publicstructYoloBox{publicfloatX;publicfloatY;publicfloatWidth;publicfloatHeight;publicfloatConfidence;publicintClassId;}整个 API 分四组一目了然分组接口作用会话YoloCreate/YoloDestroy/YoloIsGpu/YoloGetLastError加载模型、释放、查询是否 GPU、取错误信息图片YoloDetectFile/YoloDetectBytes从文件路径 / 内存字节检测信息YoloGetClassCount/YoloGetLastImageWidth/Height/YoloGetLastTiming类别数、原图尺寸、三段耗时视频YoloVideoOpen/YoloVideoReadDetect(Raw)/YoloVideoSeekToMs/YoloVideoSave*/YoloVideoClose打开视频源、逐帧检测、跳帧、录像、关闭几个设计细节值得单独说1. GPU 失败自动回退 CPU。YoloCreate传useGpu1时尝试 DirectML驱动不支持、设备不可用都无所谓——引擎内部静默回落 CPU会话照常创建。YoloIsGpu可以随时查询当前实际在用什么跑。界面上直接显示[GPU 加速]或[CPU]用户心里有数。2. 错误信息统一出口。所有函数失败返回 -1 或 NULL具体原因调YoloGetLastError拿。它甚至支持传 NULL 句柄——专门用来取YoloCreate失败的原因。3. 三段耗时分开统计。YoloGetLastTiming返回预处理 / 推理 / 后处理各自的毫秒数。调优时一眼看出瓶颈在推理还是在预处理不用猜。C# 集成实战1. P/Invoke 声明internalstaticclassYoloNative{privateconststringDllNameOnnxRuntimeYOLODll.dll;[DllImport(DllName,CallingConventionCallingConvention.Cdecl)]publicstaticexternIntPtrYoloCreate([MarshalAs(UnmanagedType.LPUTF8Str)]stringmodelPath,intinputSize,intcpuThreads,intuseGpu);[DllImport(DllName,CallingConventionCallingConvention.Cdecl)]publicstaticexternintYoloDetectFile(IntPtrhandle,[MarshalAs(UnmanagedType.LPUTF8Str)]stringimagePath,floatconfThreshold,floatnmsThreshold,[Out]YoloBox[]outBoxes,intmaxBoxes);[DllImport(DllName,CallingConventionCallingConvention.Cdecl)]publicstaticexternvoidYoloGetLastTiming(IntPtrhandle,outfloatpreprocessMs,outfloatinferenceMs,outfloatpostprocessMs);[DllImport(DllName,CallingConventionCallingConvention.Cdecl)]publicstaticexternvoidYoloDestroy(IntPtrhandle);}注意路径参数用[MarshalAs(UnmanagedType.LPUTF8Str)]——UTF-8 编码传字符串中文路径不会乱码。这是 .NET Framework 4.7 才有的特性比老派的byte[]手写编码干净得多。2. 图片检测五行代码// 创建会话模型只加载一次IntPtrsessionYoloNative.YoloCreate(models/yolov8n.onnx,inputSize:0,// 0 自动读模型输入尺寸cpuThreads:4,// CPU 线程数useGpu:1);// 1 尝试 GPU失败回退 CPUif(sessionIntPtr.Zero){stringerrorYoloNative.YoloGetLastError(IntPtr.Zero);MessageBox.Show($模型加载失败{error});return;}// 准备结果数组YoloBox[]boxesnewYoloBox[100];// 预分配避免每帧 new// 执行检测intboxCountYoloNative.YoloDetectFile(session,imagePath:test.jpg,confThreshold:0.25f,nmsThreshold:0.45f,outBoxes:boxes,maxBoxes:boxes.Length);// 取耗时YoloNative.YoloGetLastTiming(session,outfloatpreprocessMs,outfloatinferenceMs,outfloatpostprocessMs);// 处理结果for(inti0;iboxCount;i){YoloBoxboxboxes[i];Console.WriteLine(${box.ClassId}:{box.Confidence:F3}$({box.X:F0},{box.Y:F0}){box.Width:F0}x{box.Height:F0});}// 释放会话程序退出时YoloNative.YoloDestroy(session);3. 视频检测统一接口三种输入视频接口设计成打开 → 循环读帧检测 → 关闭的模式本地文件、RTSP、USB 摄像头三种输入走同一套 API// 打开视频源参数二选一// 本地文件YoloNative.YoloVideoOpen(session, video.mp4, 0, 0, 0)// RTSP流YoloNative.YoloVideoOpen(session, rtsp://192.168.1.100:554/stream, 0, 0, 0)// 摄像头YoloNative.YoloVideoOpen(session, 0, width, height, fps) // 0默认摄像头IntPtrvideoHandleYoloNative.YoloVideoOpen(session,video.mp4,0,0,0);if(videoHandleIntPtr.Zero){stringerrorYoloNative.YoloGetLastError(session);MessageBox.Show($视频打开失败{error});return;}// 准备录像可选YoloNative.YoloVideoSaveStart(videoHandle,output_with_boxes.mp4);// 循环读帧检测while(true){intresultYoloNative.YoloVideoReadDetect(videoHandle,confThreshold:0.25f,nmsThreshold:0.45f,outBoxes:boxes,maxBoxes:boxes.Length,outWidth:outintframeWidth,outHeight:outintframeHeight);if(result0)// 0 表示结束或出错break;intboxCountresult;// 这里可以绘制检测框到 frameWidth×frameHeight 的图片上// 或者直接让引擎画框并录像YoloNative.YoloVideoSaveFrame(videoHandle);// 保存当前帧带框}// 关闭录像并释放视频句柄YoloNative.YoloVideoSaveEnd(videoHandle);YoloNative.YoloVideoClose(videoHandle);4. 批量处理与循环测速WinForm 测试程序提供了文件夹批量检测和循环测速功能方便评估模型在实际业务数据上的性能// 批量处理文件夹内所有图片string[]imageFilesDirectory.GetFiles(test_images,*.jpg);foreach(stringimagePathinimageFiles){intboxCountYoloNative.YoloDetectFile(session,imagePath,0.25f,0.45f,boxes,boxes.Length);// 保存结果到 CSV 或数据库}// 循环测速预热 正式测试YoloNative.YoloGetLastTiming(session,out_,out_,out_);// 预热一次inttestCount100;longtotalMs0;for(inti0;itestCount;i){StopwatchswStopwatch.StartNew();YoloNative.YoloDetectFile(session,test.jpg,0.25f,0.45f,boxes,boxes.Length);sw.Stop();totalMssw.ElapsedMilliseconds;}doubleavgMstotalMs/(double)testCount;Console.WriteLine($平均耗时{avgMs:F2}msFPS{1000.0/avgMs:F1});性能实测与调优建议测试环境CPUIntel i7-12700HGPUNVIDIA RTX 3060内存32GB系统Windows 10 22H2模型yolov8n.onnx (640×640)性能数据输入类型分辨率平均总耗时预处理推理后处理FPS单张图片1920×108087 ms2.7 ms77.5 ms0.5 ms11.5视频流1280×72042 ms1.8 ms38.2 ms0.4 ms23.8摄像头640×48028 ms1.2 ms25.1 ms0.3 ms35.7调优建议输入尺寸模型默认 640×640如果业务场景目标较大可尝试 320×320 提升速度召回率会下降。置信度阈值默认 0.25业务场景目标明确可提高到 0.5-0.7 减少误检。NMS 阈值默认 0.45密集目标场景可适当降低到 0.3-0.4。CPU 线程数默认 4根据 CPU 核心数调整一般设为物理核心数。批处理对图片批量检测DLL 内部支持批处理比单张循环快 30%-50%。常见问题与解决方案1. 模型加载失败错误信息Failed to load model可能原因模型路径错误、ONNX 文件损坏、DirectML 驱动问题解决方案检查模型路径是否包含中文或特殊字符使用 Netron 打开 ONNX 文件确认格式正确更新显卡驱动到最新版本2. GPU 加速未生效现象YoloIsGpu(session)返回 0可能原因DirectML 不支持当前显卡、驱动版本过旧、显存不足解决方案检查显卡是否支持 DirectMLWindows 10 1709 基本都支持更新显卡驱动降低模型输入尺寸减少显存占用3. 视频流卡顿现象RTSP 流检测帧率低可能原因网络带宽不足、解码器性能瓶颈、检测耗时过长解决方案降低视频流分辨率跳帧检测每 2-3 帧检测一次使用硬件解码需要编译时开启 FFmpeg 硬件解码支持4. 内存泄漏现象长时间运行后内存持续增长可能原因未正确释放会话或视频句柄解决方案确保每个YoloCreate都有对应的YoloDestroy确保每个YoloVideoOpen都有对应的YoloVideoClose使用using语句包装会话对象总结通过 C 封装 YOLOv8 推理为 DLLC# 通过 P/Invoke 调用我们实现了高性能结构体数组零解析开销纯绿色绿色拷贝不装 Python、不装 CUDA、不装任何运行时环境开箱可用 下载与使用资源下载本项目所有资源均已打包包含推理 DLLOnnxRuntimeYOLODll.dllx64 ReleaseC# 示例代码完整的 WinForm 测试程序源码预训练模型yolov8n.onnxCOCO 80 类测试图片与视频bus.jpg 等示例文件合规方面项目里专门维护了licenses目录下载地址 百度网盘

相关新闻

绝缘类型深度解析:从基础绝缘到系统安全设计实战指南

绝缘类型深度解析:从基础绝缘到系统安全设计实战指南

1. 绝缘材料:从“隔电”到“系统守护”的本质跃迁提起“绝缘”,很多人的第一反应可能就是“不导电”,是电工胶带、是电线外皮那层塑料。这个理解没错,但太浅了。在我十多年的电气工程和电子设备维修经历里,对绝缘的认知…

2026/10/13 7:53:44 阅读更多 →
DIY生态舱CO2监测:NDIR传感器选型、Arduino集成与智能控制

DIY生态舱CO2监测:NDIR传感器选型、Arduino集成与智能控制

1. 项目概述与核心价值 最近在折腾我的“DIY海盗船”项目,这个系列已经更新到第八话了。之前我们搞定了温湿度监控、光照调节、水泵控制这些基础环境模块,让这个模拟的小生态舱运行得挺稳当。但玩久了总觉得还差点意思——舱内植物生长状态时好时坏&…

2026/10/11 10:09:44 阅读更多 →
UE5输入系统进阶:自定义与监听实现按键重映射与复合操作

UE5输入系统进阶:自定义与监听实现按键重映射与复合操作

1. 项目概述:从“按按钮”到“玩转输入”在虚幻引擎5(UE5)里鼓捣过一阵子蓝图的朋友,估计都干过这么一件事:从角色蓝图的“事件图表”里,拖出一个“事件Tick”,然后连上一个“输入动作”事件&am…

2026/10/11 15:18:08 阅读更多 →

最新新闻

PS中英文对照表制作指南:从菜单导出到PDF生成与版本维护

PS中英文对照表制作指南:从菜单导出到PDF生成与版本维护

简介:这份PS中英文对照表PDF面向Photoshop初学者及需要查阅英文界面术语的设计从业者,帮助解决中文版与英文版菜单名称对应困难、切换语言环境后找不到功能入口的问题。资源包共1个PDF文件,大小约18KB,轻量易存,适合打…

2026/10/13 17:57:33 阅读更多 →
23个AI角色协同开发:gstack如何重构软件研发流程

23个AI角色协同开发:gstack如何重构软件研发流程

第一次跑通 gstack 的完整流程时,我在终端里看到的不是一行行的错误日志,而是一群 AI 在互相评审、打回、修改、验证,最后交给我一份可以直接启动的前后端工程。那感觉很像你刚入职一家新公司,站会上产品、前端、后端、测试坐在一…

2026/10/13 17:57:33 阅读更多 →
PDMS出图全流程实战:从ADP自动出图到DRAFT手动标注与打印

PDMS出图全流程实战:从ADP自动出图到DRAFT手动标注与打印

简介:这份PDF面向工厂三维布置设计领域的技术人员与PDMS初学者,系统讲解Plant Design Management System中的出图功能,帮助读者掌握从模型到施工图纸的完整流程。内容围绕自动出图(ADP)与手动出图(DRAFT&am…

2026/10/13 17:57:33 阅读更多 →
Java核心知识点实战梳理:集合、并发、JVM与Java 8新特性

Java核心知识点实战梳理:集合、并发、JVM与Java 8新特性

很多人问我,Java知识点那么多,到底该怎么梳理?网上的资料五花八门,有的讲原理讲到源码深处,有的又浅得跟没讲一样。我自己从写业务代码到啃源码,再到现在带团队做技术评审,踩过的坑不少&#xf…

2026/10/13 17:57:33 阅读更多 →
Python第二次作业深度解析:数据流、面向对象与异常处理实战

Python第二次作业深度解析:数据流、面向对象与异常处理实战

1. 作业概览:这绝不是一次简单的“课后练习”如果你只把这份“Python第二次作业”当成一次常规的语法巩固训练,那可能真的低估它了。我在实际批改和复现这类作业时发现,很多同学的卡点并不在“会不会写代码”,而在“能不能把学过的…

2026/10/13 17:57:33 阅读更多 →
弗洛伊德解梦:噩梦为何也是潜意识的愿望满足?

弗洛伊德解梦:噩梦为何也是潜意识的愿望满足?

你有没有做过这种梦:明天就要交一份至关重要的方案,梦里你却发现自己连文件都找不到,或者更离谱,直接站在空无一人的考场里,试卷上的字全在飘。惊醒之后心跳半天才缓过来,第一反应往往是“这梦太丧了”。但…

2026/10/13 17:56:30 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →