c++ onnx之yolov5检测

yolov5和resnet比稍微麻烦了一点,主要就是多了nms部分,还有坐标点映射回原图的yolov5_scale_coords函数。流程大致分为五部分:1)图像等比例放缩,2)图像预处理,3)onnx推理,4)nms后处理,5)坐标点映射回原图

等比例放缩

还是和resnet一样的 letterbox 函数,就不重复了。

图像预处理

还是和resnet一样的,就不重复了,就cv::dnn::blobFromImage一句话。

onnx推理

和之前差不多,改下输入输出的维度、名称,然后resnet的一维输出变成yolo的二维输出,这个在 c++ 使用onnx推理 中写过了,也不重复了。

nms后处理

这个我懒得自己写,还好opencv里面有cv::dnn::NMSBoxes函数,直接用就好。
正常来说onnx推理后返回的预测值是252000 x (n+5) ,其中252000是框的总数一般是不变的, n是等于你设置的类别数,向量含义是(center_x, center_y, width, height, conf_框, conf_类别1,conf_类别2,…,,conf_类别n)。

这个函数主要就是把preds转成opencv_nms函数需要的输入 cv::Rect(left, top, width, height) 框坐标 和 float 置信度(类别置信度*框置信度)

vector<Detection> yolov5_nms(Mat preds, float conf_thres = 0.25, float iou_thres = 0.45)
{
   
	vector<cv::Rect> boxes;
	vector<float> confs;
	vector<int> classIds;
	for (int i = 0; i < preds.rows; i++)
	{
   
		float clsConf = preds.at<float>(i, 4);
		if (clsConf > conf_thres)
		{
   
			// (cx,cy,w,h) to (left,top,w,h)
			float centerX = preds.at<float>(i, 0);
			float centerY = preds.at<float>(i, 1);
			float width = preds.at<float>(i, 2);
			float height = preds.at<float>(i, 3);
			float left = centerX - width / 2;
			float top = centerY - height / 2;

			// 因为我这里只检测人,就直接这样来了,正常如果有80个类别,objConf表示最高的置信度,classId表示最高置信度的id
			float objConf = preds.at<float>(i, 5);;
			int classId = 0;

			float confidence = clsConf * objConf;

			boxes.push_back(cv::Rect(left, top, width, height));
			confs.push_back(confidence);
			classIds.push_back(classId);
		}
	}
	vector<int> nms_result;
	// 这里输入的boxes(float)被强制转为(int)了,可能会有点误差
	cv::dnn::NMSBoxes(boxes, confs, conf_thres, iou_thres, nms_result);
	cout << "amount of NMS indices: " << nms_result.size() << std::endl;
	vector<Detection> output;
	for (int i = 0; i < nms_result.size(); i++) {
   
		int idx = nms_result[i];
		Detection result;
		result.class_id = classIds[idx];
		result.confidence = confs[idx];
		result.box = boxes[idx];
		output.push_back(result);
	}
	return output;
}

坐标点映射

主要就是我要把检测的框放缩回原图,对原图进行裁减。结构体看着有点难受,可以直接输入输出改成boxes,我是因为之后可视化要标上类别信息所以写了个结构体。

vector<Detection> yolov5_scale_coords(Mat ori_img, vector<Detection> detections, Mat letter_img)
{
   
	// boxes(ltwh)(left, top, width, height)
	float ratio;
	float scale_row = (float)(letter_img.rows) / (float)(ori_img.rows);
	float scale_col= (float)(letter_img.cols) / (float)(ori_img.cols);
	ratio = min(scale_row, scale_col);
	float pad_row = ((float)(letter_img.rows) - (float)(ori_img.rows) * ratio) / 2.0;
	float pad_col = ((float)(letter_img.cols) - (float)(ori_img.cols) * ratio) / 2.0;

	// 这里的点应该要用float的,用int明显有误差
	vector<Detection> new_detections;
	int nums = detections.size();
	for (int i = 0; i < nums; ++i)
	{
   
		auto detection = detections[i];
		auto box = detection.box;
		float left = (box
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值