YOLOV8 C++ opecv_dnn模块部署

废话不多说:opencv>=4.7.0

opencv编译不做解释,需要的话翻看别的博主的编译教程

代码饱含V5,V7,V8部署内容

头文件yoloV8.h

#pragma once
#include
#include
using namespace std;
using namespace cv;
using namespace cv::dnn;
struct Detection
{
	int class_id{ 0 };//结果类别id
	float confidence{ 0.0 };//结果置信度
	cv::Rect box{};//矩形框
};
class Yolo {
public:
	bool readModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
	void drawPred(cv::Mat& img, std::vector result, std::vector color);
	virtual	vector Detect(cv::Mat& SrcImg, cv::dnn::Net& net) = 0;
	float sigmoid_x(float x) { return static_cast(1.f / (1.f + exp(-x))); }
	Mat formatToSquare(const cv::Mat& source)
	{
		int col = source.cols;
		int row = source.rows;
		int _max = MAX(col, row);
		cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC3);
		source.copyTo(result(cv::Rect(0, 0, col, row)));
		return result;
	}
	const int netWidth = 640;   //ONNX图片输入宽度
	const int netHeight = 640;  //ONNX图片输入高度


	float modelConfidenceThreshold{ 0.0 };
	float modelScoreThreshold{ 0.0 };
	float modelNMSThreshold{ 0.0 };

	std::vector classes = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
		"fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
		"elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
		"skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
		"tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
		"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
		"potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
		"microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
		"hair drier", "toothbrush" };
};

class Yolov5 :public Yolo {
public:
	vector Detect(Mat& SrcImg, Net& net);
private:
	float confidenceThreshold{ 0.25 };
	float nmsIoUThreshold{ 0.45 };
};

class Yolov7 :public Yolo {
public:
	vector Detect(Mat& SrcImg, Net& net);
private:

	float confidenceThreshold{ 0.25 };
	float nmsIoUThreshold{ 0.45 };

	const int strideSize = 3;   //stride size
	const float netStride[4] = { 8.0, 16.0, 32.0, 64.0 };
	const float netAnchors[3][6] = { {12, 16, 19, 36, 40, 28},{36, 75, 76, 55, 72, 146},{142, 110, 192, 243, 459, 401} }; //yolov7-P5 anchors
};

class Yolov8 :public Yolo {
public:
	vector Detect(Mat& SrcImg, Net& net);
private:
	float confidenceThreshold{ 0.25 };
	float nmsIoUThreshold{ 0.70 };
};

源文件yoloV8.cpp:

#include"yoloV8.h"

bool Yolo::readModel(Net& net, string& netPath, bool isCuda = false) {
	try {
		net = readNetFromONNX(netPath);
	}
	catch (const std::exception&) {
		return false;
	}
	if (isCuda) {
		net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
		net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
	}
	else {
		net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
	}
	return true;
}

void Yolo::drawPred(Mat& img, vector result, vector colors) {

	for (int i = 0; i < result.size(); ++i)
	{
		Detection detection = result[i];

		cv::Rect box = detection.box;
		cv::Scalar color = colors[detection.class_id];

		// Detection box
		cv::rectangle(img, box, color, 2);

		// Detection box text
		std::string classString = classes[detection.class_id] + ' ' + std::to_string(detection.confidence).substr(0, 4);
		cv::Size textSize = cv::getTextSize(classString, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);
		cv::Rect textBox(box.x, box.y - 40, textSize.width + 10, textSize.height + 20);

		cv::rectangle(img, textBox, color, cv::FILLED);
		cv::putText(img, classString, cv::Point(box.x + 5, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);
	}
}

//vector Yolov5::Detect(Mat& img, Net& net) {
//
//	img = formatToSquare(img);
//	cv::Mat blob;
//	cv::dnn::blobFromImage(img, blob, 1.0 / 255.0, Size(netWidth, netHeight), cv::Scalar(), true, false);
//	net.setInput(blob);
//
//	std::vector outputs;
//	net.forward(outputs, net.getUnconnectedOutLayersNames());
//
//
//
//	float* pdata = (float*)outputs[0].data;
//	float x_factor = (float)img.cols / netWidth;
//	float y_factor = (float)img.rows / netHeight;
//
//	std::vector class_ids;
//	std::vector confidences;
//	std::vector boxes;
//
//	// yolov5 has an output of shape (batchSize, 25200, 85) (Num classes + box[x,y,w,h] + confidence[c])
//	int rows = outputs[0].size[1];
//	int dimensions = outputs[0].size[2];
//
//	for (int i = 0; i < rows; ++i)
//	{
//		float confidence = pdata[4];
//		if (confidence >= modelConfidenceThreshold)
//		{
//
//			cv::Mat scores(1, classes.size(), CV_32FC1, pdata + 5);
//			cv::Point class_id;
//			double max_class_score;
//
//			minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
//
//			if (max_class_score > modelScoreThreshold)
//			{
//				confidences.push_back(confidence);
//				class_ids.push_back(class_id.x);
//
//				float x = pdata[0];
//				float y = pdata[1];
//				float w = pdata[2];
//				float h = pdata[3];
//
//				int left = int((x - 0.5 * w) * x_factor);
//				int top = int((y - 0.5 * h) * y_factor);
//
//				int width = int(w * x_factor);
//				int height = int(h * y_factor);
//
//				boxes.push_back(cv::Rect(left, top, width, height));
//			}
//		}
//		pdata += dimensions;
//	}
//
//	vector nms_result;
//	NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
//	vector detections{};
//	for (unsigned long i = 0; i < nms_result.size(); ++i) {
//		int idx = nms_result[i];
//		Detection result;
//		result.class_id = class_ids[idx];
//		result.confidence = confidences[idx];
//		result.box = boxes[idx];
//		detections.push_back(result);
//	}
//	return detections;
//}
//
//vector Yolov7::Detect(Mat& SrcImg, Net& net) {
//	Mat blob;
//	int col = SrcImg.cols;
//	int row = SrcImg.rows;
//	int maxLen = MAX(col, row);
//	Mat netInputImg = SrcImg.clone();
//	if (maxLen > 1.2 * col || maxLen > 1.2 * row) {
//		Mat resizeImg = Mat::zeros(maxLen, maxLen, CV_8UC3);
//		SrcImg.copyTo(resizeImg(Rect(0, 0, col, row)));
//		netInputImg = resizeImg;
//	}
//	vector > layer;
//	vector layer_names;
//	layer_names = net.getLayerNames();
//	blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(0, 0, 0), true, false);
//	net.setInput(blob);
//	std::vector netOutput;
//	net.forward(netOutput, net.getUnconnectedOutLayersNames());
//#if CV_VERSION_MAJOR==4 && CV_VERSION_MINOR>6
//	std::sort(netOutput.begin(), netOutput.end(), [](Mat& A, Mat& B) {return A.size[2] > B.size[2]; });//opencv 4.6 三个output顺序为40 20 80,之前版本的顺序为80 40 20 
//#endif
//	std::vector class_ids;//结果id数组
//	std::vector confidences;//结果每个id对应置信度数组
//	std::vector boxes;//每个id矩形框
//	float ratio_h = (float)netInputImg.rows / netHeight;
//	float ratio_w = (float)netInputImg.cols / netWidth;
//	int net_width = classes.size() + 5;  //输出的网络宽度是类别数+5
//	for (int stride = 0; stride < strideSize; stride++) {    //stride
//		float* pdata = (float*)netOutput[stride].data;
//		int grid_x = (int)(netWidth / netStride[stride]);
//		int grid_y = (int)(netHeight / netStride[stride]);
//		// cv::Mat tmp(grid_x * grid_y * 3, classes.size() + 5, CV_32FC1, pdata);
//		for (int anchor = 0; anchor < 3; anchor++) {	//anchors
//			const float anchor_w = netAnchors[stride][anchor * 2];
//			const float anchor_h = netAnchors[stride][anchor * 2 + 1];
//			for (int i = 0; i < grid_y; i++) {
//				for (int j = 0; j < grid_x; j++) {
//					float confidence = sigmoid_x(pdata[4]); ;//获取每一行的box框中含有物体的概率
//					cv::Mat scores(1, classes.size(), CV_32FC1, pdata + 5);
//					Point classIdPoint;
//					double max_class_socre;
//					minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
//					max_class_socre = sigmoid_x(max_class_socre);
//					if (max_class_socre * confidence >= confidenceThreshold) {
//						float x = (sigmoid_x(pdata[0]) * 2.f - 0.5f + j) * netStride[stride];  //x
//						float y = (sigmoid_x(pdata[1]) * 2.f - 0.5f + i) * netStride[stride];   //y
//						float w = powf(sigmoid_x(pdata[2]) * 2.f, 2.f) * anchor_w;   //w
//						float h = powf(sigmoid_x(pdata[3]) * 2.f, 2.f) * anchor_h;  //h
//						int left = (int)(x - 0.5 * w) * ratio_w + 0.5;
//						int top = (int)(y - 0.5 * h) * ratio_h + 0.5;
//						class_ids.push_back(classIdPoint.x);
//						confidences.push_back(max_class_socre * confidence);
//						boxes.push_back(Rect(left, top, int(w * ratio_w), int(h * ratio_h)));
//					}
//					pdata += net_width;//下一行
//				}
//			}
//		}
//	}
//
//	//执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)
//	vector nms_result;
//	NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
//	vector detections{};
//	for (unsigned long i = 0; i < nms_result.size(); ++i) {
//		int idx = nms_result[i];
//		Detection result;
//		result.class_id = class_ids[idx];
//		result.confidence = confidences[idx];
//		result.box = boxes[idx];
//		detections.push_back(result);
//	}
//	return detections;
//}

vector Yolov8::Detect(Mat& modelInput, Net& net) {
	modelInput = formatToSquare(modelInput);
	cv::Mat blob;
	cv::dnn::blobFromImage(modelInput, blob, 1.0 / 255.0, Size(netWidth, netHeight), cv::Scalar(), true, false);
	net.setInput(blob);

	std::vector outputs;
	net.forward(outputs, net.getUnconnectedOutLayersNames());


	// yolov8 has an output of shape (batchSize, 84,  8400) (Num classes + box[x,y,w,h])
	int rows = outputs[0].size[2];
	int dimensions = outputs[0].size[1];

	outputs[0] = outputs[0].reshape(1, dimensions);
	cv::transpose(outputs[0], outputs[0]);

	float* data = (float*)outputs[0].data;
	// Mat detect_output(8400, 84, CV_32FC1, data);// 8400 = 80*80+40*40+20*20
	float x_factor = (float)modelInput.cols / netWidth;
	float y_factor = (float)modelInput.rows / netHeight;

	std::vector class_ids;
	std::vector confidences;
	std::vector boxes;

	for (int i = 0; i < rows; ++i)
	{
		cv::Mat scores(1, classes.size(), CV_32FC1, data + 4);
		cv::Point class_id;
		double maxClassScore;

		minMaxLoc(scores, 0, &maxClassScore, 0, &class_id);
		if (maxClassScore > modelConfidenceThreshold)
		{
			confidences.push_back(maxClassScore);
			class_ids.push_back(class_id.x);

			float x = data[0];
			float y = data[1];
			float w = data[2];
			float h = data[3];

			int left = int((x - 0.5 * w) * x_factor);
			int top = int((y - 0.5 * h) * y_factor);

			int width = int(w * x_factor);
			int height = int(h * y_factor);

			boxes.push_back(cv::Rect(left, top, width, height));
		}
		data += dimensions;
	}

	//执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)
	vector nms_result;
	NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
	vector detections{};
	for (unsigned long i = 0; i < nms_result.size(); ++i) {
		int idx = nms_result[i];
		Detection result;
		result.class_id = class_ids[idx];
		result.confidence = confidences[idx];
		result.box = boxes[idx];
		detections.push_back(result);
	}
	return detections;
}

main.CPP

#include "yoloV8.h"
#include 
#include
#include

#define USE_CUDA false //use opencv-cuda

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


int main()
{
	string img_path = "./bus.jpg";
	string model_path3 = "./yolov8n.onnx";
	Mat img = imread(img_path);


	vector color;
	srand(time(0));
	for (int i = 0; i < 80; i++) {
		int b = rand() % 256;
		int g = rand() % 256;
		int r = rand() % 256;
		color.push_back(Scalar(b, g, r));
	}




	/*Yolov5 yolov5; Net net1;
	Mat img1 = img.clone();
	bool isOK = yolov5.readModel(net1, model_path1, USE_CUDA);
	if (isOK) {
		cout << "read net ok!" << endl;
	}
	else {
		cout << "read onnx model failed!";
		return -1;
	}
	vector result1 = yolov5.Detect(img1, net1);
	yolov5.drawPred(img1, result1, color);
	Mat dst = img1({ 0, 0, img.cols, img.rows });
	imwrite("results/yolov5.jpg", dst);



	Yolov7 yolov7; Net net2;
	Mat img2 = img.clone();
	isOK = yolov7.readModel(net2, model_path2, USE_CUDA);
	if (isOK) {
		cout << "read net ok!" << endl;
	}
	else {
		cout << "read onnx model failed!";
		return -1;
	}
	vector result2 = yolov7.Detect(img2, net2);
	yolov7.drawPred(img2, result2, color);
	dst = img2({ 0, 0, img.cols, img.rows });
	imwrite("results/yolov7.jpg", dst);*/


	Yolov8 yolov8; Net net3;
	Mat img3 = img.clone();
	bool isOK = yolov8.readModel(net3, model_path3, USE_CUDA);
	if (isOK) {
		cout << "read net ok!" << endl;
	}
	else {
		cout << "read onnx model failed!";
		return -1;
	}
	vector result3 = yolov8.Detect(img3, net3);
	yolov8.drawPred(img3, result3, color);
	Mat dst = img3({ 0, 0, img.cols, img.rows });
	cv::imshow("aaa", dst);
	imwrite("./yolov8.jpg", dst);
	cv::waitKey(0);


	return 0;
}

opencv编译需要时间久,GPU版本可以达到实时,有问题先尝试解决,搞定不了私信留言。

你可能感兴趣的:(YOLO,c++,dnn)