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

我们的目的就是要去除冗余的检测框,保留最好的一个.
有多种方式可以解决这个问题,Triggs et al. 建议使用Mean-Shift 算法,利用bbox的坐标和当前图片尺度的对数来检测bbox的多种模式.但效果可能并不如使用强分类器结合NMS的效果好.
目标检测 pipline

产生proposal后使用分类网络给出每个框的每类置信度,使用回归网络修正位置,最终应用NMS.
NMS 原理
对于Bounding Box的列表B及其对应的置信度S,采用下面的计算方式.选择具有最大score的检测框M,将其从B集合中移除并加入到最终的检测结果D中.通常将B中剩余检测框中与M的IoU大于阈值Nt的框从B中移除.重复这个过程,直到B为空.
重叠率(重叠区域面积比例IOU)阈值
常用的阈值是 0.3 ~ 0.5.
其中用到排序,可以按照右下角的坐标排序或者面积排序,也可以是通过SVM等分类器得到的得分或概率,R-CNN中就是按得分进行的排序.

就像上面的图片一样,定位一个车辆,最后算法就找出了一堆的方框,我们需要判别哪些矩形框是没用的。非极大值抑制的方法是:先假设有6个矩形框,根据分类器的类别分类概率做排序,假设从小到大属于车辆的概率 分别为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是我们保留下来的第二个矩形框。
就这样一直重复,找到所有被保留下来的矩形框。
代码示例
在R-CNN中使用了NMS来确定最终的bbox,其对每个候选框送入分类器,根据分类器的类别分类概率做排序(论文中称为greedy-NMS).但其实也可以在分类之前运用简单版本的NMS来去除一些框.
python实现的单类别nms:py_cpu_nms.py.
def py_cpu_nms(dets, thresh):
"""Pure Python NMS baseline."""
#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]
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]
order = order[inds + 1] #因为ovr数组的长度比order数组少一个,所以这里要将所有下标后移一位
return keep
Faster R-CNN的MATLAB实现与python版实现一致,代码在这里:nms.m.另外,nms_multiclass.m是多类别nms,加了一层for循环对每类进行nms而已.
NMS loss
值的注意的是对多类别检测任务,如果对每类分别进行NMS,那么当检测结果中包含两个被分到不同类别的目标且其IoU较大时,会得到不可接受的结果。如下图所示:

一种改进方式便是在损失函数中加入一部分NMS损失。NMS损失可以定义为与分类损失相同:\(L_{nms}=L_{cls}(p,u) = −\log p_u\),即真实列别u对应的log损失,p是C个类别的预测概率。实际相当于增加分类误差。
参考论文《Rotated Region Based CNN for Ship Detection》(IEEE2017会议论文)的Multi-task for NMS部分。
Soft-NMS
上述NMS算法的一个主要问题是当两个ground truth的目标的确重叠度很高时,NMS会将具有较低置信度的框去掉(置信度改成0),参见下图所示.

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

改进方法在于将置信度改为IoU的函数:f(IoU),具有较低的值而不至于从排序列表中删去.
线性函数
\[s_i=\begin{cases}
s_i, && \text{iou}(\mathcal M,b_i)<N_t \\
s_i(1-\text{iou}(\mathcal M,b_i)), && \text{iou}(\mathcal M,b_i)\ge N_t
\end{cases}
\]函数值不连续,在某一点的值发生跳跃.
高斯函数
\[s_i=s_ie^{-{\text{iou}(\mathcal M,b_i)^2}\over \sigma},\forall b_i\not \in \mathcal D
\]时间复杂度同传统的greedy-NMS,为\(\mathcal O(N^2)\).
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
# re-scoring 修改置信度
boxes[pos, 4] = weight*boxes[pos, 4]
Caffe C++ 版实现: makefile/frcnn
效果
| training data | testing data | mAP | mAP@0.5 | mAP@0.75 | mAP@S | mAP@M | mAP@L | Recall | |
|---|---|---|---|---|---|---|---|---|---|
| Baseline D-R-FCN | coco trainval | coco test-dev | 35.7 | 56.8 | 38.3 | 15.2 | 38.8 | 51.5 | |
| D-R-FCN, ResNet-v1-101, NMS | coco trainval | coco test-dev | 37.4 | 59.6 | 40.2 | 17.8 | 40.6 | 51.4 | 48.3 |
| D-R-FCN, ResNet-v1-101, SNMS | coco trainval | coco test-dev | 38.4 | 60.1 | 41.6 | 18.5 | 41.6 | 52.5 | 53.8 |
| D-R-FCN, ResNet-v1-101, MST, NMS | coco trainval | coco test-dev | 39.8 | 62.4 | 43.3 | 22.6 | 42.3 | 52.2 | 52.9 |
| D-R-FCN, ResNet-v1-101, MST, SNMS | coco trainval | coco test-dev | 40.9 | 62.8 | 45.0 | 23.3 | 43.6 | 53.3 | 60.4 |
在基于proposal方法的模型结果上应用比较好,检测效果提升:

在R-FCN以及Faster-RCNN模型中的测试阶段运用Soft-NMS,在MS-COCO数据集上mAP@[0.5:0.95]能够获得大约1%的提升(详见这里). 如果应用到训练阶段的proposal选取过程理论上也能获得提升. 在自己的实验中发现确实对易重叠的目标类型有提高(目标不一定真的有像素上的重叠,切斜的目标的矩形边框会有较大的重叠).
而在SSD,YOLO等非proposal方法中没有提升.
其它应用
边缘检测:Canny算子中的非极大值抑制是沿着梯度方向进行的,即是否为梯度方向上的极值点;(参考这里)
特征点检测:在角点检测等场景下说的非极大值抑制,则是检测中心点处的值是否是某一个邻域内的最大值.
非极大值抑制(Non-Maximum Suppression,NMS)的更多相关文章
- 目标检测 非极大值抑制(Non-Maximum Suppression,NMS)
非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素,可以理解为局部最大搜索.也可以理解为只取置信度最高的一个识别结果. 举例:  如图所示,现在 ...
- 非极大值抑制(non-maximum suppression)的理解与实现
非极大抑制(Non-Maximum Suppression) Non-Maximum Suppression for Object Detection in Python RCNN 和微软提出的 SP ...
- 非极大值抑制Non-Maximum Suppression(NMS)
非极大值抑制(Non-Maximum Suppression,NMS) 概述 非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素,可以理解为局 ...
- Non-Maximum Suppression,NMS非极大值抑制
Non-Maximum Suppression,NMS非极大值抑制概述非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素,可以理解为局部最大搜索. ...
- 非极大值抑制(NMS)
转自:https://www.cnblogs.com/makefile/p/nms.html 概述 非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的 ...
- 【56】目标检测之NMS非极大值抑制
非极大值抑制(Non-max suppression) 到目前为止你们学到的对象检测中的一个问题是,你的算法可能对同一个对象做出多次检测,所以算法不是对某个对象检测出一次,而是检测出多次.非极大值抑制 ...
- IOU和非极大值抑制
如何判断对象检测算法运作良好呢? 一.交并比(Intersection over union,IoU) 是产生的候选框(candidate bound)与原标记框(ground truth bound ...
- [DeeplearningAI笔记]卷积神经网络3.6-3.9交并比/非极大值抑制/Anchor boxes/YOLO算法
4.3目标检测 觉得有用的话,欢迎一起讨论相互学习~Follow Me 3.6交并比intersection over union 交并比函数(loU)可以用来评价对象检测算法,可以被用来进一步改善对 ...
- NMS(Non-Maximum Suppression) 非极大值抑制
NMS 非极大值抑制:找到局部最大值,并删除邻域内其他的值. 简单说一下流程: 首先剔除背景(背景无需NMS),假设有6个边界框,根据分类置信度对这6个边界框做降序排列,假设顺序为A.B.C.D.E ...
随机推荐
- ASP.NET Core MVC 过滤器介绍
过滤器的作用是在 Action 方法执行前或执行后做一些加工处理.使用过滤器可以避免Action方法的重复代码,例如,您可以使用异常过滤器合并异常处理的代码. 过滤器如何工作? 过滤器在 MVC Ac ...
- Spring Boot 系列(一)快速入门
简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置 ...
- 真实记录我入门学习Linux系统的经历
我本身来说并不是计算机专业的学生,因此今天来谈及这个话题,对大家来说,有了更多的客观公正性.对我而言,linux给我最大的财富,并不是编程能力提高了多少,而是视野的开阔.心态的转变和自学能力的提高.我 ...
- Android Studio2.1 Run APP:Error: Execution failed for task
Android Studio2.1 Run APP时,遇到错误 Error: Execution failed for task ':app:clean'. Unable to delete file ...
- 学习笔记TF027:卷积神经网络
卷积神经网络(Convolutional Neural Network,CNN),可以解决图像识别.时间序列信息问题.深度学习之前,借助SIFT.HoG等算法提取特征,集合SVM等机器学习算法识别图像 ...
- Python开发【笔记】:单线程下执行多个定时任务
单线程多定时任务 前言:公司业务需求,实例当中大量需要启动定时器的操作:大家都知道python中的定时器用的是threading.Timer,每当启动一个定时器时,程序内部起了一个线程,定时器触发执行 ...
- 学习笔记TF032:实现Google Inception Net
Google Inception Net,ILSVRC 2014比赛第一名.控制计算量.参数量,分类性能非常好.V1,top-5错误率6.67%,22层,15亿次浮点运算,500万参数(AlexNet ...
- ORA-12516: TNS: 监听程序找不到符合协议堆栈要求的可用处理程”的异常
简单说明:我们开发时多人开发,会频繁访问服务器数据库,结果当连接数大的时候,就会报ora-12516的错误,ORA-12516: TNS: 监听程序找不到符合协议堆栈要求的可用处理程"的异常 ...
- Java 垃圾回收算法
在之前Java 运行期数据区一文中,介绍了运行时内存的各个部分.其中程序计数器.虚拟机栈.本地方法栈都随线程消亡,所以,这几个区域的内存分配和回收都具备确定性.而 Java 堆和方法区不同,我们只有在 ...
- react - 解刨组件的多种写法
一,原始的createClass写法 对于写react组件,很多人第一印象往往是createClass,这是因为createClass是react组件最原始的写法,基本每个学react的人都是接触这种 ...