深度学习
文章目录
前言
非极大值抑制广泛应用在目标检测,目标跟踪,边缘检测。
一、步骤
大致步骤:
1、假设检测器检测到n个置信度的框。
2、将这些框分别按照置信度从小到大排列(从大到小皆可)
3、选择置信度最大的框放入到输出列表中,然后在原先的这个框从原先的候选框中删除。
4、计算这个框与其他框的IOU,将大于nms_threshold的框删除。
重复3-4步骤。直到原先列表里没有框框了。
1.过程描述
1.假设,经过目标检测,检测到图中有6个Bounding Boxes,共属于两个类的。每个Bounding Boxes 的置信度已经标在了图上。(假设IOU阈值为0.3)
- 我们依据所有Bounding Boxes的置信度排序。
B 0.99 > P 0.98 > B 0.88 > P 0.87 > B 0.65 > P 0.45
3.选择置信度最大的一个Bounding Boxes,为B 0.99。将这个Bounding Box移到输出列表里,原先的剩余列表为。
P 0.98 > B 0.88 > P 0.87 > B 0.65 > P 0.45
4.然后计算B 0.99与列表中剩下的Bounding boxes的IOU,从剩余列表里删除与B 0.99的IOU距离大于0.3的,删除过后的剩余列表为
P 0.98 > P 0.87 > P 0.45
5.然后重复步骤2到4。此时的输出列表为:
B 0.99
6.在剩余列表里取置信度最大的Bounding Boxes(P 0.98)放到输出列表里,此时的输出列表为:
B 0.99, P 0.98
此时的剩余列表为
P 0.87 > P 0.45
- 计算当前活跃的最大置信度Bounding Box与剩余列表的IOU,删除剩余列表里与P 0.98的IOU距离大于0.3的,删除过后的剩余列表为:
空
最后的输出列表为
P 0.99, P 0.98
8.算法结束。
2.解析
这个NMS算法是以置信度为完全信任指标的,意思就是置信度最大的肯定是预测的最准的。因为在多目标检测中,同一个图片里面可能含有多个类别的多个框框,其他类别的框框肯定是离这个置信度最大的框框"比较远的",这儿这个比较远的衡量指标就是IOU,一个循环执行的是对当前对象的所有候选框框进行处理的,所以IOU小于阈值的,就理解为"比较远了",不属于当前这个对象,就留下来,等待下一个对象来循环,而大于阈值的,是属于当前对象的,但是由于已经有了一个置信度最高的候选框,就删除。
然后再次在剩下的选择最大的框框,依次再来执行上面的过程。
提示:两个box距离越近,IOU越大,距离越远,IOU越小。
二、代码实现
bash
def bbox_ious(boxes1, boxes2, x1y1x2y2=True):
'''
两种box的位置坐标格式
'''
if x1,y1,x2,y2:#(左上点x,左上点y,右下点x,右下点y)
mx = torch.min(boxes1[0], boxes2[0])
Mx = torch.max(boxes1[2], boxes2[2])
my = torch.min(boxes1[1], boxes2[1])
My = torch.max(boxes1[3], boxes2[3])
w1 = boxes1[2] - boxes1[0]
h1 = boxes1[3] - boxes1[1]
w2 = boxes2[2] - boxes2[0]
h2 = boxes2[3] - boxes2[1]
else:#(左上点x,左上点y,box的宽,box的高)
mx = torch.min(boxes1[0] - boxes1[2] / 2.0, boxes2[0] - boxes2[2] / 2.0)
Mx = torch.max(boxes1[0] + boxes1[2] / 2.0, boxes2[0] + boxes2[2] / 2.0)
my = torch.min(boxes1[1] - boxes1[3] / 2.0, boxes2[1] - boxes2[3] / 2.0)
My = torch.max(boxes1[1] + boxes1[3] / 2.0, boxes2[1] + boxes2[3] / 2.0)
w1 = boxes1[2]
h1 = boxes1[3]
w2 = boxes2[2]
h2 = boxes2[3]
uw = Mx - mx
uh = My - my
cw = w1 + w2 - uw
ch = h1 + h2 - uh
mask = ((cw <= 0) + (ch <= 0) > 0)
area1 = w1 * h1
area2 = w2 * h2
carea = cw * ch
carea[mask] = 0
uarea = area1 + area2 - carea
return carea / uarea
def nms(boxes, nms_thresh):
'''
目标检测的非极大值抑制
boxes:{list:n} 一个nx7的列表,
n代表检测到的box数量,
7代表:4个坐标(x,y,w,h其中xy表示中心坐标,wh是bbox的宽高),2个置信度,1个类别
nms_thresh:{float} 一个浮点数,越小表示越严格
----------------
return
返回一个mx7的列表 {list:m} m表示经过nms后的剩余box数量
'''
if len(boxes) == 0:
return boxes
#下面这个张量用来保存着与1-置信度的值,相当于反转了一下,这样就可以从小到大排序进行处理
det_inverse_confs = [ 1 - bb[4] for bb in boxes]
det_inverse_confs = torch.asarray(det_inverse_confs)
_, sortIds = torch.sort(det_inverse_confs)#从小到大排序,返回排序后的值和对应的索引
out_boxes = [] #输出列表
for i in range(len(boxes)):
box_i = boxes[sortIds[i]] #从最小的值的索引开始处理,box_i是最小值的索引对应的原先的box
if box_i[4] > 0: #如果这个最小值大于0。
out_boxes.append(box_i)
for j in range(i + 1, len(boxes)):#用for循环计算这个最大置信度box与其他box的IOU
box_j = boxes[sortIds[j]]#i的下一个box,也就是次第二大的置信度的box
if bbox_iou(box_i, box_j, x1y1x2y2=False) > nms_thresh:#删除IOU大于阈值的box
box_j[4] = 0 #将IOU大于阈值的box的conf重置为0,即置信度为0后,就不会放入output_boxes,相当于删除。
return out_boxes