# mean_ap_visualize.pydeftpfp_default(det_bboxes, gt_bboxes, gt_ignore, iou_thr, area_ranges=None):"""Check if detected bboxes are true positive or false positive.
Args:
det_bbox (ndarray): the detected bbox
gt_bboxes (ndarray): ground truth bboxes of this image
gt_ignore (ndarray): indicate if gts are ignored for evaluation or not
iou_thr (float): the iou thresholds
Returns:
tuple: (tp, fp), two arrays whose elements are 0 and 1
"""
num_dets = det_bboxes.shape[0]# 这里都是相对于单张图而言的,在下方map_roc_pr函数中有循环调用
num_gts = gt_bboxes.shape[0]if area_ranges isNone:
area_ranges =[(None,None)]
num_scales =len(area_ranges)# tp and fp are of shape (num_scales, num_gts), each row is tp or fp of# a certain scale
tp = np.zeros((num_scales, num_dets), dtype=np.float32)# 这里假定num_scales=1 则tp,fp的维度均为(1,num_dets),进而对当前图片的每个预测结果进行判断
fp = np.zeros((num_scales, num_dets), dtype=np.float32)# if there is no gt bboxes in this image, then all det bboxes# within area range are false positivesif gt_bboxes.shape[0]==0:if area_ranges ==[(None,None)]:
fp[...]=1else:
det_areas =(det_bboxes[:,2]- det_bboxes[:,0]+1)*(
det_bboxes[:,3]- det_bboxes[:,1]+1)for i,(min_area, max_area)inenumerate(area_ranges):
fp[i,(det_areas >= min_area)&(det_areas < max_area)]=1return tp, fp
ious = bbox_overlaps(det_bboxes, gt_bboxes)
ious_max = ious.max(axis=1)
ious_argmax = ious.argmax(axis=1)
sort_inds = np.argsort(-det_bboxes[:,-1])for k,(min_area, max_area)inenumerate(area_ranges):
gt_covered = np.zeros(num_gts, dtype=bool)# if no area range is specified, gt_area_ignore is all Falseif min_area isNone:
gt_area_ignore = np.zeros_like(gt_ignore, dtype=bool)else:
gt_areas =(gt_bboxes[:,2]- gt_bboxes[:,0]+1)*(
gt_bboxes[:,3]- gt_bboxes[:,1]+1)
gt_area_ignore =(gt_areas < min_area)|(gt_areas >= max_area)for i in sort_inds:if ious_max[i]>= iou_thr:# 根据设定的IoU阈值对每一个预测结果对应的tp或fp赋1
matched_gt = ious_argmax[i]ifnot(gt_ignore[matched_gt]or gt_area_ignore[matched_gt]):ifnot gt_covered[matched_gt]:
gt_covered[matched_gt]=True
tp[k, i]=1else:
fp[k, i]=1# otherwise ignore this detected bbox, tp = 0, fp = 0elif min_area isNone:
fp[k, i]=1else:
bbox = det_bboxes[i,:4]
area =(bbox[2]- bbox[0]+1)*(bbox[3]- bbox[1]+1)if area >= min_area and area < max_area:
fp[k, i]=1return tp, fp # tuple: (tp, fp), two arrays whose elements are 0 and 1
下面再来看一下得到最终tp和fp值的函数
defmap_roc_pr(det_results,
gt_bboxes,
gt_labels,
gt_ignore=None,
scale_ranges=None,
iou_thr=0.5,
dataset=None,
print_summary=True):"""Evaluate mAP of a dataset.
Args:
det_results (list): a list of list, [[cls1_det, cls2_det, ...], ...]
gt_bboxes (list): ground truth bboxes of each image, a list of K*4
array.
gt_labels (list): ground truth labels of each image, a list of K array
gt_ignore (list): gt ignore indicators of each image, a list of K array
scale_ranges (list, optional): [(min1, max1), (min2, max2), ...]
iou_thr (float): IoU threshold
dataset (None or str or list): dataset name or dataset classes, there
are minor differences in metrics for different datsets, e.g.
"voc07", "imagenet_det", etc.
print_summary (bool): whether to print the mAP summary
Returns:
tuple: (mAP, [dict, dict, ...])
"""assertlen(det_results)==len(gt_bboxes)==len(gt_labels)# 与测试集的数目相同if gt_ignore isnotNone:assertlen(gt_ignore)==len(gt_labels)for i inrange(len(gt_ignore)):assertlen(gt_labels[i])==len(gt_ignore[i])
area_ranges =([(rg[0]**2, rg[1]**2)for rg in scale_ranges]if scale_ranges isnotNoneelseNone)
num_scales =len(scale_ranges)if scale_ranges isnotNoneelse1
eval_results =[]
num_classes =len(det_results[0])# positive class num
gt_labels =[
label if label.ndim ==1else label[:,0]for label in gt_labels
]
f_measure_list =[]
recall_list =[]
precision_list =[]
ap_list =[]for i inrange(num_classes):# recall 和 precison 都是针对二分类的,所以如果有多个类别则需分别计算# get gt and det bboxes of this class
cls_dets, cls_gts, cls_gt_ignore = get_cls_results(
det_results, gt_bboxes, gt_labels, gt_ignore, i)# calculate tp and fp for each image
tpfp_func =(# 这里假定调用上方分析的tpfp_default函数
tpfp_imagenet if dataset in['det','vid']else tpfp_default)
tpfp =[
tpfp_func(cls_dets[j], cls_gts[j], cls_gt_ignore[j], iou_thr,
area_ranges)for j inrange(len(cls_dets))# 循环 对每张图都得到tpfp_default的返回结果]
tp, fp =tuple(zip(*tpfp))# calculate gt number of each scale, gts ignored or beyond scale# are not counted
num_gts = np.zeros(num_scales, dtype=int)for j, bbox inenumerate(cls_gts):if area_ranges isNone:
num_gts[0]+= np.sum(np.logical_not(cls_gt_ignore[j]))else:
gt_areas =(bbox[:,2]- bbox[:,0]+1)*(
bbox[:,3]- bbox[:,1]+1)for k,(min_area, max_area)inenumerate(area_ranges):
num_gts[k]+= np.sum(
np.logical_not(cls_gt_ignore[j])&(gt_areas >= min_area)&(gt_areas < max_area))# sort all det bboxes by score, also sort tp and fp
cls_dets = np.vstack(cls_dets)
num_dets = cls_dets.shape[0]
sort_inds = np.argsort(-cls_dets[:,-1])
tp = np.hstack(tp)[:, sort_inds]
fp = np.hstack(fp)[:, sort_inds]# calculate recall and precision with tp and fp
tp = np.cumsum(tp, axis=1)# 累加操作!(随着置信度降低,进而得到对应的recall和precision用以绘制PR曲线)
fp = np.cumsum(fp, axis=1)
eps = np.finfo(np.float32).eps
recalls = tp / np.maximum(num_gts[:, np.newaxis], eps)
precisions = tp / np.maximum((tp + fp), eps)# 到这里就清楚recall和precision的值了。其具体形式如下:
……
……
……
return mean_ap, eval_results