MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现

MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现

一.重叠度iou
从在一张照片上框人脸时,因为图像金字塔的原因可能会把人脸框两次以上,每个框的坐标为[X1,Y1X2,Y2,C],其中X1,Y1是框左上角的点,X2,Y2是框右下角的点,C是置信度:这个框正确框到人脸的程度。在MTCNN中,iou包含两种:最小框iou、并集iou。
原理
1.并集iou
如下图所示,并集iou为交集面积除以并集面积,并集iou用在MTCNN中的P、R网络中

MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现_第1张图片
2.最小框iou
如果是大框包含小框的情况,就要用最小框iou,最小框iou表示交集面积除以最小框的面积,用在MTCNN中的O网络中
MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现_第2张图片
二.非极大值抑制NMS
如下图所示,NMS顾名思义,就是把正确框到人脸的框留下来,误差比较大的框删去
MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现_第3张图片
MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现_第4张图片
原理
下面的图片里有两张人脸,每张人脸上面有框,数字是置信度C,置信度C越大说明框到整个人脸的概率越大。那有人说直接留下两个置信度C最大的不就行了嘛?很明显,0.9和0.81最大,但是是在一张人脸上,这个方法不行,那下面介绍正确方法
MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现_第5张图片
如下图所示:
1.先按照置信度C排序
2.从最大的开始,依次往后计算iou,设置一个阈值,大于该阈值不保留小于该阈值保留
3.由2,排除0.81,还剩下0.8,0.7,0.6三个框再以0.8开始,往后依次计算iou
4.最后只剩下了0.9,0.8两个框
MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现_第6张图片
三.程序实现
1.
iou
首先,我随便画了几个框,坐标是
[[100,100,150,150,4],
[50,50,200,200,6],
[120,120,250,250,3],
[300,50,400,150,1],
[380,130,500,250,5],
[380,25,450,95,2]]
随便找一张背景图,并把框画在图上
MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现_第7张图片
定义iou函数,计算第一个框和后面所有框的面积:注意切片的用法

def iou(box,boxes,isMin=False):#box格式[x1,y1,x2,y2,c]
    #一个框面积
    box_area=(box[2]-box[0])*(box[3]-box[1])
    #多个框面积
    boxes_area=(boxes[:,2]-boxes[:,0])*(boxes[:,3]-boxes[:,1])
    

这是计算交集之前的技巧,计算交集先要找构成交集的点,总计四句话:
较大的左上角的横坐标,
较大的左下角的纵坐标,
较小的右下角的横坐标,
较小的右下角的纵坐标

#找交集
    xx1=np.maximum(box[0],boxes[:,0])
    yy1 = np.maximum(box[1], boxes[:, 1])
    xx2 = np.minimum(box[2], boxes[:, 2])
    yy2 = np.minimum(box[3], boxes[:, 3])

计算之前先要判断是否有交集

#判断是否有交集
    w=np.maximum(0,xx2-xx1)
    h=np.maximum(0,yy2-yy1)

计算交集面积并计算iou,有两种iou

inter=w*h
    #iou
    if isMin:#最小面积iou
        over=np.true_divide(inter,np.minimum(box_area,boxes_area))
    else:#交集除以并集iou
        over=np.true_divide(inter,(box_area+boxes_area-inter))
    return over

2.
NMS
定义NMS函数,设一个阈值thresh,并按照置信度排序

def nms(boxes,thresh=0.05,isMin=False):
    #根据置信度对框排序
    _boxes=boxes[(-boxes[:,4]).argsort()]
    r_boxes=[]

分别取排完序的第一个框和剩余的框,计算iou,保留较小iou的框

 while _boxes.shape[0]>1:
        #取出第一个框
        a_box=_boxes[0]
        #取出剩余的框
        b_boxes=_boxes[1:]
        #保留第一个框
        r_boxes.append(a_box)
        #比较iou后保留iou小的框
        index=np.where(iou(a_box,b_boxes,isMin)<thresh)
        _boxes=b_boxes[index]

下面就是主函数,自己设定了几个框,a.jpg是背景图,先把框画到背景图上,然后调用前面的NMS函数,计算完成之后得到的框再画出来,效果在下面

if __name__ == '__main__':
    bs=np.array([[100,100,150,150,4],[50,50,200,200,6],[120,120,250,250,3],
                [300,50,400,150,1],[380,130,500,250,5],[380,25,450,95,2]])
    # NMS之前
    img = image.open("a.jpg")
    draw = imgdraw.Draw(img)

    for i in range(bs.shape[0]):
        ai=bs[i, :4]
        draw.rectangle((ai[0], ai[1], ai[2],ai[3]), outline="red")
    img.show()

    img1 = image.open("a.jpg")
    draw1 = imgdraw.Draw(img1)
    b=nms(bs)
    #NMS之后
    for i in range(b.shape[0]):
        bi=b[i,:4]
        draw1.rectangle((bi[0], bi[1], bi[2], bi[3]), outline="red")
    img1.show()

结果:有一个框没有排除掉,不知道是哪里的问题,你知道的话可以留言
MTCNN中的重叠度IOU和非极大值抑制NMS原理及Python实现_第8张图片
所有程序

import PIL.ImageDraw as imgdraw
import PIL.Image  as image
import numpy as np
#iou
def iou(box,boxes,isMin=False):#box格式[x1,y1,x2,y2,c]
    #一个框面积
    box_area=(box[2]-box[0])*(box[3]-box[1])
    #多个框面积
    boxes_area=(boxes[:,2]-boxes[:,0])*(boxes[:,3]-boxes[:,1])
    #找交集
    xx1=np.maximum(box[0],boxes[:,0])
    yy1 = np.maximum(box[1], boxes[:, 1])
    xx2 = np.minimum(box[2], boxes[:, 2])
    yy2 = np.minimum(box[3], boxes[:, 3])
    #判断是否有交集
    w=np.maximum(0,xx2-xx1)
    h=np.maximum(0,yy2-yy1)
    #交集面积
    inter=w*h
    #iou
    if isMin:#最小面积iou
        over=np.true_divide(inter,np.minimum(box_area,boxes_area))
    else:#交集除以并集iou
        over=np.true_divide(inter,(box_area+boxes_area-inter))
    return over

#NMS
def nms(boxes,thresh=0.05,isMin=False):
    #根据置信度对框排序
    _boxes=boxes[(-boxes[:,4]).argsort()]
    r_boxes=[]
    while _boxes.shape[0]>1:
        #取出第一个框
        a_box=_boxes[0]
        #取出剩余的框
        b_boxes=_boxes[1:]
        #保留第一个框
        r_boxes.append(a_box)
        #比较iou后保留iou小的框
        index=np.where(iou(a_box,b_boxes,isMin)<thresh)
        _boxes=b_boxes[index]
    if _boxes.shape[0]>0:
        r_boxes.append(_boxes[0])
    return np.stack(r_boxes)#stack:组装为矩阵
if __name__ == '__main__':
    bs=np.array([[100,100,150,150,4],[50,50,200,200,6],[120,120,250,250,3],
                [300,50,400,150,1],[380,130,500,250,5],[380,25,450,95,2]])
    # NMS之前
    img = image.open("a.jpg")
    draw = imgdraw.Draw(img)

    for i in range(bs.shape[0]):
        ai=bs[i, :4]
        draw.rectangle((ai[0], ai[1], ai[2],ai[3]), outline="red")
    img.show()

    img1 = image.open("a.jpg")
    draw1 = imgdraw.Draw(img1)
    b=nms(bs)
    #NMS之后
    for i in range(b.shape[0]):
        bi=b[i,:4]
        draw1.rectangle((bi[0], bi[1], bi[2], bi[3]), outline="red")
    img1.show()






转载或引用请注明来源!

你可能感兴趣的:(神经网络,深度学习,tensorflow,机器学习)