NMS詳解


https://blog.csdn.net/m0_37605642/article/details/98358864

 

參考博客

物體檢測中常用的幾個概念遷移學習、IOU、NMS理解

目標定位和檢測系列(3):交並比(IOU)和非極大值抑制(NMS)的python實現

 

一、NMS(非極大抑制)概念

NMS即non maximum suppression即非極大抑制,顧名思義就是抑制不是極大值的元素,搜索局部的極大值。在最近幾年常見的物體檢測算法(包括rcnn、sppnet、fast-rcnn、faster-rcnn等)中,最終都會從一張圖片中找出很多個可能是物體的矩形框,然后為每個矩形框為做類別分類概率。

 

就像上面的圖片一樣,定位一個車輛,最后算法就找出了一堆的方框,我們需要判別哪些矩形框是沒用的。 
所謂非極大值抑制:先假設有6個矩形框,根據分類器類別分類概率做排序,從小到大分別屬於車輛的概率分別為A<B<C<D<E<F。

(1) 從最大概率矩形框F開始,分別判斷A、B、C、D、E與F的重疊度IOU是否大於某個設定的閾值;

(2) 假設B、D與F的重疊度超過閾值,那么就扔掉B、D;並標記第一個矩形框F,是我們保留下來的。

(3) 從剩下的矩形框A、C、E中,選擇概率最大的E,然后判斷A、C與E的重疊度,重疊度大於一定的閾值,那么就扔掉;並標記E是我們保留下來的第二個矩形框。

(4) 重復這個過程,找到所有被保留下來的矩形框。

 

二、YOLO中的NMS

參考文章 目標檢測算法之YOLO

對於每一個種類的概率,比如Dog,我們將所有98個框按照預測概率從高到低排序(為方便計算,排序前可以剔除極小概率的框,也就是把它們的概率置為0),然后通過非極大抑制NMS方法,繼續剔除多余的框:

NMS方法在這里如何運行呢?首先因為經過了排序,所以第一個框是概率最大的框(下圖橘色)。然后繼續掃描下一個框跟第一個框,看是否IOU大於0.5: 

的確IOU大於0.5,那么第二個框是多余的,將它剔除:

 繼續掃描到第三個框,它與最大概率框的IOU小於0.5,需要保留:

繼續掃描到第四個框,同理需要保留: 

繼續掃描后面的框,直到所有框都與第一個框比較完畢。此時保留了不少框。

接下來,以次大概率的框(因為一開始排序過,它在順序上也一定是保留框中最靠近上一輪的基礎框的)為基礎,將它后面的其它框於之比較。

如比較第4個框與之的IOU:

 IOU大於0.5,所以可以剔除第4個框:

總之在經歷了所有的掃描之后,對Dog類別只留下了兩個框:

這時候,或許會有疑問:明顯留下來的藍色框,並非Dog,為什么要留下?因為對計算機來說,圖片可能出現兩只Dog,保留概率不為0的框是安全的。不過的確后續設置了一定的閾值(比如0.3)來刪除掉概率太低的框,這里的藍色框在最后並沒有保留,因為它在20種類別里要么因為IOU不夠而被刪除,要么因為最后閾值不夠而被剔除。

上面描述了對Dog種類進行的框選擇。接下來,我們還要對其它19種類別分別進行上面的操作。最后進行縱向跨類的比較(為什么?因為上面就算保留了橘色框為最大概率的Dog框,但該框可能在Cat的類別也為概率最大且比Dog的概率更大,那么我們最終要判斷該框為Cat而不是Dog)。判定流程和法則如下:

得到最后的結果:

三、Python程序實現NMS

NMS的算法步驟如下:

# INPUT:所有預測出的bounding box (bbx)信息(坐標和置信度confidence), IOU閾值(大於該閾值的bbx將被移除)
for object in all objects:
    (1) 獲取當前目標類別下所有bbx的信息
    (2) 將bbx按照confidence從高到低排序,並記錄當前confidence最大的bbx
    (3) 計算最大confidence對應的bbx與剩下所有的bbx的IOU,移除所有大於IOU閾值的bbx
    (4) 對剩下的bbx,循環執行(2)和(3)直到所有的bbx均滿足要求(即不能再移除bbx)

需要注意的是,NMS是對所有的類別分別執行的。舉個栗子,假設最后預測出的矩形框有2類(分別為cup, pen),在NMS之前,每個類別可能都會有不只一個bbx被預測出來,這個時候我們需要對這兩個類別分別執行一次NMS過程。
我們用python編寫NMS代碼,假設對於一張圖片,所有的bbx信息已經保存在一個字典中,保存形式如下:

predicts_dict: {"cup": [[x1_1, y1_1, x2_1, y2_1, scores1], [x1_2, y1_2, x2_2, y2_2, scores2], ...], "pen": [[x1_1, y1_1, x2_1, y2_1, scores1], [x1_2, y1_2, x2_2, y2_2, scores2], ...]}

即目標的位置和置信度用列表儲存,每個列表中的一個子列表代表一個bbx信息。詳細的代碼如下:

import numpy as np
def non_max_suppress(predicts_dict, threshold=0.2):
    """
    implement non-maximum supression on predict bounding boxes.
    Args:
        predicts_dict: {"stick": [[x1, y1, x2, y2, scores1], [...]]}.
        threshhold: iou threshold
    Return:
        predicts_dict processed by non-maximum suppression
    """
    for object_name, bbox in predicts_dict.items():   #對每一個類別的目標分別進行NMS
        bbox_array = np.array(bbox, dtype=np.float)
 
        ## 獲取當前目標類別下所有矩形框(bounding box,下面簡稱bbx)的坐標和confidence,並計算所有bbx的面積
        x1, y1, x2, y2, scores = bbox_array[:,0], bbox_array[:,1], bbox_array[:,2], bbox_array[:,3], bbox_array[:,4]
        areas = (x2-x1+1) * (y2-y1+1)
        #print("areas shape = ", areas.shape)
 
        ## 對當前類別下所有的bbx的confidence進行從高到低排序(order保存索引信息)
        order = scores.argsort()[::-1]
        print("order = ", order)
        keep = [] #用來存放最終保留的bbx的索引信息
 
        ## 依次從按confidence從高到低遍歷bbx,移除所有與該矩形框的IOU值大於threshold的矩形框
        while order.size > 0:
            i = order[0]
            keep.append(i) #保留當前最大confidence對應的bbx索引
 
            ## 獲取所有與當前bbx的交集對應的左上角和右下角坐標,並計算IOU(注意這里是同時計算一個bbx與其他所有bbx的IOU)
            xx1 = np.maximum(x1[i], x1[order[1:]]) #當order.size=1時,下面的計算結果都為np.array([]),不影響最終結果
            yy1 = np.maximum(y1[i], y1[order[1:]])
            xx2 = np.minimum(x2[i], x2[order[1:]])
            yy2 = np.minimum(y2[i], y2[order[1:]])
            inter = np.maximum(0.0, xx2-xx1+1) * np.maximum(0.0, yy2-yy1+1)
            iou = inter/(areas[i]+areas[order[1:]]-inter)
            print("iou =", iou)
 
            print(np.where(iou<=threshold)) #輸出沒有被移除的bbx索引(相對於iou向量的索引)
            indexs = np.where(iou<=threshold)[0] + 1 #獲取保留下來的索引(因為沒有計算與自身的IOU,所以索引相差1,需要加上)
            print("indexs = ", type(indexs))
            order = order[indexs] #更新保留下來的索引
            print("order = ", order)
        bbox = bbox_array[keep]
        predicts_dict[object_name] = bbox.tolist()
        predicts_dict = predicts_dict
    return predicts_dict

 

四、行人檢測中的NMS

參考博客:https://blog.csdn.net/weixin_38632246/article/details/100542184

 

如果兩個人靠得很近,將很難確定NMS的閾值,太大則會導致誤檢多,太小導致漏檢多


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM