YOLOV8 C++ opecv_dnn模块部署

news/2024/7/10 23:29:29 标签: YOLO, c++, dnn

废话不多说:opencv>=4.7.0

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

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

头文件yoloV8.h

#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>
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<Detection> result, std::vector<cv::Scalar> color);
	virtual	vector<Detection> Detect(cv::Mat& SrcImg, cv::dnn::Net& net) = 0;
	float sigmoid_x(float x) { return static_cast<float>(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<std::string> 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<Detection> Detect(Mat& SrcImg, Net& net);
private:
	float confidenceThreshold{ 0.25 };
	float nmsIoUThreshold{ 0.45 };
};

class Yolov7 :public Yolo {
public:
	vector<Detection> 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<Detection> 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<Detection> result, vector<Scalar> 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<Detection> 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<cv::Mat> 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<int> class_ids;
//	std::vector<float> confidences;
//	std::vector<cv::Rect> 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<int> nms_result;
//	NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
//	vector<Detection> 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<Detection> 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<Ptr<Layer> > layer;
//	vector<string> 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<cv::Mat> 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<int> class_ids;//结果id数组
//	std::vector<float> confidences;//结果每个id对应置信度数组
//	std::vector<cv::Rect> 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<int> nms_result;
//	NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
//	vector<Detection> 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<Detection> 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<cv::Mat> 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<int> class_ids;
	std::vector<float> confidences;
	std::vector<cv::Rect> 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<int> nms_result;
	NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
	vector<Detection> 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 <iostream>
#include<opencv2//opencv.hpp>
#include<math.h>

#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<Scalar> 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<Detection> 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<Detection> 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<Detection> 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版本可以达到实时,有问题先尝试解决,搞定不了私信留言。


http://www.niftyadmin.cn/n/5041842.html

相关文章

【ICCV 2023】FocalFormer3D : Focusing on Hard Instance for 3D Object Detection

原文链接&#xff1a;https://arxiv.org/abs/2308.04556 1. 引言 目前的3D目标检测方法没有显式地去考虑漏检问题。   本文提出了困难实例探测&#xff08;HIP&#xff09;。受目标检测的级联解码头启发&#xff0c;HIP逐步探测误检样本&#xff0c;极大提高召回率。在每个阶…

使用jupyter运行sympy库

1.首先下载sympy插件&#xff1a; &#xff08;1&#xff09;在下图这里输入cmd (2)pip install sympy 若出现不信任此资源错误&#xff0c;改成pip install sympy--trusted-host pypi.tuna.tsinghua.edu.cn (3)检查是否安装成功 python import sympy sympy.__version__&#…

模块化软件架构:使用单体、微服务和模块化单体的优缺点

【squids.cn】 全网zui低价RDS&#xff0c;免费的迁移工具DBMotion、数据库备份工具DBTwin、SQL开发工具等 近年来&#xff0c;微服务架构在大多数软件解决方案中已经处于领先地位&#xff0c;而且在很多情况下&#xff0c;它经常被选择为我们开始开发的架构。然而&#xff0c…

苏宁滑块验证

网址&#xff1a;https://passport.suning.com/ids/login总结一下&#xff0c;别被他的表面现象给骗了&#xff0c;这玩意儿&#xff0c;个人认为&#xff0c;腾讯的都没法跟他比&#xff01;&#xff01;&#xff01; 难点&#xff1a;动态混淆&#xff0c;vmp&#xff0c;图片…

2023华为杯E题:出血性脑卒中临床智能诊疗建模(不断更新)

文章目录 一、 背景介绍二、 数据集介绍及建模目标第一题&#xff1a;血肿扩张风险相关因素探索建模。第一问要求第一问解题思路第二问第二问解体思路 第二题&#xff1a;血肿周围水肿的发生及进展建模&#xff0c;并探索治疗干预和水肿进展的关联关系第一问第一问思路第二问第…

PIL或Pillow学习1

PIL&#xff08; Python Imaging Library&#xff09;是 Python 的第三方图像处理库&#xff0c;由于其功能丰富&#xff0c;API 简洁易用&#xff0c;因此深受好评。 自 2011 年以来&#xff0c;由于 PIL 库更新缓慢&#xff0c;目前仅支持 Python 2.7 版本&#xff0c;这明显…

Spring学习笔记2 Spring的入门程序

Spring学习笔记1 启示录_biubiubiu0706的博客-CSDN博客 Spring官网地址:https://spring.io 进入github往下拉 用maven引入spring-context依赖 写spring的第一个程序 引入下面依赖,好比引入Spring的基本依赖 <dependency><groupId>org.springframework</groupId&…

2023上半年薪资报告出炉!人均月入过万?!

最近&#xff0c;大家都有听到经济回暖的消息吧&#xff1f;经过三年口罩大考之后&#xff0c;2023年上半年各行各业都迎来复苏&#xff0c;关于职场的话题讨论也不绝于耳。 现在就业环境如何&#xff1f;哪些行业更有前途&#xff1f;大家在求职时是选择一线城市还是回二、三…