2020年7月18日,OpenCV官网发布了OpenCV的最新版本OpenCV4.4.0,令我比较兴奋的是,其中支持了YOLOv4,之前的一段时间,我都在YOLO系列苦苦挣扎,虽然YOLOv4的性能很好,准确率也高,但当时opencv不支持,就导致在QT做界面时,读取不了yolov4的权重,无法进行目标检测,后来无奈只能选择了yolov3。
虽然用pytorch-yolov4也能得到很好的效果,但那样训练出来的权重文件后缀是pth,这么做,只能选择PyQT去做界面,考虑到Python的运行速度远不及C++,且到最后这个项目要进行实地的检测等等,还是放弃了。
当时我就觉得,pytorch-yolov4训练自己的模型,也只能在自己电脑上玩玩了,不能将项目落地实现。
但OpenCV4.4支持YOLOv4,它来了。。。(迟到了一个多月)


基于Opencv4.4的YOLOv4目标检测

  • 一.环境搭建
  • 二.用官方的权重进行目标检测
  • 三.用自己训练好的权重进行目标检测


一.环境搭建

1.OpenCV4.4的安装包、YOLOv4相关配置文件:
链接:https://pan.baidu.com/s/1Xg-Er1mJNCvSQyMt3B2HBw 提取码:p2ye
2.关于Visual Studio配置OpenCV,参考如下博客:
PS:我电脑上装的是VS2019,在Path系统环境变量中还是设置的vc15文件夹

二.用官方的权重进行目标检测

opencv 与 pytorch冲突 opencv和pytorch_c++


opencv 与 pytorch冲突 opencv和pytorch_opencv 与 pytorch冲突_02

源程序:

#pragma once
#include<opencv2\opencv.hpp>
#include<opencv2\dnn.hpp>
#include<fstream>
#include<iostream>

using namespace std;
using namespace cv;
using namespace cv::dnn;

int main()
{
 	//---------------------------------------加载类别---------------------------------------
 	ifstream classNamesFile("./model/coco.names");

	vector<string> classNamesVec;
 	if (classNamesFile.is_open())
 	{
  		string className = "";
  		while (std::getline(classNamesFile, className))
   			classNamesVec.push_back(className);
 	}
 	for (int i = 0; i < classNamesVec.size(); i++) {
  		cout << i + 1 << "\t" << classNamesVec[i].c_str() << endl;
 	}

	//---------------------------------------模型设置---------------------------------------
	String cfg = "./model/yolov4.cfg";
 	String weight = "./model/yolov4.weights";

	//模型读入
 	dnn::Net net = readNetFromDarknet(cfg, weight);

	//预处理读取的图像,并将图像读入网络
 	Mat frame = imread("./image/timg.jpg");
 	imshow("src", frame);
 	Mat inputBlob = blobFromImage(frame, 1.0 / 255, Size(608, 608), Scalar());
 	net.setInput(inputBlob);

	//获取未连接输出层
 	std::vector<String> outNames = net.getUnconnectedOutLayersNames();
 	for (int i = 0; i < outNames.size(); i++) {
  	cout << "output layer name : " << outNames[i].c_str() << endl;
 	}
	std::vector<Mat> outs;
 	net.forward(outs, outNames);

	//---------------------------------------目标检测---------------------------------------
 	//需要的变量
 	float* data;
 	Mat scores;

	vector<Rect> boxes;
 	vector<int> classIds;
 	vector<float> confidences;
 	int centerX, centerY, width, height, left, top;

	float confidenceThreshold = 0.2; // 置信度设置
 	double confidence;

	Point classIdPoint;

	//找出所有的目标及其位置
 	for (size_t i = 0; i < outs.size(); ++i) {
  		data = (float*)outs[i].data;
  		for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols) {
   			scores = outs[i].row(j).colRange(5, outs[i].cols);
   			minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
   			if (confidence > confidenceThreshold) {
    				centerX = (int)(data[0] * frame.cols);
    				centerY = (int)(data[1] * frame.rows);
    				width = (int)(data[2] * frame.cols);
    				height = (int)(data[3] * frame.rows);
    				left = centerX - width / 2;
    				top = centerY - height / 2;

				classIds.push_back(classIdPoint.x);
    				confidences.push_back((float)confidence);
    				boxes.push_back(Rect(left, top, width, height));
   			}
  		}
 	}

	vector<int> indices;
 	NMSBoxes(boxes, confidences, 0.3, 0.2, indices);

	//---------------------------------------效果展示---------------------------------------
	
	Scalar rectColor, textColor; //box 和 text 的颜色
 	Rect box, textBox;
 	int idx; //类别索引
 	String className;
 	Size labelSize;
	
	for (size_t i = 0; i < indices.size(); ++i) {
  		idx = indices[i];
  		className = classNamesVec[classIds[idx]];

		labelSize = getTextSize(className, FONT_HERSHEY_SIMPLEX, 0.5, 1, 0);
  		box = boxes[idx];
  		textBox = Rect(Point(box.x - 1, box.y),
   			Point(box.x + labelSize.width, box.y - labelSize.height));
  		rectColor = Scalar(idx * 11 % 256, idx * 22 % 256, idx * 33 % 256);
  		textColor = Scalar(255 - idx * 11 % 256, 255 - idx * 22 % 256, 255 - idx * 33 % 256);

		rectangle(frame, box, rectColor, 2, 8, 0);
  		rectangle(frame, textBox, rectColor, -1, 8, 0);
  		putText(frame, className.c_str(), Point(box.x, box.y - 2), FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1, 8);
  	}
  	imshow("dst", frame);
 	waitKey(0);

	return 0;
}

输出:

opencv 与 pytorch冲突 opencv和pytorch_c++_03


opencv 与 pytorch冲突 opencv和pytorch_权重_04


opencv 与 pytorch冲突 opencv和pytorch_计算机视觉_05

三.用自己训练好的权重进行目标检测

1.首先用Darknet-YOLOv4训练自己的权重文件,具体步骤参考我的这篇博客:
Windows10系统下YOLOv4—Darknet训练过程

2.训练好了之后会在darknet-master\build\darknet\x64\backup文件下生成你的权重文件,这里选择yolo-obj_4000.weights权重文件。

opencv 与 pytorch冲突 opencv和pytorch_opencv 与 pytorch冲突_06


还有选择darknet-master\build\darknet\x64文件下的yolo-obj.cfg文件。

opencv 与 pytorch冲突 opencv和pytorch_权重_07


3.修改上面程序中的几个地方,换成你需要检测的目标相关的权重配置文件。

opencv 与 pytorch冲突 opencv和pytorch_c++_08

opencv 与 pytorch冲突 opencv和pytorch_c++_09


opencv 与 pytorch冲突 opencv和pytorch_opencv_10