介紹目標檢測中三種最常見的代碼。
1 IOU代碼
#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