作用:在目标检测算法中,以Faster_Rcnn为例,对于一张图片,模型会预测生成多个Anchor(预测方框),这些预测的方框和图片中实际的真实方框肯定是不完全匹配的, 如何确定每个Anchor是大概属于哪个真实方框,通过计算两者之间IOU值即可,通常还规定一个iou阈值(iou_threshold),若预测框和真实框之间的iou值大于iou_threshold,就表明此预测框具有和真实框的相同属性(如类别、是否前景)。我们不要这种框,把大于IOU阈值的框都删掉。
非极大值抑制NMS(Non-maximum suppression)
NMS顾名思义就是抑制不是极大值的元素,可以理解为局部最大搜索。这个局部代表的是一个邻域,邻域有两个参数可变,一是邻域的维数,二是邻域的大小。NMS在计算机视觉中应用广泛,我们以行人检测为例,滑动窗口经提取特征,经分类器分类识别后,每个窗口都会得到一个分数。但是滑动窗口会导致很多窗口与其他窗口存在包含或者大部分交叉的情况。这时就需要用到NMS来选取那些邻域里分数最高(是行人的概率最大),并且抑制那些分数低的窗口。
目地:消除多余的检测框,保留最好的一个
原理:使用极大概率的备选框抑制其他与它位置接近的备选框
输入:一些备选框,每个备选框包含备选框的坐标和属于相应类别的概率(注意:这里所有类共享这些备选框);
一个重叠度的阈值,常见的阈值是0.3~0.5
输出:每个类别的备选框
代码:
import numpy as np
def nms(boxes, threshold):
# 得到每一个box的左上和右下的坐标值,以及每一个box的概率值
x1 = boxes[:, 0]
y1 = boxes[:, 1]
x2 = boxes[:, 2]
y2 = boxes[:, 3]
scores = boxes[:, 4]
# 计算每一个box的面积
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
# 对每一个box按照score降序排列
order = scores.argsort()[::-1]
# 最后保留box的集合
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:]])
# 相交区域的宽和高度,计算相交区域的面积
w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
inter = w * h
# 计算IoU值
over = inter / (areas[i] + areas[order[1:]] - inter)
# 保留IoU小于阈值的box
index = np.where(over <= threshold)[0]
# np.where(condition)返回索引
order = order[index + 1]
return keep
还有直接调用pytorch(>=1.2.0)、torchvision(>= 0.3)中封装好了的nms函数。
from torchvision.ops import nms
keep = nms(boxes,scores,iou_threshold)
#返回的keep表示为经过nms后保留下来的boxes的索引值,并且keep的中索引值是按照scores得分降序排列的
#len(keep) <= len(boxes)
#通过下列操作即可获取具体nms后的boxes
boxes = boxes[keep]
参数:
boxes (Tensor[N, 4])) – bounding boxes坐标. 格式:(x1, y1, x2, y2)
scores (Tensor[N]) – bounding boxes得分
iou_threshold (float) – IoU过滤阈值