机器学习:3DDFA V2代码复现实现人脸姿态检测欧拉角识别

文章复盘 3DDFA V2 复现要点:Windows 下修改 np.long、cpu_nms.pyx、build.py 与 MSVC 环境、编译 FaceBoxes/Sim3DR,并改写 demo 为 ONNX/GPU、pose 模式输出欧拉角。


前言

在计算机视觉领域,人脸姿态检测是一个重要的研究方向,在人脸识别、人机交互、虚拟现实、驾驶员监控等场景中都有广泛的应用。人脸姿态通常可以通过欧拉角来描述。3DDFA(3D Dense Face Alignment)是一种基于深度学习的人脸密集对齐方法,能够从单张 2D 人脸图像中重建出 3D 人脸形状和姿态。而 3DDFA V2 作为其改进版本,在精度、速度和鲁棒性上都有显著提升,不需要复杂的 3D 标注数据,仅通过 2D 图像和简单的先验知识就能实现高效的 3D 人脸重建和姿态估计。

博主最近也是需要用到人脸的姿态检测,于是复现了3DDFA V2 的代码,并且用预训练模型实现了人脸姿态角度的识别。3DDFA V2 最难的是对于windows来说在配置的这部分,由于版本的原因相对来说还是很耗时耗力的,经过一下午的查询才逐个解决bug成功复现。本文将详细介绍如何复现 3DDFA V2 的代码,从配置到微调代码,实现自己需要的功能(博主这边需要的功能是一个输入图像路径返回欧拉角的函数)


`

一、欧拉角是什么?

人脸的姿态角度通常采用欧拉角俯仰角 pitch、偏航角 yaw、滚转角 roll)来描述,这三个角度分别对应人脸在垂直方向的上下转动、水平方向的左右转动以及绕面部中心轴的旋转

二、3DDFA 代码配置

1、硬件要求

3DDFA V2的运行对硬件有一定要求,推荐配置如下:

  • CPU:至少四核处理器,推荐Intel i5及以上
  • GPU:支持CUDA的NVIDIA显卡(如GTX 1050及以上),显存2GB及以上(使用GPU加速可显著提升运行速度,若没有GPU也可使用CPU运行,但速度较慢)
  • 内存:8GB及以上

2、代码下载

3DDFA V2在github上面是有开源源代码与预训练模型的可以直接下载,地址如下:
3DDFA V2 github下载地址
在这里插入图片描述

如果登录不进github的话也有转到gitee上的开源地址如下:
3DDDFA V2 gitee下载地址

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

3、环境编译

Windows系统

相对于MacOS系统来说,Windows系统配置会繁琐很多,但是跟着博主一步一步做大概率是没有什么问题的
首先我们需要修改代码中几个会报错的点:
1、路径3DDFA_V2-master\bfm\bfm.py需要修改一个np的代码
在这里插入图片描述
需要将这个np.long改为np.int32,因为np.long是旧版的代码,在新版本的numpy中已经被弃用,必须修改,但是这个修改会带来后续的问题,也就是我们在下一步要解决的。

2、路径 3DDFA_V2-master\FaceBoxes/utils/nms/cpu_nms.pyx需要修改一段代码:在这里插入图片描述
该函数需要大幅修改,直接复制黏贴为以下既可:

def cpu_nms(np.ndarray[np.float32_t, ndim=2] dets, np.float thresh):
    cdef np.ndarray[np.float32_t, ndim=1] x1 = dets[:, 0]
    cdef np.ndarray[np.float32_t, ndim=1] y1 = dets[:, 1]
    cdef np.ndarray[np.float32_t, ndim=1] x2 = dets[:, 2]
    cdef np.ndarray[np.float32_t, ndim=1] y2 = dets[:, 3]
    cdef np.ndarray[np.float32_t, ndim=1] scores = dets[:, 4]

    cdef np.ndarray[np.float32_t, ndim=1] areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    cdef np.ndarray[np.int64_t, ndim=1] order = scores.argsort()[::-1]

    cdef int ndets = dets.shape[0]
    cdef np.ndarray[np.int64_t, ndim=1] suppressed = \
            np.zeros((ndets), dtype=np.int64)

这一步的目的是为了与之前的修改对应以免出现数值不匹配的问题,如果没有这一步的话会报错这个:
ValueError: Buffer dtype mismatch, expected ‘int_t’ but got ‘long long’
这边感谢大佬在github上面发布以及解决的issue,这边链接附在下面:
ValueError: Buffer dtype mismatch, expected ‘int_t’ but got ‘long long ISSUE github地址

3、路径3DDFA_V2-master\FaceBoxes\utils\build.py需要注释掉一行代码:
在这里插入图片描述
extra_compile_args=[“-Wno-cpp”, “-Wno-unused-function”]
这一行是用于给 C/C++ 编译器(如 gcc)传递额外的编译参数,目的是忽略某些警告(比如宏相关和未使用函数的警告)。
这一行代码需要注释掉,因为 Windows 下默认编译器是 MSVC(Visual Studio),而不是 gcc,这些参数只适用于 gcc,MSVC 不识别,会报错。如果在 Windows 下编译 Cython 扩展,保留这行会导致编译失败,提示参数无效。
在 Linux/macOS 下用 gcc 编译时可以打开,能减少无关警告。

4、电脑需要配置Microsoft Visual Studio
这个直接搜索下载安装即可
在这里插入图片描述
只需要选择红色框里面的这个进行下载安装即可。如果之前已经安装过但是没有勾选这个或者出现其他的什么问题的话一般报错信息如下:
在这里插入图片描述
这样的话一般建议就是重新安装一下,然后按照上面的步骤来。

5、进入路径 3DDFA_V2-master\3DDFA_V2-master\FaceBoxes\utils 运行如下代码:

python build.py build_ext -i

在这里插入图片描述结果显示如图就没有问题

6、进入路径 3DDFA_V2-master\3DDFA_V2-master\Sim3DR 运行如下代码:

python setup.py build_ext --inplace

结果显示如图就没有问题
在这里插入图片描述
到这一步才算是正式配置好了 这时候回到跟目录运行demo查看是否配置成功

python demo.py

结果显示如图就没有问题
在这里插入图片描述

MacOS系统

MacOS的编译比较简单,根据代码中的示例运行sh ./build.sh即可,注意一点就是MacOS需要安装Xcode,这样才会有C++工具集,另外在编译之前需要输入以下命令既可

export CFLAGS='-stdlib=libc++'
export CC=/usr/bin/clang
export CXX=/usr/bin/clang++

由于博主的电脑是windows的,所以关于MacOS这一段是借鉴以下文章里面的方法,博主并没有自己实践过,出问题的可以看看原文博客:
MacOS编译运行3DDFA_V2代码

4、代码实现

我们只需要稍微修改demo函数既可实现一个输入图片路径,返回欧拉角的函数,这边直接附上完整代码:


# coding: utf-8

__author__ = 'cleardusk'

import sys
import argparse
import cv2
import yaml

from FaceBoxes import FaceBoxes
from TDDFA import TDDFA
from utils.pose import viz_pose
from utils.functions import draw_landmarks, get_suffix
from utils.tddfa_util import str2bool

# def parse_pose(param):
#     # 适用于3DDFA V2,param为一维numpy数组
#     # param[0:12] 是仿射变换参数,param[12:15] 是欧拉角(弧度)
#     # 返回角度值
#     pitch, yaw, roll = param[12:15]
#     pitch = pitch * 180 / np.pi
#     yaw = yaw * 180 / np.pi
#     roll = roll * 180 / np.pi
#     return pitch, yaw, roll

def main(args):
    cfg = yaml.load(open(args.config), Loader=yaml.SafeLoader)

    # Init FaceBoxes and TDDFA, recommend using onnx flag
    if args.onnx:
        import os
        os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
        os.environ['OMP_NUM_THREADS'] = '4'

        from FaceBoxes.FaceBoxes_ONNX import FaceBoxes_ONNX
        from TDDFA_ONNX import TDDFA_ONNX

        face_boxes = FaceBoxes_ONNX()
        tddfa = TDDFA_ONNX(**cfg)
    else:
        gpu_mode = args.mode == 'gpu'
        tddfa = TDDFA(gpu_mode=gpu_mode, **cfg)
        face_boxes = FaceBoxes()

    # Given a still image path and load to BGR channel
    img = cv2.imread(args.img_fp)

    # Detect faces, get 3DMM params and roi boxes
    boxes = face_boxes(img)
    n = len(boxes)
    if n == 0:
        print(f'No face detected, exit')
        sys.exit(-1)
    print(f'Detect {n} faces')

    param_lst, roi_box_lst = tddfa(img, boxes)

    # # 计算欧拉角并打印(取第一个人脸)
    # # 需要用到 pose.py 中的 parse_pose
    # # from utils.pose import parse_pose
    # if param_lst:
    #     pitch, yaw, roll = parse_pose(param_lst[0])
    #     print(f"欧拉角 - Pitch: {pitch:.2f}°, Yaw: {yaw:.2f}°, Roll: {roll:.2f}°")

    # Visualization and serialization
    dense_flag = args.opt in ('2d_dense', '3d', 'depth', 'pncc', 'uv_tex', 'ply', 'obj')
    old_suffix = get_suffix(args.img_fp)
    new_suffix = f'.{args.opt}' if args.opt in ('ply', 'obj') else '.jpg'

    wfp = f'examples/results/{args.img_fp.split("/")[-1].replace(old_suffix, "")}_{args.opt}' + new_suffix

    ver_lst = tddfa.recon_vers(param_lst, roi_box_lst, dense_flag=dense_flag)

    if args.opt == 'pose':
        data_ls=viz_pose(img, param_lst, ver_lst, show_flag=args.show_flag, wfp=wfp)
        return data_ls




def check_pose(img_fp):
    parser = argparse.ArgumentParser(description='Check head pose from a single image')
    parser = argparse.ArgumentParser(description='The demo of still image of 3DDFA_V2')
    parser.add_argument('-c', '--config', type=str, default='configs/mb1_120x120.yml')
    parser.add_argument('-f', '--img_fp', type=str, default='examples/inputs/trump_hillary.jpg')
    parser.add_argument('-m', '--mode', type=str, default='cpu', help='gpu or cpu mode')
    parser.add_argument('-o', '--opt', type=str, default='2d_sparse',
                        choices=['2d_sparse', '2d_dense', '3d', 'depth', 'pncc', 'uv_tex', 'pose', 'ply', 'obj'])
    parser.add_argument('--show_flag', type=str2bool, default='true', help='whether to show the visualization result')
    parser.add_argument('--onnx', action='store_true', default=False)


    args = parser.parse_args()
    args.img_fp = img_fp
    args.opt = 'pose'  # 强制设置为姿态估计模式
    args.mode = 'gpu'  # 强制设置为GPU模式
    args.onnx = True
    data_ls=main(args)
    return data_ls

if __name__ == '__main__':
    file_ls = [
        r"C:\Users\Z\Desktop\Lip_git\Lip_reading\experiment\HeadPose\3DDFA_V2-master\examples\inputs\emma.jpg",
        r"C:\Users\Z\Desktop\Lip_git\Lip_reading\experiment\HeadPose\3DDFA_V2-master\examples\inputs\JianzhuGuo.jpg"
    ]
    for file in file_ls:
        data_ls=check_pose(file)
        print("="*50)
        print(f"Processing file: {file}")
        for i in data_ls:
            print(f"欧拉角结果: Pitch={i[0]:.2f}, Yaw={i[1]:.2f}, Roll={i[2]:.2f}")

运行结果如下:
在这里插入图片描述

機器學習:3DDFA V2代碼復現實現人臉姿態檢測歐拉角識別

整理在 Windows 上復現 3DDFA V2:np.long 與 cpu_nms、build.py、build_ext,以及 ONNX/GPU、pose 模式輸出欧拉角的程式改寫重點。

來源:https://blog.csdn.net/2403_87969572/article/details/151656986

抓取時間(ISO本地):2026-05-18 05:17:11


文章目錄


前言

在計算機視覺領域,人臉姿態檢測是一個重要的研究方向,在人臉識別、人機交互、虛擬現實、駕駛員監控等場景中都有廣泛的應用。人臉姿態通常可以通過歐拉角來描述。3DDFA(3D Dense Face Alignment)是一種基於深度學習的人臉密集對齊方法,能夠從單張 2D 人臉圖像中重建出 3D 人臉形狀和姿態。而 3DDFA V2 作為其改進版本,在精度、速度和魯棒性上都有顯著提升,不需要複雜的 3D 標註數據,僅通過 2D 圖像和簡單的先驗知識就能實現高效的 3D 人臉重建和姿態估計。

博主最近也是需要用到人臉的姿態檢測,於是復現了3DDFA V2 的代碼,並且用預訓練模型實現了人臉姿態角度的識別。3DDFA V2 最難的是對於windows來說在配置的這部分,由於版本的原因相對來說還是很耗時耗力的,經過一下午的查詢才逐個解決bug成功復現。本文將詳細介紹如何復現 3DDFA V2 的代碼,從配置到微調代碼,實現自己需要的功能(博主這邊需要的功能是一個輸入圖像路徑返回歐拉角的函數)


`

一、歐拉角是什麼?

人臉的姿態角度通常採用歐拉角俯仰角 pitch、偏航角 yaw、滾轉角 roll)來描述,這三個角度分別對應人臉在垂直方向的上下轉動、水平方向的左右轉動以及繞面部中心軸的旋轉

二、3DDFA 代碼配置

1、硬件要求

3DDFA V2的運行對硬件有一定要求,推薦配置如下:

  • CPU:至少四核處理器,推薦Intel i5及以上
  • GPU:支持CUDA的NVIDIA顯卡(如GTX 1050及以上),顯存2GB及以上(使用GPU加速可顯著提升運行速度,若沒有GPU也可使用CPU運行,但速度較慢)
  • 內存:8GB及以上

2、代碼下載

3DDFA V2在github上面是有開源源代碼與預訓練模型的可以直接下載,地址如下:
3DDFA V2 github下載地址
在這裡插入圖片描述

如果登錄不進github的話也有轉到gitee上的開源地址如下:
3DDDFA V2 gitee下載地址

在這裡插入圖片描述在這裡插入圖片描述

3、環境編譯

Windows系統

相對於MacOS系統來說,Windows系統配置會繁瑣很多,但是跟著博主一步一步做大概率是沒有什麼問題的
首先我們需要修改代碼中幾個會報錯的點:
1、路徑3DDFA_V2-master\bfm\bfm.py需要修改一個np的代碼
在這裡插入圖片描述
需要將這個np.long改為np.int32,因為np.long是舊版的代碼,在新版本的numpy中已經被棄用,必須修改,但是這個修改會帶來後續的問題,也就是我們在下一步要解決的。

2、路徑 3DDFA_V2-master\FaceBoxes/utils/nms/cpu_nms.pyx需要修改一段代碼:在這裡插入圖片描述
該函數需要大幅修改,直接複製黏貼為以下既可:

def cpu_nms(np.ndarray[np.float32_t, ndim=2] dets, np.float thresh):
    cdef np.ndarray[np.float32_t, ndim=1] x1 = dets[:, 0]
    cdef np.ndarray[np.float32_t, ndim=1] y1 = dets[:, 1]
    cdef np.ndarray[np.float32_t, ndim=1] x2 = dets[:, 2]
    cdef np.ndarray[np.float32_t, ndim=1] y2 = dets[:, 3]
    cdef np.ndarray[np.float32_t, ndim=1] scores = dets[:, 4]

    cdef np.ndarray[np.float32_t, ndim=1] areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    cdef np.ndarray[np.int64_t, ndim=1] order = scores.argsort()[::-1]

    cdef int ndets = dets.shape[0]
    cdef np.ndarray[np.int64_t, ndim=1] suppressed = \
            np.zeros((ndets), dtype=np.int64)

這一步的目的是為了與之前的修改對應以免出現數值不匹配的問題,如果沒有這一步的話會報錯這個:
ValueError: Buffer dtype mismatch, expected ‘int_t’ but got ‘long long’
這邊感謝大佬在github上面發佈以及解決的issue,這邊鏈接附在下面:
ValueError: Buffer dtype mismatch, expected ‘int_t’ but got ‘long long ISSUE github地址

3、路徑3DDFA_V2-master\FaceBoxes\utils\build.py需要註釋掉一行代碼:
在這裡插入圖片描述
extra_compile_args=[“-Wno-cpp”, “-Wno-unused-function”]
這一行是用於給 C/C++ 編譯器(如 gcc)傳遞額外的編譯參數,目的是忽略某些警告(比如宏相關和未使用函數的警告)。
這一行代碼需要註釋掉,因為 Windows 下默認編譯器是 MSVC(Visual Studio),而不是 gcc,這些參數只適用於 gcc,MSVC 不識別,會報錯。如果在 Windows 下編譯 Cython 擴展,保留這行會導致編譯失敗,提示參數無效。
在 Linux/macOS 下用 gcc 編譯時可以打開,能減少無關警告。

4、電腦需要配置Microsoft Visual Studio
這個直接搜索下載安裝即可
在這裡插入圖片描述
只需要選擇紅色框裡面的這個進行下載安裝即可。如果之前已經安裝過但是沒有勾選這個或者出現其他的什麼問題的話一般報錯信息如下:
在這裡插入圖片描述
這樣的話一般建議就是重新安裝一下,然後按照上面的步驟來。

5、進入路徑 3DDFA_V2-master\3DDFA_V2-master\FaceBoxes\utils 運行如下代碼:

python build.py build_ext -i

在這裡插入圖片描述結果顯示如圖就沒有問題

6、進入路徑 3DDFA_V2-master\3DDFA_V2-master\Sim3DR 運行如下代碼:

python setup.py build_ext --inplace

結果顯示如圖就沒有問題
在這裡插入圖片描述
到這一步才算是正式配置好了 這時候回到跟目錄運行demo查看是否配置成功

python demo.py

結果顯示如圖就沒有問題
在這裡插入圖片描述

MacOS系統

MacOS的編譯比較簡單,根據代碼中的示例運行sh ./build.sh即可,注意一點就是MacOS需要安裝Xcode,這樣才會有C++工具集,另外在編譯之前需要輸入以下命令既可

export CFLAGS='-stdlib=libc++'
export CC=/usr/bin/clang
export CXX=/usr/bin/clang++

由於博主的電腦是windows的,所以關於MacOS這一段是借鑑以下文章裡面的方法,博主並沒有自己實踐過,出問題的可以看看原文博客:
MacOS編譯運行3DDFA_V2代碼

4、代碼實現

我們只需要稍微修改demo函數既可實現一個輸入圖片路徑,返回歐拉角的函數,這邊直接附上完整代碼:


# coding: utf-8

__author__ = 'cleardusk'

import sys
import argparse
import cv2
import yaml

from FaceBoxes import FaceBoxes
from TDDFA import TDDFA
from utils.pose import viz_pose
from utils.functions import draw_landmarks, get_suffix
from utils.tddfa_util import str2bool

# def parse_pose(param):
#     # 適用於3DDFA V2,param為一維numpy數組
#     # param[0:12] 是仿射變換參數,param[12:15] 是歐拉角(弧度)
#     # 返回角度值
#     pitch, yaw, roll = param[12:15]
#     pitch = pitch * 180 / np.pi
#     yaw = yaw * 180 / np.pi
#     roll = roll * 180 / np.pi
#     return pitch, yaw, roll

def main(args):
    cfg = yaml.load(open(args.config), Loader=yaml.SafeLoader)

    # Init FaceBoxes and TDDFA, recommend using onnx flag
    if args.onnx:
        import os
        os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
        os.environ['OMP_NUM_THREADS'] = '4'

        from FaceBoxes.FaceBoxes_ONNX import FaceBoxes_ONNX
        from TDDFA_ONNX import TDDFA_ONNX

        face_boxes = FaceBoxes_ONNX()
        tddfa = TDDFA_ONNX(**cfg)
    else:
        gpu_mode = args.mode == 'gpu'
        tddfa = TDDFA(gpu_mode=gpu_mode, **cfg)
        face_boxes = FaceBoxes()

    # Given a still image path and load to BGR channel
    img = cv2.imread(args.img_fp)

    # Detect faces, get 3DMM params and roi boxes
    boxes = face_boxes(img)
    n = len(boxes)
    if n == 0:
        print(f'No face detected, exit')
        sys.exit(-1)
    print(f'Detect {n} faces')

    param_lst, roi_box_lst = tddfa(img, boxes)

    # # 計算歐拉角並打印(取第一個人臉)
    # # 需要用到 pose.py 中的 parse_pose
    # # from utils.pose import parse_pose
    # if param_lst:
    #     pitch, yaw, roll = parse_pose(param_lst[0])
    #     print(f"歐拉角 - Pitch: {pitch:.2f}°, Yaw: {yaw:.2f}°, Roll: {roll:.2f}°")

    # Visualization and serialization
    dense_flag = args.opt in ('2d_dense', '3d', 'depth', 'pncc', 'uv_tex', 'ply', 'obj')
    old_suffix = get_suffix(args.img_fp)
    new_suffix = f'.{args.opt}' if args.opt in ('ply', 'obj') else '.jpg'

    wfp = f'examples/results/{args.img_fp.split("/")[-1].replace(old_suffix, "")}_{args.opt}' + new_suffix

    ver_lst = tddfa.recon_vers(param_lst, roi_box_lst, dense_flag=dense_flag)

    if args.opt == 'pose':
        data_ls=viz_pose(img, param_lst, ver_lst, show_flag=args.show_flag, wfp=wfp)
        return data_ls




def check_pose(img_fp):
    parser = argparse.ArgumentParser(description='Check head pose from a single image')
    parser = argparse.ArgumentParser(description='The demo of still image of 3DDFA_V2')
    parser.add_argument('-c', '--config', type=str, default='configs/mb1_120x120.yml')
    parser.add_argument('-f', '--img_fp', type=str, default='examples/inputs/trump_hillary.jpg')
    parser.add_argument('-m', '--mode', type=str, default='cpu', help='gpu or cpu mode')
    parser.add_argument('-o', '--opt', type=str, default='2d_sparse',
                        choices=['2d_sparse', '2d_dense', '3d', 'depth', 'pncc', 'uv_tex', 'pose', 'ply', 'obj'])
    parser.add_argument('--show_flag', type=str2bool, default='true', help='whether to show the visualization result')
    parser.add_argument('--onnx', action='store_true', default=False)


    args = parser.parse_args()
    args.img_fp = img_fp
    args.opt = 'pose'  # 強制設置為姿態估計模式
    args.mode = 'gpu'  # 強制設置為GPU模式
    args.onnx = True
    data_ls=main(args)
    return data_ls

if __name__ == '__main__':
    file_ls = [
        r"C:\Users\Z\Desktop\Lip_git\Lip_reading\experiment\HeadPose\3DDFA_V2-master\examples\inputs\emma.jpg",
        r"C:\Users\Z\Desktop\Lip_git\Lip_reading\experiment\HeadPose\3DDFA_V2-master\examples\inputs\JianzhuGuo.jpg"
    ]
    for file in file_ls:
        data_ls=check_pose(file)
        print("="*50)
        print(f"Processing file: {file}")
        for i in data_ls:
            print(f"歐拉角結果: Pitch={i[0]:.2f}, Yaw={i[1]:.2f}, Roll={i[2]:.2f}")

運行結果如下:
在這裡插入圖片描述

Machine Learning: 3DDFA V2 Reproduction — Face Pose and Euler Angles

Reproduction notes for cleardusk/3DDFA V2 on Windows (NumPy and Cython edits, MSVC vs gcc flags), native extension builds, and a ONNX/GPU pose wrapper that prints Euler angles per face.

Captured at (local ISO): 2026-05-18 05:17:11


Preface

Head pose matters for face recognition, HCI, VR, and driver monitoring. Euler angles (pitch, yaw, roll) describe orientation. 3DDFA dense-aligns a 3D face from one 2D image; 3DDFA V2 improves accuracy and speed without heavy 3D labels.

I reproduced V2 on Windows—setup was the hard part—and wrapped a function: image path → Euler angles. This post covers environment fixes and the wrapper code.

1. What are Euler angles?

Pitch (nod), yaw (turn left/right), roll (tilt) describe head pose in 3D.

2. 3DDFA setup

Hardware

  • CPU: quad-core+, Intel i5+ recommended;
  • GPU: NVIDIA + CUDA, 2GB+ VRAM (CPU works, slower);
  • RAM: 8GB+.

Download

Build

Windows

  1. bfm/bfm.py: change np.longnp.int32 (deprecated in new NumPy).
    Insert image description here

  2. FaceBoxes/utils/nms/cpu_nms.pyx: replace cpu_nms with:

def cpu_nms(np.ndarray[np.float32_t, ndim=2] dets, np.float thresh):
    cdef np.ndarray[np.float32_t, ndim=1] x1 = dets[:, 0]
    cdef np.ndarray[np.float32_t, ndim=1] y1 = dets[:, 1]
    cdef np.ndarray[np.float32_t, ndim=1] x2 = dets[:, 2]
    cdef np.ndarray[np.float32_t, ndim=1] y2 = dets[:, 3]
    cdef np.ndarray[np.float32_t, ndim=1] scores = dets[:, 4]

    cdef np.ndarray[np.float32_t, ndim=1] areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    cdef np.ndarray[np.int64_t, ndim=1] order = scores.argsort()[::-1]

    cdef int ndets = dets.shape[0]
    cdef np.ndarray[np.int64_t, ndim=1] suppressed = \
            np.zeros((ndets), dtype=np.int64)

Fixes ValueError: Buffer dtype mismatch... — see GitHub issue #12.
Insert image description here

  1. FaceBoxes/utils/build.py: comment out extra_compile_args=["-Wno-cpp", "-Wno-unused-function"] (GCC-only; MSVC fails).
    Insert image description here

  2. Install Visual Studio with “Desktop development with C++”.
    Insert image description here
    Insert image description here

  3. In FaceBoxes/utils:

python build.py build_ext -i

Insert image description here

  1. In Sim3DR:
python setup.py build_ext --inplace

Insert image description here

  1. Root test:
python demo.py

Insert image description here

macOS

Run sh ./build.sh with Xcode/clang:

export CFLAGS='-stdlib=libc++'
export CC=/usr/bin/clang
export CXX=/usr/bin/clang++

Reference: macOS build notes (not verified by author on Mac).

Custom code

Wrapper returning Euler angles from an image path (full file):


# coding: utf-8

__author__ = 'cleardusk'

import sys
import argparse
import cv2
import yaml

from FaceBoxes import FaceBoxes
from TDDFA import TDDFA
from utils.pose import viz_pose
from utils.functions import draw_landmarks, get_suffix
from utils.tddfa_util import str2bool

# def parse_pose(param):
#     # 适用于3DDFA V2,param为一维numpy数组
#     # param[0:12] 是仿射变换参数,param[12:15] 是欧拉角(弧度)
#     # 返回角度值
#     pitch, yaw, roll = param[12:15]
#     pitch = pitch * 180 / np.pi
#     yaw = yaw * 180 / np.pi
#     roll = roll * 180 / np.pi
#     return pitch, yaw, roll

def main(args):
    cfg = yaml.load(open(args.config), Loader=yaml.SafeLoader)

    # Init FaceBoxes and TDDFA, recommend using onnx flag
    if args.onnx:
        import os
        os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
        os.environ['OMP_NUM_THREADS'] = '4'

        from FaceBoxes.FaceBoxes_ONNX import FaceBoxes_ONNX
        from TDDFA_ONNX import TDDFA_ONNX

        face_boxes = FaceBoxes_ONNX()
        tddfa = TDDFA_ONNX(**cfg)
    else:
        gpu_mode = args.mode == 'gpu'
        tddfa = TDDFA(gpu_mode=gpu_mode, **cfg)
        face_boxes = FaceBoxes()

    # Given a still image path and load to BGR channel
    img = cv2.imread(args.img_fp)

    # Detect faces, get 3DMM params and roi boxes
    boxes = face_boxes(img)
    n = len(boxes)
    if n == 0:
        print(f'No face detected, exit')
        sys.exit(-1)
    print(f'Detect {n} faces')

    param_lst, roi_box_lst = tddfa(img, boxes)

    # # 计算欧拉角并打印(取第一个人脸)
    # # 需要用到 pose.py 中的 parse_pose
    # # from utils.pose import parse_pose
    # if param_lst:
    #     pitch, yaw, roll = parse_pose(param_lst[0])
    #     print(f"欧拉角 - Pitch: {pitch:.2f}°, Yaw: {yaw:.2f}°, Roll: {roll:.2f}°")

    # Visualization and serialization
    dense_flag = args.opt in ('2d_dense', '3d', 'depth', 'pncc', 'uv_tex', 'ply', 'obj')
    old_suffix = get_suffix(args.img_fp)
    new_suffix = f'.{args.opt}' if args.opt in ('ply', 'obj') else '.jpg'

    wfp = f'examples/results/{args.img_fp.split("/")[-1].replace(old_suffix, "")}_{args.opt}' + new_suffix

    ver_lst = tddfa.recon_vers(param_lst, roi_box_lst, dense_flag=dense_flag)

    if args.opt == 'pose':
        data_ls=viz_pose(img, param_lst, ver_lst, show_flag=args.show_flag, wfp=wfp)
        return data_ls




def check_pose(img_fp):
    parser = argparse.ArgumentParser(description='Check head pose from a single image')
    parser = argparse.ArgumentParser(description='The demo of still image of 3DDFA_V2')
    parser.add_argument('-c', '--config', type=str, default='configs/mb1_120x120.yml')
    parser.add_argument('-f', '--img_fp', type=str, default='examples/inputs/trump_hillary.jpg')
    parser.add_argument('-m', '--mode', type=str, default='cpu', help='gpu or cpu mode')
    parser.add_argument('-o', '--opt', type=str, default='2d_sparse',
                        choices=['2d_sparse', '2d_dense', '3d', 'depth', 'pncc', 'uv_tex', 'pose', 'ply', 'obj'])
    parser.add_argument('--show_flag', type=str2bool, default='true', help='whether to show the visualization result')
    parser.add_argument('--onnx', action='store_true', default=False)


    args = parser.parse_args()
    args.img_fp = img_fp
    args.opt = 'pose'  # 强制设置为姿态估计模式
    args.mode = 'gpu'  # 强制设置为GPU模式
    args.onnx = True
    data_ls=main(args)
    return data_ls

if __name__ == '__main__':
    file_ls = [
        r"C:\Users\Z\Desktop\Lip_git\Lip_reading\experiment\HeadPose\3DDFA_V2-master\examples\inputs\emma.jpg",
        r"C:\Users\Z\Desktop\Lip_git\Lip_reading\experiment\HeadPose\3DDFA_V2-master\examples\inputs\JianzhuGuo.jpg"
    ]
    for file in file_ls:
        data_ls=check_pose(file)
        print("="*50)
        print(f"Processing file: {file}")
        for i in data_ls:
            print(f"欧拉角结果: Pitch={i[0]:.2f}, Yaw={i[1]:.2f}, Roll={i[2]:.2f}")

Sample output:
Insert image description here