使用ONNXRuntime部署YOLOV5(c++)

#include <fstream>
#include <sstream>
#include <iostream>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
//#include <cuda_provider_factory.h>   // 提供cuda加速
#include <onnxruntime_cxx_api.h>	 // C或c++的api

// 命名空间
using namespace std;
using namespace cv;
using namespace Ort;

// 自定义配置结构
struct Configuration
{
	public: 
	float confThreshold; // Confidence threshold
	float nmsThreshold;  // Non-maximum suppression threshold
	float objThreshold;  //Object Confidence threshold
	string modelpath;
};

// 定义BoxInfo结构类型
typedef struct BoxInfo
{
	float x1;
	float y1;
	float x2;
	float y2;
	float score;
	int label;
} BoxInfo;

// int endsWith(string s, string sub) {
// 	return s.rfind(sub) == (s.length() - sub.length()) ? 1 : 0;
// }

// const float anchors_640[3][6] = { {10.0,  13.0, 16.0,  30.0,  33.0,  23.0},
// 								 {30.0,  61.0, 62.0,  45.0,  59.0,  119.0},
// 								 {116.0, 90.0, 156.0, 198.0, 373.0, 326.0} };

// const float anchors_1280[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} };

class YOLOv5
{
public:
	YOLOv5(Configuration config);
	void detect(Mat& frame);
private:
	float confThreshold;
	float nmsThreshold;
	float objThreshold;
	int inpWidth;
	int inpHeight;
	int nout;
	int num_proposal;
	int num_classes;
	string classes[80] = {"person", "bicycle", "car", "motorbike", "aeroplane", "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", "sofa", "pottedplant",
							"bed", "diningtable", "toilet", "tvmonitor", "laptop", "mouse",
							"remote", "keyboard", "cell phone", "microwave", "oven", "toaster",
							"sink", "refrigerator", "book", "clock", "vase", "scissors",
							"teddy bear", "hair drier", "toothbrush"};

	const bool keep_ratio = true;
	vector<float> input_image_;		// 输入图片
	void normalize_(Mat img);		// 归一化函数
	void nms(vector<BoxInfo>& input_boxes);  
	Mat resize_image(Mat srcimg, int *newh, int *neww, int *top, int *left);

	Env env = Env(ORT_LOGGING_LEVEL_ERROR, "yolov5-6.1"); // 初始化环境
	Session *ort_session = nullptr;    // 初始化Session指针选项
	SessionOptions sessionOptions = SessionOptions();  //初始化Session对象
	//SessionOptions sessionOptions;
	vector<char*> input_names;  // 定义一个字符指针vector
	vector<char*> output_names; // 定义一个字符指针vector
	vector<vector<int64_t>> input_node_dims; // >=1 outputs  ,二维vector
	vector<vector<int64_t>> output_node_dims; // >=1 outputs ,int64_t C/C++标准
};

YOLOv5::YOLOv5(Configuration config)
{
	this->confThreshold = config.confThreshold;
	this->nmsThreshold = config.nmsThreshold;
	this->objThreshold = config.objThreshold;
	this->num_classes = sizeof(this->classes)/sizeof(this->classes[0]);  // 类别数量
	this->inpHeight = 640;
	this->inpWidth = 640;
	
	string model_path = config.modelpath;
	//std::wstring widestr = std::wstring(model_path.begin(), model_path.end());  //用于UTF-16编码的字符

	//gpu, https://blog.csdn.net/weixin_44684139/article/details/123504222
	//CUDA加速开启
   // OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0);

	sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);  //设置图优化类型
	//ort_session = new Session(env, widestr.c_str(), sessionOptions);  // 创建会话,把模型加载到内存中
	//ort_session = new Session(env, (const ORTCHAR_T*)model_path.c_str(), sessionOptions); // 创建会话,把模型加载到内存中
	ort_session = new Session(env, (const char*)model_path.c_str(), sessionOptions);
	size_t numInputNodes = ort_session->GetInputCount();  //输入输出节点数量                         
	size_t numOutputNodes = ort_session->GetOutputCount(); 
	AllocatorWithDefaultOptions allocator;   // 配置输入输出节点内存
	for (int i = 0; i < numInputNodes; i++)
	{
		input_names.push_back(ort_session->GetInputName(i, allocator));		// 内存
		Ort::TypeInfo input_type_info = ort_session->GetInputTypeInfo(i);   // 类型
		auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();  // 
		auto input_dims = input_tensor_info.GetShape();    // 输入shape
		input_node_dims.push_back(input_dims);	// 保存
	}
	for (int i = 0; i < numOutputNodes; i++)
	{
		output_names.push_back(ort_session->GetOutputName(i, allocator));
		Ort::TypeInfo output_type_info = ort_session->GetOutputTypeInfo(i);
		auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();
		auto output_dims = output_tensor_info.GetShape();
		output_node_dims.push_back(output_dims);
	}
	this->inpHeight = input_node_dims[0][2];
	this->inpWidth = input_node_dims[0][3];
	this->nout = output_node_dims[0][2];      // 5+classes
	this->num_proposal = output_node_dims[0][1];  // pre_box

}

Mat YOLOv5::resize_image(Mat srcimg, int *newh, int *neww, int *top, int *left)
{
	int srch = srcimg.rows, srcw = srcimg.cols;
	*newh = this->inpHeight;
	*neww = this->inpWidth;
	Mat dstimg;
	if (this->keep_ratio && srch != srcw) {
		float hw_scale = (float)srch / srcw;
		if (hw_scale > 1) {
			*newh = this->inpHeight;
			*neww = int(this->inpWidth / hw_scale);
			resize(srcimg, dstimg, Size(*neww, *newh), INTER_AREA);
			*left = int((this->inpWidth - *neww) * 0.5);
			copyMakeBorder(dstimg, dstimg, 0, 0, *left, this->inpWidth - *neww - *left, BORDER_CONSTANT, 114);
		}
		else {
			*newh = (int)this->inpHeight * hw_scale;
			*neww = this->inpWidth;
			resize(srcimg, dstimg, Size(*neww, *newh), INTER_AREA);
			*top = (int)(this->inpHeight - *newh) * 0.5;
			copyMakeBorder(dstimg, dstimg, *top, this->inpHeight - *newh - *top, 0, 0, BORDER_CONSTANT, 114);
		}
	}
	else {
		resize(srcimg, dstimg, Size(*neww, *newh), INTER_AREA);
	}
	return dstimg;
}

void YOLOv5::normalize_(Mat img)
{
	//    img.convertTo(img, CV_32F);
	int row = img.rows;
	int col = img.cols;
	this->input_image_.resize(row * col * img.channels());  // vector大小
	for (int c = 0; c < 3; c++)  // bgr
	{
		for (int i = 0; i < row; i++)  // 行
		{
			for (int j = 0; j < col; j++)  // 列
			{
				float pix = img.ptr<uchar>(i)[j * 3 + 2 - c];  // Mat里的ptr函数访问任意一行像素的首地址,2-c:表示rgb
				this->input_image_[c * row * col + i * col + j] = pix / 255.0;

			}
		}
	}
}

void YOLOv5::nms(vector<BoxInfo>& input_boxes)
{
	sort(input_boxes.begin(), input_boxes.end(), [](BoxInfo a, BoxInfo b) { return a.score > b.score; }); // 降序排列
	vector<float> vArea(input_boxes.size());
	for (int i = 0; i < input_boxes.size(); ++i)
	{
		vArea[i] = (input_boxes[i].x2 - input_boxes[i].x1 + 1)
			* (input_boxes[i].y2 - input_boxes[i].y1 + 1);
	}
	// 全初始化为false,用来作为记录是否保留相应索引下pre_box的标志vector
	vector<bool> isSuppressed(input_boxes.size(), false);  
	for (int i = 0; i < input_boxes.size(); ++i)
	{
		if (isSuppressed[i]) { continue; }
		for (int j = i + 1; j < input_boxes.size(); ++j)
		{
			if (isSuppressed[j]) { continue; }
			float xx1 = max(input_boxes[i].x1, input_boxes[j].x1);
			float yy1 = max(input_boxes[i].y1, input_boxes[j].y1);
			float xx2 = min(input_boxes[i].x2, input_boxes[j].x2);
			float yy2 = min(input_boxes[i].y2, input_boxes[j].y2);

			float w = max(0.0f, xx2 - xx1 + 1);
			float h = max(0.0f, yy2 - yy1 + 1);
			float inter = w * h;	// 交集
			if(input_boxes[i].label == input_boxes[j].label)
			{
				float ovr = inter / (vArea[i] + vArea[j] - inter);  // 计算iou
				if (ovr >= this->nmsThreshold)
				{
					isSuppressed[j] = true;
				}
			}	
		}
	}
	// return post_nms;
	int idx_t = 0;
       // remove_if()函数 remove_if(beg, end, op) //移除区间[beg,end)中每一个“令判断式:op(elem)获得true”的元素
	input_boxes.erase(remove_if(input_boxes.begin(), input_boxes.end(), [&idx_t, &isSuppressed](const BoxInfo& f) { return isSuppressed[idx_t++]; }), input_boxes.end());
	// 另一种写法
	// sort(input_boxes.begin(), input_boxes.end(), [](BoxInfo a, BoxInfo b) { return a.score > b.score; }); // 降序排列
	// vector<bool> remove_flags(input_boxes.size(),false);
	// auto iou = [](const BoxInfo& box1,const BoxInfo& box2)
	// {
	// 	float xx1 = max(box1.x1, box2.x1);
	// 	float yy1 = max(box1.y1, box2.y1);
	// 	float xx2 = min(box1.x2, box2.x2);
	// 	float yy2 = min(box1.y2, box2.y2);
	// 	// 交集
	// 	float w = max(0.0f, xx2 - xx1 + 1);
	// 	float h = max(0.0f, yy2 - yy1 + 1);
	// 	float inter_area = w * h;
	// 	// 并集
	// 	float union_area = max(0.0f,box1.x2-box1.x1) * max(0.0f,box1.y2-box1.y1)
	// 					   + max(0.0f,box2.x2-box2.x1) * max(0.0f,box2.y2-box2.y1) - inter_area;
	// 	return inter_area / union_area;
	// };
	// for (int i = 0; i < input_boxes.size(); ++i)
	// {
	// 	if(remove_flags[i]) continue;
	// 	for (int j = i + 1; j < input_boxes.size(); ++j)
	// 	{
	// 		if(remove_flags[j]) continue;
	// 		if(input_boxes[i].label == input_boxes[j].label && iou(input_boxes[i],input_boxes[j])>=this->nmsThreshold)
	// 		{
	// 			remove_flags[j] = true;
	// 		}
	// 	}
	// }
	// int idx_t = 0;
    // // remove_if()函数 remove_if(beg, end, op) //移除区间[beg,end)中每一个“令判断式:op(elem)获得true”的元素
	// input_boxes.erase(remove_if(input_boxes.begin(), input_boxes.end(), [&idx_t, &remove_flags](const BoxInfo& f) { return remove_flags[idx_t++]; }), input_boxes.end());
}

void YOLOv5::detect(Mat& frame)
{
	int newh = 0, neww = 0, padh = 0, padw = 0;
	Mat dstimg = this->resize_image(frame, &newh, &neww, &padh, &padw);
	this->normalize_(dstimg);
	// 定义一个输入矩阵,int64_t是下面作为输入参数时的类型
	array<int64_t, 4> input_shape_{ 1, 3, this->inpHeight, this->inpWidth };

    //创建输入tensor
	auto allocator_info = MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
	Value input_tensor_ = Value::CreateTensor<float>(allocator_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size());

	// 开始推理
	vector<Value> ort_outputs = ort_session->Run(RunOptions{ nullptr }, &input_names[0], &input_tensor_, 1, output_names.data(), output_names.size());   // 开始推理
	/generate proposals
	vector<BoxInfo> generate_boxes;  // BoxInfo自定义的结构体
	float ratioh = (float)frame.rows / newh, ratiow = (float)frame.cols / neww;
	float* pdata = ort_outputs[0].GetTensorMutableData<float>(); // GetTensorMutableData
	for(int i = 0; i < num_proposal; ++i) // 遍历所有的num_pre_boxes
	{
		//nout=85    cx,cy,w,h,box_score,class_score1,class_score2,.....,class_score80
		int index = i * nout;      // prob[b*num_pred_boxes*(classes+5)]  
		float obj_conf = pdata[index + 4];  // 置信度分数
		if (obj_conf > this->objThreshold)  // 大于阈值
		{
			int class_idx = 0;
			float max_class_socre = 0;
			for (int k = 0; k < this->num_classes; ++k)
			{
				if (pdata[k + index + 5] > max_class_socre)
				{
					max_class_socre = pdata[k + index + 5];
					class_idx = k;
				}
			}
			max_class_socre *= obj_conf;   // 最大的类别分数*置信度
			if (max_class_socre > this->confThreshold) // 再次筛选
			{ 
				//const int class_idx = classIdPoint.x;
				float cx = pdata[index];  //x
				float cy = pdata[index+1];  //y
				float w = pdata[index+2];  //w
				float h = pdata[index+3];  //h

				float xmin = (cx - padw - 0.5 * w)*ratiow;
				float ymin = (cy - padh - 0.5 * h)*ratioh;
				float xmax = (cx - padw + 0.5 * w)*ratiow;
				float ymax = (cy - padh + 0.5 * h)*ratioh;

				generate_boxes.push_back(BoxInfo{ xmin, ymin, xmax, ymax, max_class_socre, class_idx });
			}
		}
	}

	// Perform non maximum suppression to eliminate redundant overlapping boxes with
	// lower confidences
	nms(generate_boxes);
	for (size_t i = 0; i < generate_boxes.size(); ++i)
	{
		int xmin = int(generate_boxes[i].x1);
		int ymin = int(generate_boxes[i].y1);
		rectangle(frame, Point(xmin, ymin), Point(int(generate_boxes[i].x2), int(generate_boxes[i].y2)), Scalar(0, 0, 255), 2);
		string label = format("%.2f", generate_boxes[i].score);
		label = this->classes[generate_boxes[i].label] + ":" + label;
		putText(frame, label, Point(xmin, ymin - 5), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 255, 0), 1);
	}
}

int main(int argc,char *argv[])
{
	clock_t startTime,endTime; //计算时间
	Configuration yolo_nets = { 0.3, 0.5, 0.3,"/home/user/下载/yolov5s.onnx" };
	YOLOv5 yolo_model(yolo_nets);
	string imgpath = "/home/user/yolov5-onnxruntime-master/images/bus.jpg";
	Mat srcimg = imread(imgpath);

	double timeStart = (double)getTickCount();
	startTime = clock();//计时开始	
	yolo_model.detect(srcimg);
	endTime = clock();//计时结束
	double nTime = ((double)getTickCount() - timeStart) / getTickFrequency();
	cout << "clock_running time is:" <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
    cout << "The run time is:" << (double)clock() /CLOCKS_PER_SEC<< "s" << endl;
	cout << "getTickCount_running time :" << nTime << "sec\n" << endl;
	// static const string kWinName = "Deep learning object detection in ONNXRuntime";
	// namedWindow(kWinName, WINDOW_NORMAL);
	// imshow(kWinName, srcimg);
	imshow("rusult",srcimg);
	imwrite("restult_ort.jpg",srcimg);
	waitKey(0);
	// destroyAllWindows();
	return 0;
}

yolov5使用onnxruntime进行c++部署_AI、明察秋毫的博客-CSDN博客

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 首先,您需要将Yolov5模型转换为ONNX格式。您可以使用PyTorch将模型转换为ONNX格式,然后使用ONNX Runtime C++ API加载和运行模型。 以下是一些步骤: 1. 安装PyTorch和ONNX Runtime 2. 使用PyTorch将Yolov5模型转换为ONNX格式。您可以使用以下代码: ``` import torch import torchvision # Load the model model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True) # Export the model to ONNX format input_shape = (1, 3, 640, 640) torch.onnx.export(model, torch.randn(*input_shape), "yolov5s.onnx", opset_version=11) ``` 3. 在C++中加载和运行模型。您可以使用以下代码: ``` #include <iostream> #include <vector> #include <chrono> #include <opencv2/opencv.hpp> #include "onnxruntime_cxx_api.h" using namespace std; using namespace cv; using namespace std::chrono; using namespace onnxruntime; int main() { // Load the model Ort::SessionOptions session_options; session_options.SetIntraOpNumThreads(1); session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test"); Ort::Session session(env, "yolov5s.onnx", session_options); // Get input and output names auto input_names = session.GetInputNames(); auto output_names = session.GetOutputNames(); // Create input tensor Ort::AllocatorWithDefaultOptions allocator; Ort::Value input_tensor(nullptr); Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); vector<int64_t> input_shape = {1, 3, 640, 640}; input_tensor = Ort::Value::CreateTensor<float>(memory_info, reinterpret_cast<float*>(new float[input_shape[0] * input_shape[1] * input_shape[2] * input_shape[3]]), input_shape.data(), input_shape.size()); // Load image Mat image = imread("test.jpg"); cvtColor(image, image, COLOR_BGR2RGB); resize(image, image, Size(640, 640)); float* input_data = input_tensor.GetTensorMutableData<float>(); for (int i = 0; i < 640 * 640 * 3; i++) { input_data[i] = image.data[i] / 255.0; } // Run inference auto start = high_resolution_clock::now(); vector<Ort::Value> output_tensors = session.Run(output_names, &input_names[0], &input_tensor, 1); auto end = high_resolution_clock::now(); auto duration = duration_cast<milliseconds>(end - start); cout << "Inference time: " << duration.count() << " ms" << endl; // Get output tensor Ort::Value& output_tensor = output_tensors[0]; float* output_data = output_tensor.GetTensorMutableData<float>(); // Process output for (int i = 0; i < 25200; i++) { if (output_data[i * 6 + 4] > 0.5) { int x1 = output_data[i * 6 + 0] * 640; int y1 = output_data[i * 6 + 1] * 640; int x2 = output_data[i * 6 + 2] * 640; int y2 = output_data[i * 6 + 3] * 640; cout << "Object detected: " << output_data[i * 6 + 5] << " (" << x1 << ", " << y1 << ") (" << x2 << ", " << y2 << ")" << endl; } } return 0; } ``` 这个例子假设您有一张名为“test.jpg”的图像,它将被用作模型的输入。它还假设您的模型输出是一个大小为[1, 25200, 6]的张量,其中25200是预测的边界框数,6是每个边界框的属性数(左上角和右下角坐标,置信度和类别)。 请注意,这只是一个简单的例子,您需要根据您的模型和数据进行适当的修改。 ### 回答2: 在使用ONNXRuntime C部署Yolov5之前,首先需要明确的是Yolov5是目标检测算法,而ONNXRuntime C则是一个高性能的推理框架,可以用来推理基于ONNX格式的深度学习模型,这包括Yolov5。 以下是ONNXRuntime C部署Yolov5的步骤参考: 1. 转换模型:由于Yolov5模型原先是以PyTorch格式存储,因此需要将其转化为ONNX格式。具体的转换方法可以参考ONNX官方文档,或者使用现成的转换脚本,如https://github.com/jkjung-avt/yolov5_onnx/blob/main/yolov5_onnx.py。 2. 编写C程序:根据ONNXRuntime C的API,编写C语言程序实现Yolov5模型的加载和推理。可以参考ONNXRuntime官方示例中的代码模板,进行修改和调整,完成模型的加载和推理功能。关键代码如下: ```c // 运行初始化,加载模型 OrtEnv* env; OrtCreateEnv(ORT_LOGGING_LEVEL_WARNING, "test", &env); OrtSessionOptions* session_options = OrtCreateSessionOptions(); OrtSession* session; OrtCreateSession(env, model_path, session_options, &session); // 获取模型输入输出信息 OrtStatus* status; OrtTensorTypeAndShapeInfo* input_info; OrtSessionGetInputTypeInfo(session, 0, &input_info); OrtAllocator* allocator; OrtCreateDefaultAllocator(&allocator); size_t num_inputs; OrtStatus* get_num_input = OrtSessionGetInputCount(session, &num_inputs); OrtValue** input_tensor = (OrtValue**)malloc(num_inputs * sizeof(OrtValue*)); OrtStatus* input_status = OrtCreateTensorAsOrtValue(allocator, input_info, &input_tensor[0]); OrtTypeInfo* type_info; OrtStatus* output_status = OrtSessionGetOutputTypeInfo(session, 0, &type_info); // 给输入tensor赋值 float* input = input_tensor[0]->GetTensorMutableData<float>(); for (int i = 0; i < input_size; i++) { input[i] = input_data[i]; } // 运行模型,获取结果 OrtValue* output_tensor = NULL; const char* output_names[] = { output_name }; OrtStatus* run_status = OrtRun(session, NULL, input_names, &input_tensor[0], num_inputs, output_names, 1, &output_tensor); float* output = output_tensor->GetTensorMutableData<float>(); ``` 3. 编译C程序:使用C编译器,如gcc,编译C程序,并将ONNXRuntime C的库文件链接到程序中,如: ```bash gcc main.c -lonnxruntime ``` 4. 运行C程序:运行编译后的程序,并输入Yolov5需要检测的图片或视频数据,程序将输出检测结果,包括检测框、置信度和类别等信息。 需要注意的几个点: 1. ONNXRuntime C需要先安装ONNXRuntime库,并将其包含到系统路径中。 2. 在程序中需要指定Yolov5的输入尺寸和类别数等信息。 3. 在使用Yolov5推理时,需要先对输入数据进行预处理,如尺寸缩放、通道变换和数据类型转换等。 4. 在编程时,需要对ONNXRuntime C的API进行深入学习,以保证程序的正确性和稳定性。同时,还需要对Yolov5的算法和原理有一定的了解,以便进行模型的参数调整和优化。 ### 回答3: 随着深度学习的广泛应用,越来越多的框架和工具被开发出来,但由于它们之间的差异,将模型从一个框架转换到另一个框架是一项具有挑战性和耗费时间的工作。ONNX(Runtime)是一种广泛接受的中间表示,它可以使不同的框架之间的模型转换变得容易。这篇文章将介绍如何使用ONNXRuntime C++ API来部署一个YOLOv5的模型。 首先,我们需要下载YOLOv5模型的权重和cfg文件,可以从Github上的YOLOv5仓库中下载。在下载完这两个文件后,我们需要用Python中的train.py将它们转换成ONNX文件,具体地,可以使用如下命令: ``` python3 train.py --weights yolov5s.pt --cfg models/yolov5s.yaml --img 640 --batch 1 --no-autoanchor --fuse python3 models/yolo.py --cfg models/yolov5s.yaml --weights yolov5s.pt --names models/coco.names ``` 这将生成名为“yolov5s.onnx”的模型文件。现在,我们可以使用ONNXRuntime C++ API加载和运行它。 首先,我们需要在C++中安装ONNXRuntime的API,可以从官方网站(https://www.onnxruntime.ai/)下载ONNXRuntime C++ API安装文件。安装完成后,我们可以开始编写C++代码来加载和运行YOLOv5模型。 我们需要使用以下头文件: ``` #include "onnxruntime_cxx_api.h" #include <opencv2/opencv.hpp> ``` 接下来,我们需要定义一些变量来存储模型信息。我们可以使用onnxruntime::Env类初始化ONNXRuntime。 ``` std::string model_path = "yolov5s.onnx"; std::shared_ptr<onnxruntime::Environment> env = onnxruntime::Environment::Create(); ``` 然后,我们需要创建一个会话,该会话将包含模型。通过onnxruntime::Session类,我们可以加载模型并返回一个会话句柄。 ``` std::shared_ptr<onnxruntime::Session> session = std::make_shared<onnxruntime::Session>(*env, model_path, nullptr); ``` 我们还需要创建一个输入模型。我们需要使用onnxruntime::Tensor类,它将用于加载输入数据。 ``` std::vector<int64_t> input_node_dims = { 1, 3, 640, 640 }; auto memory_info = onnxruntime::MemoryInfo::CreateCpu(ONNXRUNTIME_CPU, onnxruntime::DeviceAllocatorRegistrationFlags::None); auto input_tensor = onnxruntime::make_unique<onnxruntime::Tensor>(onnxruntime::DataType::Float, onnxruntime::TensorShape(input_node_dims), memory_info); ``` 现在,我们有了将图像转换为ONNX模型所需的一切。我们需要加载图像,将其尺寸调整为模型的输入大小,并使用OpenCV库将图像像素值转换为浮点数。然后我们可以将数据复制到输入_tensor中。 ``` cv::Mat img = cv::imread("test.jpg"); cv::resize(img, img, cv::Size(640, 640), cv::INTER_AREA); img.convertTo(img, CV_32FC3, 1 / 255.0); memcpy(input_tensor->MutableData<float>(), img.data, img.total() * img.elemSize()); ``` 现在,我们可以将输入_tensor传递给模型并运行。 ``` std::vector<const char*> input_node_names = { "input" }; std::vector<const char*> output_node_names = { "output" }; std::vector<OrtValue> output_tensors; OrtTensorScales scales = { nullptr, 0 }; session->Run(Ort::RunOptions{ nullptr }, input_node_names.data(), &input_tensor, input_node_dims.size(), output_node_names.data(), output_node_names.size(), output_tensors, scales); ``` 最后,我们可以使用输出张量中的数据进行后处理,以获得目标框位置和类别预测结果等信息。 这些就是使用ONNXRuntime C++ API来部署YOLOv5模型的基本步骤。当然,如果我们要获得更高的精度和更快的速度,还可以使用各种技术来优化模型和代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值