Esempio n. 1
0
    def __rnet_detect(self, image, pnet_boxes, conf, nms):

        _img_dataset = []
        _pnet_boxes = utils.to_square(pnet_boxes)
        for _box in _pnet_boxes:
            _x1 = int(_box[0])
            _y1 = int(_box[1])
            _x2 = int(_box[2])
            _y2 = int(_box[3])

            img = image.crop((_x1, _y1, _x2, _y2))
            img = img.resize((24, 24))
            img_data = self.__image_transform(img)
            _img_dataset.append(img_data)

        img_dataset = torch.stack(_img_dataset)
        img_dataset = img_dataset.to(self.device)

        _cls, _offset = self.rnet(img_dataset)

        _cls = _cls.cpu().data.numpy()
        offset = _offset.cpu().data.numpy()

        #得到R网络置信度达标的索引
        idxs, _ = np.where(_cls > conf)
        _box = _pnet_boxes[idxs]
        # print(_box)
        # print(_box[:,0])
        #得到一组_x1/_y1/_x2/_y2
        _x1 = (_box[:, 0])
        _y1 = (_box[:, 1])
        _x2 = (_box[:, 2])
        _y2 = (_box[:, 3])

        #得到一组ow/oh
        ow = _x2 - _x1
        oh = _y2 - _y1

        # 得到一组x1/y1/x2/y2/cls
        x1 = _x1 + ow * offset[idxs][:, 0]
        y1 = _y1 + oh * offset[idxs][:, 1]
        x2 = _x2 + ow * offset[idxs][:, 2]
        y2 = _y2 + oh * offset[idxs][:, 3]
        cls = _cls[idxs][:, 0]

        # print(x1)
        # print(cls)
        #合并成一组组的x1,y1,x2,y2
        boxes = [x1, y1, x2, y2, cls]
        # print(np.shape(boxes))
        #nms之前将一组组的x1,y1,x2,y2转换成一组组的box
        boxes = utils.nms(np.array(boxes).T, nms)
        # print(np.shape(boxes))
        return boxes
    def __rnet_detect(self, image, pnet_boxes):

        _img_dataset = []  # 创建空列表,存放抠图
        _pnet_boxes = utils.to_square(
            pnet_boxes)  # ★给p网络输出的框,找出中心点,沿着最大边长的两边扩充成“正方形”,再抠图
        for _box in _pnet_boxes:  # ★遍历每个框,每个框返回框4个坐标点,抠图,放缩,数据类型转换,添加列表
            _x1 = int(_box[0])
            _y1 = int(_box[1])
            _x2 = int(_box[2])
            _y2 = int(_box[3])

            img = image.crop((_x1, _y1, _x2, _y2))  # 根据4个坐标点抠图
            img = img.resize((24, 24))  # 放缩在固尺寸
            img_data = self.__image_transform(img)  # 将图片数组转成张量
            _img_dataset.append(img_data)

        img_dataset = torch.stack(
            _img_dataset)  # stack堆叠(默认在0轴),此处相当数据类型转换,见例子2★
        if self.isCuda:
            img_dataset = img_dataset.cuda()  # 给图片数据采用cuda加速

        _cls, _offset = self.rnet(img_dataset)  # ★★将24*24的图片传入网络再进行一次筛选

        cls = _cls.cpu().data.numpy()  # 将gpu上的数据放到cpu上去,在转成numpy数组
        offset = _offset.cpu().data.numpy()
        # print("r_cls:",cls.shape)  # (11, 1):P网络生成了11个框
        # print("r_offset:", offset.shape)  # (11, 4)

        boxes = []  # R 网络要留下来的框,存到boxes里
        idxs, _ = np.where(
            cls > r_cls
        )  # 原置信度0.6是偏低的,时候很多框并没有用(可打印出来观察),可以适当调高些;idxs置信度框大于0.6的索引;★返回idxs:0轴上索引[0,1],_:1轴上索引[0,0],共同决定元素位置,见例子3
        for idx in idxs:  # 根据索引,遍历符合条件的框;1轴上的索引,恰为符合条件的置信度索引(0轴上索引此处用不到)
            _box = _pnet_boxes[idx]
            _x1 = int(_box[0])
            _y1 = int(_box[1])
            _x2 = int(_box[2])
            _y2 = int(_box[3])

            ow = _x2 - _x1  # 基准框的宽
            oh = _y2 - _y1

            x1 = _x1 + ow * offset[idx][0]  # 实际框的坐标点
            y1 = _y1 + oh * offset[idx][1]
            x2 = _x2 + ow * offset[idx][2]
            y2 = _y2 + oh * offset[idx][3]

            boxes.append([x1, y1, x2, y2, cls[idx][0]])  # 返回4个坐标点和置信度

        return utils.nms(np.array(boxes),
                         r_nms)  # 原r_nms为0.5(0.5要往小调),上面的0.6要往大调;小于0.5的框被保留下来
    def __onet_detect(self, image, rnet_boxes):

        _img_dataset = []  # 创建列表,存放抠图r
        _rnet_boxes = utils.to_square(
            rnet_boxes)  # 给r网络输出的框,找出中心点,沿着最大边长的两边扩充成“正方形”
        for _box in _rnet_boxes:  # 遍历R网络筛选出来的框,计算坐标,抠图,缩放,数据类型转换,添加列表,堆叠
            _x1 = int(_box[0])
            _y1 = int(_box[1])
            _x2 = int(_box[2])
            _y2 = int(_box[3])

            img = image.crop((_x1, _y1, _x2, _y2))  # 根据坐标点“抠图”
            img = img.resize((48, 48))
            img_data = self.__image_transform(img)  # 将抠出的图转成张量
            _img_dataset.append(img_data)

        img_dataset = torch.stack(_img_dataset)  # 堆叠,此处相当数据格式转换,见例子2
        if self.isCuda:
            img_dataset = img_dataset.cuda()

        _cls, _offset = self.onet(img_dataset)
        cls = _cls.cpu().data.numpy()  # (1, 1)
        offset = _offset.cpu().data.numpy()  # (1, 4)

        boxes = []  # 存放o网络的计算结果
        idxs, _ = np.where(
            cls > o_cls
        )  # 原o_cls为0.97是偏低的,最后要达到标准置信度要达到0.99999,这里可以写成0.99998,这样的话出来就全是人脸;留下置信度大于0.97的框;★返回idxs:0轴上索引[0],_:1轴上索引[0],共同决定元素位置,见例子3
        for idx in idxs:  # 根据索引,遍历符合条件的框;1轴上的索引,恰为符合条件的置信度索引(0轴上索引此处用不到)
            _box = _rnet_boxes[idx]  # 以R网络做为基准框
            _x1 = int(_box[0])
            _y1 = int(_box[1])
            _x2 = int(_box[2])
            _y2 = int(_box[3])

            ow = _x2 - _x1  # 框的基准宽,框是“方”的,ow=oh
            oh = _y2 - _y1

            x1 = _x1 + ow * offset[idx][
                0]  # O网络最终生成的框的坐标;生样,偏移量△δ=x1-_x1/w*side_len
            y1 = _y1 + oh * offset[idx][1]
            x2 = _x2 + ow * offset[idx][2]
            y2 = _y2 + oh * offset[idx][3]

            boxes.append([x1, y1, x2, y2, cls[idx][0]])  # 返回4个坐标点和1个置信度
        print(boxes)
        return utils.nms(np.array(boxes), isMin=True,
                         thresh=o_nms)  # 用最小面积的IOU;原o_nms(IOU)为小于0.7的框被保留下来
    def __onet_detect(self, image, rnet_boxes):
        """
        此函数为人脸检测的主函数
        :param image: 原图片
        :param rnet_boxes: r网络的检测结果
        :return: o网络的检测结果
        """
        _img_dataset = []

        # -------------调用to_square方法对p网络的输出框变成正方形---------------
        _rnet_boxes = torch.from_numpy(utils.to_square(rnet_boxes))

        # --------------计算建议框在原图中的位置--------------------------------
        _x1 = _rnet_boxes[:, 0]
        _y1 = _rnet_boxes[:, 1]
        _x2 = _rnet_boxes[:, 2]
        _y2 = _rnet_boxes[:, 3]

        # --------------对建议框进行封装----------------------------------
        crops_np = np.vstack((_x1, _y1, _x2, _y2)).transpose(1, 0)

        # ------------------抠图并做成数据集----------------------------------------
        for _box in crops_np:
            img = image.crop(_box)
            img = img.resize((48, 48))
            img_data = self.__data_transforms(img)
            _img_dataset.append(img_data)

        # ----------------对数据集进行封装---------------------
        _img_dataset = torch.stack(
            _img_dataset).cuda() if self.iscuda else torch.stack(_img_dataset)

        # -------------传入r网络进行计算-------------------------
        _cls, _offset = self.onet(_img_dataset)

        # -----------------数据移动至cpu----------------------
        cls, offset = _cls.cpu(), _offset.cpu()

        # -------------计算符合阈值数据的掩码和索引-------------------
        mask = cls[:, 0:] > o_cls
        idxs = mask.nonzero()[:, 0]

        # ----------------获得传入数据中符合阈值的数据--------------------
        _box = _rnet_boxes[idxs]

        # -------------获得符合阈值的r网络的输出数据--------------------
        cls = cls[idxs]
        cls = cls.reshape(cls.size(0))
        offset = offset[idxs]

        # --------------------计算建议框位置-----------------------==============>一回儿试试能不能删除掉
        _x1 = _box[:, 0]
        _y1 = _box[:, 1]
        _x2 = _box[:, 2]
        _y2 = _box[:, 3]

        # ----------------------计算建议框的宽和高-------------------------
        w = _x2 - _x1
        h = _y2 - _y1

        # -------------------计算实际框位置------------------------------
        x1 = _x1 + w * offset[:, 0]
        y1 = _y1 + h * offset[:, 1]
        x2 = _x2 + w * offset[:, 2]
        y2 = _y2 + h * offset[:, 3]

        # ----------------------将反算结果进行封装-------------------------
        boxes = torch.stack((x1, y1, x2, y2, cls.to(torch.float64)),
                            dim=1).detach().numpy()

        if boxes.shape[0] > 0:
            return utils.nms(boxes, True, thresh=o_nms)
        else:
            return np.array([[0, 0, 0, 0, 0]])