YOLO模型实现了快速目标识别的功能。 本文将介绍一下OpencvSharp 调用YOLO V5 模型的方法。
一.训练模型
模型训练使用github上的方法 https://github.com/ultralytics/yolov5 。相关项目里有着详细的介绍和使用方法说明
二.模型导出
上述模型训练方法使用的工具是Pytorch,可以导出.pt后缀的模型。但opencvsharp调用这个pt文件运行时有异常,估计是没有完全适配好。所以需要导出为onnx格式的模型文件。这样opencvsharp就可以正常调用了.导出语句可以参考下面的例子,其中export.py 就是上述yolov5项目里根目录就有的py文件。
python export.py --data xxxx.yaml --weights best.pt --img-size 224 416 --include onnx
三.c#调用
完成步骤二之后,会得到一个onnx文件,这里是best.onnx 。相应的c#调用函数如下:
详细说明参考注释
//读取模型
OpenCvSharp.Dnn.Net net = OpenCvSharp.Dnn.CvDnn.ReadNetFromOnnx("best.onnx");
//读取一张图片 我使用的模型 输入的是单色图片
Mat temp = Cv2.ImRead("Cam1_20221216124637_6629.BMP", ImreadModes.Grayscale);
//将图片缩放到合适大小
Cv2.Resize(temp, temp,new OpenCvSharp.Size(416,224));
DateTime date1 = DateTime.Now;
//将图片转化为tensor数据格式
Mat tensor_mat = OpenCvSharp.Dnn.CvDnn.BlobFromImage(temp, 1 / 255.0);
//输入tensor数据,节点是images,这个是export.py定义好的
net.SetInput(tensor_mat, "images");
//输出数据,节点是output,这个也是export.py定义好的
Mat result = net.Forward("output");
//维度变换
result = result.Reshape(1,result.Size().Width);
//预测框
List<Rect> boxes = new List<Rect>();
//根据阈值挑选出的识别出对象的框的序号
List<int> indices = new List<int>();
//预测框的得分
List<float> scores = new List<float>();
//循环结果数据,生成预测框大小得分等数据
for (int r = 0; r < result.Rows; r++) {
float cx = result.At<float>(r, 0);
float cy = result.At<float>(r, 1);
float w = result.At<float>(r, 2);
float h = result.At<float>(r, 3);
float sc = result.At<float>(r, 4);
Mat confs = result.Row(r).ColRange(5, 6);
confs *= sc;
double minV,maxV;
Cv2.MinMaxIdx(confs,out minV, out maxV);
scores.Add((float)maxV);
boxes.Add(new Rect((int)(cx - w / 2), (int)(cy - h / 2), (int)w, (int)h));
indices.Add(r);
}
int[] _indices;
//使用opencv NMSBoxes函数处理数据,得到预测结果
//其中0.6 0.45 是阈值
OpenCvSharp.Dnn.CvDnn.NMSBoxes(boxes, scores, 0.6f, 0.45f,out _indices);
DateTime date2 = DateTime.Now;
TimeSpan ts = date2 - date1;
Console.WriteLine("No. of Seconds (Difference) = {0}", ts.TotalMilliseconds);
//_indices 这个数组里保存了预测出的结果
for (int i = 0; i < _indices.Length; i++)
{
//预测框的序号
int idx = _indices[i];
//将框画出来 方便看一下 boxes[idx]一般就是想用的结果
Cv2.Rectangle(temp, boxes[idx],new OpenCvSharp.Scalar(127));
// scores[idx] 这个是得分
Console.WriteLine("scores:" + scores[idx]);
}
主页改版了?
换换口味~~