飘易博客(作者:Flymorn)
订阅《飘易博客》RSS,第一时间查看最新文章!
飘易首页 | 留言本 | 关于我 | 订阅Feed

AI大模型之探测人脸姿态:左右、上下旋转,头部倾斜角度

Author:飘易 Source:飘易
Category:AI大模型 PostTime:2026/4/13 18:38:38
正 文:

数字人项目中,有时用户上传的人脸素材不符合数字人的要求,项目中就需要对人脸进行检测,探测人脸姿态:左右、上下,头部倾斜角度,如果人脸的左右、上下,头部倾斜的角度大于一定阈值时,就提示用户重新上传素材,而不是等待人工审核后发现不符合要求,再驳回。


飘易这里采用的是开源项目 SynergyNet

https://github.com/choyingw/SynergyNet 

可探测人脸姿态:左右、上下,头部倾斜角度。

一、SynergyNet部署步骤

1、下载源码

下载 https://github.com/choyingw/SynergyNet/archive/refs/heads/main.zip  并解压

2、创建conda环境

conda create --name SynergyNet
conda activate SynergyNet

3、安装依赖包

PyTorch 1.9 (should also be compatiable with 1.0+ versions), Torchvision, Opencv, Scipy, Matplotlib, Cython 

我安装的是:

torch                 2.0.0+cu118(可先离线下载whl文件,再安装)
torchaudio            2.0.1+cu118
torchvision           0.15.1+cu118

pip install torchvision==0.15.1 torchaudio==2.0.1 --index-url https://download.pytorch.org/whl/cu118

4、下载数据包

Download data:

https://drive.google.com/file/d/1YVBRcXmCeO1t5Bepv67KVr_QKcOur3Yy/view?usp=sharing

https://drive.google.com/file/d/1SQsMhvAmpD1O8Hm0yEGom0C0rXtA0qs8/view?usp=sharing

Extract these data under the repo root下载后解压到项目根目录.

These data are processed from [3DDFA] and [FSA-Net].


Download pretrained weights下载与训练权重文件:

https://drive.google.com/file/d/1BVHbiLTfX6iTeJcNbh-jgHjWDoemfrzG/view?usp=sharing

Put the model under 'pretrained/'

5、编译Compile Sim3DR and FaceBoxes:

cd Sim3DR
./build_sim3dr.sh
cd ../FaceBoxes
./build_cpu_nms.sh


【这里注意,windows下不能直接执行,需变通】:

【编译 Sim3DR】:

cd Sim3DR
python setup.py build_ext --inplace
提示(下面有一些警告,不影响使用):
Compiling lib/rasterize.pyx because it changed.
[1/1] Cythonizing lib/rasterize.pyx
E:\conda\facecheck\lib\site-packages\Cython\Compiler\Main.py:381: FutureWarning: Cython directive 'language_level' not set, using '3str' for now (Py3). This has changed from earlier releases! File: E:\conda\facecheck\Code\Sim3DR\lib\rasterize.pyx
  tree = Parsing.p_module(s, pxd, full_module_name)
cl: 命令行 warning D9002 :忽略未知选项“-std=c++11”
rasterize.cpp
E:\conda\facecheck\lib\site-packages\numpy\core\include\numpy\npy_1_7_deprecated_api.h(14) : Warning Msg: Using deprecated NumPy API, disable it with #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
cl: 命令行 warning D9002 :忽略未知选项“-std=c++11”
rasterize_kernel.cpp
lib/rasterize_kernel.cpp(110): warning C4305: “=”: 从“double”到“float”截断
lib/rasterize_kernel.cpp(148): warning C4305: “=”: 从“double”到“float”截断
lib/rasterize_kernel.cpp(257): warning C4244: “=”: 从“int”转换到“float”,可能丢失数据
lib/rasterize_kernel.cpp(258): warning C4244: “=”: 从“int”转换到“float”,可能丢失数据
lib/rasterize_kernel.cpp(330): warning C4244: “=”: 从“int”转换到“float”,可能丢失数据
lib/rasterize_kernel.cpp(331): warning C4244: “=”: 从“int”转换到“float”,可能丢失数据
lib/rasterize_kernel.cpp(416): warning C4244: “=”: 从“int”转换到“float”,可能丢失数据
lib/rasterize_kernel.cpp(417): warning C4244: “=”: 从“int”转换到“float”,可能丢失数据
  正在创建库 build\temp.win-amd64-cpython-310\Release\lib\Sim3DR_Cython.cp310-win_amd64.lib 和对象 build\temp.win-amd64-cpython-310\Release\lib\Sim3DR_Cython.cp310-win_amd64.exp
正在生成代码
已完成代码的生成


【编译FaceBoxes】:

cd FaceBoxes/utils/
python build.py build_ext --inplace

编译前,必须要先改下文件,不然无法编译通过:

1)windows环境下,打开build.py文件,修改47行:

extra_compile_args=["-Wno-cpp", "-Wno-unused-function"], #"-Wno-cpp", "-Wno-unused-function"
改为:
extra_compile_args=['std=c99'],


2)打开 FaceBoxes\utils\nms\cpu_nms.pyx :

搜索 np.int_t 替换为 np.int64_t


一定改完之后再编译,不然运行项目时会报错:

ValueError: Buffer dtype mismatch, expected 'int_t' but got 'long long'


返回(下面有一些警告,不影响使用):

Compiling nms/cpu_nms.pyx because it changed.
[1/1] Cythonizing nms/cpu_nms.pyx
E:\conda\facecheck\lib\site-packages\Cython\Compiler\Main.py:381: FutureWarning: Cython directive 'language_level' not set, using '3str' for now (Py3). This has changed from earlier releases! File: E:\conda\facecheck\Code\FaceBoxes\utils\nms\cpu_nms.pyx
  tree = Parsing.p_module(s, pxd, full_module_name)
cl: 命令行 warning D9024 :无法识别的源文件类型“std=c99”,假定为对象文件
cl: 命令行 warning D9027 :源文件“std=c99”被忽略
cpu_nms.c
E:\conda\facecheck\lib\site-packages\numpy\core\include\numpy\npy_1_7_deprecated_api.h(14) : Warning Msg: Using deprecated NumPy API, disable it with #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
nms/cpu_nms.c(5191): warning C4244: “=”: 从“npy_intp”转换到“int”,可能丢失数据
nms/cpu_nms.c(5281): warning C4244: “=”: 从“__pyx_t_5numpy_int64_t”转换到“int”,可能丢失数据
nms/cpu_nms.c(5457): warning C4244: “=”: 从“__pyx_t_5numpy_int64_t”转换到“int”,可能丢失数据
nms/cpu_nms.c(5584): warning C4244: “函数”: 从“double”转换到“__pyx_t_5numpy_float32_t”,可能丢失数据
nms/cpu_nms.c(5594): warning C4244: “函数”: 从“double”转换到“__pyx_t_5numpy_float32_t”,可能丢失数据
nms/cpu_nms.c(5995): warning C4244: “=”: 从“npy_intp”转换到“unsigned int”,可能丢失数据
nms/cpu_nms.c(6255): warning C4018: “<”: 有符号/无符号不匹配
nms/cpu_nms.c(6766): warning C4018: “<”: 有符号/无符号不匹配
nms/cpu_nms.c(6899): warning C4244: “=”: 从“double”转换到“float”,可能丢失数据
nms/cpu_nms.c(6910): warning C4244: “=”: 从“double”转换到“float”,可能丢失数据
nms/cpu_nms.c(6931): warning C4244: “=”: 从“double”转换到“float”,可能丢失数据
nms/cpu_nms.c(6950): warning C4244: “=”: 从“double”转换到“float”,可能丢失数据
nms/cpu_nms.c(6993): warning C4244: “=”: 从“double”转换到“float”,可能丢失数据
  正在创建库 build\temp.win-amd64-cpython-310\Release\nms\cpu_nms.cp310-win_amd64.lib 和对象 build\temp.win-amd64-cpython-310\Release\nms\cpu_nms.cp310-win_amd64.exp正在生成代码
已完成代码的生成


6、推理Inference(默认gpu)

python singleImage.py -f img
或
python singleImage_simple.py

The default inference requires a compatible GPU to run. If you would like to run on a CPU, please comment the .cuda() and load the pretrained weights into cpu.


推理时遇到错误:

OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.

解决:

需要在 singleImage.py 或 singleImage_simple.py 文件顶部写入环境变量:

import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"


二、实际调用

我们先来写检测函数 face_dec:

# 初始化 Mediapipe Face Mesh
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(
    static_image_mode=True,   # 如果是视频改成 False
    max_num_faces=1,
    refine_landmarks=True,
    min_detection_confidence=0.5,
)

# 检测人脸 mediapipe 方案
def dec_face(image, idnx=0):
    #image = cv2.imread(r'test\a13.jpg') # 加载图片
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    h, w, _ = image.shape
    
    # 检测人脸
    results = face_mesh.process(image)

    # 取 landmarks
    if results.multi_face_landmarks:
        landmarks = results.multi_face_landmarks[0].landmark
        landmark_indices = [1, 133, 362, 78, 308, 152] # 鼻尖、眼睛、嘴角、下巴
        # 提取几个关键点,适合估计头部姿态
        image_points = np.array([
            (landmarks[1].x * w, landmarks[1].y * h),     # 鼻尖
            (landmarks[133].x * w, landmarks[133].y * h), # 左眼内角
            (landmarks[362].x * w, landmarks[362].y * h), # 右眼内角
            (landmarks[78].x * w, landmarks[78].y * h),   # 嘴左
            (landmarks[308].x * w, landmarks[308].y * h), # 嘴右
            (landmarks[152].x * w, landmarks[152].y * h)  # 下巴
        ], dtype='double')
       

        # 绘制关键点
        if 1 == 1:
            for (x, y) in image_points:
                center_coordinates = (int(x), int(y))  # 像素坐标整数化
                color = (0, 255, 0)  # 绿色 (BGR格式)
                thickness = 2        # 线宽
                radius = 3           # 半径
                cv2.circle(image, center_coordinates, radius, color, thickness)        
            for idx, (x, y) in enumerate(image_points):#打序号
                center_coordinates = (int(x), int(y))
                cv2.circle(image, center_coordinates, 3, (0, 255, 0), 2)
                cv2.putText(image, str(idx), (int(x)+5, int(y)-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)        
            cv2.imshow('Face with Key Points', image)#显示图像
            cv2.waitKey(0)
            cv2.destroyAllWindows()

        # 世界坐标 face_mesh 3D标准模型
        model_points = np.array([
            (landmarks[idx].x * w, landmarks[idx].y * h, landmarks[idx].z * w)
            for idx in landmark_indices
        ], dtype='double')


        # 相机内参矩阵 - 自适应 focal_length
        x_list = [lm.x for lm in landmarks]
        y_list = [lm.y for lm in landmarks]

        xmin = min(x_list) * w
        xmax = max(x_list) * w
        ymin = min(y_list) * h
        ymax = max(y_list) * h

        face_width = xmax - xmin
        face_height = ymax - ymin

        focal_length = 1.2 * max(face_width, face_height)
        center = (w / 2, h / 2)

        camera_matrix = np.array([
            [focal_length, 0, center[0]],
            [0, focal_length, center[1]],
            [0, 0, 1]
        ], dtype='double')

        dist_coeffs = np.zeros((4, 1))  # 假设无畸变
        success, rotation_vector, translation_vector = cv2.solvePnP(
            model_points, image_points, camera_matrix, dist_coeffs, flags=cv2.SOLVEPNP_ITERATIVE)

        # 将旋转向量转换成旋转矩阵
        rmat, _ = cv2.Rodrigues(rotation_vector)

        # 从旋转矩阵提取欧拉角 (pitch, yaw, roll)
        sy = np.sqrt(rmat[0, 0] ** 2 + rmat[1, 0] ** 2)
        singular = sy < 1e-6

        if not singular:
            x = np.arctan2(rmat[2, 1], rmat[2, 2])
            y = np.arctan2(-rmat[2, 0], sy)
            z = np.arctan2(rmat[1, 0], rmat[0, 0])
        else:
            x = np.arctan2(-rmat[1, 2], rmat[1, 1])
            y = np.arctan2(-rmat[2, 0], sy)
            z = 0

        # 弧度转角度 - Pitch (上下抬头低头)\Yaw (左右转头)\Roll (头部倾斜)
        pitch = float(np.degrees(x)) 
        yaw = float(np.degrees(y))
        roll = float(np.degrees(z))

        print(f"{idnx}.Pitch (上下抬头低头): {pitch:.2f}, Yaw (左右转头): {yaw:.2f}, Roll (头部倾斜): {roll:.2f}")
        
        # 判断人脸选择角度 大于45°非法
        if abs(pitch) > 45 or abs(yaw) > 45 or abs(pitch) > 45:
            print(f"{idnx}.Pitch (上下抬头低头): {pitch:.2f}, Yaw (左右转头): {yaw:.2f}, Roll (头部倾斜): {roll:.2f}")
            return 1
        
        return 0

    else:
        print(f"{idnx}.没有检测到人脸")
        return -1

然后来检测图片:

dec_face(cv2.imread(r'.\img\0109.png'))


随便拿几张图片来验证下:

Pitch (上下抬头低头): 9.87, Yaw (左右转头): 3.43, Roll (头部倾斜): 0.26 


Pitch (上下抬头低头): -6.23, Yaw (左右转头): 0.87, Roll (头部倾斜): 0.22


Pitch (上下抬头低头): 1.10, Yaw (左右转头): 12.63, Roll (头部倾斜): 0.27


Pitch (上下抬头低头): -2.81, Yaw (左右转头): 8.94, Roll (头部倾斜): -0.17


Pitch (上下抬头低头): -32.13, Yaw (左右转头): -16.38, Roll (头部倾斜): -173.63


如果检测的是视频,需要把视频的所有帧进行遍历,逐帧判断每一个画面是否有人脸旋转的角度过大即可。


作者:飘易
来源:飘易
版权所有。转载时必须以链接形式注明作者和原始出处及本声明。
上一篇:Docker环境Phpmyadmin的部署方式实践
下一篇:Docker容器配置LNMP Web服务器环境流程
0条评论 “AI大模型之探测人脸姿态:左右、上下旋转,头部倾斜角度”
No Comment .
发表评论
名称(*必填)
邮件(选填)
网站(选填)

记住我,下次回复时不用重新输入个人信息
© 2007-2030 飘易博客 Www.Piaoyi.Org 版权所有 Sitemap