首先下载 Yolo 训练好的模型:https://pjreddie.com/media/files/yolov3.weights
共3个文件:yolov3.cfg,yolov3.weights,coco.names
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenCvSharp;
using OpenCvSharp.Dnn;
namespace OpenCvSharpYolo3
{
class Program
{
static string[] Labels;
static void Main()
{
const string Cfg = @"h:\csharp\yolov3\yolov3.cfg";
const string Weight = @"h:\csharp\yolov3\yolov3.weights";
const string Names = @"h:\csharp\yolov3\coco.names";
const float threshold = 0.5f; //置信度阈值
const float nmsThreshold = 0.3f; //nms 阈值
//读入标签
Labels = File.ReadAllLines(Names).ToArray();
string videofile = @"h:\csharp\videos\vtest.avi";
var net = CvDnn.ReadNetFromDarknet(Cfg, Weight);
//读入模型和设置
net.SetPreferableBackend(3); // 3:DNN_BACKEND_OPENCV
net.SetPreferableTarget(0); //dnn target cpu
Cv2.NamedWindow("Result", WindowMode.Normal);
VideoCapture capture = new VideoCapture(videofile);
while (true)
{
Mat org = new Mat();
capture.Read(org);
if (org.Empty())
break;
//生成blob, 块尺寸可以是320/416/608
var blob = CvDnn.BlobFromImage(org, 1.0 / 255, new Size(320, 320), new Scalar(), true, false);
// 输入数据
net.SetInput(blob);
//获得输出层名
var outNames = net.GetUnconnectedOutLayersNames();
//转换成 Mat[]
var outs = outNames.Select(_ => new Mat()).ToArray();
net.Forward(outs, outNames);
//从输出中获得最佳的结果
//GetBestResult(outs, org, threshold, nmsThreshold);
//for nms
var classIds = new List<int>();
var confidences = new List<float>();
var probabilities = new List<float>();
var boxes = new List<Rect2d>();
var w = org.Width;
var h = org.Height;
const int prefix = 5; //分类概率
foreach (var prob in outs)
{
for (var i = 0; i < prob.Rows; i++)
{
var confidence = prob.At<float>(i, 4);
if (confidence > threshold) //置信度大于阈值
{
//获得识别概率
Cv2.MinMaxLoc(prob.Row[i].ColRange(prefix, prob.Cols), out _, out Point max);
var classes = max.X;
var probability = prob.At<float>(i, classes + prefix);
if (probability > threshold) //概率大于阈值
{
var centerX = prob.At<float>(i, 0) * w;
var centerY = prob.At<float>(i, 1) * h;
var width = prob.At<float>(i, 2) * w;
var height = prob.At<float>(i, 3) * h;
//准备nms(非极大值抑制)数据
classIds.Add(classes);
confidences.Add(confidence);
probabilities.Add(probability);
boxes.Add(new Rect2d(centerX, centerY, width, height));
}
}
}
}
//nms(非极大值抑制)提取分数最高的
//去除重叠和低置信度的目标框
CvDnn.NMSBoxes(boxes, confidences, threshold, nmsThreshold, out int[] indices);
foreach (var i in indices)
{
//画出目标方框并标注置信度和分类标签
var box = boxes[i];
//Draw(image, classIds[i], confidences[i], probabilities[i], box.X, box.Y, box.Width, box.Height);
//标签字符串
int classes = classIds[i];
var label = string.Format("{0} {1:0.0}%", Labels[classIds[i]], probabilities[i] * 100);
var x1 = (box.X - box.Width / 2) < 0 ? 0 : box.X - box.Width / 2;
//画方框
org.Rectangle(new Point(x1, box.Y - box.Height / 2), new Point(box.X + box.Width / 2, box.Y + box.Height / 2), Scalar.Red, 1);
//标签字符大小
var textSize = Cv2.GetTextSize(label, HersheyFonts.HersheyTriplex, 0.5, 1, out var baseline);
//画标签背景框
Cv2.Rectangle(org, new Rect(new Point(x1, box.Y - box.Height / 2 - textSize.Height - baseline),
new Size(textSize.Width, textSize.Height + baseline)), Scalar.Red, Cv2.FILLED);
Cv2.PutText(org, label, new Point(x1, box.Y - box.Height / 2 - baseline), HersheyFonts.HersheyTriplex, 0.5, Scalar.White);
}
//显示结果
Cv2.ImShow("Result", org);
int key = Cv2.WaitKey(10);
if (key == 27)
break;
}
}
}
}