You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中绕Roll、Pitch、Yaw轴旋转MediaPipe面部关键点?

面部关键点姿态校正(解决Roll/Pitch/Yaw旋转问题)

要校正人脸的Pitch(俯仰)和Yaw(偏航)旋转,你需要用到3D关键点数据(仅2D的x/y坐标无法准确完成这两个轴的旋转,因为缺少深度信息)。以下是具体的Python实现步骤:

前提准备

确保你的CSV文件包含MediaPipe输出的完整3D关键点(每个点有x、y、z三个值,z为相对于鼻尖的深度)。如果之前只存了2D数据,需要重新导出包含z列的CSV。

步骤1:计算人脸当前的姿态角(Roll/Pitch/Yaw)

通过OpenCV的solvePnP方法,利用几个关键面部点(鼻尖、双眼外角、下巴尖)来估算姿态角:

import numpy as np
import math
import cv2
import pandas as pd

# 读取CSV中的3D关键点数据(假设每行是一个点的x,y,z)
df = pd.read_csv("face_landmarks.csv")
points_3d = df[["x", "y", "z"]].values

# 图像尺寸(根据你的原始图像设置,若用归一化坐标可忽略,这里用示例值)
img_w, img_h = 640, 480

# 定义标准正视人脸的3D参考点(相对位置即可)
model_points = np.array([
    (0.0, 0.0, 0.0),        # 鼻尖(MediaPipe索引1)
    (-30.0, -125.0, -30.0), # 左眼外角(索引33)
    (30.0, -125.0, -30.0),  # 右眼外角(索引263)
    (0.0, 150.0, -10.0)     # 下巴尖(索引152)
], dtype=np.float64)

# 从你的关键点中提取对应图像点(转换为像素坐标,若用归一化则跳过*img_w/h)
image_points = np.array([
    (points_3d[1][0] * img_w, points_3d[1][1] * img_h),
    (points_3d[33][0] * img_w, points_3d[33][1] * img_h),
    (points_3d[263][0] * img_w, points_3d[263][1] * img_h),
    (points_3d[152][0] * img_w, points_3d[152][1] * img_h)
], dtype=np.float64)

# 相机内参(近似值,无畸变)
camera_matrix = np.array(
    [[img_w, 0, img_w/2],
     [0, img_h, img_h/2],
     [0, 0, 1]], dtype=np.float64
)
dist_coeffs = np.zeros((4,1))

# 计算旋转向量和平移向量
success, rotation_vec, translation_vec = cv2.solvePnP(model_points, image_points, camera_matrix, dist_coeffs)

# 将旋转向量转换为欧拉角(Roll, Pitch, Yaw)
rotation_mat, _ = cv2.Rodrigues(rotation_vec)
euler_angles = cv2.decomposeProjectionMatrix(np.hstack((rotation_mat, translation_vec)))[6]
roll, pitch, yaw = euler_angles[0], euler_angles[1], euler_angles[2]

步骤2:构建逆旋转矩阵抵消姿态

用负的姿态角构建旋转矩阵,将关键点旋转至正视状态:

# 将欧拉角转换为弧度,并取负值(抵消原旋转)
roll_rad = math.radians(-roll)
pitch_rad = math.radians(-pitch)
yaw_rad = math.radians(-yaw)

# 绕X轴(Pitch)的旋转矩阵
Rx = np.array([
    [1, 0, 0],
    [0, math.cos(pitch_rad), -math.sin(pitch_rad)],
    [0, math.sin(pitch_rad), math.cos(pitch_rad)]
])

# 绕Y轴(Yaw)的旋转矩阵
Ry = np.array([
    [math.cos(yaw_rad), 0, math.sin(yaw_rad)],
    [0, 1, 0],
    [-math.sin(yaw_rad), 0, math.cos(yaw_rad)]
])

# 绕Z轴(Roll)的旋转矩阵(你之前用的2D矩阵其实是这个的2D版本)
Rz = np.array([
    [math.cos(roll_rad), -math.sin(roll_rad), 0],
    [math.sin(roll_rad), math.cos(roll_rad), 0],
    [0, 0, 1]
])

# 组合旋转矩阵(顺序为Z-Y-X,对应Roll→Yaw→Pitch的旋转抵消)
total_rot_mat = Ry @ Rx @ Rz

步骤3:对所有关键点应用旋转校正

# 以鼻尖为中心平移(避免旋转后偏移)
nose_point = points_3d[1]
points_centered = points_3d - nose_point

# 应用旋转
points_rotated = (total_rot_mat @ points_centered.T).T

# 移回原位置
points_corrected = points_rotated + nose_point

步骤4:投影回2D平面(可选,用于可视化)

如果需要2D坐标进行可视化,用相机内参做透视投影:

# 3D转2D投影
points_2d_corrected = (camera_matrix @ points_corrected.T).T
# 透视除法
points_2d_corrected = points_2d_corrected[:, :2] / points_2d_corrected[:, 2, np.newaxis]

注意事项

  1. 若你只有2D坐标,无法准确校正Pitch/Yaw,因为缺少深度信息会导致透视变形无法还原,建议重新提取MediaPipe的3D关键点。
  2. 欧拉角的旋转顺序可能需要根据实际情况调整,若校正后姿态不对,可以尝试调整旋转矩阵的组合顺序(比如Rx @ Ry @ Rz)。
  3. MediaPipe的x/y是归一化到[0,1]的值,若需要像素坐标,记得乘以图像的宽和高。

内容的提问来源于stack exchange,提问作者Walu Gulu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:10:16