计算nms必须首先计算iou值.
def compute_iou(rec1, rec2):
"""
computing IoU
:param rec1: (y0, x0, y1, x1), which reflects
(top, left, bottom, right)
:param rec2: (y0, x0, y1, x1)
:return: scala value of IoU
"""
# computing area of each rectangles
S_rec1 = (rec1[2] - rec1[0]) * (rec1[3] - rec1[1])
S_rec2 = (rec2[2] - rec2[0]) * (rec2[3] - rec2[1])
# computing the sum_area
sum_area = S_rec1 + S_rec2
# find the each edge of intersect rectangle
left_line = max(rec1[1], rec2[1])
right_line = min(rec1[3], rec2[3])
top_line = max(rec1[0], rec2[0])
bottom_line = min(rec1[2], rec2[2])
# judge if there is an intersect
if left_line >= right_line or top_line >= bottom_line:
return 0
else:
intersect = (right_line - left_line) * (bottom_line - top_line)
return intersect / (sum_area - intersect)
做个记录
下面函数是对boxlists1的框使用nms.
def reufion_to_file(filename, boxlists1, imglists):
with open(filename, 'w') as ff:
for i in range(len(boxlists1)):
print(i, ' imge :', imglists[i])
new_boxes = []
res_boxes = []
bbolist = boxlists1[i]
print('all num of boxes :', len(bbolist))
if len(bbolist) > 0:
# 处理数据,框小于4用4代替, 最小分数设置TH
bbolist = str2num(bbolist)
bbolist = np.array(bbolist)
indx = bbolist[:,2] < 4
bbolist[indx, 2] = 3
indx = bbolist[:, 3] < 4
bbolist[indx, 3] = 3
indx = bbolist[:, 4] >= TH
bbolist = bbolist[indx]
# 对每张图的bbolist使用nms
if len(bbolist) > 0:
new_boxes.append(bbolist[0])
for boxe1 in bbolist:
for boxe2 in new_boxes:
rec1 = [boxe1[0], boxe1[1], boxe1[0] + boxe1[2], boxe1[1] + boxe1[3]]
rec2 = [boxe2[0], boxe2[1], boxe2[0] + boxe2[2], boxe2[1] + boxe2[3]]
iou = compute_iou(rec1, rec2)
if iou > IOU :
break
if iou <= IOU:
new_boxes.append(boxe1)
soft-nms如下:
def soft_nms(box, threshold=0.001, sigma=0.5, Nt=0.3, method=1):
N = len(box)
for i in range(N):
maxscore = box[i, 4]
maxpos = i
tx1 = box[i, 0]
ty1 = box[i, 1]
tx2 = box[i, 2]
ty2 = box[i, 3]
ts = box[i, 4]
pos = i + 1
# get max box
while pos < N:
if maxscore < box[pos, 4]:
maxscore = box[pos, 4]
maxpos = pos
pos = pos + 1
# add max box as a detection
box[i, 0] = box[maxpos, 0]
box[i, 1] = box[maxpos, 1]
box[i, 2] = box[maxpos, 2]
box[i, 3] = box[maxpos, 3]
box[i, 4] = box[maxpos, 4]
# swap ith box with position of max box
box[maxpos, 0] = tx1
box[maxpos, 1] = ty1
box[maxpos, 2] = tx2
box[maxpos, 3] = ty2
box[maxpos, 4] = ts
tx1 = box[i, 0]
ty1 = box[i, 1]
tx2 = box[i, 2]
ty2 = box[i, 3]
ts = box[i, 4]
pos = i + 1
# NMS iterations, note that N changes if detection box fall below threshold
while pos < N:
x1 = box[pos, 0]
y1 = box[pos, 1]
x2 = box[pos, 2]
y2 = box[pos, 3]
s = box[pos, 4]
area = (x2 * y2)#(x2 - x1 + 1) * (y2 - y1 + 1)
iw = (min(tx1 + tx2, x1 + x2) - max(tx1, x1) + 1) #(min(tx2, x2) - max(tx1, x1) + 1)
if iw > 0:
ih = (min(ty1 + ty2, y1 + y2) - max(ty1, y1) + 1) #(min(ty2, y2) - max(ty1, y1) + 1)
if ih > 0:
ua = float(tx2 * ty2 + area - iw * ih)#float((tx2 - tx1 + 1) * (ty2 - ty1 + 1) + area - iw * ih)
ov = iw * ih / ua # iou between max box and detection box
if method == 1: # linear
if ov > Nt:
weight = 1 - ov
else:
weight = 1
elif method == 2: # gaussian
weight = np.exp(-(ov * ov) / sigma)
else: # original NMS
if ov > Nt:
weight = 0
else:
weight = 1
box[pos, 4] = weight * box[pos, 4]
# if box score falls below threshold, discard the box by swapping with last box
# update N
if box[pos, 4] < threshold:
box[pos, 0] = box[N - 1, 0]
box[pos, 1] = box[N - 1, 1]
box[pos, 2] = box[N - 1, 2]
box[pos, 3] = box[N - 1, 3]
box[pos, 4] = box[N - 1, 4]
N = N - 1
pos = pos - 1
pos = pos + 1
keep = [i for i in range(N)]
return keep
使用soft-nms
def reufion_to_file_nums(filename, boxlists1, imglists):
with open(filename, 'w') as ff:
for i in range(len(boxlists1)):
print(i, ' imge :', imglists[i])
bbolist = boxlists1[i]
print('all num of boxes :', len(bbolist))
if len(bbolist) > 0:
# 处理数据,框小于4用4代替, 最小分数设置TH
bbolist = str2num(bbolist)
bbolist = np.array(bbolist)
indx = bbolist[:,2] < 4
bbolist[indx, 2] = 3
indx = bbolist[:, 3] < 4
bbolist[indx, 3] = 3
remain = soft_nms(bbolist, threshold=TH, sigma=sigma, Nt=Nt, method=method)
bbolist = bbolist[remain]
print('after nums num of boxes : ', len(bbolist), '\n')
scorce = bbolist[:,-1].astype(str)
bbolist = bbolist.astype(int).astype(str)
bbolist[:,-1] = scorce
img_name = imglists[i]
ff.write(img_name + '\n')
ff.write(str(len(bbolist)) + '\n')
for boexs in bbolist:
boexs = ' '.join(boexs)
ff.writelines(boexs + '\n')
目标检测时出现多个框重合,也可以把iou高的一批框进整合,得到一个中心框.如下:
def GeneralEnsemble(dets, iou_thresh=0.5, weights=None):
assert (type(iou_thresh) == float)
ndets = len(dets)
if weights is None:
w = 1 / float(ndets)
weights = [w] * ndets
else:
assert (len(weights) == ndets)
s = sum(weights)
for i in range(0, len(weights)):
weights[i] /= s
out = list()
used = list()
for idet in range(0, ndets):
det = dets[idet]
# 从某一个模型开始进行搜集相似的box
for box in det:
if box in used:
continue
used.append(box)
# 已经对比过的盒子
# Search the other detectors for overlapping box of same class
found = []
for iodet in range(0, ndets):
# 从某一个模型开始进行搜集相似的盒子
odet = dets[iodet]
# 从其他box
if odet == det:
continue
bestbox = None
bestiou = iou_thresh
for obox in odet:
if not obox in used:
# Not already used
iou = computeIOU(box, obox)
if iou > bestiou:
# 某个框与box重合度比较大
#
bestiou = iou
bestbox = obox
if not (bestbox is None):
# 只融合重合度最大的那个,每个检测只有以一个
w = weights[iodet]
found.append((bestbox, w))
used.append(bestbox)
# Now we've gone through all other detectors
if len(found) == 0:
new_box = list(box)
new_box[4] /= ndets
out.append(new_box)
else:
allboxes = [(box, weights[idet])]
allboxes.extend(found)
# 中心点
xc = 0.0
yc = 0.0
bw = 0.0
bh = 0.0
conf = 0.0
wsum = 0.0
for bb in allboxes:
# 对这一批相似重合度极大的box的list,求得其中的中心点
# 求聚类中心
w = bb[1]
wsum += w
b = bb[0]
xc += w * b[0]
yc += w * b[1]
bw += w * b[2]
bh += w * b[3]
conf += w * b[4]
xc /= wsum
yc /= wsum
bw /= wsum
bh /= wsum
new_box = [xc, yc, bw, bh, conf]
out.append(new_box)
return out
参考:
soft-nms
网友评论