MTCNN--Pnet--decode

现在我们记录下如何在训练好P_net模型后,来把网络输出decode出人脸框的坐标,坐标偏移,以及landmarks
首先看下模型的输出,我们恢复P_net训练好的模型输入一张(height,width,3)的图片
输出为(height_,width_,2) (height_,width_,4)暂时先不考虑landmark的输出
由于整个P_net为fcn,所以height_和width_的大小完全取决于height,width的大小。也就是说是不固定的。
1.现在我们有了网络的输出,只需要根据这个输出来decode即可。首先在这里才考虑图像金字塔

#net_size : 这里为12
#min_face_size : 为20
current_scale = net_size / min_face_size
#然后我们根据这个current_scale将图片resize,得到一个scale下的tup
while min(im_resize.shape[0],im_resize.shape[1]) > net_size:
	scale = current_scale * 0.79
这个就是图像金字塔

2.现在我们以某个scale下的图片为例进行解析

cls_map : P_net的输出face  or  no_face  (height_,width_,2)
reg : P_net的第二个输出  (height_,width_,4)
#这里为什么要取第二个维度,和训练的时候有关,因为part在第二个,其余在第一个
cls_map = cls_map[1]
#0.5为score的阈值
t_indx = np.where(cls_map>0.5)
#找到满足上式的对于位置的offset
off_x1,off_y1,off_x2,off_y2 = [reg[t_indx[0],reg[t_indx[1],i] for i in range(4)]
reg = np.array([off_x1,off_y1,off_x2,off_y2])
#找到对应位置的score
score = cls_map[t_indx[0],t_indx[1]
#########现在我们要找对应到原图的bbox坐标
#这里的2是对应到构建网络是max_pooling步长为2所有要乘以2,t_indx[1]对应的哪一列,所有为x1 + 。
x1 = np.round(2 * t_indx[1]/scale)
y1 = np.round(2 * t_indx[0]/scale)
x2 = np.round((2 * t_indx[1] + 12)  / scale)
y2 = np.round((2 * t_indx[0] + 12)  / scale)
#这里我们可以看到,在MTCNN中也是使用一个类似于heat_map的特征图来decode出坐标信息,与cornernet不
#同的是,MTCNN只有一个heat_map图,每个点可以decode出四个坐标,而cornernet有左上和右下俩个#heatmap图,每个图只能decode出对应的点的坐标。其实这就是一个trade off的过程,MTCNN网络结构简
#单,但是导致只有要给heatmap,故每个点会decode出一个box,所有box会很多,也就是所谓的很多候选框,
#需要使用nmp来计算去,并且需要多层网络级联R,O。而cornernet网络输出比较复杂,但是解决了会有很多候
#选框的问题。
最后把decode出的信息放在一起方便处理
boundingbox = np.vstack(x1,y1,x2,y2,score,reg)
boundingbox = boundingbox.T

3 结合offset信息decode出最后映射到原图的坐标信息

我们以boundingbox中的一个box为例
w_b = box[:,2] - box[:,0] + 1
h_b = box[:,3] - box[:,1] + 1
r_x1 = box[:,0] + box[:,5] * w_b
r_y1 = box[:,1] + box[:,6] * h_b
r_x2 = box[:,2] + box[:,7] * w_b
r_y2 = box[:,3] + box[:,8] * h_b

这里我们解释下为什么要这么decode,offset在制作数据集时候的公式为 offset_x1 = (x1 - nx1)/size
这里size为裁剪后图片的大小,和这里的scale后的虽然数值不同,但是意义相同。带入我们decode公式发现
我们在boundingbox中的x1,这些原来是对应的nx1。这个很好理解,这里贴上nx1的推导公式就很明显了。

在这里插入图片描述

至此我们对于P_net的第一个输出和第二个输出的decode全部完成。这里再贴一下使用到的nms代码及原理

nms:非极大值抑制,字面理解,非极大值的极大值指的的候选框的score得分,那么怎么抑制呢?使用的是iou 大于某个阈值便抑制!!!
举例 A B C D E F四个候选框,根据score得分从大到小排序:F B C A E D
1 找得分最大的F
2 计算其余的与F 的IOU,假设 B 和E的IOU大于阈值则(认为他们与F是同一个,故去掉B,E,且标记F为一个true候选框)
3 由于第二部还剩下C A D三个候选框,继续重复上述过程
4 直到所有候选框都进行了上述操作

def py_nms(dets, thresh, mode="Union"):

    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]
	
	#每一个候选框面积
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    #从大到小排
    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)
        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
        if mode == "Union":
            ovr = inter / (areas[i] + areas[order[1:]] - inter)
        elif mode == "Minimum":
            ovr = inter / np.minimum(areas[i], areas[order[1:]])
        #keep
        inds = np.where(ovr <= thresh)[0]
        order = order[inds + 1]

    return keep
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值