ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

(目标检测)基于opencv dnn模块的yolov5部署

2022-02-06 12:02:53  阅读:371  来源: 互联网

标签:box yolov5 float int dnn opencv num grid anchor


  • 这边文章将介绍基于dnn模块的yolov5 onnx模型的部署 包括读取模型和数据处理和后处理
  • 先给出整个项目的源码
  • yolov5版本为4.0
  • opencv 为 4.5.2
  • 使用的模型是自己训练的 类别数为5的模型
  • 不同的版本此源码可能会报错 由于opencv版本报错解决办法
  • 部署需要一些yolov5的基本知识支持 网上比比皆是

文章目录

opencv dnn模块的使用

onnx模型导出

  • 具体可以参考yolov5的官方github的Tutorials
    在这里插入图片描述
  • 运行py文件 yolov5-4.0/models/export.py即可导出onnx
python models/export.py --weights ./weights/yolov5s.pt --img 640 --batch 1

onnx模型分析

  • 可以使用“Netron”这个软件去查看onnx模型的具体网络

  • 在这里插入图片描述
    在这里插入图片描述在这里插入图片描述

  • 上图可以看出网络输出有三层 由先到后为

    • 1×3×80×80×10
    • 1×3×40×40×10
    • 1×3×20×20×10
  • 10 == 类别数(5) + bbox 的 xywh + confidence

  • 80 40 20分别为不同数量的grid cell 用于检测大物体 中物体 小物体

  • 3 代表每个grid cell有三个anchor boxs

在这里插入图片描述

输出层数据处理

  • 代码中每一行都有详细的注释
	int n = 0, q = 0, i = 0, j = 0, nout = this->classes.size() + 5, row_ind = 0;
	// 遍历三种大小的grid cell
	for (n = 0; n < 3; n++)   
	{
		int num_grid_x = (int)(this->inpWidth / this->stride[n]);
		int num_grid_y = (int)(this->inpHeight / this->stride[n]);
		// 遍历每个grid cell 的 3种大小 anchor box
		for (q = 0; q < 3; q++)    
		{
			const float anchor_w = this->anchors[n][q * 2];
			const float anchor_h = this->anchors[n][q * 2 + 1];
			// 每种anchor box 遍历每个grid cell
			for (i = 0; i < num_grid_y; i++)
			{
				for (j = 0; j < num_grid_x; j++)
				{
					// 访问第q种anchor box对应的数据
					float *ptrData = (float*)outs[n].data + q * num_grid_x * num_grid_y * nout;
                    //float* pdata = (float*)outs[0].data + q * num_grid_x * num_grid_y * nout;
					// 访问第 ij 个 grid cell 的10个数据
					int offset = i * num_grid_x * nout + j * nout;
					ptrData += offset;
					// 访问10个数据的 第5个数据 即 confidence置信度
					// cout << "pdata[4]:" << pdata[4] << endl ;
					auto pBox = ptrData + 4;
					// 归一化置信度
                    float box_score = sigmoid_xx(*pBox); 
					if (box_score > this->objThreshold)
					{
						// cout << "outs[n].cols: " << outs[n].cols << endl;
						// cout << "outs[n].rows: " << outs[n].rows << endl;
						// cout << "outs[n].row: " << outs[n].row(1) << endl;
						// cout << " outs[n].row(row_ind): " <<  outs[n].row(row_ind) << endl;
						// 取出10个数据的后5个 即类别信息 用以判断哪个类别
						Mat score_test ;
						for(uint8_t iter = 5 ; iter < nout ; iter ++){
							score_test.push_back(*(ptrData + iter)); 
						}
						// 把矩阵数据转化为队列
						score_test = score_test.reshape(0,1);
						// cout  << score_test.data << endl;
                        //Mat scores = outs[0].row(row_ind).colRange(5, outs[0].cols);
                        Point classIdPoint;
                        double max_class_socre;
                        // Get the value and location of the maximum score.
						// 获取类别数据中得分最高的数据 并返回索引
                        minMaxLoc(score_test, 0, &max_class_socre, 0, &classIdPoint);
						// 归一化得分最高的数据
                        max_class_socre = sigmoid_x((float)max_class_socre);
						if (max_class_socre > this->confThreshold)
						{
							//pxy的取值范围是[-0.5,1.5],pwh的取值范围是(0,4*anchors[i]]
							//用了跨网格匹配规则,要跨网格预测
							// 将每个grid cell中 bbox 的相对坐标 转换为正个图片的坐标
							float cx = (sigmoid_x(*ptrData) * 2.f - 0.5f + j) * this->stride[n];  ///cx
							float cy = (sigmoid_x(*(ptrData+1)) * 2.f - 0.5f + i) * this->stride[n];   ///cy
							float w = powf(sigmoid_x(*(ptrData+2)) * 2.f, 2.f) * anchor_w;   ///w
							float h = powf(sigmoid_x(*(ptrData + 3)) * 2.f, 2.f) * anchor_h;  ///h
							
							int left = (cx - 0.5*w)*ratiow;
							int top = (cy - 0.5*h)*ratioh;  
							//cout << "(left,top)" << Point2d(left,top) << endl;
							classIds.push_back(classIdPoint.x);
							confidences.push_back(max_class_socre);
							boxes.push_back(Rect(left, top, (int)(w*ratiow), (int)(h*ratioh)));
						}	
					}
					row_ind++;
				}
			}
		}
	}
	

后处理(非极大值抑制&画框)

	// Perform non maximum suppression to eliminate redundant overlapping boxes with
	// lower confidences
	vector<int> indices;
	NMSBoxes(boxes, confidences, this->confThreshold, this->nmsThreshold, indices);
	for (size_t i = 0; i < indices.size(); ++i)
	{
		int idx = indices[i];
		Rect box = boxes[idx];
		this->drawPred(classIds[idx], confidences[idx], box.x, box.y,
			box.x + box.width, box.y + box.height, frame);
		cout << "bbox x" << box.x << endl;
		cout << "bbox y" << box.y << endl;
		cout << "bbox width" << box.width << endl;
		cout << "bbox height" << box.height << endl;
		cout << "--------------" << endl;
		
	}

数据处理图解

在这里插入图片描述

标签:box,yolov5,float,int,dnn,opencv,num,grid,anchor
来源: https://blog.csdn.net/KNIGHT_HOY/article/details/122789180

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有