opencv部署onnx,并对jpg图片进行批量检测生成xml重要信息

 yolo.h

#pragma once
#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>

#define YOLO_P6 false //是否使用P6模型

struct Output {
	int id;             //结果类别id
	float confidence;   //结果置信度
	cv::Rect box;       //矩形框

};

class Yolo {
public:
	Yolo() {
	}
	~Yolo() {}
	bool readModel(cv::dnn::Net& net, std::string& netPath, bool isCuda); //读取模型
	bool Detect(cv::Mat& SrcImg, cv::dnn::Net& net, std::vector<Output>& output); //前向传播
	void drawPred(cv::Mat& img, std::vector<Output> result, std::vector<cv::Scalar> color); //绘制矩形框
	void PathDB(std::string image_path, std::string imwrite_path, std::string xmlpath); //读取以及存放路径
	void CreateXml(const char* img_name, const char* img_path, int img_width, int img_heigh, int check_number, std::string xmlpath); //, const char* object_name, int xmin, int ymin, int xmax, int ymax,std::string xmlpath
private:
#if(defined YOLO_P6 && YOLO_P6==true)
	const float netAnchors[4][6] = { { 19,27, 44,40, 38,94 },{ 96,68, 86,152, 180,137 },{ 140,301, 303,264, 238,542 },{ 436,615, 739,380, 925,792 } };

	const int netWidth = 1280;  //ONNX图片输入宽度
	const int netHeight = 1280; //ONNX图片输入高度

	const int strideSize = 4;  //stride size
#else
	const float netAnchors[3][6] = { { 10,13, 16,30, 33,23 },{ 30,61, 62,45, 59,119 },{ 116,90, 156,198, 373,326 } };

	const int netWidth = 640;   //ONNX图片输入宽度
	const int netHeight = 640;  //ONNX图片输入高度

	const int strideSize = 3;   //stride size
#endif // YOLO_P6

	const float netStride[4] = { 8, 16.0,32,64 };

	float boxThreshold = 0.7;
	float classThreshold = 0.7;

	float nmsThreshold = 0.40;
	float nmsScoreThreshold = boxThreshold * classThreshold;

	//std::vector<std::string> className = { "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" };  //COCO数据集类别

	std::vector<std::string> className = { "worter","open","unslot","broken","people","openwin","nocap" };  //铁路数据集类别


	/*std::vector<std::string> className = { "element"};*/
};

yolo.cpp

#include <iostream>
#include"yolo.h"
#include "tinystr.h";
#include "tinyxml.h";
#include <list>
using namespace std;
using namespace cv;
using namespace cv::dnn;


bool Yolo::readModel(Net& net, string& netPath, bool isCuda = true) {
	try {
		net = readNet(netPath);
	}
	catch (const std::exception&) {
		return false;
	}
	//cuda
	if (isCuda) {
		net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
		net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA_FP16);
	}
	//cpu
	else {
		net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
	}
	return true;
}
bool Yolo::Detect(Mat& SrcImg, Net& net, vector<Output>& output) {
	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;
	}
	blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(0, 0, 0), true, false);
	//如果在其他设置没有问题的情况下但是结果偏差很大,可以尝试下用下面两句语句
	//blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(104, 117, 123), true, false);
	//blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(114, 114,114), true, false);
	net.setInput(blob);
	std::vector<cv::Mat> netOutputImg;
	net.forward(netOutputImg, net.getUnconnectedOutLayersNames());
	std::vector<int> classIds;//结果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 = className.size() + 5;  //输出的网络宽度是类别数+5
	float* pdata = (float*)netOutputImg[0].data;
	for (int stride = 0; stride < strideSize; stride++) {    //stride
		int grid_x = (int)(netWidth / netStride[stride]);
		int grid_y = (int)(netHeight / netStride[stride]);
		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 box_score = pdata[4]; ;//获取每一行的box框中含有某个物体的概率
					if (box_score >= boxThreshold) {
						cv::Mat scores(1, className.size(), CV_32FC1, pdata + 5);
						Point classIdPoint;
						double max_class_socre;
						minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
						max_class_socre = (float)max_class_socre;
						if (max_class_socre >= classThreshold) {
							//rect [x,y,w,h]
							float x = pdata[0];  //x
							float y = pdata[1];  //y
							float w = pdata[2];  //w
							float h = pdata[3];  //h
							int left = (x - 0.5 * w) * ratio_w;
							int top = (y - 0.5 * h) * ratio_h;
							classIds.push_back(classIdPoint.x);
							confidences.push_back(max_class_socre * box_score);
							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, nmsScoreThreshold, nmsThreshold, nms_result);
	for (int i = 0; i < nms_result.size(); i++) {
		int idx = nms_result[i];
		Output result;
		result.id = classIds[idx];
		result.confidence = confidences[idx];
		result.box = boxes[idx];
		output.push_back(result);
	}
}                        // 图片名字            绝对路径         宽度            高度                                      物体类别        x小坐标   y小坐标    x大坐标   y大坐标         保存xml路径
void Yolo::CreateXml(const char* img_name, const char* img_path, int img_width, int img_heigh, int check_number, std::string xmlpath)//const char* object_name, int xmin, int ymin, int xmax, int ymax, 
{
	std::string a = "E:/DeployYoloV5/DeployYoloV5/1.jpg";
	const char* p = a.data();

	TiXmlDocument doc;     //创建一个文档类
	   //创建一个描述,构造参数(version,encoding,standalone)
	TiXmlElement* rootElement = new TiXmlElement("annotation");      //创建一个根element root

	TiXmlElement* PersonElement = new TiXmlElement("image");
	TiXmlElement* PersonElement2 = new TiXmlElement("img_size");
	

	rootElement->LinkEndChild(PersonElement);
	rootElement->LinkEndChild(PersonElement2);
	
	PersonElement->SetAttribute("img_name", img_name);
	PersonElement->SetAttribute("img_path", img_path);
	PersonElement2->SetAttribute("width", img_width);
	PersonElement2->SetAttribute("height", img_heigh);

	TiXmlElement* PersonElement3 = new TiXmlElement("object");
	rootElement->LinkEndChild(PersonElement3);
	PersonElement3->SetAttribute("Check_objectnumber", check_number);
	/*PersonElement3->SetAttribute("name", object_name);
	PersonElement3->SetAttribute("xmin", xmin);
	PersonElement3->SetAttribute("ymin", ymin);
	PersonElement3->SetAttribute("xmax", xmax);
	PersonElement3->SetAttribute("ymax", ymax);*/
	doc.LinkEndChild(rootElement);//文档添加root element

	string filenamexml = ".xml";
	//cout << xmlpath;
	string totalpath = xmlpath + filenamexml; 
	const char* path = totalpath.data();
	doc.SaveFile(path);//保存到文件new.xml
}

void Yolo::drawPred(Mat& img, vector<Output> result, vector<Scalar> color) {
	for (int i = 0; i < result.size(); i++) {
		//cout << result.size(); //查看检测到物体的数量
		int left, top;
		left = result[i].box.x;
		top = result[i].box.y;
		

		
		int color_num = i;
		rectangle(img, result[i].box, color[result[i].id], 10, 8);  //在图片中划出矩形框
		string label = className[result[i].id] + ":" + to_string(result[i].confidence);
		
		
		int baseLine;
		Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
		top = max(top, labelSize.height);
		putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 5, color[result[i].id], 3);
	}
	Mat dst;
	//resize(img, dst, Size(), 0.2, 0.3); //图片进行比例缩放
	//imshow("1", dst); //展示窗口
	//waitKey();  //窗口等待
	//destroyAllWindows();  // 关闭所有窗口
	//system("pause"); //让控制台暂停,等待用户信号
}

const char* object_name[100]; //声明一个char类型用于保存类别名字
void Yolo::PathDB(string image_path, string imwrite_path, std::string xmlpath) {  // 读取模型路径  
	Yolo test;
	Net net;
	string model_path = "E:/yolov5-master/runs/train/exp/weights/best.onnx";
	if (test.readModel(net, model_path, false)) {
		cout << "read net ok!" << endl; 
	}
	else {
		cout << "No found path of onnx!";
	}

	//生成随机颜色
	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));
	}
	vector<String>src_test;
	vector<Output> result;
	Mat img = imread(image_path);
	glob(image_path, src_test, false);//将文件夹路径下的所有图片路径保存到src_test中
	
	if (src_test.size() == 0) {//判断文件夹里面是否有图片
		printf("No image in file ! Please check the folder for pictures\n");
		exit(1);
	}
	//aaa();
	for (int i = 0; i < src_test.size(); i++)
	{
		Mat img = imread(src_test[i]);
		int pos = src_test[i].find_last_of("\\"); // 切分找到最后一个名字
		string imagepatht = src_test[i];
		const char* image_pathcc = imagepatht.data(); //传入图片绝对路径
		//cout << image_pathcc;
		string save_name = src_test[i].erase(0, pos);
		const char* image_name = save_name.data(); //传入图片名字
		cv::Mat dst;
		
		if (test.Detect(img, net, result)) 
		{

			test.drawPred(img, result, color);
			if (result.size() > 0)
			{				
				string name_xml_path = xmlpath + save_name;
				cout << name_xml_path;
				CreateXml(image_name, image_pathcc, img.rows, img.cols, result.size(), name_xml_path);   //xml生成	
				imwrite(imwrite_path + save_name, img);  //把有问题的图片进行保存																								   // label xm ym xmax ymax
				
			}
			result.clear(); // 对每次循环检测到图片信息的结果进行一次清除
			img.release(); //释放资源
		}

		else
		{
			cout << "Detect Failed!" << endl;
		}
		continue;
	}
	
}

YoloSave.cpp

// YoloSave.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include "yolo.h";
#include <iostream>
#include<opencv2//opencv.hpp>
#include<math.h>

using namespace std;
using namespace cv;
using namespace dnn;
int main(int argc, char* argv[]) //argc 总参数个数  argv[]是arcg个参数
{
	Yolo path;
	/*cout << "参数个数:" << argc << endl;
	cout << "参数内容:";*/
	for (int i = 0; i < argc; ++i)
	{
		cout << argv[i] << endl;
	}

	cout << "=============="<<endl;
	string str1 = argv[1];
	string str2 = argv[2];
	string str3 = argv[3];
		//cout << str1 << endl;
		//cout << str2 << endl;
		//cout << str3 << endl;
	
	path.PathDB(str1,str2,str3); //image_path, imwrite_path, svacexml_path
	//system("pause");
	

	
	return 0;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

#############################################################################

其余的头文件与源文件为xml提供的

需要传3个string类型的参数:

cmd命令行输入:

YoloSave.exe E:/yolov5-master/image_test E:/DeployYoloV5/YoloSave/outputimg E:/DeployYoloV5/YoloSave\outxml

查看结果:

这两个文件夹中生成了对应的检测到有问题的图片以及对应的xml

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是一个简单的使用OpenCVONNXRuntime在C++平台部署YOLOv7实时目标检测的代码示例: ```c++ #include <iostream> #include <chrono> #include <opencv2/opencv.hpp> #include <onnxruntime_cxx_api.h> using namespace std; using namespace cv; using namespace std::chrono; using namespace Ort; int main() { // 加载模型 Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test"); Ort::SessionOptions session_options; OrtSession* session; Ort::AllocatorWithDefaultOptions allocator; const char* model_path = "yolov7.onnx"; session = new Ort::Session(env, model_path, session_options); // 加载图像 Mat frame = imread("test.jpg"); if (frame.empty()) { cout << "读取图像失败!" << endl; return -1; } // 预处理图像 Mat input_blob = blobFromImage(frame, 1 / 255.0, Size(416, 416), Scalar(0, 0, 0), true, false); Tensor input_tensor = Tensor( DataType::FLOAT, {1, 3, input_blob.rows, input_blob.cols}, input_blob.data ); // 运行模型 vector<const char*> input_names = {"input_1"}; vector<const char*> output_names = {"Identity_1", "Identity_2", "Identity_3"}; vector<Ort::Value> input_tensors = {input_tensor}; vector<Ort::Value> output_tensors = session->Run(Ort::RunOptions{}, input_names.data(), input_tensors.data(), input_names.size(), output_names.data(), output_names.size()); // 后处理输出结果 vector<Mat> detections; for (int i = 0; i < output_tensors.size(); i++) { float* output_data = output_tensors[i].GetTensorMutableData<float>(); vector<int64_t> output_shape = output_tensors[i].GetTensorTypeAndShapeInfo().GetShape(); Mat detection(output_shape[1], output_shape[0], CV_32F, output_data); detections.push_back(detection); } float confidence_threshold = 0.5; vector<int> class_ids; vector<float> confidences; vector<Rect> boxes; for (int i = 0; i < detections.size(); i++) { for (int j = 0; j < detections[i].rows; j++) { float* data = detections[i].ptr<float>(j); float confidence = data[4]; if (confidence > confidence_threshold) { int class_id = j; float left = data[0] * frame.cols; float top = data[1] * frame.rows; float right = data[2] * frame.cols; float bottom = data[3] * frame.rows; int width = right - left + 1; int height = bottom - top + 1; class_ids.push_back(class_id); confidences.push_back(confidence); boxes.push_back(Rect(left, top, width, height)); } } } for (int i = 0; i < boxes.size(); i++) { Scalar color(0, 255, 0); rectangle(frame, boxes[i], color, 2); string label = format("%.2f", confidences[i]); int baseline; Size label_size = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseline); rectangle(frame, Point(boxes[i].x, boxes[i].y - label_size.height - baseline), Point(boxes[i].x + label_size.width, boxes[i].y), color, FILLED); putText(frame, label, Point(boxes[i].x, boxes[i].y - baseline), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0)); } // 显示结果 namedWindow("YOLOv7", WINDOW_NORMAL); resizeWindow("YOLOv7", 800, 600); imshow("YOLOv7", frame); waitKey(0); // 释放资源 delete session; return 0; } ``` 这段代码首先使用ONNXRuntime加载YOLOv7模型,然后利用OpenCV读取图像并进行预处理,接着调用ONNXRuntime运行模型,最后根据模型输出结果进行后处理并显示检测结果。需要注意的是,这段代码只是一个简单的示例,实际部署时需要根据具体的场景进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝士是只猫

开源使得世界变得更美丽

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值