MTCNN中P网络的输出格式,根据输出筛选置信度C比较大的,并找到与C对应的偏移量(使用的时候,不是训练)

MTCNN中P网络的输出格式,根据输出筛选置信度C比较大的,并找到与C对应的偏移量(使用的时候,不是训练)

1.首先来看P网络

class PNet(nn.Module):

    def __init__(self):
        super(PNet, self).__init__()

        self.pre_layer = nn.Sequential(
            nn.Conv2d(3, 10, kernel_size=3, stride=1),  # conv1
            nn.PReLU(),  # PReLU1
            nn.MaxPool2d(kernel_size=3, stride=2),  # pool1
            nn.Conv2d(10, 16, kernel_size=3, stride=1),  # conv2
            nn.PReLU(),  # PReLU2
            nn.Conv2d(16, 32, kernel_size=3, stride=1),  # conv3
            nn.PReLU()  # PReLU3
        )

        self.conv4_1 = nn.Conv2d(32, 1, kernel_size=1, stride=1)
        self.conv4_2 = nn.Conv2d(32, 4, kernel_size=1, stride=1)

    def forward(self, x):
        x = self.pre_layer(x)
        cond = F.sigmoid(self.conv4_1(x))
        offset = self.conv4_2(x)
        return cond, offset

p网络的输出有5个量,一个置信度,4个偏移量,又因为传入P网络的图片肯定要比12×12大,所以经卷积后输出的特征图的尺寸一定大于1,应该是N×N×5
在这里插入图片描述
使用的时候是往P网络中传入一张图片,所以批次N是1
P网络最后的返回值是置信度cond和偏移量offset
cond的格式是[N,C,H,W]=[1,1,H,W]通道是1
offset的格式是[N,C,H,W]=[1,4,H,W]通道是4
2.反算,根据P网络的输出到原图的映射,p网络输出了很多框组数据[[_X1,_Y1,_X2,_Y2,C1],[_X1,_Y1,_X2,_Y2,C2]…](偏移量和置信度)想要在原图上画框,先选择C大的,说明有人脸的可能性大,再根据筛选出来的C的索引找到对应的偏移量offset,组成[_X1,_Y1,_X2,_Y2,C1],根据公式计算在原图中的坐标。

 _cls, _offest = self.pnet(img_data)

            cls, offest = _cls[0][0].cpu().data, _offest[0].cpu().data
            idxs = torch.nonzero(torch.gt(cls, 0.6))

            for idx in idxs:
                boxes.append(self.__box(idx, offest, cls[idx[0], idx[1]], scale))

            scale *= 0.7
            _w = int(w * scale)
            _h = int(h * scale)

            img = img.resize((_w, _h))
            min_side_len = min(_w, _h)

        return utils.nms(np.array(boxes), 0.5)

    # 将回归量还原到原图上去
    def __box(self, start_index, offset, cls, scale, stride=2, side_len=12):

        _x1 = (start_index[1] * stride) / scale
        _y1 = (start_index[0] * stride) / scale
        _x2 = (start_index[1] * stride + side_len) / scale
        _y2 = (start_index[0] * stride + side_len) / scale

        ow = _x2 - _x1
        oh = _y2 - _y1

        _offset = offset[:, start_index[0], start_index[1]]
        x1 = _x1 + ow * _offset[0]
        y1 = _y1 + oh * _offset[1]
        x2 = _x2 + ow * _offset[2]
        y2 = _y2 + oh * _offset[3]

        return [x1, y1, x2, y2, cls]

_cls的格式是[N,C,H,W]=[1,1,H,W]通道是1
_offset的格式是[N,C,H,W]=[1,4,H,W]通道是4
先看_cls
因为传入P网络的图片肯定要比12*12大,所以经卷积后输出的特征图的尺寸一定大于1,假设输出的尺寸是[1,1,2,2]
_offset和_cls一样的道理

 cls, offest = _cls[0][0].cpu().data, _offest[0].cpu().data

第一步:筛选出来C大的
先看cls。p网络输出的_cls如下图,格式是[1,1,2,2],_cls[0][0],第一个0是批次,全取,第二个0是通道,取第一个通道,实际只有一个通道,也就是批次后面的全取,也就是把这张特征图上面的所有置信度c都取出来,所以cls代表所有的置信度。
在这里插入图片描述
再看offset,p网络输出的_offset[0]格式是[1,4,2,2],_offset[0],第一个0是批次,全取,也就是批次后面的全取,也就是把4个通道的特征图都取
在这里插入图片描述
好,记住, cls是(二维h,w)
在这里插入图片描述
offest是(三维c h w)
在这里插入图片描述

idxs = torch.nonzero(torch.gt(cls, 0.6))

从所有的c中筛选出c大于0.6的,并记下索引为idxs是一个二维数组,为什么呢?假如所有c如下
在这里插入图片描述
其实索引是

c1[[0,0],
c2[1,0],
c3[2,0],
c4[3,0]]

可以看出c3=0.8,c4=0.7大于0.6,那么就输出c3,c4的索引 [[2,0],[3,0]]
在这里插入图片描述
好,通过以上工作,已经拿到了想要的置信度的索引(置信度是多少还不知道)
第二步:根据筛选出来的C的索引,拿到与之对应的偏移量offset,start_index是C的索引

_offset = offset[:, start_index[0], start_index[1]]

前面说过,offset是三维的,形状(c,h,w)=(4,2,2)
举个例子:offset是一个(c,h,w)=(4,2,2)的数组(Tensor),cls是置信度,cls=0.8,0.7满足要求,下面我们取cls=0.8,0.7对应的offset

import torch
cls=torch.Tensor([[0.6],
           [0.4],
           [0.8],
           [0.7]])
offset=torch.Tensor([[[0.6],[0.4],
                      [0.3],[0.8]],

                     [[0.5],[0.7],
                      [0.6],[0.4]],

                     [[0.3],[0.8],
                      [0.5],[0.7]],

                     [[0.4],[0.9],
                      [0.5],[0.7]]])
idxs=torch.nonzero(torch.gt(cls,0.6))
print(idxs)#idxs=[[2, 0],[3, 0]]
for idx in idxs:#idx=[2,0],[3,0]
    _offset=offset[:,idx[0],idx[1]]#offset[:,2,0]   offset[:,3,0]   
    print(_offset)

在这里插入图片描述
偏移量:
_x1=_offset[0]
_y1=_offset[1]
_x2=_offset[2]
_y2=_offset[3]
这样就取出来了
在这里插入图片描述
到现在为止,取出了置信度比较大的C的索引 idx,(C具体是多少还不知道)和与C对应的offset。
但是想要反算,去原图中画框,必须知道[_X1,_Y1,_X2,_Y2,C](偏移量和置信度),我们现在知道了四个偏移量_X1,_Y1,_X2,_Y2,较大的C的索引,还差C的具体数值,下面介绍方法。
前面的例子

cls=torch.Tensor([[0.6],
           [0.4],
           [0.8],
           [0.7]])

较大的C的索引idxs= [[2,0],[3,0]],用一个for循环一个一个取,先取第一个C,idx=[2,0], C=cls[idx[0],idx[1]] = cls[2,0] = 0.8,再取第二个
idx=[3,0], C=cls[idx[0],idx[1]] = cls[3,0] = 0.7
这样就得到了两组数[0.3,0.6,0.5,0.5, 0.8], [0.8,0.4,0.7,0.7, 0.7]
再回到原图画两个框,具体怎么画,公式是什么,看下一篇博文。

发布了19 篇原创文章 · 获赞 2 · 访问量 908

猜你喜欢

转载自blog.csdn.net/weixin_44928646/article/details/104653089