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]])