HeadPose Estimation头部姿态估计头部朝向(Android)

HeadPose Estimation头部姿态估计头部朝向(Android)

目录

0.前言

本篇,将介绍一种基于深度学习的头部姿态估计模型FSA-Net。鄙人已经复现论文的结果,并对FSA-Net进行了轻量化,以便在移动端可以跑起来;目前Android Demo已经集成人脸检测和头部朝向模型,在普通手机可实时检测(30ms左右),CPU支持多线程处理,GPU支持OpenCL加速处理,先看一下效果哈:

 CPU-4线程GPU
HeadPose Estimation头部姿态估计头部朝向(Android)HeadPose Estimation头部姿态估计头部朝向(Android)

Android Demo支持的特性主要如下: 

  • 支持人脸检测:已经集成了轻量化的人脸检测,在普通手机只需要15ms左右,持CPU多线程处理,GPU支持OpenCL加速处理
  • 支持头部姿态估计:已经集成了轻量化的头部姿态估计,在普通手机只需要7ms左右,持CPU多线程处理,GPU支持OpenCL加速处理
  • 支持多人头部姿态估计
  • Demo支持图片,视频,摄像头等多种方式输入数据
  • 整个过程在普通手机可实时检测,30ms左右

1.HeadPose

头部姿态估计(Head Pose Estimation ),也称头部朝向估计,主要是获得脸部朝向的角度信息,即欧拉角(pitch,yaw,roll)表示。

头部姿态估计方法很多,主要可以分为两大类

(1)基于PNP的头部姿态估计方法

使用透视变换可以完成2D到3D的转换,可以简单的想象为将照片上的人脸图像按照一定的角度进行多点拉扯形成3D图像,然后根据角度来判断姿态。使用的方法原理为使用2D平面上人脸的特征点和3D空间内对应的坐标点,按照求解pnp问题的思路。找到一个映射关系,从而估计头部的姿态。

经典的 Head Pose Estimation 算法的步骤一般为:

  1. 2D人脸关键点检测;
  2. 3D人脸模型匹配;
  3. 求解3D点和对应2D点的转换关系;
  4. 根据旋转矩阵求解欧拉角。

基于PNP的头部姿态估计是比较传统的算法,其效果比较依赖人脸关键点检测,实际测试误差还是比较大。

可参考资料:基于3D通用模型的头部姿态估计_一半糊涂、的博客-CSDN博客_头部姿态估计

(2)基于深度学习的方法 

基于深度学习的方法,把脸部朝向的角度信息,即欧拉角(pitch,yaw,roll)当作一个多任务的回归模型(也可以转为分类)。其模型输入一张RGB人脸图像,输出三个值,代表头部朝向的欧拉角,(pitch,yaw,roll)。相比传统的头部姿态估计算法,该方法不依赖于人脸关键点,精度更高效果更好。

比如论文《Fine-Grained Head Pose Estimation Without Keypoints》就是这么简单粗暴:

HeadPose Estimation头部姿态估计头部朝向(Android)

论文地址:https://arxiv.org/abs/1710.00925v2
代码链接:https://github.com/natanielruiz/deep-head-pose

当然,还有FSA-Net,本博客就是在FSA-Net的基础上进行优化

参考资料:FSA-Net学习笔记_南风不竞:的博客-CSDN博客

2.pitch、yaw、roll三个角的区别

欧拉角(pitch,yaw,roll)遵循三维空间右手笛卡尔坐标原则:

蓝色的代表偏航角绿色的代表俯仰角红色的代表滚转角

HeadPose Estimation头部姿态估计头部朝向(Android)

欧拉角说明图示
pitch俯仰,将物体绕X轴旋转(localRotationX),即点头 上负下正pitch yaw roll 的区别(转载) - 江南雨 - 江南雨的博客
yaw航向,将物体绕Y轴旋转(localRotationY),即摇头 左正右负pitch yaw roll 的区别(转载) - 江南雨 - 江南雨的博客
roll横滚,将物体绕Z轴旋转(localRotationZ), 即转头(歪头)左负右正pitch yaw roll 的区别(转载) - 江南雨 - 江南雨的博客

3.头部姿态估计评价指标

头部姿态估计主要有两种评价准则

(1)平均绝对误差(MAE)

HeadPose Estimation头部姿态估计头部朝向(Android)

(2)平均精度

HeadPose Estimation头部姿态估计头部朝向(Android)

4.头部姿态估计数据

数据集说明
AFLW2000
BIWI
  • 数据集包含20人的超过15,000张图像(6位女性和14位男性-两次记录了4个人)。
  • 对于每一帧,都提供深度图像,相应的rgb图像(均为640×480像素)和注释。
  • 头部姿势范围涵盖大约+ -75度偏航和+ -60度俯仰。
  • 地面真相以头部的3D位置及其旋转的形式提供
  • 下载地址:https://data.vision.ee.ethz.ch/cvl/gfanelli/head_pose/head_forest.html

5.FSA-Net介绍

FSA-Net 是2019年CVPR中的一篇文章,下面是FSA-NET模型架构图:

首先,输入的图片经过两条流(two Stream)。两条流在3个stage各自提取一个特征图。相同stage提取出的特征图经过fusion module(图中的绿色框)。

原文:fusion module 首先将每个stage的两个feature map,通过element-wise multiplication得到combined feature map。然后通过c 1×1 的卷积将特征图变成c个channel。最后,用平均池化将特征图变成 w*h,最终,我们得到k个stage的特征图Uk  .如上图的 U1-Uk.

得到了K个大小为 HeadPose Estimation头部姿态估计头部朝向(Android) 特征图后,聚合模块的任务就是将其聚合为一个更小的更representative的特征图,具体来说就是将特征图精简为  HeadPose Estimation头部姿态估计头部朝向(Android)。已有的一些方法如capsule 和NetVLAD没有关注空间之间的相对信息。所以在进入特征聚合模块前,先进行空间聚合(spatial grouping)

GitHub – shamangary/FSA-Net: [CVPR19] FSA-Net: Learning Fine-Grained Structure Aggregation for Head Pose Estimation from a Single Image

6. 头部姿态估计

目前Android Demo已经集成人脸检测头部朝向模型,支持以下功能:

  • 支持人脸检测:已经集成了轻量化的人脸检测,在普通手机只需要15ms左右,持CPU多线程处理,GPU支持OpenCL加速处理
  • 支持头部姿态估计:已经集成了轻量化的头部姿态估计,在普通手机只需要7ms左右,持CPU多线程处理,GPU支持OpenCL加速处理
  • 支持多人头部姿态估计
  • Demo支持图片,视频,摄像头等多种方式输入数据
  • 整个过程在普通手机可实时检测,30ms左右

HeadPose Estimation头部姿态估计头部朝向(Android)

算法核心代码,都采用C++实现,这是JNI部分,也是接口的核心代码:

package com.cv.tnn.model;

import android.graphics.Bitmap;

public class Detector {

    static {
        System.loadLibrary("tnn_wrapper");
    }


    /***
     * 初始化关键点检测模型
     * @param face_model: 人脸检测模型(不含后缀名)
     * @param head_model: 头部朝向模型(不含后缀名)
     * @param root:模型文件的根目录,放在assets文件夹下
     * @param model_type:模型类型
     * @param num_thread:开启线程数
     * @param useGPU:关键点的置信度,小于值的坐标会置-1
     */
    public static native void init(String face_model,String head_model, String root, int model_type, int num_thread, boolean useGPU);

    /***
     * 检测关键点
     * @param bitmap 图像(bitmap),ARGB_8888格式
     * @param score_thresh:置信度阈值
     * @param iou_thresh:  IOU阈值
	 * @param dst_bitmap图像(bitmap),头部姿态估计可视化效果图
     * @return
     */
    public static native FrameInfo[] detect(Bitmap bitmap, float score_thresh, float iou_thresh,Bitmap dst_bitmap);
}

Android源码的头部朝向坐标绘制,我是使用的OpenCV绘制实现的,然后把绘制好Bitmap图像通过JNI映射到上层,并进行显示,核心显示代码如下:

/***
 * 绘制yaw,pitch,roll坐标轴(左手坐标系)
 * @param imgBRG 输入必须是BGR格式的图像
 * @param pitch红色X
 * @param yaw 绿色Y
 * @param roll 蓝色Z
 * @param center 坐标原始点
 * @param vis
 * @param size
 */
void draw_yaw_pitch_roll_in_left_axis(cv::Mat &imgBRG, float pitch, float yaw, float roll,
                                      cv::Point center, int size, int thickness, bool vis) {

    float cx = center.x;
    float cy = center.y;
    char text[200];
    sprintf(text, "(pitch,yaw,roll)=(%3.1f,%3.1f,%3.1f)", pitch, yaw, roll);
    pitch = pitch * PI / 180;
    yaw = -yaw * PI / 180;
    roll = roll * PI / 180;
    // X-Axis pointing to right. drawn in red
    float x1 = size * (cos(yaw) * cos(roll)) + cx;
    float y1 = size * (cos(pitch) * sin(roll) + cos(roll) * sin(pitch) * sin(yaw)) + cy;
    cv::Scalar color_yaw_x(0, 0, 255); //BGR;
    // Y-Axis | drawn in green
    float x2 = size * (-cos(yaw) * sin(roll)) + cx;
    float y2 = size * (cos(pitch) * cos(roll) - sin(pitch) * sin(yaw) * sin(roll)) + cy;
    cv::Scalar color_pitch_y(0, 255, 0);
    // Z-Axis (out of the screen) drawn in blue
    float x3 = size * (sin(yaw)) + cx;
    float y3 = size * (-cos(yaw) * sin(pitch)) + cy;
    cv::Scalar color_roll_z(255, 0, 0);
    float tipLength = 0.2;
    cv::arrowedLine(imgBRG, cv::Point(int(cx), int(cy)), cv::Point(int(x1), int(y1)), color_yaw_x,
                    thickness,
                    tipLength);
    cv::arrowedLine(imgBRG, cv::Point(int(cx), int(cy)), cv::Point(int(x2), int(y2)), color_pitch_y,
                    thickness,
                    tipLength);
    cv::arrowedLine(imgBRG, cv::Point(int(cx), int(cy)), cv::Point(int(x3), int(y3)), color_roll_z,
                    thickness,
                    tipLength);
    if (vis) {
        cv::putText(imgBRG,
                    text,
                    cv::Point(cx, cy),
                    cv::FONT_HERSHEY_COMPLEX,
                    0.5,
                    (0, 0, 255));
    }
}

一些Android测试测试效果:https://panjinquan.blog.csdn.net/article/details/124943419

Android效果图 CPU-4线程GPU
HeadPose Estimation头部姿态估计头部朝向(Android)HeadPose Estimation头部姿态估计头部朝向(Android)HeadPose Estimation头部姿态估计头部朝向(Android)

一些图片测试效果:

HeadPose Estimation头部姿态估计头部朝向(Android)HeadPose Estimation头部姿态估计头部朝向(Android)
HeadPose Estimation头部姿态估计头部朝向(Android)HeadPose Estimation头部姿态估计头部朝向(Android)

7. 头部姿态估计Android源码下载

HeadPose Estimation头部姿态估计头部朝向(Android)

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2022年5月30日 上午11:01
下一篇 2022年5月30日 上午11:04