soft-nms代碼如下:
def soft_nms(np.ndarray[float, ndim=2] boxes, float sigma=0.5, float Nt=0.3, float threshold=0.001, unsigned int method=0):
cdef unsigned int N = boxes.shape[0]
cdef float iw, ih, box_area
cdef float ua
cdef int pos = 0
cdef float maxscore = 0
cdef int maxpos = 0
cdef float x1,x2,y1,y2,tx1,tx2,ty1,ty2,ts,area,weight,ov
for i in range(N):
maxscore = boxes[i, 4]
maxpos = i
tx1 = boxes[i,0]
ty1 = boxes[i,1]
tx2 = boxes[i,2]
ty2 = boxes[i,3]
ts = boxes[i,4]
pos = i + 1
# get max box
while pos < N:
if maxscore < boxes[pos, 4]:
maxscore = boxes[pos, 4]
maxpos = pos
pos = pos + 1
# add max box as a detection
boxes[i,0] = boxes[maxpos,0]
boxes[i,1] = boxes[maxpos,1]
boxes[i,2] = boxes[maxpos,2]
boxes[i,3] = boxes[maxpos,3]
boxes[i,4] = boxes[maxpos,4]
# swap ith box with position of max box
boxes[maxpos,0] = tx1
boxes[maxpos,1] = ty1
boxes[maxpos,2] = tx2
boxes[maxpos,3] = ty2
boxes[maxpos,4] = ts
tx1 = boxes[i,0]
ty1 = boxes[i,1]
tx2 = boxes[i,2]
ty2 = boxes[i,3]
ts = boxes[i,4]
pos = i + 1
# NMS iterations, note that N changes if detection boxes fall below threshold
while pos < N:
x1 = boxes[pos, 0]
y1 = boxes[pos, 1]
x2 = boxes[pos, 2]
y2 = boxes[pos, 3]
s = boxes[pos, 4]
area = (x2 - x1 + 1) * (y2 - y1 + 1)
iw = (min(tx2, x2) - max(tx1, x1) + 1)
if iw > 0:
ih = (min(ty2, y2) - max(ty1, y1) + 1)
if ih > 0:
ua = 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
boxes[pos, 4] = weight*boxes[pos, 4]
# if box score falls below threshold, discard the box by swapping with last box
# update N
if boxes[pos, 4] < threshold:
boxes[pos,0] = boxes[N-1, 0]
boxes[pos,1] = boxes[N-1, 1]
boxes[pos,2] = boxes[N-1, 2]
boxes[pos,3] = boxes[N-1, 3]
boxes[pos,4] = boxes[N-1, 4]
N = N - 1
pos = pos - 1
pos = pos + 1
keep = [i for i in range(N)]
return keep
調用例子爲:
soft_nms(boxes, Nt=0.5, method=2)
當時很迷惑,爲什麼返回時一個index,直接返回boxes不好嗎?
然後當時想,可能因爲傳入的boxes在函數中會被修改,所以就不需要再return回來了
爲了驗證這個想法,我記錄了soft-nms前與soft-nms後的score值
score_before = boxes[:, 4]
soft_nms(boxes, Nt=0.5, method=2)
score_after = boxes[:, 4]
diff = score_before - score_after
然後看他們的差值diff,如果不爲0的話,說明我的boxes的值確實是發生了變化的。但是發現diff居然一直爲零,然後就在soft-nms上耗了一個下午。。。。
先說結論吧:
- 我驗證的方式是錯誤的!!!!
- 調用soft-nms的時候,boxes確實是有變化的,所以不需要再return
原理
上面兩個結論用到的原理都一樣,就是:在python中,變量賦值的時候是以引用
的方式賦值的,例如:
a = [1]
b = a
print(id(a))
print(id(b))
你會發現a
和b
的id是一樣的!因爲他們就是指向的是同一個地址!如果你改變了a
,b
也會跟着變,例如
a.append(2)
print(a)
print(b)
b雖然沒有append,但是結果也會變爲[1,2]
爲什麼驗證的方式是錯誤
這就是了爲什麼我的驗證方法是錯誤的,因爲他們指向的是同一個地址,所以結果兩個scores當然會相同!Orz
爲什麼不用return boxes呢?
因爲boxes在傳入函數後,不是傳一個值進去,而是傳入了boxes的地址,所以在裏面的修改,會對原boxes地址上的值進行直接修改
當我們在後續再讀取boxes的時候,因爲是讀boxes地址的值,而地址上的值已經被改過了,所以我們讀到的就是修改後的值了,所以函數中不需要再return boxes回來