NMS非极大值抑制的原理与代码实现

来源:互联网 发布:java的webservice 编辑:程序博客网 时间:2024/06/05 20:14

原理

对于Bounding Box的列表B及其对应的置信度S,采用下面的计算方式.选择具有最大score的检测框M,将其从B集合中移除并加入到最终的检测结果D中.通常将B中剩余检测框中与M的IoU大于阈值Nt的框从B中移除.重复这个过程,直到B为空。

实现步骤

这里写图片描述

(1)将所有框的得分排序,选中最高分及其对应的框
(2)遍历其余的框,如果和当前最高分框的重叠面积(IOU)大于一定阈值,我们就将框删除。
(3)从未处理的框中继续选一个得分最高的,重复上述过程。

实现代码

MATLAB

%% NMS:non maximum suppressionfunction pick = nms(boxes,threshold,type)% boxes: m x 5,表示有m个框,5列分别是[x1 y1 x2 y2 score]% threshold: IOU阈值% type:IOU阈值的定义类型    % 输入为空,则直接返回    if isempty(boxes)      pick = [];      return;    end    % 依次取出左上角和右下角坐标以及分类器得分(置信度)    x1 = boxes(:,1);    y1 = boxes(:,2);    x2 = boxes(:,3);    y2 = boxes(:,4);    s = boxes(:,5);    % 计算每一个框的面积    area = (x2-x1+1) .* (y2-y1+1);    %将得分升序排列    [vals, I] = sort(s);    %初始化    pick = s*0;    counter = 1;    % 循环直至所有框处理完成    while ~isempty(I)        last = length(I); %当前剩余框的数量        i = I(last);%选中最后一个,即得分最高的框        pick(counter) = i;        counter = counter + 1;          %计算相交面积        xx1 = max(x1(i), x1(I(1:last-1)));        yy1 = max(y1(i), y1(I(1:last-1)));        xx2 = min(x2(i), x2(I(1:last-1)));        yy2 = min(y2(i), y2(I(1:last-1)));          w = max(0.0, xx2-xx1+1);        h = max(0.0, yy2-yy1+1);         inter = w.*h;        %不同定义下的IOU        if strcmp(type,'Min')            %重叠面积与最小框面积的比值            o = inter ./ min(area(i),area(I(1:last-1)));        else            %交集/并集            o = inter ./ (area(i) + area(I(1:last-1)) - inter);        end        %保留所有重叠面积小于阈值的框,留作下次处理        I = I(find(o<=threshold));    end    pick = pick(1:(counter-1));end

Python

import numpy as npcimport numpy as npcdef inline np.float32_t max(np.float32_t a, np.float32_t b):    return a if a >= b else bcdef inline np.float32_t min(np.float32_t a, np.float32_t b):    return a if a <= b else bdef cpu_soft_nms(np.ndarray[float, ndim=2] boxes, float sigma=0.5, float Nt=0.3, float threshold=0.001, unsigned int method=0):    cdef unsigned int N = boxes.shape[0]    cdef float iw, ih, box_area    cdef float ua    cdef int pos = 0    cdef float maxscore = 0    cdef int maxpos = 0    cdef float x1,x2,y1,y2,tx1,tx2,ty1,ty2,ts,area,weight,ov    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]            # 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 keepdef cpu_nms(np.ndarray[np.float32_t, ndim=2] dets, np.float thresh):    cdef np.ndarray[np.float32_t, ndim=1] x1 = dets[:, 0]    cdef np.ndarray[np.float32_t, ndim=1] y1 = dets[:, 1]    cdef np.ndarray[np.float32_t, ndim=1] x2 = dets[:, 2]    cdef np.ndarray[np.float32_t, ndim=1] y2 = dets[:, 3]    cdef np.ndarray[np.float32_t, ndim=1] scores = dets[:, 4]    cdef np.ndarray[np.float32_t, ndim=1] areas = (x2 - x1 + 1) * (y2 - y1 + 1)    cdef np.ndarray[np.int_t, ndim=1] order = scores.argsort()[::-1]    cdef int ndets = dets.shape[0]    cdef np.ndarray[np.int_t, ndim=1] suppressed = \            np.zeros((ndets), dtype=np.int)    # nominal indices    cdef int _i, _j    # sorted indices    cdef int i, j    # temp variables for box i's (the box currently under consideration)    cdef np.float32_t ix1, iy1, ix2, iy2, iarea    # variables for computing overlap with box j (lower scoring box)    cdef np.float32_t xx1, yy1, xx2, yy2    cdef np.float32_t w, h    cdef np.float32_t inter, ovr    keep = []    for _i in range(ndets):        i = order[_i]        if suppressed[i] == 1:            continue        keep.append(i)        ix1 = x1[i]        iy1 = y1[i]        ix2 = x2[i]        iy2 = y2[i]        iarea = areas[i]        for _j in range(_i + 1, ndets):            j = order[_j]            if suppressed[j] == 1:                continue            xx1 = max(ix1, x1[j])            yy1 = max(iy1, y1[j])            xx2 = min(ix2, x2[j])            yy2 = min(iy2, y2[j])            w = max(0.0, xx2 - xx1 + 1)            h = max(0.0, yy2 - yy1 + 1)            inter = w * h            ovr = inter / (iarea + areas[j] - inter)            if ovr >= thresh:                suppressed[j] = 1    return keep

参考博客:http://blog.csdn.net/shuzfan/article/details/52711706
     http://www.cnblogs.com/makefile/p/nms.html

原创粉丝点击