『7x24小时有问必答』

前言

经常有人问:C# 能不能调用 YOLOv8 做物体检测?答案当然是可以。不过市面上的方案大多是基于 ONNX Runtime 或者 OpenVINO,用 NCNN 的倒是少见。
NCNN 是腾讯开源的轻量级推理框架,主打移动端和嵌入式设备,在 PC 上同样表现不错。这套封装的初衷很简单——把 YOLOv8 的推理过程打包成 C# 可直接调用的接口,不用关心张量怎么构造、NMS 怎么实现,几行代码就能跑起来。

项目介绍

Yolov8NcnnCsharp  是一个基于腾讯 NCNN 框架的 YOLOv8 C# 封装库。它把 NCNN 的推理逻辑封装成两个 DLL(Yolov8ChenZhe.dll  和  Yolov8Ncnn.dll),通过一个叫  CZyolov8  的类对外暴露接口。
这套封装的核心价值在于:你不用懂 NCNN 的底层实现,也不用操心图像预处理和后处理的细节,只需要加载模型文件,调用识别方法,就能拿到检测结果。所有推理逻辑都跑在 NCNN 引擎上,支持 CPU 和 GPU 两种推理模式。

项目功能

模型加载:加载 NCNN 框架的 param、bin 和 names 三个文件,支持带密码的加密模型
屏幕实时检测:指定屏幕区域,持续识别画面中的物体,返回位置和类别信息
图片检测:传入图片二进制数据或图片路径,返回检测结果
快速检测模式:只返回是否检测到物体,不输出详细结果,适合做触发判断
GPU 加速:支持 NVIDIA 显卡推理,也可在核显上运行
多线程支持:检测函数本身是单线程的,但可以在后台线程中循环调用实现实时检测
检测耗时统计:每次推理返回毫秒级耗时,方便调优

项目特点

基于腾讯 NCNN 框架,推理效率高
原生 C# 封装,接口简单直观
支持屏幕区域实时检测,适合做自动化工具
支持图片文件或二进制数据输入,灵活适配不同场景
自动管理检测结果的容器,避免重复分配内存
模型加载与推理分离,可运行时切换模型
支持模型加密密码,保护模型版权
开箱即用,两行代码就能完成推理

项目技术

技术项
说明
开发框架
.NET 10.0
推理引擎
腾讯 NCNN
封装语言
C#
模型格式
NCNN param + bin(可从 ONNX 转换)
类别配置
.names 文件,按行对应类别 ID
推理模式
CPU / GPU
目标平台
x86(32 位)
输入尺寸
640×640(可配置)

项目代码

下面是这套封装的完整使用示例,从环境配置到调用推理,一步步拆开来看。

第一步:准备环境

项目基于.NET 10.0 SDK,建议使用 32 位环境运行——因为开源的 DLL 是 32 位的。如果你的 C# 环境是 64 位,打包的时候选择 32 位运行即可。
下载安装 .NET SDK 10.0
https://dotnet.microsoft.com/zh-cn/

安装完成后在 cmd 里验证:
dotnet --version

# 显示 10.0.xxx 代表环境配置成功

新建一个控制台项目:
dotnet new console

把两个 DLL 文件复制到项目根目录:
Yolov8ChenZhe.dll
Yolov8Ncnn.dll

第二步:配置项目文件

修改  project.csproj,引用封装 DLL 并确保 NCNN 原生库能随程序一起发布:
<Project  Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>

       <OutputType>Exe<!--OutputType-->

       <TargetFramework>net10.0<!--TargetFramework-->

       <ImplicitUsings>enable<!--ImplicitUsings-->

       <Nullable>enable<!--Nullable-->

<!--PropertyGroup-->

<ItemGroup>

       <Reference  Include="Yolov8ChenZhe">

          <HintPath>Yolov8ChenZhe.dll<!--HintPath-->

       <!--Reference-->

<!--ItemGroup-->

<ItemGroup>

       <Content  Include="Yolov8Ncnn.dll">

          <CopyToOutputDirectory>PreserveNewest<!--CopyToOutputDirectory-->

       <!--Content-->

<!--ItemGroup-->

<!--Project-->

第三步:加载模型

在代码里引入命名空间并实例化  CZyolov8  对象:
using  Yolov8ChenZhe;

public  static  CZyolov8 cZyolov8 =  new  CZyolov8();

加载模型需要三个文件:
.param:NCNN 的模型结构文件,描述网络结构
.bin:NCNN 的模型权重文件,存储训练好的参数
.names:自定义的类别名文件,按行对应识别 ID
.names  文件的格式很简单,按行写即可。比如识别苹果和香蕉:
apple

banana

加载模型的代码:
bool  IsLoadSuccess = cZyolov8.LoadModelFromFile(

      paramFile: Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,  "./aaa.param")),

      binFile: Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,  "./aaa.bin")),

      namesFile: Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,  "./aaa.names")),

      cpuThreads:  1,         // CPU 线程数,建议填 1

      useGpu:  true,           // 开启 GPU 加速

      deviceId:  0,            // 显卡设备 ID

      password:  ""             // 模型密码,没有就留空

);

加载成功返回  true,失败返回  false。不推荐多线程同时加载模型,可能会崩溃。

第四步:开始推理

屏幕实时检测

在后台线程循环调用  DetectScreenArea,可以持续检测屏幕指定区域:
public  static  List<yolotarget> targets =  new  List<yolotarget>();

publicstaticstring  resultText =  "";

publicstaticint  useTime =  0;

Task.Run(() =>

{

       while  (true)

      {

             bool  IsDetectSuccess = cZyolov8.DetectScreenArea(

                  left:  0, top:  0, width:  1920, height:  1080,

                  targets:  out  Program.targets,

                  resultText:  out  Program.resultText,

                  useTime:  out  Program.useTime,

                  confidence:  0.4d,

                  targetSize:  640

            );

             if  (IsDetectSuccess)

            {

                   foreach  (YoloTarget i  in  Program.targets)

                  {

                        Console.WriteLine($"对象ID:{i.ObjId}--X:{i.X}--Y:{i.Y}--宽:{i.W}--高:{i.H}--可信度:{i.Prob}--名称:{i.Name}");

                  }

            }

      }

});

每个  YoloTarget  包含以下字段:
ObjId:识别对象的类别 ID
XY:检测框左上角坐标
WH:检测框宽度和高度
Prob:置信度(0~1)
Name:对应的类别名称
如果只需要判断屏幕上有没有目标物体,可以用快速模式:
bool  IsDetectSuccess = cZyolov8.DetectScreenAreaFast(

      left:  0, top:  0, width:  1920, height:  1080,

      confidence:  0.4d,

      targetSize:  640

);

// 返回 true 表示检测到物体,false 表示没有

图片检测

传入图片的二进制数据:

byte[] imageBytes = File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,  "./1.jpg"));

bool  IsDetectImageSuccess = cZyolov8.DetectImage(

      imageBytes: imageBytes,

      targets:  out  Program.targets,

      resultText:  out  Program.resultText,

      useTime:  out  Program.useTime,

      confidence:  0.4d,

      targetSize:  640

);

也可以直接传入图片路径:
string  imagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,  "./1.jpg");

bool  IsDetectImageSuccess = cZyolov8.DetectFile(

      imageFile: imagePath,

      targets:  out  Program.targets,

      resultText:  out  Program.resultText,

      useTime:  out  Program.useTime,

      confidence:  0.4d,

      targetSize:  640

);

第五步:卸载模型

推理结束后,调用  UnloadModel  释放资源:
bool  IsUninstallModelSuccess = cZyolov8.UnloadModel();

运行与打包

运行(32 位环境):
dotnet run

打包成单文件:
dotnet publish -c Release -r win-x86 --self-contained true -p:PublishSingleFile=true

项目效果

在实际使用中,这套封装的表现比较稳定。在 i7-10700 平台上,CPU 推理单帧耗时大概在 10-15ms 左右,开启 GPU 后能压到 8ms 以内。检测精度取决于你用的模型本身——这套封装只是推理工具,不包含模型训练能力,你需要自己准备训练好的 NCNN 格式模型。
DetectScreenArea  接口很适合做桌面自动化工具,比如监控某个应用界面上的特定图标或按钮,检测到后自动触发后续操作。搭配  DetectScreenAreaFast  做快速判断,能进一步降低 CPU 占用。

项目源码

目录结构
├── Program.cs                          # 示例代码

├── Yolov8ChenZhe.dll               # C# 封装 DLL

├── Yolov8Ncnn.dll                    # NCNN 原生库(32 位)

└── models/                              # 模型示例(守望先锋目标检测)

      ├── aaa.param

      ├── aaa.bin

      └── aaa.names

模型准备:如果你手里有 YOLOv8 的 ONNX 模型,可以用 NCNN 提供的  onnx2ncnn  工具转换成 param + bin 格式。具体命令参考 NCNN 官方文档。。

总结

这套封装把 NCNN 推理 YOLOv8 的过程简化到了极致:两个 DLL、一个类、几个方法调用,就能跑起目标检测。不需要懂 NCNN 的底层实现,也不用自己写图像预处理和后处理代码。特别适合两类场景:一是桌面自动化工具需要做视觉识别,二是想快速验证 YOLOv8 在 C# 环境下的运行效果。
当然,这套方案也有局限。目前只提供了 32 位版本,如果需要 64 位需要自己重新编译;模型必须转换成 NCNN 格式,多了一步转换工作;GPU 支持依赖 NVIDIA 显卡,核显虽然也能跑但效率会差一些。不过对于大部分桌面应用场景来说,这些都不是大问题。
如果大家需要在一个 C# 项目里集成 YOLOv8 物体检测能力,又不想折腾 ONNX Runtime 那一套复杂的接口,这个封装值得一试。

关键词

最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠]  社区,与其他热爱技术的同行一起交流心得,共同成长!
作者:小码编匠
出处:gitee.com/smallcore/DotNetCore
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!

END

推荐阅读

觉得有收获?不妨分享让更多人受益
关注「DotNet技术匠」,共同提升技术实力

收藏
点赞
分享
在看
</yolotarget></yolotarget>

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码