基于PaddleHub的头部姿态估计项目-3

一、摘要背景

随着科技的发展,对于人脸识别技术的应用已经影响到人们生活的方方面面,另外,PaddleHub 近期发布了人脸关键点检测模型face_landmark_localization,该模型转换自 https://github.com/lsy17096535/face-landmark ,支持同一张图中的多个人脸检测。它可以识别人脸中的68个关键点。这个模型成为这项技术的重要支撑。所以,我想利用这项技术做一个简单的头部姿态识别项目。

基于PaddleHub的头部姿态估计项目-3_第1张图片

 

 

物体相对于相机的姿态可以使用旋转矩阵和平移矩阵表示。可以用世界坐标系,相机坐标系,像素坐标系等等。

基于PaddleHub的头部姿态估计项目-3_第2张图片

得到旋转矩阵后就可以计算欧拉角。

基于PaddleHub的头部姿态估计项目-3_第3张图片

二、项目主要代码

2.1安装paddlehub环境

import paddle.fluid 
paddle.fluid.install_check.run_check()

2.2载入模块,加入所引用的目录

import cv2
import numpy as np
import paddlehub as hub
from paddlehub.common.logger import logger
import time
import math
import os

2.3加载头部关键点坐标,头部投影点坐标以及投影点连线坐标

# 头部关键点坐标
        self.model_points = np.array([
            [6.825897, 6.760612, 4.402142],
            [1.330353, 7.122144, 6.903745],
            [-1.330353, 7.122144, 6.903745],
            [-6.825897, 6.760612, 4.402142],
            [5.311432, 5.485328, 3.987654],
            [1.789930, 5.393625, 4.413414],
            [-1.789930, 5.393625, 4.413414],
            [-5.311432, 5.485328, 3.987654],
            [2.005628, 1.409845, 6.165652],
            [-2.005628, 1.409845, 6.165652],
            [2.774015, -2.080775, 5.048531],
            [-2.774015, -2.080775, 5.048531],
            [0.000000, -3.116408, 6.097667],
            [0.000000, -7.415691, 4.070434],
            [-7.308957, 0.913869, 0.000000],
            [7.308957, 0.913869, 0.000000],
            [0.746313,0.348381,6.263227],
            [0.000000,0.000000,6.763430],
            [-0.746313,0.348381,6.263227],
            ], dtype='float')
# 头部投影点坐标
        self.reprojectsrc = np.float32([
            [10.0, 10.0, 10.0],
            [10.0, 10.0, -10.0], 
            [10.0, -10.0, -10.0],
            [10.0, -10.0, 10.0], 
            [-10.0, 10.0, 10.0], 
            [-10.0, 10.0, -10.0], 
            [-10.0, -10.0, -10.0],
            [-10.0, -10.0, 10.0]])
        # 头部投影点连线坐标
        self.line_pairs = [
            [0, 1], [1, 2], [2, 3], [3, 0],
            [4, 5], [5, 6], [6, 7], [7, 4],
            [0, 4], [1, 5], [2, 6], [3, 7]
        ]

2.4预测人脸的68个关键点坐标,从face_landmark_localization的检测结果抽取姿态估计需要的点坐标

def get_face_landmark(self, image):
        """
        预测人脸的68个关键点坐标
        images(ndarray): 单张图片的像素数据
        """
        try:
            # 选择GPU运行,use_gpu=True,并且在运行整个教程代码之前设置CUDA_VISIBLE_DEVICES环境变量
            res = self.module.keypoint_detection(images=[image], use_gpu=False)
            return True, res[0]['data'][0]
        except Exception as e:
            logger.error("Get face landmark localization failed! Exception: %s " % e)
            return False, None
        
    def get_image_points_from_landmark(self, face_landmark):
        """
        从face_landmark_localization的检测结果抽取姿态估计需要的点坐标
        """
        image_points = np.array([
            face_landmark[17], face_landmark[21], 
            face_landmark[22], face_landmark[26], 
            face_landmark[36], face_landmark[39], 
            face_landmark[42], face_landmark[45], 
            face_landmark[31], face_landmark[35],
            face_landmark[48], face_landmark[54],
            face_landmark[57], face_landmark[8],
            face_landmark[14], face_landmark[2], 
            face_landmark[32], face_landmark[33],
            face_landmark[34], 
            ], dtype='float')
        return image_points
    
    def caculate_pose_vector(self, image_points):
        """

 2.5获取旋转向量和平移向量

 # 相机视角
        center = (self.img_size[1]/2, self.img_size[0]/2)
        focal_length = center[0] / np.tan(60/ 2 * np.pi / 180)
        camera_matrix = np.array([
            [focal_length, 0, center[0]],
            [0, focal_length, center[1]],
            [0, 0, 1]],
            dtype = "float")
        dist_coeffs = np.zeros((4,1))
        
        success, rotation_vector, translation_vector= cv2.solvePnP(self.model_points, 
                                                                   image_points,
                                                                   camera_matrix, 
                                                                   dist_coeffs)
                                                                   
        reprojectdst, _ = cv2.projectPoints(self.reprojectsrc, rotation_vector, translation_vector, camera_matrix, dist_coeffs)

        return success, rotation_vector, translation_vector, camera_matrix, dist_coeffs, reprojectdst

    def caculate_euler_angle(self, rotation_vector, translation_vector):

2.6将旋转向量转换为欧拉角

        rvec_matrix = cv2.Rodrigues(rotation_vector)[0]
        proj_matrix = np.hstack((rvec_matrix, translation_vector))
        euler_angles = cv2.decomposeProjectionMatrix(proj_matrix)[6]
        pitch, yaw, roll = [math.radians(_) for _ in euler_angles]
        return pitch, yaw, roll

2.7表示出投影立方体

            alpha=0.3
            if not hasattr(self, 'before'):
                self.before = reprojectdst
            else:
                reprojectdst = alpha * self.before + (1-alpha)* reprojectdst
            reprojectdst = tuple(map(tuple, reprojectdst.reshape(8, 2)))
            for start, end in self.line_pairs:
                cv2.line(img, reprojectdst[start], reprojectdst[end], (0, 0, 255))

2.8作品示例

 基于PaddleHub的头部姿态估计项目-3_第4张图片

基于PaddleHub的头部姿态估计项目-3_第5张图片

三、收获与总结

 经过这几周的暑期实践过程,我深感学习程序语言的不容易,以及我在这方面知识的匮乏。这几周我经常在mooc上面学习python这门语言的相关用法。即便如此,做出这个项目也是非常不容易。这个过程中出现了很多错误,语法不正确,无法显示坐标系等等。我询问同学,不断改进,才勉强运行。学习本来就不是一蹴而就的,我以后会多加练习,尝试着做一些简单的项目去增加自己的知识,提升自己撰写代码的能力。

 

参考文献:

https://aistudio.baidu.com/aistudio/projectdetail/369186

https://zhuanlan.zhihu.com/p/51208197

https://www.icourse163.org/search.htm?search=python%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95#/

https://www.paddlepaddle.org.cn/

你可能感兴趣的:(基于PaddleHub的头部姿态估计项目-3)