非極大值抑制-NMS
阿新 • • 發佈:2019-01-06
圖片來源
原理如下:
非極大值抑制的方法是:在進行目標檢測時會產生很多候選區域,如圖所示產生了1~5號框,而這些候選區域一般會有好多重疊的部分,先對這些框的概率從大到小進行排序,然後按概率從大到小遍歷所有框:
(1)從最大概率1號矩形框開始,分別判斷剩下的框與該框的重疊度IOU(IOU的計算)是否大於某個設定的閾值;
(2)假設2、3與1的IOU超過閾值,那麼就扔掉2、3;並標記第一個矩形框1保留下來。
(3)從剩下的矩形框4、5中,選擇概率最大的4,然後判斷4、5的IOU,IOU大於一定的閾值,那麼就扔掉;並標記4為第二個矩形框。
就這樣一直重複,找到所有被保留下來的矩形框。
程式碼如下:
def non_max_suppression_fast(boxes, probs, overlap_thresh=0.9, max_boxes=300):
# code used from here: http://www.pyimagesearch.com/2015/02/16/faster-non-maximum-suppression-python/
# if there are no boxes, return an empty list
if len(boxes) == 0:
return []
# 獲取框的座標
x1 = boxes[:, 0 ]
y1 = boxes[:, 1]
x2 = boxes[:, 2]
y2 = boxes[:, 3]
np.testing.assert_array_less(x1, x2)
np.testing.assert_array_less(y1, y2)
# if the bounding boxes integers, convert them to floats --
# this is important since we'll be doing a bunch of divisions
if boxes.dtype.kind == "i" :
boxes = boxes.astype("float")
# pick用來存放選取的框的索引
pick = []
# 計算框的面積
area = (x2 - x1) * (y2 - y1)
# 排序,返回框的概率從小到大的索引值
idxs = np.argsort(probs)
# 按框的概率從大到小迴圈遍歷
while len(idxs) > 0:
# 獲取索引列表中的最後一個索引,並將索引值新增到pick列表中
last = len(idxs) - 1
i = idxs[last]
pick.append(i)
# 計算選取的框與剩下框的交集
xx1_int = np.maximum(x1[i], x1[idxs[:last]])
yy1_int = np.maximum(y1[i], y1[idxs[:last]])
xx2_int = np.minimum(x2[i], x2[idxs[:last]])
yy2_int = np.minimum(y2[i], y2[idxs[:last]])
ww_int = np.maximum(0, xx2_int - xx1_int)
hh_int = np.maximum(0, yy2_int - yy1_int)
area_int = ww_int * hh_int
# 計算選取的框與剩下框的並集
area_union = area[i] + area[idxs[:last]] - area_int
# 計算交併比
overlap = area_int/(area_union + 1e-6)
# 刪除掉重疊率較高的和最後一個索引(因為最後一個已經加入到pick中)
idxs = np.delete(idxs, np.concatenate(([last],
np.where(overlap > overlap_thresh)[0])))
#如果選取的框的數量達到上限就停止
if len(pick) >= max_boxes:
break
# return only the bounding boxes that were picked using the integer data type
boxes = boxes[pick].astype("int")
probs = probs[pick]
return boxes, probs