前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于Pyramidbox实现的大规模人脸检测

基于Pyramidbox实现的大规模人脸检测

原创
作者头像
夜雨飘零
修改2020-07-09 14:26:51
5810
修改2020-07-09 14:26:51
举报
文章被收录于专栏:CSDN博客CSDN博客

原文博客:Doi技术团队 链接地址:https://blog.doiduoyi.com/authors/1584446358138 初心:记录优秀的Doi技术团队学习经历 本文链接:基于Pyramidbox实现的大规模人脸检测

前言

今天来水一片文章,基于开源的Pyramidbox大规模人脸检测编写的PaddlePaddle教程,为了方便训练预测,本教程做了一定的修改。这个模型虽然大,但是符合大规模人群中也可以准确地检测到人脸,就是遮挡比较严重也能正确检测。

本教程源码:https://resource.doiduoyi.com/#2mgg861

PyramidBox 是一种基于SSD的单阶段人脸检测器,它利用上下文信息解决困难人脸的检测问题。如下图所示,PyramidBox在六个尺度的特征图上进行不同层级的预测。该工作主要包括以下模块:LFPN、Pyramid Anchors、CPM、Data-anchor-sampling。

在这里插入图片描述
在这里插入图片描述

LFPN: LFPN全称Low-level Feature Pyramid Networks, 在检测任务中,LFPN可以充分结合高层次的包含更多上下文的特征和低层次的包含更多纹理的特征。高层级特征被用于检测尺寸较大的人脸,而低层级特征被用于检测尺寸较小的人脸。为了将高层级特征整合到高分辨率的低层级特征上,我们从中间层开始做自上而下的融合,构建Low-level FPN。

Pyramid Anchors: 该算法使用半监督解决方案来生成与人脸检测相关的具有语义的近似标签,提出基于anchor的语境辅助方法,它引入有监督的信息来学习较小的、模糊的和部分遮挡的人脸的语境特征。使用者可以根据标注的人脸标签,按照一定的比例扩充,得到头部的标签(上下左右各扩充1/2)和人体的标签(可自定义扩充比例)。

CPM: CPM全称Context-sensitive Predict Module, 本方法设计了一种上下文敏感结构(CPM)来提高预测网络的表达能力。

Data-anchor-sampling: 设计了一种新的采样方法,称作Data-anchor-sampling,该方法可以增加训练样本在不同尺度上的多样性。该方法改变训练样本的分布,重点关注较小的人脸。

下面这张图可以体现Pyramidbox在大规模人群中人脸检测的强大,不知道你信不信,反正我信了。

在这里插入图片描述
在这里插入图片描述

训练

首先下载数据集,下载链接如下,把他们下载解压到项目根目录下的data目录中。

https://share.weiyun.com/5WjCBWV
https://share.weiyun.com/5ot9Qv1
https://share.weiyun.com/5vSUomP
http://mmlab.ie.cuhk.edu.hk/projects/WIDERFace/support/bbx_annotation/wider_face_split.zip

该数据集解压之后的结构是这样的,检测你的路径是否正确了。

data
|-- download.sh
|-- wider_face_split
|   |-- readme.txt
|   |-- wider_face_train_bbx_gt.txt
|   |-- wider_face_val_bbx_gt.txt
|   `-- ...
|-- WIDER_train
|   `-- images
|       |-- 0--Parade
|       ...
|       `-- 9--Press_Conference
`-- WIDER_val
    `-- images
        |-- 0--Parade
        ...
        `-- 9--Press_Conference

然后是下载预训练模型,下载链接如下,把预训练模型解压到项目的根目录下。

http://paddlemodels.bj.bcebos.com/vgg_ilsvrc_16_fc_reduced.tar.gz

最后直接执行train.py就可以了,模型比较大,如何显存不足,可以设置batch_size小一点。该模型支持多卡训练,可以通过设置export CUDA_VISIBLE_DEVICES=0,1,2,3指定使用的GPU,并设置参数num_devices想要使用的GPU数量。

多少的读者应该也是使用Windows训练的吧,笔者也是,但Windows下PaddlePaddle不支持多线程读取数据,所以参数use_multiprocess需要设置为False。

训练保存的模型存放在output目录中。

预测

上面训练保存的或者下载的模型都是是持久化参数,这里说一下,官方提供的PyramidBox模型下载地址为:http://paddlemodels.bj.bcebos.com/PyramidBox_WiderFace.tar.gz。这些持久化参数在预测中非常不方便,以下载的模型为例,解压下载的模型到根目录,下面写一段代码把这些持久化参数转换预测模型,预测参数会保存在pyramidbox_model中,只有modelparams两个文件。

import paddle.fluid as fluid
from pyramidbox import PyramidBox

use_gpu = True
model_dir = 'PyramidBox_WiderFace'
save_infer_model_path = 'pyramidbox_model'

place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
exe = fluid.Executor(place)
main_program = fluid.Program()
startup_program = fluid.Program()
image_shape = [3, 1024, 1024]
with fluid.program_guard(main_program, startup_program):
    network = PyramidBox(
        data_shape=image_shape,
        sub_network=True,
        is_infer=True)
    infer_program, nmsed_out = network.infer(main_program)
    fetches = [nmsed_out]
    fluid.io.load_persistables(exe, model_dir, main_program=infer_program)
    # save model and program
    fluid.io.save_inference_model(save_infer_model_path,
                                  ['image'], [nmsed_out], exe, main_program=infer_program,
                                  model_filename='model', params_filename='params')

接下来就是预测,编写infer.py代码,创建执行器并加载Pyramidbox模型,加载的就是上一步转换的预测模型。

import time
import cv2
import numpy as np
import paddle.fluid as fluid
from PIL import Image
from PIL import ImageDraw

use_gpu = True
# 创建执行器
place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())

# 预测模型路径
save_path = 'pyramidbox_model/'
[infer_program,
 feeded_var_names,
 target_var] = fluid.io.load_inference_model(dirname=save_path,
                                             executor=exe,
                                             model_filename='model',
                                             params_filename='params')

该函数获取变换图片到一定范围的尺度, 通过这个尺度改变输入图片的大小。

def get_shrink(height, width):
    max_shrink_v1 = (0x7fffffff / 577.0 / (height * width)) ** 0.5
    max_shrink_v2 = ((678 * 1024 * 2.0 * 2.0) / (height * width)) ** 0.5

    def get_round(x, loc):
        str_x = str(x)
        if '.' in str_x:
            str_before, str_after = str_x.split('.')
            len_after = len(str_after)
            if len_after >= 3:
                str_final = str_before + '.' + str_after[0:loc]
                return float(str_final)
            else:
                return x

    max_shrink = get_round(min(max_shrink_v1, max_shrink_v2), 2) - 0.3
    if 1.5 <= max_shrink < 2:
        max_shrink = max_shrink - 0.1
    elif 2 <= max_shrink < 3:
        max_shrink = max_shrink - 0.2
    elif 3 <= max_shrink < 4:
        max_shrink = max_shrink - 0.3
    elif 4 <= max_shrink < 5:
        max_shrink = max_shrink - 0.4
    elif max_shrink >= 5:
        max_shrink = max_shrink - 0.5

    shrink = max_shrink if max_shrink < 1 else 1
    return shrink, max_shrink

编写一个可以显示预测图像的函数,在图像中画上预测的框,并显示在桌面。

def draw_image(img_path, bboxes):
    image = Image.open(img_path)
    draw = ImageDraw.Draw(image)
    for i in range(len(bboxes)):
        xmin, ymin, xmax, ymax = bboxes[i]
        (left, right, top, bottom) = (xmin, xmax, ymin, ymax)
        draw.line([(left, top), (left, bottom), (right, bottom), (right, top), (left, top)], width=4, fill='red')

    # 显示图像
    cv2.imshow('result image', cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR))
    cv2.waitKey(1)

该函数为使用模型检测人脸,该函数包括了图像预处理,首先是要把图片从HWC转化为CHW,然后PIL打开图片是RBG的,但训练的时候是用的是BGR,所以要转换为BGR,最后减去均值和乘缩放值。

def detect_face(image, shrink):
    image_shape = [3, image.size[1], image.size[0]]
    if shrink != 1:
        h, w = int(image_shape[1] * shrink), int(image_shape[2] * shrink)
        image = image.resize((w, h), Image.ANTIALIAS)
        image_shape = [3, h, w]

    img = np.array(image)
    print(img.shape)
    # HWC to CHW
    if len(img.shape) == 3:
        img = np.swapaxes(img, 1, 2)
        img = np.swapaxes(img, 1, 0)
    print(img.shape)
    # RBG to BGR
    img = img[[2, 1, 0], :, :]
    mean = [104., 117., 123.]
    scale = 0.007843
    img = img.astype('float32')
    img -= np.array(mean)[:, np.newaxis, np.newaxis].astype('float32')
    img = img * scale
    img = [img]
    img = np.array(img)

    detection, = exe.run(infer_program,
                         feed={feeded_var_names[0]: img},
                         fetch_list=target_var,
                         return_numpy=False)
    detection = np.array(detection)
    # layout: xmin, ymin, xmax. ymax, score
    if np.prod(detection.shape) == 1:
        print("No face detected")
        return np.array([[0, 0, 0, 0, 0]])
    det_conf = detection[:, 1]
    det_xmin = image_shape[2] * detection[:, 2] / shrink
    det_ymin = image_shape[1] * detection[:, 3] / shrink
    det_xmax = image_shape[2] * detection[:, 4] / shrink
    det_ymax = image_shape[1] * detection[:, 5] / shrink

    det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf))
    return det

最后传一张图片的路径,预测并展示检测后的图像。通过设置阈值confs_threshold过滤掉得分比较低的人脸框。

def infer(image_path, confs_threshold):
    if True:
        image = Image.open(image_path)
        if image.mode == 'L':
            image = image.convert('RGB')
        shrink, max_shrink = get_shrink(image.size[1], image.size[0])

        start = time.time()
        det0 = detect_face(image, shrink)
        dets = det0
        end = time.time()
        print("预测时间: %f" % (end - start))

        keep_index = np.where(dets[:, 4] >= confs_threshold)[0]
        dets = dets[keep_index, :]
        draw_image(image_path, dets[:, 0:4])


if __name__ == '__main__':
    confs_threshold = 0.15
    image_path = 'dataset/images/0acc15e8965111eab2edc8ff285a4318.jpg'
    infer(image_path, confs_threshold)

    cv2.waitKey(0)
    cv2.destroyAllWindows()

以下是本程序执行之后的效果图:

在这里插入图片描述
在这里插入图片描述

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 训练
  • 预测
相关产品与服务
人脸识别
腾讯云神图·人脸识别(Face Recognition)基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、比对、搜索、验证、五官定位、活体检测等多种功能,为开发者和企业提供高性能高可用的人脸识别服务。 可应用于在线娱乐、在线身份认证等多种应用场景,充分满足各行业客户的人脸属性识别及用户身份确认等需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档