非极大值抑制NMS&soft-NMS

NMS(非极大值抑制)

非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素,可以理解为局部最大搜索。由下图可见,同一个物体可能有好几个框,我们的目标是一个物体只须保留一个最优的框:于是我们就要用到非极大值抑制,来抑制那些冗余的框: 抑制的过程是一个迭代-遍历-消除的过程。
在这里插入图片描述
NMS python实现代码:

def cpu_nums(dets, thresh=0.7):
    x1 = dets[:,0]
    y1 = dets[:,1]
    x2 = dets[:,2]
    y2 = dets[:,3]
    scores = dets[:,4]

    areas = (x2 - x1 + 1)*(y2 - y1 + 1) # 检测框box的面积

    index = scores.argsort()[::-1]  #将每个box的置信度由高到低排序,并返回其在原列表中的索引
    keep = []   # 保留经nms后的box的索引

    while index.size > 0: 

        i = index[0]

        keep.append(i)

        #  求检测框之间的交集的面积
        x11 = np.maximum(x1[i], x1[index[1:]])
        y11 = np.maximum(y1[i], y1[index[1:]])
        x22 = np.minimum(x2[i], x2[index[1:]])
        y22 = np.minimum(y2[i], y2[index[1:]])

        w = np.maximum(0, x22-x11+1)
        h = np.maximum(0, y22-y11+1)
        overlaps = w*h

        ious = overlaps/(areas[i] + areas[index[1:]] - overlaps)   # 检测框的交并比

        idx = np.where(ious < thresh)[0]  # 保留IoU小于阈值的box

        index = index[idx+1]  # idx的长度 比index的长度小1, 所以+1

    return keep

Soft-NMS

论文:http://cn.arxiv.org/abs/1704.04503
github:https://github.com/bharatsingh430/soft-nms
问题探究:
在这里插入图片描述
该图像有两个马的检测的置信度(红色和绿色显示),其得分分别为0.95和0.8。绿色检测框与红色检测框有明显的重叠。最好是完全压制绿色框,并将其赋值为0,还是稍低一点,为0.4比较好?

绝大部分目标检测方法,最后都要用到 NMS-非极大值抑制进行后处理。 通常的做法是将检测框按得分排序,然后保留得分最高的框,同时删除与该框重叠面积大于一定比例的其它框。

这种贪心式方法存在如上图所示的问题: 红色框和绿色框是当前的检测结果,二者的得分分别是0.95和0.80。如果按照传统的NMS进行处理,首先选中得分最高的红色框,然后绿色框就会因为与之重叠面积过大而被删掉。

另一方面,NMS的阈值也不太容易确定,设小了会出现下图的情况(绿色框因为和红色框重叠面积较大而被删掉),设置过高又容易增大误检。

解决方法:不要粗鲁地删除所有IOU大于阈值的框,而是降低其置信度。
在这里插入图片描述
传统NMS:
在这里插入图片描述
改进的NMS(soft-NMS):

  1. 线性函数
    在这里插入图片描述
  2. 高斯函数
    在这里插入图片描述
    分析上面的两种改进形式,思想都是:M为当前得分最高框,b i 为待处理框,b i 和M的IOU越大,b i 的得分s i 就下降的越厉害。

soft-NMS python 实现代码:

def cpu_soft_nms(dets, sigma = 0.5, Nt = 0.7, method = 0, weight = 0, thresh = 0.2 ):
    box_len = len(dets)   # box的个数
    for i in range(box_len):
        max_scores = dets[i, 4]

        tmpx1 = dets[i,0]
        tmpy1 = dets[i,1]
        tmpx2 = dets[i,2]
        tmpy2 = dets[i,3]
        ts = dets[i,4]
        max_pos = i

        pos = i+1
        while pos < box_len:
            if dets[max_pos, 4] < dets[pos, 4]:
                max_scores = dets[pos, 4]
                max_pos = pos

            pos += 1

        # 选取置信度最高的框
        # dets[i,0] = dets[max_pos, 0]
        # dets[i,1] = dets[max_pos, 1]
        # dets[i,2] = dets[max_pos, 2]
        # dets[i,3] = dets[max_pos, 3]
        # dets[i,4] = dets[max_pos, 4]
        dets[i,:] = dets[max_pos, :]

        dets[max_pos, 0] = tmpx1
        dets[max_pos, 1] = tmpy1
        dets[max_pos, 2] = tmpx2
        dets[max_pos, 3] = tmpy2
        dets[max_pos, 4] = ts

        # 将置信度最高的 box 赋给临时变量
        tmpx1, tmpy1, tmpx2, tmpy2, ts = dets[i,0], dets[i,1], dets[i,2], dets[i,3], dets[i,4]

        pos = i+1
        while pos < box_len:

            x1 = boxes[pos,0]
            y1 = boxes[pos,1]
            x2 = boxes[pos,2]
            y2 = boxes[pos,3]

            area = (x2 - x1 + 1)*(y2 - y1 + 1)

            iw = (min(tmpx2, x2) - max(tmpx1, x1) + 1)
            ih = (min(tmpy2, y2) - max(tmpy1, y1) + 1)
            if iw > 0 and ih >0:
                overlaps = iw * ih
                ious = overlaps/((tmpx2 - tmpx1 + 1) * (tmpy2 - tmpy1 + 1) + area - overlaps)

                if method==1:    # 线性
                    if ious > Nt:
                        weight = 1 - ious
                    else:
                        weight = 1
                elif method==2:   # gaussian
                    weight = np.exp(-(ious**2)/sigma)
                else:        # original NMS
                    if ious > Nt:
                        weight = 0
                    else:
                        weight = 1

                # 赋予该box新的置信度
                dets[pos, 4] = weight*dets[pos, 4]
                # print(dets[pos, 4])

                # 如果box得分低于阈值thresh,则通过与最后一个框交换来丢弃该框
                if dets[pos,4]< thresh:
                    dets[pos,0], dets[pos,1], dets[pos,2], dets[pos,3] = dets[box_len-1,0], dets[box_len-1,1], dets[box_len-1,2],dets[box_len-1,3]
                    dets[pos,4] = dets[pos,4]

                    box_len = box_len-1
                    pos = pos-1
            pos +=1

    keep = [i for i in range(box_len)]
    return keep

参考资料:http://www.cnblogs.com/makefile/p/nms.html

https://blog.csdn.net/shuzfan/article/details/71036040

猜你喜欢

转载自blog.csdn.net/bingbingxie1/article/details/86571112
今日推荐