目標檢測中基礎概念之IOU、NMS及SoftNMS

目標檢測中基礎概念之IOU、NMS及SoftNMS

轉載請註明原出處:https://blog.csdn.net/ouyangfushu/article/details/87438585

作者:SyGoing

QQ:  2446799425

   提到目標檢測就不可避免的會經常涉及到IOU和NMS,無論採用何種目標檢測算法,算法再牛逼都後會用到這些概念。雖然簡單,但是還是有必要打好基礎。

 一、IOU

IOU爲候選檢測框的交集與並集的比,比較簡單,如圖所示

一目瞭然,代碼實現也很簡單這裏給出C++代碼實現:

struct Bbox

{

    int x1;

    int y1;

    int x2;

    int y2;

};

float IOU(Bbox a, Bbox b)

{

    float xx1 = std::max(a.x1, b.x1);

    float yy1 = std::max(a.y1, b.y1);

    float xx2 = std::min(a.x2, b.x2);

    float yy2 = std::min(a.y2, b.y2);

    float iw = (xx2 - xx1 + 1);

    if (iw < 0) {

        iw = 0.f;

    }

    float ih= (yy2 - yy1 + 1);

    if (ih < 0) {

        ih = 0.f;

    }

    return iw*ih;

}

二、NMS

對於檢測模型預測出的IOU閾值大於設定閾值的候選框進行非極大值抑制操作得到最終的檢測結果。算法過程是一個迭代-遍歷-消除的過程,傳統的NMS算法流程:

(1)將所有框的得分排序,選中最高分及其對應的框

(2)遍歷其餘的框,如果和當前最高分框的重疊面積(IOU)大於一定閾值,我們就將框刪除

(3)從未處理的框中繼續選一個得分最高的,重複上述過程直到沒有滿足條件的。

1、C++代碼實現:

//最好理解的一種實現方式 接近真實理論。

bool cmpScore(Bbox lsh, Bbox rsh) {

    if (lsh.score < rsh.score)

        return true;

    else

        return false;

}

void nms(std::vector<Bbox> &boundingBox_, const float overlap_threshold, string modelname) {

    if (boundingBox_.empty()) {

        return;

    }

    sort(boundingBox_.begin(), boundingBox_.end(), cmpScore);

    float IOU = 0;

    float maxX = 0;

    float maxY = 0;

    float minX = 0;

    float minY = 0;

    std::vector<int> vPick;

    int nPick = 0;

    std::multimap<float, int> vScores;

    const int num_boxes = boundingBox_.size();

    vPick.resize(num_boxes);

    for (int i = 0; i < num_boxes; ++i) {

        vScores.insert(std::pair<float, int>(boundingBox_[i].score, i));

    }

    while (vScores.size() > 0) {

        int last = vScores.rbegin()->second;

        vPick[nPick] = last;

        nPick += 1;

        for (std::multimap<float, int>::iterator it = vScores.begin(); it != vScores.end();) {

            int it_idx = it->second;

            maxX = std::max(boundingBox_.at(it_idx).x1, boundingBox_.at(last).x1);

            maxY = std::max(boundingBox_.at(it_idx).y1, boundingBox_.at(last).y1);

            minX = std::min(boundingBox_.at(it_idx).x2, boundingBox_.at(last).x2);

            minY = std::min(boundingBox_.at(it_idx).y2, boundingBox_.at(last).y2);

            //maxX1 and maxY1 reuse

            maxX = ((minX - maxX + 1)>0) ? (minX - maxX + 1) : 0;

            maxY = ((minY - maxY + 1)>0) ? (minY - maxY + 1) : 0;

            //IOU reuse for the area of two bbox

            IOU = maxX * maxY;

            if (!modelname.compare("Union"))

            IOU = IOU / (boundingBox_.at(it_idx).area +  boundingBox_.at(last).area - IOU);

            else if (!modelname.compare("Min")) {

            IOU = IOU / ((boundingBox_.at(it_idx).area < boundingBox_.at(last).area) ? boundingBox_.at(it_idx).area : boundingBox_.at(last).area);

            }

            if (IOU > overlap_threshold) {

                it = vScores.erase(it);

            }

            else {

                it++;

            }

        }

    }

 

    vPick.resize(nPick);

    std::vector<Bbox> tmp_;

    tmp_.resize(nPick);

    for (int i = 0; i < nPick; i++) {

        tmp_[i] = boundingBox_[vPick[i]];

    }

    boundingBox_ = tmp_;

}

2、Python實現的NMS:

#傳統nms算法 python版本
def nms_cpu(dets,thresh):
    x1=dets[:
,0]
    y1=dets[:
,1]
    x2=dets[:
,2]
    y2=dets[:
,3]
    scores=dets[:
,4]
    areas=(x2-x1+
1)*(y2-y1+1)
   
#從大到小排序,取index
   
order = scores.argsort()[::-1]
   
#keep爲最後保留的邊框
   
keep=[]
   
while order.size>0:
        i=order[
0]
        keep.append(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
       
# /並得到iou
       
iou=inter/(areas[i]+areas[order[1:]]-inter)
       
# ind爲所有與窗口iiou值小於threshold值的窗口的index,其他窗口此次都被窗口i吸收
       
inds= np.where(iou <= thresh)[0]
       
# 下一次計算前要把窗口i去除,所有i對應的在order裏的位置是0,所以剩下的加1
       
order = order[inds + 1]
   
return keep

 

   三、SoftNMS

   目前大多數目標檢測算法仍然使用的傳統的非極大值抑制算法,貌似也夠用樣,但是大神對於傳統NMS提出了質疑,認爲其可能使得檢測框被濾除掉。實際上算法本身已經檢測出了目標,但是因爲nms簡單地將大於IOU閾值的檢測框濾除,而被濾除的檢測框IOU值僅僅比預先定義的小一點點並且是正確的;如果簡單地將閾值調低則又會造成精確度下降

As per the design of the algorithm, if an object lies within the predefined overlap threshold, it leads to a miss.

傳統NMS的抑制過程可表示如下

基於上述問題作者提出了SoftNMS,SoftNMS僅僅是對抑制IOU大於閾值時做了微妙的處理,即對分數做係數懲罰(decay)。文章提出的解決辦法具體爲線性懲罰IOU高於閾值的,或者高斯懲罰,即在分數上乘上一個0-1之間的係數。

1)關於IOU的線性函數,該函數並不連續,

2)關於IOU的高斯函數,該函數連續,不會出現斷層。實際代碼實現也多采用高斯函數。

IOU值越小則懲罰越小(係數越大),越大則懲罰越大(係數越小)

算法僞代碼:

其中,D爲最終要保留的檢測框集合,B爲檢測框集合(初始狀態爲網絡檢測的檢測框,softnms階段會作爲中間集合逐步濾除直到爲空),M爲while循環中分數最大的檢測框,每一步中D與M求並集,並且從B中濾除出M。

----摘自 paper:《Improving Object Detection With One Line of Code》

詳情參見論文及源碼:

https://arxiv.org/pdf/1704.04503.pdf
github:https://github.com/bharatsingh430/soft-nms

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章