EmguCV学习笔记 C# 11.5 目标检测
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。
教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客
教程C#版本请访问:EmguCV学习笔记 C# 目录-CSDN博客
笔者的博客网址:https://blog.csdn.net/uruseibest
教程配套文件及相关说明以及如何获得pdf教程和代码,请移步:EmguCV学习笔记
学习VB.Net知识,请移步: vb.net 教程 目录_vb中如何用datagridview-CSDN博客
学习C#知识,请移步:C# 教程 目录_c#教程目录-CSDN博客
11.5 目标检测
11.5.1 Yolo
YOLO(You Only Look Once)是一种流行的目标检测算法,它使用单个神经网络同时进行对象检测和对象分类。相比于传统的目标检测算法,YOLO在目标检测任务中表现优秀,有更快的速度和更高的准确性,被广泛应用于自动驾驶、安防监控等领域。
【代码位置:frmChapter11】Button3_Click
//目标检测:yolo
private void Button3_Click(object sender, EventArgs e)
{
//对象分类,coco.names文件提供了80类对象
string[] classnames = System.IO.File.ReadAllLines("C:\\learnEmgucv\\yolo\\coco.names");
//需要测试的图像文件
Mat m = new Mat("C:\\learnEmgucv\\dnntest.jpg", ImreadModes.Color);
int hm = m.Height;
int wm = m.Width;
Net net;
//读取yolo的推理模型文件
net = DnnInvoke.ReadNetFromDarknet("C:\\learnEmgucv\\yolo\\yolov3.cfg",
"C:\\learnEmgucv\\yolo\\yolov3.weights");
net.SetPreferableBackend(Emgu.CV.Dnn.Backend.OpenCV);
net.SetPreferableTarget(Target.Cpu);
Mat blob;
//注意:BlobFromImage的size参数
//以前使用(416,416),现在是(608, 608),参看yolov3.cfg。
//如果继续使用(416,416),那么会有部分物体检测不出
blob = DnnInvoke.BlobFromImage(m, 1.0 / 255.0, new Size(608, 608), new MCvScalar(0, 0, 0), true, false);
net.SetInput(blob);
//获取推理模型中未连接的输出层名称列表
string[] names = net.UnconnectedOutLayersNames;
//或者以下方法获得
//int[] outLayers = net.UnconnectedOutLayers;
//string[] layerNames = net.LayerNames;
//string[] names = new string[outLayers.Length];
//for (int i = 0; i < outLayers.Length; i++)
// names[i] = layerNames[outLayers[i] - 1];
VectorOfMat mout = new VectorOfMat();
net.Forward(mout, names);
//只有一张图片,只需要mout(0)即可
Mat mout1 = new Mat();
mout1 = mout[0];
//返回二维数组
Single[,] detection;
detection = (Single[,])mout1.GetData();
int rows = detection.GetLength(0);
int cols = detection.GetLength(1);
//置信度
List<Single> lstYoloConf = new List<Single>();
//方框坐标
List<Rectangle> lstYoloRects = new List<Rectangle>();
//识别到的物体序号
List<int> lstYoloIndex = new List<int>();
//行数为检测出对象的数量
//每列从 0 到 84,一共85个元素,
// 0-1为矩形区域的中心坐标X和Y的百分比
// 2-3为矩形的宽度和高度的百分比
// 4为矩形区域的置信度
// 5-84为对应的80类对象分别的置信度
//存在两个置信度
for (int i = 0; i < rows; i++)
{
//第一个置信度是矩形区域的置信度
Single conf = detection[i, 4];
//先判断矩形区域的置信度是否符合要求
if (conf > 0.5)
{
Single x = detection[i, 0] * wm; //百分比,需要乘以源图像的宽度
Single y = detection[i, 1] * hm; //百分比,需要乘以源图像的高度
Single w = detection[i, 2] * wm; //百分比,需要乘以源图像的宽度
Single h = detection[i, 3] * hm; //百分比,需要乘以源图像的高度
for (int k = 5; k <= 84; k++)
{
//第二个置信度是检测出的对象分类的置信度
//判断对象分类的置信度是否符合要求
if (detection[i, k] > 0.5)
{
lstYoloConf.Add(conf);
lstYoloRects.Add(new Rectangle((int)(x - w / 2), (int)(y - h / 2), (int)w, (int)h));
//注意,是从第6个(索引为5)开始
lstYoloIndex.Add(k - 5);
}
}
}
}
//利用NMS把重复位置的rectangle去除
int[] selectedObj;
selectedObj = DnnInvoke.NMSBoxes(lstYoloRects.ToArray(), lstYoloConf.ToArray(), 0.2F, 0.3F);
for (int i = 0; i < lstYoloRects.Count; i++)
{
//只画出被保留下來的rectangle
if (selectedObj.Contains(i))
{
//输出检测出的对象所在矩形区域
CvInvoke.Rectangle(m, lstYoloRects[i], new MCvScalar(0, 255, 0), 1);
//获得检测出的对象的种类名称
string objName = classnames[lstYoloIndex[i]];
//输出检测出的对象名称
CvInvoke.PutText(m, objName,
new Point(lstYoloRects[i].X, lstYoloRects[i].Y - 5),
FontFace.HersheyTriplex, 0.3, new MCvScalar(0, 0, 255));
//输出检测出的置信度
CvInvoke.PutText(m, lstYoloConf[i].ToString(),
new Point(lstYoloRects[i].X + 40, lstYoloRects[i].Y - 5),
FontFace.HersheyComplex, 0.3, new MCvScalar(255, 0, 0));
}
}
ImageBox1.Image = m;
}
输出结果如下图所示:
图11-2 使用YOLO进行目标检测的结果
11.5.2 SSD
SSD(Single Shot MultiBox Detector)是一种流行的目标检测算法,它使用单个神经网络同时进行对象检测和对象分类。相比于传统的目标检测算法,SSD可以快速准确地检测出图像中的对象,被广泛应用于自动驾驶、安防监控等领域。
【代码位置:frmChapter11】Button4_Click
//ssd
private void Button4_Click(object sender, EventArgs e)
{
//对象分类,object_detection_classes_pascal_voc.txt文件提供了21类对象(含background)
string[] classnames = System.IO.File.ReadAllLines("C:\\learnEmgucv\\ssd\\object_detection_classes_pascal_voc.txt");
//需要测试的图像文件
Mat m = new Mat("C:\\learnEmgucv\\dnntest.jpg", ImreadModes.Color);
Single hm = m.Height;
Single wm = m.Width;
Net net;
//读取SSD的推理模型文件
net = DnnInvoke.ReadNetFromCaffe("C:\\learnEmgucv\\ssd\\MobileNetSSD_deploy.prototxt.txt",
"C:\\learnEmgucv\\ssd\\MobileNetSSD_deploy.caffemodel");
net.SetPreferableBackend(Emgu.CV.Dnn.Backend.OpenCV);
net.SetPreferableTarget(Target.Cpu);
//输入图像必须是(300,300),参看MobileNetSSD_deploy.prototxt.txt中input_shape
Mat mCopy = new Mat();
CvInvoke.Resize(m, mCopy, new Size(300, 300));
Mat blob = DnnInvoke.BlobFromImage(mCopy, 0.007843, new Size(300, 300),
new MCvScalar(127.5,127.5, 127.5), false, false);
net.SetInput(blob);
//
Mat mout = new Mat();
mout = net.Forward();
//返回四维数组
Single[,,,] fout;
fout = (Single[,,,] )mout.GetData();
//检测到的所有对象的数量
int allObjCount = fout.GetLength(2);
//识别到的对象序号
List<int> lstSsdIndex = new List<int>();
//置信度
List<Single> lstSsdConf = new List<Single>();
//矩形
List<Rectangle> lstSsdRects = new List<Rectangle>();
for (int i = 0; i < allObjCount; i++)
{
//置信度
Single conf;
conf = fout[0, 0, i, 2];
if (conf > 0.5)
{
lstSsdConf.Add(conf);
//对应对象序号
lstSsdIndex.Add((int)fout[0,0,i,1]);
//左上角X
int lbx = (int)(fout[0, 0, i, 3] * wm);
//左上角Y
int lby = (int)(fout[0, 0, i, 4] * hm);
//右下角X
int rtx = (int)(fout[0, 0, i, 5] * wm);
//右下角Y
int rty = (int)(fout[0, 0, i, 6] * hm);
//对应矩形
lstSsdRects.Add(new Rectangle(lbx, lby, rtx - lbx, rty - lby));
}
}
for (int i = 0; i < lstSsdIndex.Count; i++)
{
//检测出的对象所在矩形区域
CvInvoke.Rectangle(m, lstSsdRects[i], new MCvScalar(0, 255, 0), 1);
string objName = classnames[lstSsdIndex[i]];
Console.WriteLine(objName + lstSsdConf[i]);
//输出检测出的对象名称
CvInvoke.PutText(m, objName,
new Point(lstSsdRects[i].X, lstSsdRects[i].Y - 5),
FontFace.HersheyTriplex, 0.3, new MCvScalar(0, 0, 255));
//输出检测出的置信度
CvInvoke.PutText(m, lstSsdConf[i].ToString(),
new Point(lstSsdRects[i].X + 40, lstSsdRects[i].Y - 5),
FontFace.HersheyComplex, 0.3, new MCvScalar(255, 0, 0));
}
ImageBox1.Image = m;
}
输出结果如下图所示:
图11-3使用SSD进行目标检测的结果