NMS 和 Soft-NMS


轉自https://zhuanlan.zhihu.com/p/42018282

一  NMS

NMS算法的大致思想:對於有重疊的候選框:若大於規定閾值(某一提前設定的置信度)則刪除,低於閾值的保留。對於無重疊的候選框:都保留。

所謂非極大值抑制:先假設有6個輸出的矩形框(即proposal_clip_box),根據分類器類別分類概率做排序,從小到大分別屬於車輛的概率(scores)分別為A、B、C、D、E、F。
(1)從最大概率矩形框F開始,分別判斷A~E與F的重疊度IOU是否大於某個設定的閾值;
(2)假設B、D與F的重疊度超過閾值,那么就扔掉B、D;並標記第一個矩形框F,是我們保留下來的。
(3)從剩下的矩形框A、C、E中,選擇概率最大的E,然后判斷E與A、C的重疊度,重疊度大於一定的閾值,那么就扔掉;並標記E是我們保留下來的第二個矩形框。
就這樣一直重復,找到所有被保留下來的矩形框。

 

如上圖F與BD重合度較大,可以去除BD。AE重合度較大,我們刪除A,保留scores較大的E。C和其他重疊都小保留C。最終留下了C、E、F三個。

相關代碼:

# coding:utf-8
import numpy as np
def py_cpu_nms(dets, thresh):
    """Pure Python NMS baseline."""
    # 所有圖片的坐標信息,字典形式儲存??
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]

    areas = (x2 - x1 + 1) * (y2 - y1 + 1)  # 計算出所有圖片的面積
    order = scores.argsort()[::-1]  # 圖片評分按升序排序

    keep = []  # 用來存放最后保留的圖片的相應評分
    while order.size > 0:
        i = order[0]  # i 是還未處理的圖片中的最大評分
        keep.append(i)  # 保留改圖片的值
        # 矩陣操作,下面計算的是圖片i分別與其余圖片相交的矩形的坐標
        tmp=x1[order[1:]]
        xxxx = x1[i]
        xx1 = np.maximum(x1[i], x1[order[1:]])
        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)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        # 計算重疊比例
        ovr = inter / (areas[i] + areas[order[1:]] - inter)

        # 只保留比例小於闕值的圖片,然后繼續處理
        inds = np.where(ovr <= thresh)[0]
        indsd= inds+1
        order = order[inds + 1]

    return keep
boxes = np.array([[100, 100, 150, 168, 0.63],[166, 70, 312, 190, 0.55],[221, 250, 389, 500, 0.79],[12, 190, 300, 399, 0.9],[28, 130, 134, 302, 0.3]])
thresh = 0.1
keep = py_cpu_nms(boxes, thresh)
print(keep)

 

 

二 soft NMS

論文鏈接:

github:bharatsingh430/soft-nms

soft NMS提出尤其對密集物體檢測的檢測效果有一定的提升作用.

絕大部分目標檢測方法,最后都要用到 NMS-非極大值抑制進行后處理。 通常的做法是將檢測框按得分排序,然后保留得分最高的框,同時刪除與該框重疊面積大於一定比例的其它框。

這種貪心式方法存在如下圖所示的問題: 紅色框和綠色框是當前的檢測結果,二者的得分分別是0.95和0.80。如果按照傳統的NMS進行處理,首先選中得分最高的紅色框,然后綠色框就會因為與之重疊面積過大而被刪掉。

另一方面,NMS的閾值也不太容易確定,設小了會出現下圖的情況(綠色框因為和紅色框重疊面積較大而被刪掉),設置過高又容易增大誤檢。

思路:不要粗魯地刪除所有IOU大於閾值的框,而是降低其置信度

soft NMS算法的大致思路為:M為當前得分最高框,bi 為待處理框,bi 和M的IOU越大,bi 的得分si 就下降的越厲害。

算法結構如圖所示:

NMS中:

soft NMS中:

(1)線性加權:

(2)高斯加權:

soft NMS仍然有問題:其閾值仍然需要手工設定

soft NMS的相關代碼如下:

# coding:utf-8
import numpy as np
def soft_nms(boxes, sigma=0.5, Nt=0.1, threshold=0.001, method=1):
    N = boxes.shape[0]
    pos = 0
    maxscore = 0
    maxpos = 0

    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]
                    print(boxes[:, 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
boxes = np.array([[100, 100, 150, 168, 0.63],[166, 70, 312, 190, 0.55],[221, 250, 389, 500, 0.79],[12, 190, 300, 399, 0.9],[28, 130, 134, 302, 0.3]])
keep = soft_nms(boxes)
print(keep)

 

 


免責聲明!

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



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