1. 为什么输出是 x, y, z 而不是只有 x, y?

虽然图像是二维的(像素坐标系只有 x,yx, yx,y),但 Face Mesh 模块通过深度信息估计输出了三维坐标 x,y,zx, y, zx,y,z。以下是具体原因:

1.1 图像是二维的,但人脸是三维的
  • 即使图像本身是二维的,人脸是一个三维物体。MediaPipe 使用机器学习模型从二维图像中推测出三维的深度信息。
  • Z 轴:代表每个关键点相对于人脸中心的深度值,单位通常是相对值,用来估计人脸在三维空间中的形状。
1.2 MediaPipe 的 3D 推测原理
  • 模型基于训练数据,从多个角度学习了三维人脸的结构。
  • 关键点 x, y, z 含义:
    • xxx: 水平方向坐标,归一化为 [0, 1]。
    • yyy: 垂直方向坐标,归一化为 [0, 1]。
    • zzz: 深度值,相对归一化坐标,用于表示点距离摄像头或基准平面的远近关系。

2. 归一化比例因子是什么?

2.1 归一化的含义

归一化比例因子是为了让坐标值适配不同大小的输入图像。归一化的主要目的是消除因图像尺寸不同带来的影响,使关键点坐标具有通用性。

  • 归一化公式:
    xnormalized=ximage width,ynormalized=yimage height x_{\text{normalized}} = \frac{x}{\text{image width}}, \quad y_{\text{normalized}} = \frac{y}{\text{image height}} xnormalized=image widthx,ynormalized=image heighty
    其中:

    • x,yx, yx,y 是像素坐标。
    • image width\text{image width}image widthimage height\text{image height}image height 是输入图像的宽度和高度。
  • 归一化的优点:

    • 无论图像大小如何,关键点的坐标值都在 [0, 1] 范围内。
    • 便于在模型中使用或与其他图像对齐。
2.2 Z 坐标的归一化
  • zzz 的归一化是相对深度值,通常以人脸框的宽度为基准单位。例如:
    znormalized=zface width z_{\text{normalized}} = \frac{z}{\text{face width}} znormalized=face widthz
  • 归一化后的 zzz 是无单位值,可以反映人脸中某些关键点在深度上的相对关系,例如鼻尖相对于面部其他部分是否更靠近摄像头。

3. 小图 sub_face_mini 为什么需要?

小图 sub_face_mini 是从原始图像中裁剪得到的人脸区域(ROI,Region of Interest)。裁剪的目的是降低计算成本或为后续处理提供专注区域。

3.1 小图的作用
  1. 局部增强精度

    • 后续操作(如表情识别、属性分析)可能需要对脸部局部细节进行处理。通过裁剪小图,可以集中分析人脸特定区域的特征。
  2. 降低计算复杂度

    • 使用完整图像可能会浪费计算资源,而裁剪的小图减少了无关背景,降低计算成本。
  3. 便于进一步操作:

    • 小图可以用于表情识别、年龄估计、化妆检测等任务。
    • 特定应用可能只需要眼睛、嘴巴等局部区域,裁剪后的小图为后续裁剪提供了基础。
3.2 小图裁剪的逻辑
  • 通过检测到的关键点(如眼睛、嘴巴、下巴等的坐标)裁剪出一个包含整个人脸的矩形区域。
  • 裁剪过程:
    • 找到关键点的边界框。
    • 根据边界框裁剪图像:
      ROI=image[ymin:ymax,xmin:xmax] \text{ROI} = \text{image}[y_{\text{min}}:y_{\text{max}}, x_{\text{min}}:x_{\text{max}}] ROI=image[ymin:ymax,xmin:xmax]
示例代码
import cv2
import mediapipe as mp

# 初始化 Face Mesh 模块
mp_face_mesh = mp.solutions.face_mesh.FaceMesh()

# 加载图像
image = cv2.imread("face.jpg")
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

# 检测人脸关键点
results = mp_face_mesh.process(rgb_image)

# 提取人脸区域小图
if results.multi_face_landmarks:
    for face_landmarks in results.multi_face_landmarks:
        h, w, _ = image.shape
        # 根据关键点找到边界框
        x_min = int(min([lm.x for lm in face_landmarks.landmark]) * w)
        y_min = int(min([lm.y for lm in face_landmarks.landmark]) * h)
        x_max = int(max([lm.x for lm in face_landmarks.landmark]) * w)
        y_max = int(max([lm.y for lm in face_landmarks.landmark]) * h)
        
        # 裁剪人脸小图
        sub_face_mini = image[y_min:y_max, x_min:x_max]
        cv2.imshow("Cropped Face", sub_face_mini)

cv2.waitKey(0)
cv2.destroyAllWindows()

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐