非极大值抑制(NMS)

      极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素,可以理解为局部最大搜索。这个局部代表的是一个邻域,邻域有两个参数可变,一是邻域的维数,二是邻域的大小。这里不讨论通用的NMS算法(参考论文《Efficient Non-Maximum Suppression》对1维和2维数据的NMS实现),而是用于目标检测中提取分数最高的窗口的。例如在行人检测中,滑动窗口经提取特征,经分类器分类识别后,每个窗口都会得到一个分数。但是滑动窗口会导致很多窗口与其他窗口存在包含或者大部分交叉的情况。这时就需要用到NMS来选取那些邻域里分数最高(是行人的概率最大),并且抑制那些分数低的窗口。NMS在计算机视觉领域有着非常重要的应用,如视频目标跟踪、数据挖掘、3D重建、目标识别以及纹理分析等。

    在R-CNN中对于2000多个region proposals得到特征向量(4096维)后,输入到SVM中进行打分(score)。除了背景以外VOC数据集共有20类。那么2000*4096维特征矩阵与20个SVM组成的权重矩阵4096*20相乘得到结果为2000*20维矩阵。这个矩阵2000行表示有2000个框。20列为每一个框属于这20个类的score(置信度)。也就是说每一列即每一类有2000个不同的分值。那么每一类有这么多候选框肯定大多冗余。所以需要利用非极大值抑制方法进行删除重叠候选框。

       NMS算法的输入:2000个候选框的位置坐标(两个顶点的x,y坐标,共4个值)、score分数值(置信度)。

       NMS算法的输出:所有满足筛选条件的建议框(可能不止一个)。

       NMS算法的大致思想:对于有重叠的候选框:若大于规定阈值(某一提前设定的置信度)则删除,低于阈值的保留。

                                            对于无重叠的候选框:都保留。

人脸检测框重叠例子

 

目标检测 pipline

NMS 原理

对于矩形框的列表H及其对应的置信度S,

建造一个存放待处理候选框的集合H,初始化为包含全部N个框;建造一个存放最优框的集合M,初始化为空集。

1、将所有集合 H 中的框进行排序,选出置信度分数最高的框 S,从集合 H 移到集合 M;

2、遍历集合H中的框,分别与框M计算交并比(Interection-over-union,IoU),如果高于某个阈值(一般为0~0.5),则认为此框与M重叠,将此框从集合 H 中去除。

3、回到第1步进行迭代,直到集合 H 为空。集合 M 中的框为我们所需。
重叠率(重叠区域面积比例IOU)阈值:常用的阈值是 0.3 ~ 0.5,可以使用交叉验证来选择最优的参数

                                 

如上图,人脸识别已经识别出了 5 个候选框,但是我们只需要最后保留两个人脸。

首先选出分数最大的框(0.98),然后遍历剩余框,计算 IoU,会发现露丝脸上的两个绿框都和 0.98 的框重叠率很大,都要去除。然后只剩下杰克脸上两个框,选出最大框(0.81),然后遍历剩余框(只剩下0.67这一个了),发现0.67这个框与 0.81 的 IoU 也很大,去除。

Soft-NMS

上述NMS算法的一个主要问题是当两个ground truth的目标的确重叠度很高时,NMS会将具有较低置信度的框去掉(置信度改成0),参见下图所示.

                论文:《Improving Object Detection With One Line of Code
改进之处:   
                      algorithm

改进方法在于将置信度改为IoU的函数:f(IoU),具有较低的值而不至于从排序列表中删去.

        线性函数                               

         高斯函数                               

转载自:https://www.cnblogs.com/makefile/p/nms.html

实例:

import numpy as np

def py_cpu_nms(dets, thresh):
#x1、y1、x2、y2、以及score赋值
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]
    #每一个检测框的面积
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    #  #按照score置信度降序排序
    order = scores.argsort()[::-1]#argsort()函数默认是将x中的元素从小到大排列,[::-1]设置从大到小排列
    keep = []
    #  #保留的结果框集合
    while order.size > 0:
        i = order[0]
        keep.append(i)#保留该类剩余box中得分最高的一个
        # #得到相交区域,左上及右下
        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:]])
        #计算相交的面积,不重叠时面积为0
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        #计算IoU:重叠面积 /(面积1+面积2-重叠面积)
        ovr = inter / (areas[i] + areas[order[1:]] - inter)
        #保留IoU小于阈值的box,删除大于阈值的框
        inds = np.where(ovr <= thresh)[0]#np.where()[0] 表示行的索引,np.where()[1] 则表示列的索引
        order = order[inds + 1]  #因为ovr数组的长度比order数组少一个,所以这里要将所有下标后移一位
    return keep

def soft_nms(dets, thresh,method):
#x1、y1、x2、y2、以及score赋值
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]
    #每一个检测框的面积
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    #  #按照score置信度降序排序
    order = scores.argsort()[::-1]#argsort()函数默认是将x中的元素从小到大排列,[::-1]设置从大到小排列

    i = order[0]
    # #得到相交区域,左上及右下
    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:]])
    #计算相交的面积,不重叠时面积为0
    w = np.maximum(0.0, xx2 - xx1 + 1)
    h = np.maximum(0.0, yy2 - yy1 + 1)
    inter = w * h
    #计算IoU:重叠面积 /(面积1+面积2-重叠面积)
    ovr = inter / (areas[i] + areas[order[1:]] - inter)
    #保留IoU小于阈值的box,删除大于阈值的框
    if method==1:
        inds = np.where(ovr >= thresh)[0]#np.where()[0] 表示行的索引,np.where()[1] 则表示列的索引
        weight=1-ovr[inds]
        dets[order[inds+1], 4]=weight*dets[order[inds+1],4]#修改分数
        #dets[inds, 4]=weight*dets[inds,4]#修改分数
    if method==2:
        weight=np.exp(-(ovr * ovr)/0.3)
        dets[order[1:], 4] = weight * dets[order[1:], 4]
    return dets[:,4]
if __name__=='__main__':
    det=np.array([[1,1,3,3,0.8],[2,2,4,5,0.5],[3,2,5,4,0.9]])
    thresh=0.3
    f=py_cpu_nms(det, thresh)
    scores=soft_nms(det, thresh,2)
    print(scores)
    print(f)

区分np.max、np.maximum、np.argmax:

np.max(a, axis=None, out=None, keepdims=False) 
求序列的最值,最少接收一个参数.axis:默认为列向(也即 axis=0),axis = 1 时为行方向的最值;

np.maximum(X, Y, out=None) 
X 与 Y 逐位比较取其大者;最少接收两个参数
np.maximum([-2, -1, 0, 1, 2], 0) 输出:array([0, 0, 0, 1, 2])

argmax 函数就是用来求一个array中最大值的下标。注意要输入是二维array,返回一个索引。

  • 5
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值