使用c++推理yolov8的关键点模型

依赖库

  • opencv

导出onnx

yolo export model=./runs/segment/train2/weights/best.pt imgsz=640 format=onnx opset=12

代码

说明

yolov8会先检测出目标区域,然后再在目标区域进行关键点检测。我这个模型一张图中只要一个目标区域需要检测关键点,也即预期只有一个目标检测框。

#include<iostream>
#include<opencv.hpp>
#include<filesystem>

/*
yolov8关键点推理
*/

namespace fs = std::filesystem;

cv::Mat modify_image_size(const cv::Mat& img)
{
	auto max = std::max(img.rows, img.cols);
	cv::Mat ret = cv::Mat::zeros(max, max, CV_8UC3);
	img.copyTo(ret(cv::Rect(0, 0, img.cols, img.rows)));

	return ret;
}

bool shouldSkip(int n) 
{
	static int count = 0;
	count++;
	if (count == 3) 
	{
		count = 0;
		return true;
	}
	return false;
}

int main()
{
	const char* onnx_file{ "./best.onnx" }; // 关键点模型
	constexpr int input_size[2]{ 640, 640 };
	constexpr double confidence_threshold{ 0.9 };
	constexpr double iou_threshold{ 0.50 }; // iou threshold
	constexpr double mask_threshold{ 0.50 }; // segment mask threshold
	const int numPts = 4; // 多少个关键点

	constexpr bool cuda_enabled{ false };
	const std::string testPath("./027.png");
	// 分离出文件名
	std::string filename;
	if (std::filesystem::exists(std::filesystem::path(testPath)) == false)
	{
		std::cout << testPath << " is not exists." << std::endl;
		return -1;
	}
	else
	{
		filename = std::filesystem::path(testPath).filename().string();
		std::cout << "filename = " << filename << std::endl;
	}

	const std::string result_dir{ "./predictResult" };

	auto net = cv::dnn::readNetFromONNX(onnx_file);
	if (net.empty())
	{
		std::cerr << "Error: there are no layers in the network: " << onnx_file << std::endl;
		return -1;
	}

	if (cuda_enabled) {
		net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
		net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
	}
	else {
		net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
	}
	std::cout << "read model complete." << std::endl;

	if (!fs::exists(result_dir))
	{
		fs::create_directories(result_dir);
	}

#pragma region 预测
	cv::Mat frame = cv::imread(testPath, cv::IMREAD_COLOR);
	if (frame.empty())
	{
		std::cerr << "Warning: unable to load image: " << testPath << std::endl;
		return -1;
	}

	auto tstart = std::chrono::high_resolution_clock::now();
	cv::Mat bgr = modify_image_size(frame);
	std::cout << "bgr.size=" << bgr.size << std::endl;
#if 0
	cv::imshow("w", bgr);
	cv::waitKey();
#endif

	cv::Mat blob;
	cv::dnn::blobFromImage(bgr, blob, 1.0 / 255.0, cv::Size(input_size[1], input_size[0]), cv::Scalar(), true, false);
	net.setInput(blob);

	std::vector<cv::Mat> outputs;
	net.forward(outputs, net.getUnconnectedOutLayersNames());
	std::cout << "outputs.size = " << outputs.size() << std::endl;

	cv::Mat result = outputs[0];
	std::cout << result.size << std::endl;
#pragma endregion

	std::vector<int> class_ids;
	std::vector<cv::Rect> boxes;
	std::vector<cv::Point> keyPoints;

	float scalex = frame.cols * 1.f / input_size[1]; // note: image_preprocess function
	float scaley = frame.rows * 1.f / input_size[0];
	auto scale = (scalex > scaley) ? scalex : scaley;

	cv::Mat data0 = cv::Mat(outputs[0].size[1], outputs[0].size[2], CV_32FC1, outputs[0].data).t();
	std::cout << "data0.size=" << data0.size << std::endl;
	std::cout << "data0.cols=" << data0.cols << ", data0.rows=" << data0.rows << std::endl;

	const float* data = (float*)data0.data;
	std::vector<float> confidences;
	std::vector<std::vector<float>> keypts;

	for (auto i = 0; i < data0.rows; ++i)
	{// 遍历每一行的box
		if (*(data + 4) > confidence_threshold)
		{
			confidences.emplace_back(*(data + 4));
			//keypts.emplace_back(std::vector<float>(data + 5, data + data0.cols));

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

#if 1
			int left = std::max(0, std::min(int((x - 0.5 * w) * scale), frame.cols));
			int top = std::max(0, std::min(int((y - 0.5 * h) * scale), frame.rows));
			int width = std::max(0, std::min(int(w * scale), frame.cols - left));
			int height = std::max(0, std::min(int(h * scale), frame.rows - top));
#endif			
			boxes.emplace_back(cv::Rect(left, top, width, height));
			std::vector<float> rowPtsInfo;
			for (int ipt = 5; ipt < data0.cols; ipt+=3)
			{
				std::cout << "ipt=" << ipt << std::endl;
				float x = *(data + ipt);
				x = std::max(0, std::min(int(std::round(x * scale)), frame.cols));
				float y = *(data + ipt + 1);
				y = std::max(0, std::min(int(std::round(y * scale)), frame.rows));
				float score = *(data + ipt + 2);

				rowPtsInfo.push_back(x);
				rowPtsInfo.push_back(y);
				rowPtsInfo.push_back(score);
			}
			keypts.emplace_back(rowPtsInfo);

			for (int j = 0; j < 17; ++j)
			{
				std::cout << *(data + j) << " ";
			}
			std::cout << std::endl;
		}		
		data += data0.cols;
	}

#if 0
#pragma region 方法1是取box最高得分对应的关键点,可能不是很准确

	std::vector<int> nms_result;// 返回得分最高的box的索引
	cv::dnn::NMSBoxes(boxes, confidences, confidence_threshold, iou_threshold, nms_result);
#if 0
	for (const auto item : nms_result)
	{
		std::cout << item << " ";
	}
	std::cout << std::endl;
#endif

	const cv::Size shape_src(frame.cols, frame.rows), // 原始图像大小
		shape_input(input_size[1], input_size[0]); // 640

	for (size_t i = 0; i < nms_result.size(); ++i)
	{
		auto index = nms_result[i];// 对应的索引
		cv::Rect box = boxes[index];
#if 1
		cv::rectangle(frame, box, cv::Scalar(0, 0, 255));
		cv::imshow("w", frame);
		cv::waitKey();
#endif
		std::vector<float> pointsInfo = keypts[index];
		for (int i = 0; i < pointsInfo.size(); i += 3)
		{
			cv::Point loc(pointsInfo[i], pointsInfo[i+1]);

			cv::circle(frame, loc, 2, cv::Scalar(0, 0, 255), -1);			
		}
	}
	cv::imshow("w", frame);
	cv::waitKey();
#pragma endregion
#endif

#if 1
#pragma region 方法2,遍历所有关键点,取每个位置关键点得分最高的
	cv::Mat ptsMat(keypts.size(), 3 * numPts, CV_32F);
	std::cout << ptsMat.rows << ",,," << ptsMat.cols << std::endl;
	std::cout << keypts[0].size() << std::endl;
	for (int row = 0; row < ptsMat.rows; ++row)
	{
		for (int col = 0; col < ptsMat.cols; ++col)
		{
			ptsMat.at<float>(row, col) = keypts[row][col];
		}
	}
	std::cout << ptsMat << std::endl;

	std::vector<cv::Point> taPts;
	for (int findCol = 2; findCol < ptsMat.cols; findCol += 3)
	{
		double minVal, maxVal;
		cv::Point minLoc, maxLoc;

		cv::minMaxLoc(ptsMat.col(findCol), &minVal, &maxVal, &minLoc, &maxLoc);
		int findRow = maxLoc.y;
		
		cv::Point taLoc(findCol, findRow);
		float x = ptsMat.at<float>(findRow, findCol - 2);
		float y = ptsMat.at<float>(findRow, findCol - 1);

		cv::circle(frame, cv::Point(x,y), 2, cv::Scalar(0, 0, 255), -1);		
	}
	cv::imshow("w", frame);
	cv::waitKey();
	cv::imwrite(result_dir + "\\" + filename, frame);

	/*for (int irow = 0; irow < keypts.size(); ++irow)
	{
		std::vector<float> pointsInfo = keypts[irow];

		for (int i = 0; i < pointsInfo.size(); i += 3)
		{
			cv::Point loc(pointsInfo[i], pointsInfo[i + 1]);

			cv::circle(frame, loc, 2, cv::Scalar(0, 0, 255), -1);
			cv::imshow("w", frame);
			cv::waitKey();
		}
	}*/
#pragma endregion
#endif

	return 0;
}

结果

在这里插入图片描述

### 回答1: yolov5.zip文件是一个YOLOv5模型的压缩文件,用于进行对象识别任务的推理YOLOv5是一种基于深度学习的计算机视觉算法,它能够以高效且准确的方式检测图像或视频中的多个对象。 要推理yolov5.zip中的YOLOv5模型,首先需要解压缩该文件,并确保具备相应的依赖库和环境。接下来,通过将待测试的图像或视频输入到模型中,可以获得关于图像中对象的类别、位置以及置信度的信息。 推理YOLOv5模型的过程主要分为三个步骤:预处理、模型推理和后处理。在预处理阶段,输入的图像会被调整大小、标准化和转换成适合模型输入的格式。在模型推理阶段,通过将图像输入到YOLOv5模型中,使用模型的权重和结构进行前向传播,生成包含目标边界框和类别置信度的输出。最后,在后处理阶段,根据设定的阈值将置信度较低的边界框去除,并进行非极大值抑制操作以过滤重叠的边界框,最终得到最终的目标检测结果。 通过推理yolov5.zip中的YOLOv5模型,可以快速准确地识别出图像或视频中的多个对象,为计算机视觉领域的诸多应用提供有力的支持,如智能安防、自动驾驶、机器人视觉等。 ### 回答2: 为了使用yolov5.zip来推理yolov5,您需要按照以下步骤进行操作: 1. 下载yolov5.zip文件并解压缩。确保您已经获得了yolov5模型的权重文件、类别标签文件以及模型推理所需的其他文件。 2. 确保您已经安装了适当的深度学习框架,例如PyTorch或TensorFlow,并已安装了与yolov5模型兼容的版本。 3. 在您的代码中导入所需的库和模块。这可能包括导入PyTorch或TensorFlow,以及导入yolov5模型的相关模块。 4. 创建yolov5模型的实例,并加载预训练权重。您可以使用模型的权重文件将其加载到您的模型实例中。 5. 对需要进行目标检测的图像或视频进行预处理。这可能涉及图像缩放、归一化和格式转换等步骤,以确保输入数据与模型的要求相匹配。 6. 调用您的模型实例进行推理。将预处理后的图像或视频作为输入传递给模型,并获取输出的预测结果。 7. 根据您的需求,对模型的输出进行后处理。这可能包括解码预测边界框、滤除低置信度的预测结果、进行非最大抑制等步骤,以获取最终的目标检测结果。 8. 根据模型输出的目标检测结果,您可以对图像或视频进行可视化处理,例如在图像中绘制边界框、添加类别标签等。 请注意,以上步骤仅是一般推理yolov5的流程示例。实际操作可能会因具体情况而有所不同,因此您可能需要根据您的具体环境和需求进行适当的调整和修改。 ### 回答3: 要使用yolov5.zip文件进行yolov5目标检测的推理,您可以按照以下步骤进行操作: 1. 解压文件:将yolov5.zip文件解压缩到您的计算机上的任意文件夹中。 2. 准备数据:确保您已经准备好要进行目标检测的图像数据。这些图像可以位于单个文件夹下,也可以按照子文件夹的方式组织。 3. 配置模型:打开解压后的文件夹,您会看到yolov5文件夹中有一个名为"yolov5s.yaml"(或者是其他版本的配置文件)的文件。您可以根据需要修改该文件,例如更改检测阈值、使用不同的预训练权重等。 4. 进行推理:打开命令行终端,并进入yolov5文件夹。然后可以运行以下命令来进行目标检测的推理操作: ``` python detect.py --source <输入文件路径或文件夹路径> --weights yolov5s.pt --conf <置信度阈值> ``` 其中,`<输入文件路径或文件夹路径>`是您要进行目标检测的图像文件或文件夹的路径。`yolov5s.pt`是预训练权重文件的路径,可以根据需要修改为其他版本的权重文件。`<置信度阈值>`是您希望设置的检测阈值,一般为0.25到0.5之间的数值。运行命令后,yolov5会对输入的图像数据进行目标检测,并在命令行终端上显示检测结果。 通过以上步骤,您可以使用yolov5.zip文件进行yolov5目标检测的推理操作。请注意,为了能够成功运行推理,您需要确保已经正确安装了Python和相关依赖库,并且您的计算机支持CUDA(如果要使用GPU加速)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值