简介:本资源面向希望将Yolov8系列模型落地到C#工程中的开发者与深度学习爱好者,提供一套可直接运行的部署源码与配套数据,帮助解决从Python训练到C#推理的跨语言集成难题。压缩包共56个文件,约3.02MB,以cs源码、csproj工程文件、cpp与h底层接口、jpg示例图片及txt标签文件为主,涵盖TensorRTSharp、OpenVinoSharp、CommonSharp、ResultSharp等模块,并附sln解决方案便于整体编译。资源中已包含检测与分类标签转换脚本及多张演示图片,模型文件因体积较大需按说明自行下载转换。目前已有329人学习关注。读者可借此快速理解C#调用Yolov8的完整链路,掌握推理封装、结果解析与工程组织方式,适合作为人工智能部署方向的学习参考或项目原型基础。
1. 拿到这份 C# 部署 YOLOv8 源码,先搞清楚它能省掉哪段弯路
如果你用 C# 写过桌面端或工控上位机,又刚好被要求「把 YOLOv8 检测跑进现有程序里」,大概率经历过这个循环:Python 侧训练推理都顺,一到 C# 就卡在推理引擎的封装上,TensorRT 的 C++ API 翻半天,OpenVINO 的 C# 绑定又找不到能直接跑的样例。这份「基于 Csharp 部署 Yolov8 系列模型完整源码+数据」解决的正是这一段——它不是教你训练模型,而是把训练好的 YOLOv8 权重,通过 TensorRTSharp 和 OpenVinoSharp 两套封装,落到一个能编译、能出图的 C# 解决方案里。
资源本体是一个 Visual Studio 解决方案基于Csharp部署Yolov8.sln,配套src目录下拆出了TensorRTSharp、OpenVinoSharp、CommonSharp、ResultSharp、ModelDeployPlatform以及两个 Extern 外部依赖工程,demo目录里放了 10 张测试图和det_lable.txt、cls_lable.txt标签文件。模型文件因为体积原因没有直接打包,需要按说明自行下载转换。适合两类人:一是要在 Windows 上做 GPU 推理的 C# 开发者,二是想在 Intel 核显/CPU 上跑轻量检测的工控场景。下面按「结构 → 编译 → 推理 → 排错 → 进阶」的顺序拆开讲。
2. 源码结构拆解:TensorRTSharp 与 OpenVinoSharp 两条推理链路怎么选
2.1 先看清 src 下每个工程的角色
打开解决方案,src里的工程不是平铺的,而是按「推理后端 + 公共层 + 业务层」分了三层。理解这个分层,后面改代码才不会乱。
| 工程名 | 角色 | 依赖方向 |
|---|---|---|
| TensorRTSharp | NVIDIA GPU 推理封装,封装 TensorRT 的 C++ API | 依赖 TensorRTSharpExterm |
| OpenVinoSharp | Intel CPU/核显推理封装,封装 OpenVINO Runtime | 依赖 OpenVinoSharpExtern |
| CommonSharp | 图像预处理、后处理、NMS 等公共逻辑 | 被两个后端共用 |
| ResultSharp | 推理结果数据结构与绘制 | 依赖 CommonSharp |
| ModelDeployPlatform | 上层调用示例,串起加载、推理、出图 | 依赖上面全部 |
| TensorRTSharpExterm / OpenVinoSharpExtern | 原生动态库的 C# 互操作层 | 最底层 |
TensorRTSharpExterm和OpenVinoSharpExtern这两个名字带 Extern 的工程,本质是 P/Invoke 声明和原生库的桥接。很多人编译报「DllNotFound」,问题几乎都出在这一层——C# 侧声明了nvonnxparser或openvino的入口,但运行时目录里没有对应的.dll。
2.2 两条链路的选型理由
TensorRTSharp 走的是 NVIDIA 路线:YOLOv8 的.pt先导出 ONNX,再由 TensorRT 解析成 engine,推理时吃满 GPU。它的优势是延迟低,适合 1080p 以上、帧率要求高的场景;代价是 engine 与 GPU 架构、TensorRT 版本强绑定,换机器要重新生成。
OpenVinoSharp 走的是 Intel 路线:ONNX 经 OpenVINO 的模型优化器转成 IR(.xml+.bin),在 CPU 或核显上推理。它的优势是部署环境干净,不需要装 CUDA,工控机、办公本都能跑;代价是纯 CPU 下大模型帧率一般,适合 yolov8n/s 这类小模型。
选哪条,先问自己三个问题:目标机器有没有 NVIDIA 独显?推理是离线批处理还是实时视频流?模型是 n/s 还是 m/l?前两个答案决定后端,第三个决定模型规模。我一般会先用 OpenVinoSharp 把流程跑通,确认预处理和后处理没问题,再切 TensorRTSharp 压延迟——因为后处理逻辑是共用的,先跑通一条能省掉大量对照调试。
2.3 编译前必须补齐的原生依赖
源码能编译不代表能运行,原生库要单独准备。常见做法是:
# TensorRT 路线:确认本机 CUDA / cuDNN / TensorRT 版本三者匹配 # 以 TensorRT 8.6 + CUDA 11.8 为例,把下列目录加入 PATH 或拷到输出目录 # TensorRT/lib/*.dll # CUDA/bin/cudart64_*.dll、cublas64_*.dll # cuDNN/bin/cudnn64_*.dll # OpenVINO 路线:安装 OpenVINO Runtime 后,把 runtime/bin 下的 dll 拷到输出目录 # openvino.dll、openvino_intel_cpu_plugin.dll、openvino_ir_frontend.dll这段不是让你照抄路径,而是说明「C# 工程引用的是托管封装,真正干活的是这些原生 dll」。参数上要盯住版本:TensorRT 8.x 和 10.x 的 API 差异很大,源码里TensorRTSharp的封装是按某个大版本写的,版本对不上会在创建 builder 时直接抛异常。OpenVINO 同理,2023 和 2024 的 Runtime 接口有调整。判断方法很简单——看TensorRTSharpExterm里 P/Invoke 的函数名,去对应版本的官方头文件里搜,搜不到就是版本不匹配。
3. 从 ONNX 到 C# 推理:模型转换与最小可运行调用
3.1 模型文件为什么没打包,怎么自己转
资源里model目录只有一份「模型较大无法上传,请按照要求进行下载转换.txt」,这是合理的——YOLOv8 权重和转换后的 engine/IR 动辄几十上百 MB,塞进压缩包不现实。转换链路是固定的:
# 第一步:Python 侧把 .pt 导出为 ONNX,注意 opset 和动态轴 yolo export model=yolov8n.pt format=onnx opset=12 simplify=True dynamic=False # 第二步(TensorRT 路线):ONNX 转 engine,可用 trtexec 先验证 trtexec --onnx=yolov8n.onnx --saveEngine=yolov8n.engine --fp16 # 第二步(OpenVINO 路线):ONNX 转 IR mo --input_model yolov8n.onnx --output_dir ./ir --compress_to_fp16opset=12是兼容性比较稳的选择,太低不支持某些算子,太高部分推理后端解析不了。dynamic=False把输入固定成 640×640,能省掉动态 shape 带来的额外开销,代价是输入尺寸必须严格对齐。--fp16在支持半精度的卡上能明显降显存、提帧率,但精度敏感的任务要对比一下 mAP 再决定。转完先别急着进 C#,用trtexec或 OpenVINO 自带的 benchmark 跑一遍,确认模型本身没问题,否则后面报错你分不清是模型还是代码。
3.2 最小可运行的 C# 推理调用
ModelDeployPlatform里已经把加载、预处理、推理、后处理串好了,核心调用形态大致是这样:
// 以 OpenVINO 后端为例,TensorRT 后端接口形态类似 using var model = new OpenVinoModel("yolov8n.xml", "yolov8n.bin", "CPU"); using var image = Cv2.ImRead("demo/demo_1.jpg"); // 预处理:letterbox 到 640x640,保持长宽比,填充灰边 var input = Preprocess.Letterbox(image, 640, 640); // 推理:输入张量形状 [1,3,640,640],输出 [1,84,8400] var outputs = model.Infer(input); // 后处理:置信度过滤 + NMS,标签从 cls_lable.txt 读 var results = Postprocess.Decode(outputs, confThreshold: 0.25f, iouThreshold: 0.45f); ResultSharp.Draw(image, results, "cls_lable.txt"); Cv2.ImWrite("out.jpg", image);逻辑上分四段:预处理负责把任意尺寸图变成网络要的固定输入,letterbox 是关键,直接 resize 会让目标变形、坐标还原时对不上;推理段把张量喂给后端;后处理段做置信度阈值和 NMS;绘制段把框画回原图。参数里confThreshold和iouThreshold是最常调的两个——漏检多就降 conf,框重叠多就降 iou。cls_lable.txt和det_lable.txt的区别要分清:前者是分类标签,后者是检测类别名,用错文件会出现框对了但类别名全错的情况。
3.3 输入输出张量的对齐检查
推理跑不通,八成是张量形状对不上。YOLOv8 检测模型输出通常是[1, 84, 8400],84 = 4 个框坐标 + 80 类分数,8400 是候选框数。如果你用的是自定义数据集,类别数变了,84 这个维度就会变,后处理里写死的解析逻辑要跟着改。检查方法是在推理后打印一次输出维度:
Console.WriteLine($"output dims: {string.Join(",", outputs[0].Shape)}"); // 期望看到类似 1,84,8400;若是 1,8400,84 说明转置了,后处理要相应调整这个打印看着土,但能省掉大量「框画歪了」的排查时间。分类模型输出维度又不一样,别拿检测的后处理套分类。
4. 避坑与排查:编译能过但跑不起来的五类问题
4.1 现象:启动即报 DllNotFoundException
原因基本是原生 dll 没进输出目录,或者位数不匹配(x64 工程引了 x86 的库)。解决:把 TensorRT/OpenVINO 的运行时 dll 拷到bin/Debug/netX.x下,确认解决方案平台是 x64。用 Dependencies 工具看一眼托管 dll 的依赖树,缺哪个补哪个。
4.2 现象:engine 文件换台机器就加载失败
TensorRT engine 和 GPU 架构、驱动、TensorRT 版本绑定,A 机器生成的 engine 到 B 机器上大概率反序列化失败。解决:engine 不要跨机器拷贝,在目标机器上用 ONNX 重新生成;或者干脆分发 ONNX,首次运行时现场构建 engine 并缓存。
4.3 现象:检测框位置整体偏移或缩放
原因是预处理用了直接 resize 而不是 letterbox,后处理还原坐标时没按同样的比例和填充量反算。解决:预处理和后处理的缩放比例、padding 值必须成对出现,建议把这两个参数封装进同一个结构体传递,避免两处各写一套。
4.4 现象:CPU 推理帧率只有个位数
多半是用了 yolov8m/l 这类大模型跑纯 CPU,或者 OpenVINO 没指定推理设备、默认走了低效路径。解决:换 yolov8n/s,IR 转换时开--compress_to_fp16,初始化时显式指定CPU或GPU设备,并开异步推理把预处理和推理重叠起来。
4.5 现象:类别名全错或框全挤在一类
cls_lable.txt的行顺序和训练时的类别索引不一致,或者检测任务误用了分类标签文件。解决:标签文件的行号就是类别 id,逐行核对训练时的names配置,顺序错一位全盘皆错。
5. 进阶:把推理封装成可复用服务与精度验证
5.1 用统一接口屏蔽两个后端
ModelDeployPlatform里两条链路是分开调的,实际项目里更值得做的是抽一个接口,让上层不关心底层是 TensorRT 还是 OpenVINO:
public interface IYoloDetector : IDisposable { IReadOnlyList<Detection> Detect(Mat image); } // TensorRT 实现 public class TensorRtDetector : IYoloDetector { /* 加载 engine,复用 CommonSharp 前后处理 */ } // OpenVINO 实现 public class OpenVinoDetector : IYoloDetector { /* 加载 IR,复用同一套前后处理 */ }这样切换后端只改一行工厂代码,前后处理逻辑因为都在CommonSharp里,天然共用。我一般会再加一个配置项控制confThreshold、iouThreshold和设备类型,方便现场调参不用重新编译。
5.2 精度验证别只看「框画出来了」
框能画出来只说明流程通了,不代表结果可信。验证方法:拿demo目录里那 10 张图,分别用 Python 侧 ultralytics 和 C# 侧跑一遍,对比框数量、类别、坐标。坐标允许有小数点级误差,但类别和框数量应该一致。如果 C# 侧少框,优先查 NMS 的 iou 阈值和置信度阈值是否和 Python 侧一致;如果坐标系统性偏移,回到 4.3 查 letterbox。
| 对比项 | Python 侧 | C# 侧 | 允许偏差 |
|---|---|---|---|
| 框数量 | N | N | 0 |
| 类别 id | 一致 | 一致 | 0 |
| 坐标 | 基准 | 对比 | 1~2 像素 |
| 置信度 | 基准 | 对比 | 0.01 以内 |
5.3 一个容易被忽略的细节:图像通道顺序
OpenCV 读进来是 BGR,YOLOv8 训练时用的是 RGB。预处理里如果忘了Cv2.CvtColor(image, image, ColorConversionCodes.BGR2RGB),模型照样出框,但置信度会普遍偏低、小目标漏检明显。这个坑不报错,只表现为「效果比 Python 差一点」,最难查。从那以后我每次接新后端,都强制拿同一张图对比 BGR 和 RGB 两种输入的输出差异,确认通道顺序对了再往下做。希望帮到你。
本文还有配套的精品资源,点击获取