c++ opencv调用yolo onnx文件

网上找了一段代码,测试c++ opencv调用yolo onnx文件

yolov8n.onnx opencv版本是4.12 ,另外测试了4.4和4.6版本的opencv运行有问题,可能对opencv版本有要求,有待研究,都在编译了contrib库的情况下测试的

cpp 复制代码
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include <chrono>

int main()
{
	// 加载 ONNX 模型
	std::string modelPath = "yolov8n.onnx";
	cv::dnn::Net net = cv::dnn::readNetFromONNX(modelPath);
	net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
	net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);

	// 定义完整的COCO数据集类别名称
	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"
	};

	// 打开视频文件或摄像头
	// 0 表示默认摄像头,也可以替换为视频文件路径如 "video.mp4"
	cv::VideoCapture cap("nfs.mp4");

	// 检查视频是否成功打开
	if (!cap.isOpened()) {
		std::cerr << "Error: Unable to open video source" << std::endl;
		return -1;
	}

	// 获取视频的帧率
	double fps = cap.get(cv::CAP_PROP_FPS);
	if (fps == 0) fps = 30.0; // 默认帧率

	// 用于计算FPS的变量
	auto lastTime = std::chrono::high_resolution_clock::now();
	int frameCount = 0;
	double currentFps = 0.0;

	cv::Mat frame;
	while (true) {
		// 读取帧
		cap >> frame;

		// 检查是否成功读取帧
		if (frame.empty()) {
			std::cout << "End of video or error reading frame" << std::endl;
			break;
		}

		// 计算FPS
		frameCount++;
		auto currentTime = std::chrono::high_resolution_clock::now();
		auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastTime).count();

		if (elapsedTime >= 1000) { // 每秒更新一次FPS
			currentFps = frameCount / (elapsedTime / 1000.0);
			frameCount = 0;
			lastTime = currentTime;
		}

		// 将图像转换为blob格式
		cv::Mat blob = cv::dnn::blobFromImage(frame, 1 / 255.0, cv::Size(640, 640), cv::Scalar(0, 0, 0), true, false);
		net.setInput(blob);

		// 前向传播, 获取检测结果
		std::vector <cv::Mat> outputs;
		net.forward(outputs, net.getUnconnectedOutLayersNames());

		// output.size [ 1, 84, 8400]
		int rows = outputs[0].size[2];

		// 每个目标存储了多少个值(x,y,w,h+类别数)
		int length = outputs[0].size[1];

		// 转成单通道
		outputs[0] = outputs[0].reshape(1, length);

		// 按对角线翻转
		cv::transpose(outputs[0], outputs[0]);

		float* data = (float*)outputs[0].data;
		float xFactor = (float)frame.cols / 640;
		float yFactor = (float)frame.rows / 640;

		// 解析检测结果
		std::vector<int> classIds;
		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 classId;
			double maxClassScore;
			// 读取最大置信度并获得它的索引
			cv::minMaxLoc(scores, 0, &maxClassScore, 0, &classId);

			if (maxClassScore > 0.1)
			{
				confidences.push_back(maxClassScore);
				classIds.push_back(classId.x);

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

				int left = int((x - 0.5 * w) * xFactor);
				int top = int((y - 0.5 * h) * yFactor);

				int width = int(w * xFactor);
				int height = int(h * yFactor);

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

		// 执行非最大抑制,以消除具有较低置信度的冗余重叠框(NMS)
		std::vector<int> nmsResult;
		cv::dnn::NMSBoxes(boxes, confidences, 0.25, 0.7, nmsResult);
		for (int i = 0; i < nmsResult.size(); i++)
		{
			int idx = nmsResult[i];
			int classId = classIds[idx];
			float confidence = confidences[idx];
			cv::Rect box = boxes[idx];

			// 绘制检测框并显示类别名称
			cv::rectangle(frame, box, cv::Scalar(0, 0, 255), 2);
			cv::putText(frame, classes[classId] + ": " + std::to_string(confidence).substr(0, 4),
				cv::Point(box.x, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 255));
		}

		// 在图像上显示FPS
		std::string fpsText = "FPS: " + std::to_string(static_cast<int>(currentFps));
		cv::putText(frame, fpsText, cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);

		// 显示结果
		cv::imshow("YOLO Detection", frame);

		// 按ESC键退出
		if (cv::waitKey(1) == 27) {
			break;
		}
	}

	// 释放资源
	cap.release();
	cv::destroyAllWindows();

	return 0;
}
相关推荐
云程笔记37 分钟前
021.损失函数深度解读:YOLO的定位、置信度、分类损失计算
人工智能·yolo·机器学习·计算机视觉·分类·数据挖掘
念恒1230640 分钟前
Linux初识
linux·服务器·c++
旖-旎1 小时前
哈希表(存在重复元素)(3)
数据结构·c++·学习·算法·leetcode·散列表
计算机安禾1 小时前
【数据结构与算法】第39篇:图论(三):最小生成树——Prim算法与Kruskal算法
开发语言·数据结构·c++·算法·排序算法·图论·visual studio code
fish_xk1 小时前
c++内存管理
开发语言·c++·算法
羊羊小栈1 小时前
基于「YOLO目标检测 + 多模态AI分析」的智慧农业茶叶病害检测预警系统
人工智能·yolo·目标检测·计算机视觉·毕业设计·大作业
chh5632 小时前
C++--内存管理
java·c语言·c++·windows·学习·面试
Yungoal2 小时前
C++ 标准模板库STL(Standard Template Library)
c++·哈希算法·散列表
我真不是小鱼2 小时前
cpp刷题打卡记录27——无重复字符的最长子串 & 找到字符串中所有字母的异位词
数据结构·c++·算法·leetcode
一直不明飞行2 小时前
C++:string,写法s.find(‘@‘) != s.end()是否有问题
开发语言·c++·算法