PV-RCNN代码解读——TP,FP,TN,FN的计算
PV-RCNN:,
配套实践篇:
PV-RCNN代码测试——TP,FP,TN,FN的计算(⼆)
(⼀)⽬标检测模型评估的简介
后⾯的代码中涉及到⽬标检测中⼏个重要的定义:
True positives : 正样本被正确识别为正样本,飞机的图⽚被正确的识别成飞机。
True negatives: 负样本被正确识别为负样本,飞机的图⽚被正确地识别为不是⼤雁。
Fal positives: 负样本被错误识别为正样本,飞机的图⽚被错误地识别成了⼤雁。
Fal negatives: 正样本被错误识别为负样本,飞机的图⽚被错误地识别为不是飞机。
Precision :检索出来的条⽬中有多⼤⽐例是我们需要的。
Recall:我们需要的条⽬中有多⼤⽐例被检索出来了。
(⼆)compute_statistics_jit函数
compute_statistics_jit函数的调⽤
# pcdet/datats/kitti/kitti_object_eval_python/eval.py
# 计算统计量tp, fp, fn, similarity, thresholds
rets = compute_statistics_jit(
overlaps[i],# 单个图像的iou值b/n gt和dt
gt_datas_list[i],# N x 5阵列
dt_datas_list[i],# N x 6阵列
ignored_gts[i],# 长度N数组,-1、0、1
ignored_dets[i],# 长度N数组,-1、0、1
dontcares[i],# ⽆关框数量x 4
metric,# 0, 1, 或 2 (bbox, bev, 3d)
min_overlap=min_overlap,# 浮动最⼩IOU阈值为正
thresh=0.0,# 忽略得分低于此值的dt。
compute_fp=Fal)
tp, fp, fn, similarity, thresholds, _ = rets
compute_statistics_jit函数的定义
# pcdet/datats/kitti/kitti_object_eval_python/eval.py
# 计算统计量tp, fp, fn, similarity, thresholds
def compute_statistics_jit(overlaps,
gt_datas,
dt_datas,
ignored_gt,
ignored_det,
dc_bboxes,
metric,
min_overlap,
thresh=0,
compute_fp=Fal,# 如果我们在计算召回阈值(recall thresholds),则将compute_fp设置为Fal。
compute_aos=Fal):
det_size = dt_datas.shape[0]
gt_size = gt_datas.shape[0]
dt_scores = dt_datas[:,-1]
dt_alphas = dt_datas[:,4]
gt_alphas = gt_datas[:,4]
gt_alphas = gt_datas[:,4]
dt_bboxes = dt_datas[:,:4]
gt_bboxes = gt_datas[:,:4]
assigned_detection =[Fal]* det_size # 存储是否每个检测都分配给了⼀个gt。
ignored_threshold =[Fal]* det_size # 如果检测分数低于阈值,则存储数组
if compute_fp:
for i in range(det_size):
if(dt_scores[i]< thresh):
ignored_threshold[i]=True
NO_DETECTION =-10000000
tp, fp, fn, similarity =0,0,0,0
泡温泉穿什么衣服# thresholds = [0.0]
# delta = [0.0]
thresholds = np.zeros((gt_size,))
thresh_idx =0# ⽤于计算阈值
delta = np.zeros((gt_size,))
delta_idx =0
#! detection-toolbox的作者补充的代码 ----
世界森林日
extra ={
#! 对于每个gt框,存储它是否为-1 (忽略), 0 (fal negative (不匹配)), 1 (true positive (匹配))
"gt_box_type": np.full((gt_size,),-1),
#! 对于每个dt框,存储它是否为-1 (⽆关), 0 (fal positive (不匹配)), 1 (true positive (匹配))
#! -1表⽰它在don't care范围内,属于其他类,等等
"dt_box_type": np.full((det_size,),-1),
#! 存储匹配对象的idx
"gt_box_matched_idx": np.full((gt_size,),-1),
"dt_box_matched_idx": np.full((det_size,),-1)
}
#! 遍历gt框
for i in range(gt_size):#遍历gt
if ignored_gt[i]==-1:#! 不要匹配完全不相关的gt框
continue
det_idx =-1#! 储存对此gt存储的最佳检测的idx
valid_detection = NO_DETECTION #! 存储到⽬前为⽌检测到的最⼤分数。
max_overlap =0#! 最佳检测的overlap。best是最⾼重叠
assigned_ignored_det =Fal
for j in range(det_size):#遍历dt
if(ignored_det[j]==-1):#! 与完全不相关的dt框不匹配
continue
if(assigned_detection[j]):#! 如果已经分配了dt,请跳过(分配给更好的gt)
continue
if(ignored_threshold[j]):#! 如果dt分数低于阈值,则跳过
continue
overlap = overlaps[j, i]#! 当前此dt和此gt之间的overlap
dt_score = dt_scores[j]#! 当前dt的分数
if(not compute_fp # compute_fp为fal,则这是唯⼀重要的部分
and(overlap > min_overlap)# 找到⾜够的重叠
and dt_score > valid_detection):# 找最⾼分的检测
det_idx = j
valid_detection = dt_score
elif(compute_fp #! 当compute_fp为true时,我们基于overlap进⾏选择
and(overlap > min_overlap)#! compute_fp为true。这意味着我们正在度量,⽽不是设置阈值。
and(overlap > max_overlap or assigned_ignored_det)#! 如果重叠⾜够(⽐以前的重叠好,或者我们不关⼼以前的重复)and ignored_det[j]==0):#⽽当前的需求是我们所关⼼的,
max_overlap = overlap # 分配
max_overlap = overlap # 分配
det_idx = j #更新重叠的det_idx
valid_detection =1#由于我们没有按分数排名,因此我们对有效检测进⾏了留⼀法检验。
assigned_ignored_det =Fal#⽤留⼀法来表明已经分配了关⼼的单位
elif(compute_fp #! compute_fp为true。
and(overlap > min_overlap)#! 如果重叠⾜够
and(valid_detection == NO_DETECTION)#尚未分配任何东西
and ignored_det[j]==1):#是我们不关⼼的检测
珍惜水资源手抄报
det_idx = j #我们分配它,因为我们将max_overlap保留为默认设置,因此任何内容都可以覆盖它。
valid_detection =1
assigned_ignored_det =True
#? ⼀个奇怪的事情是我们不关⼼的事物,如果我们分配第⼀个,则下⼀个⽆法覆盖它,因为valid_detection!= NO_DETECTION if(valid_detection == NO_DETECTION)#! 如果我们⽆法将此gt与任何东西匹配
and ignored_gt[i]==0:#⽽这是我们关⼼的事情
fn +=1#那将是⼀个fal negative
extra['gt_box_type'][i]=0
elif((valid_detection != NO_DETECTION)#! 如果我们确实将此gt与某些内容匹配
and(ignored_gt[i]==1or ignored_det[det_idx]==1)):#gt是我们不关⼼的东西,或者det是我们不关⼼的东西
assigned_detection[det_idx]=True#! 我们分配它
# 为什么?可能是因为如果我们不分配它,那么以后它将是⼀个误报(未分配的det)
extra['gt_box_type'][i]=-1
extra['dt_box_type'][det_idx]=-1
elif valid_detection != NO_DETECTION:#! 如果我们确实将此gt与某些内容匹配,
日历制作模板
#! 剩下的条件是:gt是我们关⼼的东西,det是我们关⼼的东西
#! true positive.
extra['gt_box_type'][i]=1
extra['dt_box_type'][det_idx]=1
extra['gt_box_matched_idx'][i]= det_idx
extra['dt_box_matched_idx'][det_idx]= i
坐井观天的故事tp +=1# 仅在tp上添加阈值。
# thresholds.append(dt_scores[det_idx])
thresholds[thresh_idx]= dt_scores[det_idx]#! 在这⾥,我们还将det分数附加到阈值的末尾
thresh_idx +=1
if compute_aos:
# delta.append(gt_alphas[i] - dt_alphas[det_idx])
delta[delta_idx]= gt_alphas[i]- dt_alphas[det_idx]
delta_idx +=1
assigned_detection[det_idx]=True#! 然后,将检测分配为True
#! 在没有检测到结果并且gt是我们不在乎的时候
el:
extra['gt_box_type'][i]=-1
#? 到⽬前为⽌,我们还没有使⽤ dc boxes。这是因为它们仅⽤于误报计算(fal positive )因为我们还没有研究过不匹配的检测
#? 如果⾥⾯有⼀个不匹配的东西不在乎,我们就不算它为FP
if compute_fp:
for i in range(det_size):#! 遍历检测
if(not(assigned_detection[i]#未分配给gt
or ignored_det[i]==-1#! 不同的类别
or ignored_det[i]==1#! ⼤⼩不同
or ignored_threshold[i])):#! 不低于分数阈值
fp +=1
extra['dt_box_type'][i]=0#! fal positive!
#! 这是我们从⽆关区域中收集到的检测数量。我们将从fp中减去它。
nstuff =0
if metric ==0:#! Metric == 0 是 2d bbox
overlaps_dt_dc = image_box_overlap(dt_bboxes, dc_bboxes,0)#! dt盒和dc盒之间的ious。
for i in range(dc_bboxes.shape[0]):
for j in range(det_size):
# 跳过上⾯没有添加到fp的内容
# 跳过上⾯没有添加到fp的内容
if(assigned_detection[j]):
continue
if(ignored_det[j]==-1or ignored_det[j]==1):
continue
if(ignored_threshold[j]):
continue
男士短发图片if overlaps_dt_dc[j, i]> min_overlap:#! 如果两者之间的重叠⼤于min_overlap
assigned_detection[j]=True# 将检测结果分配给dc
nstuff +=1#并将其添加到我们从fp中获得的东西中。
extra['dt_box_type'][j]=-1
fp -= nstuff # 从FP减去nstuff
if compute_aos:
tmp = np.zeros((fp + delta_idx,))
# tmp = [0] * fp
for i in range(delta_idx):
tmp[i + fp]=(1.0+ np.cos(delta[i]))/2.0
# tmp.append((1.0 + np.cos(delta[i])) / 2.0)
便宜的近义词# asrt len(tmp) == fp + tp
# asrt len(delta) == tp
if tp >0or fp >0:
similarity = np.sum(tmp)
el:
similarity =-1科学哲学
'''
!我们在这⾥说明条件。
!
if compute_fp:
! tp和fn在这⾥,fp和similarity就没有⽤
! thresholds[:thresh_idx] = thresholds
!因此,基本上,我们必须使⽤⼯具来计算召回率和匹配的dts的得分。
'''
return tp, fp, fn, similarity, thresholds[:thresh_idx]
致谢:detection-toolbox的作者将代码中的注释写的太清晰了,对我理解代码起到了很⼤帮助。有需要的读者可以看。我的其他PV-RCNN代码解读系列⽂章,如果对你有帮助的话,请给我点赞哦~