如何将YOLOv4特征向量转换为边界框?TensorRT C++实现疑问
从TensorRT输出解析YOLOv4边界框的步骤
先明确你的输出结构:18个通道对应3个锚框,每个锚框包含[tx, ty, tw, th, conf, class_prob](4个坐标偏移值+1个置信度+1个类别概率,因为你做的是人像检测,类别数为1)。
1. 遍历三个尺度的输出
三个尺度(52×52、26×26、13×13)分别对应小、中、大目标的检测,需要逐个处理:
- 对每个尺度的网格点(i,j)(i为行索引,j为列索引),遍历3组通道(0-5、6-11、12-17,每组对应一个锚框)
- 取出每组通道的6个值:
tx, ty, tw, th, conf, cls_prob
2. 计算图像绝对坐标
YOLO的输出是基于网格的偏移量,需要转换为图像的真实坐标:
- 先匹配对应尺度的预定义锚框(YOLOv4针对这三个尺度的标准锚框为:10,13 16,30 33,23;30,61 62,45 59,119;116,90 156,198 373,326,必须和训练模型时用的锚框完全一致)
- 计算网格内的相对中心坐标:
cx = j + sigmoid(tx),cy = i + sigmoid(ty)(sigmoid将偏移量映射到0-1范围,对应网格内的相对位置) - 计算框的真实宽高:
bw = anchor_w * exp(tw),bh = anchor_h * exp(th)(exp还原宽高的缩放比例) - 转换为图像绝对坐标(以YOLOv4常用的416×416输入尺寸为例):
x1 = (cx - bw/2) * 416y1 = (cy - bh/2) * 416x2 = (cx + bw/2) * 416y2 = (cy + bh/2) * 416
若预处理时缩放的图像尺寸不是416×416,替换对应数值即可;最后需将坐标映射回原始图像尺寸。
3. 过滤低置信度框
- 计算框的综合得分:
score = sigmoid(conf) * sigmoid(cls_prob)(原始输出为logit值,需用sigmoid转换为0-1的概率) - 设置置信度阈值(比如0.5),过滤掉得分低于阈值的框
4. 非极大值抑制(NMS)
同一个目标会被多个框重复检测,用NMS去重:
- 将所有保留的框按得分降序排序
- 遍历每个框,移除与它交并比(IOU)大于阈值(比如0.5)的其他框
C++代码示例片段
// 假设已获取三个尺度的输出数据,存放在float* out1, out2, out3中 // 定义对应三个尺度的锚框 float anchors[3][6] = { {10.0f,13.0f, 16.0f,30.0f, 33.0f,23.0f}, // 52x52尺度 {30.0f,61.0f, 62.0f,45.0f, 59.0f,119.0f}, // 26x26尺度 {116.0f,90.0f, 156.0f,198.0f, 373.0f,326.0f} // 13x13尺度 }; // 处理52x52尺度输出 int grid_size = 52; float* output = out1; for(int i = 0; i < grid_size; i++){ for(int j = 0; j < grid_size; j++){ for(int anchor_idx = 0; anchor_idx < 3; anchor_idx++){ int channel_base = anchor_idx * 6; float tx = output[(i*grid_size + j)*18 + channel_base + 0]; float ty = output[(i*grid_size + j)*18 + channel_base + 1]; float tw = output[(i*grid_size + j)*18 + channel_base + 2]; float th = output[(i*grid_size + j)*18 + channel_base + 3]; float conf = output[(i*grid_size + j)*18 + channel_base + 4]; float cls_prob = output[(i*grid_size + j)*18 + channel_base + 5]; // 实现sigmoid函数 auto sigmoid = [](float x){ return 1.0f / (1.0f + exp(-x)); }; float cx = j + sigmoid(tx); float cy = i + sigmoid(ty); float bw = anchors[0][anchor_idx*2] * exp(tw); float bh = anchors[0][anchor_idx*2+1] * exp(th); // 转换为416x416图像的绝对坐标 float x1 = (cx - bw/2.0f) * 416.0f; float y1 = (cy - bh/2.0f) * 416.0f; float x2 = (cx + bw/2.0f) * 416.0f; float y2 = (cy + bh/2.0f) * 416.0f; // 计算得分并过滤 float score = sigmoid(conf) * sigmoid(cls_prob); if(score > 0.5){ // 保存框信息:x1, y1, x2, y2, score // ... } } } } // 同理处理26x26和13x13尺度的输出,注意对应anchors的索引(anchors[1]和anchors[2]) // 最后对所有保存的框执行NMS
注意事项
- 锚框必须和训练YOLOv4模型时使用的完全一致,否则坐标计算会出现偏差
- 若输入图像尺寸不是416×416,需调整坐标缩放的系数
- 可自行实现更高效的sigmoid和exp函数,替代标准库函数提升性能
内容的提问来源于stack exchange,提问作者fettahyildiz
相关产品推荐
相关产品推荐

