介绍目标检测中三种最常见的代码。

#IOU代码 
#box格式 (xmin,ymin,xmax,ymax)
def computeIOU(A, B):
    #assert A.size()==4 and B.size()==4, "must have 4 numbers"
    bxmin = max(A[0],B[0])
    bymin = max(A[1],B[1])
    bxmax = min(A[2],B[2])
    bymax = min(A[3],B[3])
    w = max(0, bxmax-bxmin + 1)
    h = max(0, bymax-bymin + 1)
    inter = w * h
    union = (A[2]-A[0]+1)*(A[3]-A[1]+1) + (B[2]-B[0]+1)*(B[3]-B[1]+1) - inter
    return inter / union


#数据测试 https://www.aiuai.cn/aifarm1127.html
A = [39, 63, 203, 112]
B = [54, 66, 198, 114]
print(computeIOU(A,B))  #0.7980093676814989

2 NMS代码

#NMS代码  
#dets格式array([[xmin,ymin,xmax,ymax,score],...]),shape(n,5)
def NMS(dets, thresh):
    #解析坐标值,若dets格式不同,需要注意顺序
    bxmin,bymin,bxmax,bymax,scores = dets[:,0],dets[:,1],dets[:,2],dets[:,3],dets[:,4]
    areas = (bxmax-bxmin+1) * (bymax-bymin+1)  #shape(n,) 各个预测框的面积
    order = scores.argsort()[::-1]  #按得分降序排列
    keep = []  #保留下来的预测框
    while order.size>0:
        i = order[0]  #这一轮中得分最高的预测框,用该主框来抑制其他重复框
        keep.append(i)
        #计算主框和其余框IOU
        xx = np.maximum(bxmin[i], bxmin[order[1:]])
        yy = np.maximum(bymin[i], bymin[order[1:]])
        XX = np.minimum(bxmax[i], bxmax[order[1:]])
        YY = np.minimum(bymax[i], bymax[order[1:]])
        w = np.maximum(0.0, XX-xx)
        h = np.maximum(0.0, YY-yy)
        inter = w * h
        iou = inter / (areas[i] + areas[order[1:]] - inter)
        idx = np.where(iou <= thresh)[0]  #找到iou值小于阈值的索引
        order = order[idx+1]  #更新order。前面的order已排除主框,故相比原索引减少了1
    return keep


#测试
import numpy as np

dets=[[0,0,100,100,0.9],[10,10,90,90,0.7],[50,50,120,120,0.8],[60,60,130,130,0.5]]
dets = np.array(dets)
keep = NMS(dets, 0.5)
print(keep)  #[0, 2]

3 mAP

#VOC计算AP的两种方式
def voc_ap(rec, prec, use_07_metric=False):
""" 
输入recall和precision,输出AP
Compute VOC AP given precision and recall.
If use_07_metric is true, uses the VOC 07 11 point method (default:False).
"""
    if use_07_metric:
        # 11 point metric
        ap = 0.
        for t in np.arange(0., 1.1, 0.1):
            if np.sum(rec >= t) == 0:
                p = 0
            else:
                p = np.max(prec[rec >= t])
            ap = ap + p / 11.
    else:
        # correct AP calculation
        # first append sentinel values at the end
        mrec = np.concatenate(([0.], rec, [1.]))
        mpre = np.concatenate(([0.], prec, [0.]))
        print(mpre)
        # compute the precision envelope
        for i in range(mpre.size - 1, 0, -1):
            mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
        # to calculate area under PR curve, look for points 
        # where X axis (recall) changes value
        i = np.where(mrec[1:] != mrec[:-1])[0]  #获取rec区间变化点
        ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) #在recall轴上积分

    return ap