NMS(non maximum suppression),中文名非极大值抑制,在很多计算机视觉任务中都有广泛应用,如:边缘检测、目标检测等。
非极大值抑制顾名思义就是抑制不是极大值的元素,搜索局部的极大值。这个局部代表的是一个邻域,邻域有两个参数可变,一是邻域的维数,二是邻域的大小。这里不讨论通用的NMS算法,而是用于在目标检测中用于提取分数最高的窗口的。例如在行人检测中,滑动窗口经提取特征,经分类器分类识别后,每个窗口都会得到一个分数。但是滑动窗口会导致很多窗口与其他窗口存在包含或者大部分交叉的情况。这时就需要用到NMS来选取那些邻域里分数最高(是行人的概率最大),并且抑制那些分数低的窗口。
这里主要以人脸检测中的应用为例,来说明NMS,并给出Matlab和C++示例程序。
人脸检测的一些概念
(1) 绝大部分人脸检测器的核心是分类器,即给定一个尺寸固定图片,分类器判断是或者不是人脸;
(2)将分类器进化为检测器的关键是:在原始图像上从多个尺度产生窗口,并resize到固定尺寸,然后送给分类器做判断。最常用的方法是滑动窗口。
以下图为例,由于滑动窗口,同一个人可能有好几个框(每一个框都带有一个分类器得分)
这里写图片描述
而我们的目标是一个人只保留一个最优的框:
于是我们就要用到非极大值抑制,来抑制那些冗余的框: 抑制的过程是一个迭代-遍历-消除的过程。
(1)将所有框的得分排序,选中最高分及其对应的框:
这里写图片描述
(2)遍历其余的框,如果和当前最高分框的重叠面积(IOU)大于一定阈值,我们就将框删除。
这里写图片描述
(3)从未处理的框中继续选一个得分最高的,重复上述过程。
这里写图片描述
下面给出MATLAB下的快速NMS代码,并带有详细的注释:
%% NMS:non maximum suppression
function 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
function pick = nms(boxes, overlap)
% pick = nms(boxes,overlap)
% Non-maximumsuppression.
% Greedily selecthigh-scoring detections and skip detections
% that are significantlycovered by a previously selected detection.
% boxes = boxes';
if isempty(boxes)
pick = [];
else
x1 = boxes(:,1);
y1 = boxes(:,2);
x2 = boxes(:,3);
y2 = boxes(:,4);
% x1 = boxes(:,1);
% y1 = boxes(:,2);
% x2 = boxes(:,2);
% y2 = boxes(:,4);
s = boxes(:,end);
area = (x2-x1+1) .* (y2-y1+1);%Çó³öËùÓÐÃæ»ý
[vals, I] = sort(s);
pick = [];
while ~isempty(I)
last = length(I);
i = I(last);
pick = [pick; i];
suppress = [last];
for pos = 1:last-1
j = I(pos);
xx1 = max(x1(i), x1(j));
yy1 = max(y1(i), y1(j));
xx2 = min(x2(i), x2(j));
yy2 = min(y2(i), y2(j));
w = xx2-xx1+1;
h = yy2-yy1+1;
if w > 0 && h > 0
% compute overlap
o = w * h / min(area(i),area(j));
% o = w/area(j);
if o > overlap
suppress = [suppress; pos];
end
end
end
I(suppress) = [];
end
end
输入的窗口的位置和分数,以及窗口面积交叉是多大比例进行抑制。boxes应当是N*5的矩阵,一行代表着一个窗口,包括[x,y,width,height ,score ],overlap是介于0~1的实数。输出的是局部分数最大的窗口序号序列。
程序解读:首先计算出所有窗口的面积,对所有窗口的分数进行从小到大排序取出最高分数的序号。循环计算1到次高分数窗口与最高分数窗口的交叉面积与两者间最小面积的比例,若超过overlap那么把这一窗口抑制了。交叉面积怎么计算呢?如下图对应于程序
xx1 = max(x1(i), x1(j));
yy1 = max(y1(i), y1(j));
xx2 = min(x2(i), x2(j));
yy2 = min(y2(i), y2(j));
w = xx2-xx1+1;
h = yy2-yy1+1;
if w > 0 && h > 0
% compute overlap
o = w * h / min(area(i),area(j));
if o > overlap
suppress = [suppress; pos];
end
end