# yolov测试各项指标的流程:
-
载入模型, 其中包括类别数等;
-
按照 batch_size 逐张图片进行预测
-
得到预测标签:
predn
和 实际标签labelsn
, 其中 末尾的n
表示经过了原图适配的 bbox坐标.predn: {tensor: (3,6)},表示预测到了3个标签, 表示[x1, y1, x2, y2, confidence, class] tensor([[754.00000, 86.00000, 767.00000, 104.00000, 1.00000, 0.00000], [676.00006, 241.00000, 689.00006, 260.00000, 1.00000, 0.00000], [731.00000, 311.00000, 752.00000, 327.00000, 1.00000, 0.00000]], device='cuda:0')
labelsn: {tensor: (3, 5)}, 实际有3个标签, 表示[class, x1, y1, x2, y2] tensor([[ 0.00000, 731.00000, 311.00000, 752.00000, 327.00000], [ 0.00000, 676.00006, 241.00000, 689.00006, 260.00000], [ 0.00000, 754.00000, 86.00000, 767.00000, 104.00000]], device='cuda:0')
-
计算混淆矩阵,
confusion_matrix.process_batch(predn, labelsn)
-
iou = box_iou(labels[:, 1:], detections[:, :4])
# 调用general中计算iou的方式计算iou假设两个 bbox 分别为: (突然心生疑问: 这个坐标怎么疑似表示为了 左下右上 的方式. 以往都是 左上右下 , 什么时候转成这样的呢?)
如果你也有这样的疑问, 那你就大错特错了…因为: 坐标系不一样. 如下图所示, 看到这个你就明白了.
所以, 坐标表示还是 左上右下 的! 切记.
# 实际box box1: {tensor:(3, 4)} tensor([[731.00000, 311.00000, 752.00000, 327.00000], [676.00006, 241.00000, 689.00006, 260.00000], [754.00000, 86.00000, 767.00000, 104.00000]], device='cuda:0') # 预测box box2: {tensor:{3, 4}} tensor([[754.00000, 86.00000, 767.00000, 104.00000], [676.00006, 241.00000, 689.00006, 260.00000], [731.00000, 311.00000, 752.00000, 327.00000]], device='cuda:0')
# 首先利用 box 的转置矩阵, 方便求面积, box1.T tensor([[731.00000, 676.00006, 754.00000], [311.00000, 241.00000, 86.00000], [752.00000, 689.00006, 767.00000], [327.00000, 260.00000, 104.00000]], device='cuda:0') box2.T tensor([[754.00000, 676.00006, 731.00000], [ 86.00000, 241.00000, 311.00000], [767.00000, 689.00006, 752.00000], [104.00000, 260.00000, 327.00000]], device='cuda:0')
则得到:
b o x 1 的 a r e a 1 = ( b o x 1 [ 2 ] . T − b o x 1 [ 0 ] ) ∗ ( b o x 1 [ 3 ] − b o x 1 [ 1 ] ) = t e n s o r ( [ 336. , 247. , 234. ] ) 同理求得 a r e a 2 = t e n s o r ( [ 234. , 247. , 336. ] ) box1 的 area1 = (box1[2].T - box1[0]) * (box1[3] - box1[1]) = tensor([336., 247., 234.]) \\ 同理求得 area2 = tensor([234., 247., 336.]) box1的area1=(box1[2].T−box1[0])∗(box1[3]−box1[1])=tensor([336.,247.,234.])同理求得area2=tensor([234.,247.,336.])然后一番操作, 就求出来了 IOU…
-
-
重点关注的几个变量:
targets: (真实标签) 存储此次 batch_size 中的所有变量, [当前BS中bbox数量, 6], 其中6维度依次是: [img_index, class, x, y, w, h]
out: 模型训练的结果, 包括所有的 bbox 以及置信度等,
- out: 经过NMS, 得到筛选过的 bbox, 成为了一个list, len(list) 表示图片的数量, 也就是 BS.
- out[0]: 此个 BS 中 第一张图片的预测结果, [bbox 数量, 6], 其中6维度依次是: [x1, y1, x2, y2, confidence, class]
依次遍历 targets 和 out, 分别得到 labels 和 pred,
pred: 此张图片预测的结果, 也就是 out[index]
predn: 经过 scale_coords
将预测的坐标信息 (pred的 bbox) 转换回相对原图尺度. 注意: 是 xyxy 格式的坐标信息转化为相对于原图的坐标信息.
labels: 第 i 个BS中真实标签信息, 也就是第 i 张图片
labelsn: 真实标签信息 xywh2xyxy, 然后再经过 scale_coords
转为相对原图的坐标信息
因此, 存在一个问题… yolo格式标签原来就是相对于原图的坐标信息, 什么时候转化为了 不是归一化后的[x,y, w,h] 呢?
原来是在
dataloader
中, 坐标是根据训练图像大小转化过 坐标信息的.LoadImagesAndLabels -> xywhn2xyxy
自定义性能测试文件
如果我想要更改 test.py / val.py
文件为从已有的两组标签中衡量性能, 我该如何做呢?
数据准备:
├─MOT16-02
│ ├─det
│ │ └─det.txt
│ ├─gt
│ │ └─gt.txt
│ ├─img1
│ │ ├─000001.jpg
│ │ ├─000002.jpg
│ │ ├─000003.jpg
其中, det/det.txt
文件包括 10列, 分别为:
1,-1,1359.1,413.27,120.26,362.77,2.3092,-1,-1,-1
1,-1,571.03,402.13,104.56,315.68,1.5028,-1,-1,-1
1,-1,650.8,455.86,63.98,193.94,0.33276,-1,-1,-1
1,-1,721.23,446.86,41.871,127.61,0.27401,-1,-1,-1
1,-1,454.06,434.36,97.492,294.47,0.20818,-1,-1,-1
<frame>, <id>, <bb_left>, <bb_top>, <bb_width>, <bb_height>, <conf>, <x>, <y>, <z>
<第几帧>, <轨迹编号, 在这里都是-1>, <bb_left>, <bb_top>, <bb_width>, <bb_height>, <conf>, <MOT3D_x>, <MOT3D_y>, <MOT3D_z>
注意: 最后三列是 MOT3D 用到的内容,2D检测总是为-1.
其中, gt/gt.txt
文件包括 10列, 分别为:
1,1,912,484,97,109,0,7,1
2,1,912,484,97,109,0,7,1
3,1,912,484,97,109,0,7,1
4,1,912,484,97,109,0,7,1
5,1,912,484,97,109,0,7,1
<frame>, <id>, <bb_left>, <bb_top>, <bb_width>, <bb_height>, <flag>, <class>, <visibility ratio>
<frame>, <运动轨迹ID号, 也就是第几个人>, <bb_left>, <bb_top>, <bb_width>, <bb_height>, <目标轨迹是否进入考虑范围内的标志,0表示忽略,1表示active>, <该轨迹对应的目标种类>, <目标可见比例, box的visibility ratio>
其中, seqinfo.ini
文件主要介绍视频的帧率、分辨率等基本信息。
其中有几个字段还是不清楚, 因此先根据标签画一下图片, 可视化一下标签和图片的匹配度.
-
分别载入 det/gt 格式标签;
- det: [x1, y1, x2, y2, confidence, class]
- gt: [img_index, class, x, y, x, y]
-
然后就可以直接根据坐标画框了. 关于
name
是可选的, 可以传入一个list
-
首先根据上面重点关注的几个变量出发, 找到入口处, 也就是循环遍历开始的地方.
-
准备好标签文件, 类型为: