0
点赞
收藏
分享

微信扫一扫

Opencv C++部署YOLOv3v4

梦想家们 2022-01-10 阅读 47

一.推理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;
}

// Get the video writer initialized to save the output video
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;

其中,如果OpneCV是用英特尔的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

举报

相关推荐

0 条评论