一.推理C++源码
0.源码链接
https://learnopencv.com/deep-learning-based-object-detection-using-yolov3-with-opencv-python-c/
1.初始化参数
//初始化参数
float confThreshold = 0.5; // 置信度阈值
float nmsThreshold = 0.4; // 非极大值抑制阈值
int inpWidth = 416; //网络输入尺寸宽度
int inpHeight = 416; //网络输入尺寸高度
2.加载模型与类别标签
//加载类别名称
string classesFile = "coco.names";
ifstream ifs(classesFile.c_str());
string line;
while (getline(ifs, line)) classes.push_back(line);
//给模型喂养配置文件与权重文件
String modelConfiguration = "yolov3.cfg";
String modelWeights = "yolov3.weights";
//加载网络模型
Net net = readNetFromDarknet(modelConfiguration, modelWeights);
net.setPreferableBackend(DNN_BACKEND_OPENCV);
net.setPreferableTarget(DNN_TARGET_CPU);
3.读取输入图片
outputFile = "yolo_out_cpp.avi";
if (parser.has("image"))
{
//打开图片文件
str = parser.get<String>("image");
ifstream ifile(str);
if (!ifile) throw("error");
cap.open(str);
str.replace(str.end()-4, str.end(), "_yolo_out_cpp.jpg");
outputFile = str;
}
else if (parser.has("video"))
{
//打开视频文件
str = parser.get<String>("video");
ifstream ifile(str);
if (!ifile) throw("error");
cap.open(str);
str.replace(str.end()-4, str.end(), "_yolo_out_cpp.avi");
outputFile = str;
}
//打开网络摄像机
else cap.open(parser.get<int>("device"));
catch(...) {
cout << "Could not open the input image/video stream" << endl;
return 0;
}
//初始化视频存储器,存储输出视频
if (!parser.has("image")) {
video.open(outputFile, VideoWriter::fourcc('M','J','P','G'), 28, Size(cap.get(CAP_PROP_FRAME_WIDTH), cap.get(CAP_PROP_FRAME_HEIGHT)));
}
4.处理每一帧
//处理每一帧
while (waitKey(1) < 0)
{
//从视频获取图像
cap >> frame;
// Stop the program if reached end of video
if (frame.empty()) {
cout << "Done processing !!!" << endl;
cout << "Output file is stored as " << outputFile << endl;
waitKey(3000);
break;
}
//从原图像创建一个4D的blob
blobFromImage(frame, blob, 1/255.0, cv::Size(inpWidth, inpHeight), Scalar(0,0,0), true, false);
//为网络设置输入
net.setInput(blob);
//运行前向推理的过程,得到输出层的输出
vector<Mat> outs;
net.forward(outs, getOutputsNames(net));
//移除低置信度的输出框
postprocess(frame, outs);
//展示效率信息。函数getPerfProfile返回每一层的推理时间
vector<double> layersTimes;
double freq = getTickFrequency() / 1000;
double t = net.getPerfProfile(layersTimes) / freq;
string label = format("Inference time for a frame : %.2f ms", t);
putText(frame, label, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255));
//保存带有检测框的一帧图像
Mat detectedFrame;
frame.convertTo(detectedFrame, CV_8U);
if (parser.has("image")) imwrite(outputFile, detectedFrame);
else video.write(detectedFrame);
imshow(kWinName, frame);
}
二.forward函数
//运行前向推理的过程,得到输出层的输出
vector<Mat> outs;
net.forward(outs, getOutputsNames(net));
函数getOutputsNames()
的输出为网络中的三个不同尺度的输出层名称(分别预测大、中、小物体)。
net.forward()
函数根据输出层名称得到输出结果,输出内容outs
为一个Mat
数组,每个Mat
为5+nc维度向量组(n行5+nc列矩阵,nc为类别的数量)。outs
数组的每一个元素都是一个5+nc维向量(总共有三个元素,均为Mat),该5+nc维向量是每一个输出层的输出,形式为blob二进制对象。
YOLOv4网络的输出为矩形框,每个矩形框由一个向量表示,所有矩形框组成一个向量组。每个向量的长度为类别数 + 5个参数,这五个参数的前四个分别是矩形框在图像上的位置center_x, center_y, width, height(均为比例,范围在0-1之间),第五个参数是该矩形框可能包含物体的置信度。从向量的第六个参数开始,分别表示矩形框中物体对应每个类别的置信度。
参考链接:https://www.freesion.com/article/72531365556/
三.net.setPreferableBackend与net.setPreferableTarget
1.setPreferableBackend()函数形参
DNN_BACKEND_INFERENCE_ENGINE;
DNN_BACKEND_OPENCV;
DNN_BACKEND_HALIDE;
DNN_BACKEND_CUDA;
DNN_BACKEND_DEFAULT;
其中,如果OpenCV是用英特尔的Inference Engine library编译的话,那么DNN_BACKEND_DEFAULT为DNN_BACKEND_INFERENCE_ENGINE,否则为DNN_BACKEND_OPENCV。
2.setPreferableTarget()函数形参
List of supported combinations backend / target:
| | DNN_BACKEND_OPENCV | DNN_BACKEND_INFERENCE_ENGINE | DNN_BACKEND_HALIDE | DNN_BACKEND_CUDA |
|------------------------|--------------------|------------------------------|--------------------|-------------------|
| DNN_TARGET_CPU | + | + | + | |
| DNN_TARGET_OPENCL | + | + | + | |
| DNN_TARGET_OPENCL_FP16 | + | + | | |
| DNN_TARGET_MYRIAD | | + | | |
| DNN_TARGET_FPGA | | + | | |
| DNN_TARGET_CUDA | | | | + |
| DNN_TARGET_CUDA_FP16 | | | | + |
参考链接:https://blog.csdn.net/weixin_43996161/article/details/113994433