然後關鍵的部分來了,我們對iou進行篩選,若iou大於我們所設定的閾值,則我們認為,此框與基準框檢測的為同一目標,為重複檢測,我們就將其抑制,若iou低於我們設定的閾值,我們就進行下一步的迴圈,取出經過第一輪所篩選後的框,仍然取出剩下的框的分數最高的box,作為新的基準框,對剩下的框再次計算iou,仍然遵循上述的iou大於則抑制,小於等於則進入下一輪迴圈,直至框的數量為0.
這樣說可能仍然有些難以理解。
我們舉個例子會更好理解。假設我們**人臉出現了七個框:
分數分別為[0.9,0.8,0.7,0.6,0.5,0.4,0.3]
首先我們取出分數為0.9的框,作為基準框,剩餘的六個框依次與其進行iou計算
計算的iou假設為[0.7,0.8,0.6,0.4,0.6,0.2]
假設我們設定的iou閾值thresh為0.5,
則上述與基準框iou大於0.5的框均會抑制,即只剩下iou為0.4和0.2的框,也就是對應的分數為0.5和0.3的框。
此時我們進行新一輪的迴圈,我們將分數最高的0.5取出,將此框為基準框,計算剩下的box與其iou,若iou大於0.5則抑制,iou小於等於0.5則保留,假設剩下的分數為0.3的框與基準框iou為0.3,則保留,進入下一輪的迴圈。
如此多次迴圈後,每次的基準框都會被保留,直到所有的box數量為0。
好了,原理已經清楚,剩下的就是準備使用numpy手撕nms函式了。
我們首先從**的結果中獲得box的資訊:
以dets來接收box的資訊,
從dets中讀取box的資訊:
#dets為送入nms的框的資訊的集合,它是[x1,x2,y1,y2,score]的集合
#依次讀取x1,x2,y1,y2注意此時的他們都不是單獨的數,而是乙個用於存放所有的box的資訊集合
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
scores = dets[:, 4]
讀取了座標資訊和分數資訊後,我們求取其面積,為後面的iou計算做準備:
areas = (x2 - x1)*(y2 - y1)
但是實際中,我們為了保證區域面積不為零所以常用下面的方式:
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
接下來我們要對分數進行排序,因為我們始終需要進行一項取最高的分數的操作,所以我們一開始就對分數進行由高到低的排序,這樣後面就無需重複操作。
order = scores.argsort()[::-1]
x = np.array([3, 1, 2])np.argsort(x)
array([1, 2, 0])
可以看出numpy中的argsort函式可以對乙個array進行由低到高的操作,並返回其索引值。上面的返回值1,2,0代表著由低到高分別是第0號元素,第2號元素,第3號元素。
我們需要的是由高到低,所以進行[::-1]倒順序操作。
得到的order就是分數由高到低的box的索引值。
然後我們建立乙個空的list來存放我們的nms結果(即每輪迴圈的基準box)
keep =
最關鍵的迴圈步驟:
我們首先判斷box數量是否為零,由於我們擁有了order,order的size就是box的多少,所以我們先判斷:
while order.size > 0:
判斷大於零,我們進行操作,依照上面的,由於order已經由高到低,所以我們讀取order[0],作為基準框,並將基準框,裝入我們的結果中:
xx1 = np.maximum(x1[i], x1[order[1:]]) #與基準框相比大的xmin
yy1 = np.maximum(y1[i], y1[order[1:]]) #與基準框相比大的ymin
xx2 = np.minimum(x2[i], x2[order[1:]]) #與基準框相比小的xmax
yy2 = np.minimum(y2[i], y2[order[1:]]) #與基準框相比小的ymax
這裡我們使用了numpy的maximum和minimum操作,我們來看看,這兩個函式是如何工作的,
np.maximum([-2, -1, 0, 1, 2], 0)array([0, 0, 0, 1, 2])
先找到滿足條件的值,然後返回大的那個,所以此時就是先比較基準框與其他框的四個點的大小,得到的即是重合的四個點四個座標,每個框都會與基準框有乙個重疊的區域我們把它定義為inter,inter的寬和高為:
w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
同樣的為了保證inter 面積不會小於零,所以我們將其寬高與0進行比較。
inter = w * h
計算各個框與基準框重疊的面積,然後計算iou:
ovr = inter / (areas[i] + areas[order[1:]] - inter) #計算iou
我們定義ovr為iou,iou的定義為兩個框的重疊面積除以總的union,
下一步,在與基準框iou計算的所有框中我們進行篩選,大於閾值的抑制,保留小於閾值的,注意此時的box的數量時比所有的box少一的,因為我們取出了基準框:
inds = np.where(ovr <= thresh)[0]
a = np.array([2,4,6,8,10])np.where(a > 5) # 返回索引
(array([2, 3, 4]),)
a[np.where(a > 5)] # 等價於 a[a>5]array([ 6, 8, 10]).
inds為我們儲存的與基準框iou小於閾值的框的索引值,此索引值是0到n-1中取的,n為總共所有的box,由於已經取出了order[0],所以減去1。
然後我們更新box,即是更新order,從inds來更新,由於一開始我們取出了order[0],所以我們在使用inds來更新order時需要加1操作。
order = order[inds + 1]
import numpy as np
def py_cpu_nms(dets, thresh):
"""pure python nms baseline."""
#dets為送入nms的框的資訊的集合,它是[x1,y1,x2,y2,score]的集合
x1 = dets[:, 0] #依次讀取x1,x2,y1,y2注意此時的他們都不是單獨的數,而是乙個用於存放所有的box的資訊集合
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
scores = dets[:, 4]
areas = (x2 - x1 + 1) * (y2 - y1 + 1) #計算各個box的面積,為了避免出現為0,所以使用了加1
order = scores.argsort()[::-1] #將scores按照由高到低的方式進行排序,並返回由高到低的索引值給order,order也是乙個list
keep = #用於存放最後的結果
while order.size > 0: #迴圈,直至order中沒有元素
i = order[0] #讀取分數最大的box的索引並保留
xx1 = np.maximum(x1[i], x1[order[1:]]) #將剩餘的box與分數最大的box進行求重疊面積的座標計算,此時xx1,yy1,xx2,yy2也是乙個個集合
yy1 = np.maximum(y1[i], y1[order[1:]])
xx2 = np.minimum(x2[i], x2[order[1:]])
yy2 = np.minimum(y2[i], y2[order[1:]])
w = np.maximum(0.0, xx2 - xx1 + 1) #計算重疊區域的wh計算,得出的結果仍然不是單獨的數,是乙個集合
h = np.maximum(0.0, yy2 - yy1 + 1)
inter = w * h #inter也是集合 是重疊區域的面積
ovr = inter / (areas[i] + areas[order[1:]] - inter) #計算iou
inds = np.where(ovr <= thresh)[0] #保留那些iou小於閾值的box的索引值,即剩下的box(仍是按照分數高低進行,因為一開始就是按照分數由高到低遍歷)
order = order[inds + 1] #由於order[0]一開始就被取出,所以索引值需要加一,即新的order也是乙個列表
return keep
以上就是nms的全部內容了,若對您有幫助,不勝榮幸。
後續有空的話可能會更新soft-nms的手撕**。
python實現目標跟蹤(opencv)
1.單目標跟蹤 import cv2 import sys major ver,minor ver,subminor ver cv2.version split print major ver,minor ver,subminor ver if name main 建立 tracker type m...
使用SSD實現目標檢測
本人主要參考這位大神的研究 利用這位大神的 執行了一遍ssd,之後會進一步研究ssd框架的原理和利用ssd布置自己的機械人。安裝和實現的過程中遇到了下面的一些編譯和執行的問題,我想先記錄下來,以備不時之需。第一 在對進行檢測的時候遇到 import matplotlib.pyplot as plt ...
python opencv實現目標區域裁剪功能
這個任務是自己在專案中資料處理的一部分內容,待處理的如下所示 我需要將目標區域給裁剪出來,要不然在後期訓練網路的時候整幅影象過大,且目標區域過小,得到結果不好,還會加劇計算量。在網上找了各個大佬的部落格看,沒找到合適的,便自己動手寫了,順便自己的小破站剛搭建起來,記錄一下自己的思路。思路去尋找目標區...