C#使用YOLO26进行图像识别(目标检测)

纯属个人意见,用python做开发,对象类型不明确和包冲突的问题很烦人,所以还是想用熟悉的C#去做图像识别。其实用C#做也很简单。

本文只实现使用模型进行检测,所以需要预先准备好已经训练好的模型。我们以官方训练好的模型yolo26n.pt为例。

一、导出ONNX模型

在python中,将.pt模型导出为ONNX格式。

python 复制代码
from ultralytics import YOLO

model = YOLO("yolo26n.pt")

model.export(format="onnx")

运行上述代码,即可生成一个名为yolo26n.onnx的文件,可在C#中使用。

二、安装环境

在NuGet中安装Microsoft.ML.OnnxRuntime库。

另外,我们对图像的处理使用OpenCV,所以需要安装OpenCVSharp的库:OpenCvSharp4OpenCvSharp4.ExtensionsOpenCvSharp4.runtime.win

三、图像预处理

YOLO模型的图片输入大小是640*640,所以需要先将图片转为此大小:

C# 复制代码
int maxEdge = Math.Max(src.Rows, src.Cols);
float ratio = 1.0f * ModelSize / maxEdge;
int newHeight = (int)(src.Rows * ratio);
int newWidth = (int)(src.Cols * ratio);
Mat resize_image = src.Resize(new Size(newWidth, newHeight));
int width = resize_image.Cols;
int height = resize_image.Rows;
if (width != ModelSize || height != ModelSize)
{
    resize_image = resize_image.CopyMakeBorder(0, ModelSize - newHeight, 0, ModelSize - newWidth, BorderTypes.Constant, new Scalar(255, 255, 255));
}

另外,对于RGB颜色图片,YOLO模型处理的颜色顺序是RGB,但OpenCV中存储图片的默认顺序是BGR,两者是反转的,需要先反过来:

C# 复制代码
Cv2.CvtColor(resize_image, resize_image, ColorConversionCodes.BGR2RGB);

然后,我们需要将像素数据进行归一化:

C# 复制代码
var input_tensor = new DenseTensor<float>(new[] { 1, 3, ModelSize, ModelSize });
for (int y = 0; y < resize_image.Height; y++)
{
    for (int x = 0; x < resize_image.Width; x++)
    {
        input_tensor[0, 0, y, x] = resize_image.At<Vec3b>(y, x)[0] / 255f;
        input_tensor[0, 1, y, x] = resize_image.At<Vec3b>(y, x)[1] / 255f;
        input_tensor[0, 2, y, x] = resize_image.At<Vec3b>(y, x)[2] / 255f;
    }
}

四、导入和运行模型

加载模型:

C# 复制代码
var OnnxSession = new InferenceSession(modelPath);

运行模型,得到结果:

C# 复制代码
var input_container = new List<NamedOnnxValue>()
{
    NamedOnnxValue.CreateFromTensor(OnnxSession.InputNames[0], input_tensor)
};

var result_infer = OnnxSession.Run(input_container);
var results_onnxvalue = result_infer.ToArray();
var result_tensors = results_onnxvalue[0].AsTensor<float>();
var result_array = result_tensors.ToArray();

五、处理结果数据

yolo26n模型的检测结果是一个三维数组:

第一维对应每张输入图像。输入可以是多张图片,每张图片对应一组二维结果。

第二维是每一组检测结果。默认都是300项,已按置信度由高到低排序,所以发现置信度偏低的项,就可以停止检索了。另外,结果默认已做了非极大值抑制,没有必要再排除可能重复的框。

第三维有6项,分别是x1, y1, x2, y2, confidence, classId。

这里需要说明的是,yolo26n使用COCO数据进行训练,类型定义为:

复制代码
0: 'person', 1: 'bicycle', 2: 'car', 3: 'motorcycle', 4: 'airplane', 5: 'bus', 6: 'train', 7: 'truck', 8: 'boat', 9: 'traffic light', 10: 'fire hydrant', 11: 'stop sign', 12: 'parking meter', 13: 'bench', 14: 'bird', 15: 'cat', 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 20: 'elephant', 21: 'bear', 22: 'zebra', 23: 'giraffe', 24: 'backpack', 25: 'umbrella', 26: 'handbag', 27: 'tie', 28: 'suitcase', 29: 'frisbee', 30: 'skis', 31: 'snowboard', 32: 'sports ball', 33: 'kite', 34: 'baseball bat', 35: 'baseball glove', 36: 'skateboard', 37: 'surfboard', 38: 'tennis racket', 39: 'bottle', 40: 'wine glass', 41: 'cup', 42: 'fork', 43: 'knife', 44: 'spoon', 45: 'bowl', 46: 'banana', 47: 'apple', 48: 'sandwich', 49: 'orange', 50: 'broccoli', 51: 'carrot', 52: 'hot dog', 53: 'pizza', 54: 'donut', 55: 'cake', 56: 'chair', 57: 'couch', 58: 'potted plant', 59: 'bed', 60: 'dining table', 61: 'toilet', 62: 'tv', 63: 'laptop', 64: 'mouse', 65: 'remote', 66: 'keyboard', 67: 'cell phone', 68: 'microwave', 69: 'oven', 70: 'toaster', 71: 'sink', 72: 'refrigerator', 73: 'book', 74: 'clock', 75: 'vase', 76: 'scissors', 77: 'teddy bear', 78: 'hair drier', 79: 'toothbrush'

下面的代码提取出检测结果,代码中将识别框转回了原图大小。

C# 复制代码
Dictionary<int, List<Prediction>> predictions = new Dictionary<int, List<Prediction>>();
for (int i = 0; i < result_array.Length; i += 6)
{
    float x1 = result_array[i];
    float y1 = result_array[i + 1];
    float x2 = result_array[i + 2];
    float y2 = result_array[i + 3];
    float score = result_array[i + 4];
    int classId = (int)result_array[i + 5];

    if (score > minScore)
    {
        Prediction p = new Prediction()
        {
            Score = score,
            BBox = new Rect((int)Math.Round(x1 / ratio), (int)Math.Round(y1 / ratio), (int)Math.Round((x2 - x1) / ratio), (int)Math.Round((y2 - y1) / ratio))
        };
        if (predictions.ContainsKey(classId))
        {
            predictions[classId].Add(p);
        }
        else
        {
            predictions.Add(classId, new List<Prediction>() { p });
        }
    }
    else
    {
        break;
    }
}

测试原图:

测试结果:

相关推荐
h64648564h10 小时前
CANN 昇腾图像预处理流水线:CV 算子深度解读
opencv·计算机视觉·目标跟踪
深度学习lover10 小时前
<数据集>yolo水下垃圾识别<目标检测>
人工智能·深度学习·yolo·目标检测·水下垃圾数据集
白日做梦Q11 小时前
Docker部署YOLOv8训练+推理完整教程(含报错解决)
yolo·docker·容器
魔法阵维护师11 小时前
从零开发游戏需要学习的c#模块,第二十三章(粒子效果 —— 让游戏“活”起来本课目标)
学习·游戏·c#
魔法阵维护师11 小时前
从零开发游戏需要学习的c#模块,第二十二章(音效与背景音乐)
学习·游戏·c#
动物园猫12 小时前
人群计数行人检测数据集分享(适用于YOLO系列深度学习检测任务)
人工智能·深度学习·yolo
爱睡懒觉的焦糖玛奇朵19 小时前
【从视频到数据集:焦糖玛奇朵的魔法工具使用说明】
人工智能·python·深度学习·学习·算法·yolo·音视频
魔法阵维护师1 天前
从零开发游戏需要学习的c#模块,第十六章(安装 MonoGame 并创建第一个窗口)
学习·游戏·c#·monogame
吴可可1231 天前
用Teigha修改并保存CAD文件
数据库·算法·c#