【yolov5 ONNX】c++ 加载 导出的onnx模型

46 篇文章 4 订阅
6 篇文章 0 订阅

注意: cuda toolkit 版本 CUDA Toolkit 11.3 Downloads | NVIDIA Developer

                编译opencv使用的cuda toolkit版本

                cudnn版本与cuda对应

               

#include <fstream>

#include <opencv2/opencv.hpp>
//#include <torch/csrc/jit/frontend/tree.h>


std::vector<std::string> load_class_list()
{
	std::vector<std::string> class_list;
	std::ifstream ifs("weights/block.txt");
	std::string line;
	while (getline(ifs, line))
	{
		class_list.push_back(line);
	}
	return class_list;
}

void load_net(cv::dnn::Net& net, bool is_cuda)
{
	auto result = cv::dnn::readNetFromONNX("weights/best.onnx");//readNet   代码可用 版本有问题
	if (is_cuda)
	{
		std::cout << "Attempty to use CUDA\n";
		result.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
		result.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
		//result.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA_FP16);
	}
	else
	{
		std::cout << "Running on CPU\n";
		result.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
		result.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
	}
	net = result;
}

const std::vector<cv::Scalar> colors = { cv::Scalar(255, 255, 0), cv::Scalar(0, 255, 0), cv::Scalar(0, 255, 255), cv::Scalar(255, 0, 0) };

const float INPUT_WIDTH = 416.0;//640
const float INPUT_HEIGHT = 416.0;//640
const float SCORE_THRESHOLD = 0.2;
const float NMS_THRESHOLD = 0.4;
const float CONFIDENCE_THRESHOLD = 0.4;

struct Detection
{
	int class_id;
	float confidence;
	cv::Rect box;
};

cv::Mat format_yolov5(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;
}

void detect(cv::Mat& image, cv::dnn::Net& net, std::vector<Detection>& output, const std::vector<std::string>& className) {
	cv::Mat blob;

	auto input_image = format_yolov5(image);

	cv::dnn::blobFromImage(input_image, blob, 1. / 255., cv::Size(INPUT_WIDTH, INPUT_HEIGHT), cv::Scalar(), true, false);
	net.setInput(blob);
	std::vector<cv::Mat> outputs;
	std::vector<cv::String> blobnames = net.getUnconnectedOutLayersNames();
	std::cout << "before forward\n";
	net.forward(outputs, blobnames);//da4dnn::checkVersions CUDART version 11030 reported by cuDNN 8200 does not match with the version reported by CUDART 11010


	//outputs = net.forward();
	std::cout << "after forward\n";
	float x_factor = input_image.cols / INPUT_WIDTH;
	float y_factor = input_image.rows / INPUT_HEIGHT;

	float* data = (float*)outputs[0].data;

	const int dimensions = 85;
	const int rows = 1;//25200

	std::vector<int> class_ids;
	std::vector<float> confidences;
	std::vector<cv::Rect> boxes;

	for (int i = 0; i < rows; ++i) {

		float confidence = data[4];// data[4]
		if (confidence >= CONFIDENCE_THRESHOLD) {

			float* classes_scores = data + 5;
			cv::Mat scores(1, className.size(), CV_32FC1, classes_scores);
			cv::Point class_id;
			double max_class_score;
			minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
			if (max_class_score > SCORE_THRESHOLD) {

				confidences.push_back(confidence);

				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 += 85;

	}

	std::vector<int> nms_result;
	cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, nms_result);
	for (int 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];
		output.push_back(result);
	}
}

int main(int argc, char** argv)
{

	std::vector<std::string> class_list = load_class_list();

	cv::Mat frame;
	cv::VideoCapture capture("1.mp4");
	if (!capture.isOpened())
	{
		std::cerr << "Error opening video file\n";
		return -1;
	}

	bool is_cuda = argc > 1 && strcmp(argv[1], "cuda") == 0;
	is_cuda = true;//手动设置
	cv::dnn::Net net;
	load_net(net, is_cuda);

	auto start = std::chrono::high_resolution_clock::now();
	int frame_count = 0;
	float fps = -1;
	int total_frames = 0;

	while (true)
	{
		capture.read(frame);
		if (frame.empty())
		{
			std::cout << "End of stream\n";
			break;
		}

		std::vector<Detection> output;
		detect(frame, net, output, class_list);

		frame_count++;
		total_frames++;

		int detections = output.size();

		for (int i = 0; i < detections; ++i)
		{

			auto detection = output[i];
			auto box = detection.box;
			auto classId = detection.class_id;
			const auto color = colors[classId % colors.size()];
			cv::rectangle(frame, box, color, 3);

			cv::rectangle(frame, cv::Point(box.x, box.y - 20), cv::Point(box.x + box.width, box.y), color, cv::FILLED);
			cv::putText(frame, class_list[classId].c_str(), cv::Point(box.x, box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
		}

		if (frame_count >= 30)
		{

			auto end = std::chrono::high_resolution_clock::now();
			fps = frame_count * 1000.0 / std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

			frame_count = 0;
			start = std::chrono::high_resolution_clock::now();
		}

		if (fps > 0)
		{

			std::ostringstream fps_label;
			fps_label << std::fixed << std::setprecision(2);
			fps_label << "FPS: " << fps;
			std::string fps_label_str = fps_label.str();

			cv::putText(frame, fps_label_str.c_str(), cv::Point(10, 25), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2);
		}

		cv::imshow("output", frame);

		if (cv::waitKey(1) != -1)
		{
			capture.release();
			std::cout << "finished by user\n";
			break;
		}
	}

	std::cout << "Total frames: " << total_frames << "\n";

	return 0;
}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 好的,这是一个比较复杂的任务,需要分几个步骤来完成。下面是大致的步骤: 1. 使用 C++ 编写动态链接库封装 YOLOv5,可以使用 OpenCV 库来读取图像和进行预处理。 2. 导入 ONNX 模型,可以使用 ONNX Runtime 库来和运行 ONNX 模型。 3. 实现前向推理代码,将输入图像喂给 ONNX 模型,并获取输出结果。 4. 将输出结果进行解析,得到检测框和分类结果。 5. 使用 LaView 软件进行调用和测试。 下面是详细的步骤: 1. 使用 C++ 编写动态链接库封装 YOLOv5,可以使用 OpenCV 库来读取图像和进行预处理。 首先,需要下 YOLOv5 的源码,并编译生成可执行文件。然后,将可执行文件中的预测部分封装成一个动态链接库,提供给其他程序调用。 以下是一个简单的示例代码,它使用 OpenCV 库读取图像,对图像进行预处理(将图像缩放到模型输入大小),并将预处理后的图像传递给 YOLOv5 进行预测: ```cpp #include "yolov5.h" #include <opencv2/opencv.hpp> YoloV5::YoloV5() { // 初始化 YOLOv5 模型 // ... } std::vector<ObjectDetectionResult> YoloV5::detect(const cv::Mat& image) { // 对图像进行预处理 cv::Mat input_image; cv::resize(image, input_image, cv::Size(640, 640)); // 将图像缩放到模型输入大小 // 将输入图像传递给 YOLOv5 进行预测 // ... // 解析输出结果,得到检测框和分类结果 std::vector<ObjectDetectionResult> results; // ... return results; } ``` 2. 导入 ONNX 模型,可以使用 ONNX Runtime 库来和运行 ONNX 模型。 首先,需要将 YOLOv5 的 PyTorch 模型导出ONNX 格式。然后,可以使用 ONNX Runtime 库来和运行 ONNX 模型。 以下是一个简单的示例代码,它使用 ONNX Runtime 库和运行 ONNX 模型: ```cpp #include <onnxruntime_cxx_api.h> Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test"); // 初始化 ONNX Runtime 环境 Ort::SessionOptions session_options; session_options.SetIntraOpNumThreads(1); session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); Ort::Session session(env, "model.onnx", session_options); // ONNX 模型 Ort::AllocatorWithDefaultOptions allocator; // 准备输入数据 std::vector<int64_t> input_shape = {1, 3, 640, 640}; Ort::Value input_tensor = Ort::Value::CreateTensor<float>(allocator, input_data.data(), input_shape.data(), input_shape.size()); // 运行模型 auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names.data(), &input_tensor, input_names.size(), output_names.data(), output_names.size()); ``` 3. 实现前向推理代码,将输入图像喂给 ONNX 模型,并获取输出结果。 在使用 ONNX Runtime 运行 ONNX 模型之前,需要先准备输入数据,然后将输入数据传递给模型。在获取输出结果后,需要对输出结果进行解析,得到检测框和分类结果。 以下是一个简单的示例代码,它实现了前向推理代码: ```cpp #include <onnxruntime_cxx_api.h> std::vector<ObjectDetectionResult> YoloV5::detect(const cv::Mat& image) { // 对图像进行预处理 cv::Mat input_image; cv::resize(image, input_image, cv::Size(640, 640)); // 将图像缩放到模型输入大小 // 准备输入数据 std::vector<float> input_data = prepare_input_data(input_image); // 运行模型 auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names.data(), &input_tensor, input_names.size(), output_names.data(), output_names.size()); // 解析输出结果,得到检测框和分类结果 std::vector<ObjectDetectionResult> results = parse_output_data(output_tensors); return results; } ``` 4. 将输出结果进行解析,得到检测框和分类结果。 解析输出结果是实现动态链接库的一个重要部分。在解析输出结果之前,需要先了解模型的输出格式。 YOLOv5 模型的输出格式为一个包含多个数组的结构体,每个数组对应一个输出层的输出。每个数组的形状为 (batch_size, num_anchors * (num_classes + 5), grid_size, grid_size),其中,batch_size 为 1,num_anchors 为每个格子预测的锚框数量,num_classes 为类别数量,grid_size 为输出特征图的大小。 以下是一个简单的示例代码,它解析了 YOLOv5 模型的输出结果,得到检测框和分类结果: ```cpp #include <onnxruntime_cxx_api.h> std::vector<ObjectDetectionResult> YoloV5::parse_output_data(const Ort::Value& output_tensor) { std::vector<ObjectDetectionResult> results; // 获取输出数据 auto output_data = output_tensor.GetTensorMutableData<float>(); // 解析输出数据 // ... return results; } ``` 5. 使用 LaView 软件进行调用和测试。 最后,可以使用 LaView 软件调用动态链接库,并测试模型的性能和准确度。 在 LaView 中,可以使用 DLL 节点调用动态链接库,通过设置节点的输入和输出参数,将图像传递给动态链接库,获取检测框和分类结果。 以下是一个简单的示例代码,它在 LaView 中使用 DLL 节点调用动态链接库: ```cpp #include <opencv2/opencv.hpp> #include "yolov5.h" YoloV5 yolo_v5; int main() { // 读取图像 cv::Mat image = cv::imread("test.jpg"); // 调用动态链接库进行检测 auto results = yolo_v5.detect(image); // 显示结果 for (auto& result : results) { cv::rectangle(image, result.rect, cv::Scalar(0, 255, 0), 2); cv::putText(image, result.label, result.rect.tl(), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2); } cv::imshow("result", image); cv::waitKey(0); return 0; } ``` ### 回答2: 首先,编写动态链接库封装yolov5可以按以下步骤操作: 1. 下yolov5的源码并解压。 2. 在C语言中创建一个动态链接库的项目。 3. 在项目中包含yolov5的源码文件,并根据需要进行配置。 4. 编写C语言代码来调用yolov5的函数和方法,例如模型、进行目标检测等。 5. 编译项目生成动态链接库文件(.dll或.so文件)。 然后,导入onnx模型可以按以下步骤操作: 1. 将onnx模型文件拷贝到你的项目文件夹中。 2. 在C代码中使用相应的库来导入onnx模型。 3. 调用相应的函数或方法来导入的模型。 最后,使用laview进行调用测试可以按以下步骤操作: 1. 下laview,并安装到你的计算机上。 2. 在laview中创建一个测试项目,导入你编写的动态链接库文件。 3. 使用laview提供的界面和功能,调用动态链接库中的函数来进行yolov5目标检测测试。 4. 检查测试结果,并根据需要进行调试和优化。 总之,根据以上步骤,你可以使用C语言编写动态链接库封装yolov5,导入onnx模型,并使用laview进行调用测试。 ### 回答3: 要使用C语言编写动态链接库封装Yolov5并导入ONNX模型,可以按照以下步骤进行: 1. 首先,你需要了解Yolov5的模型结构和ONNX模型的导入方式。Yolov5是一个目标检测算法,可以使用C语言实现其网络结构和相关函数。而ONNX模型可以使用相关的C库导入并进行推理。 2. 在C语言中,你需要编写一个动态链接库,其中封装了Yolov5的模型结构和相关函数。你可以创建一个名为"yolov5.c"的文件,并在其中实现Yolov5的网络结构和相关函数。 3. 下一步是导入ONNX模型。你可以使用ONNX Runtime库来ONNX模型,并进行推理。在"yolov5.c"文件中,你需要添相应的ONNX Runtime库的引用,并编写导入ONNX模型的代码。 4. 在导入ONNX模型后,你可以使用LaView库进行调用和测试。LaView是一个图像处理库,可以用于在视觉算法中和处理图像数据。你可以在"yolov5.c"文件中添相应的LaView库的引用,并编写相应的调用和测试代码。 5. 最后,你需要编译动态链接库。使用适当的编译器命令,将"yolov5.c"文件编译成动态链接库。确保将ONNX Runtime库和LaView库链接到动态链接库中。 完成以上步骤后,你就可以使用这个动态链接库进行Yolov5的目标检测,并使用LaView库对图像进行处理和展示。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值