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

如何借助MediaPipe实现3米以上距离的精准人脸朝向检测?

远距离人脸朝向检测解决方案

问题核心

当人物距离摄像头3米以上时,MediaPipe Face Mesh因面部像素占比过低,无法精准识别面部关键点;姿态估计中的单个面部关键点(如鼻子)受分辨率限制,检测误差大,但身体髋部等大区域关键点的身体朝向检测稳定。

可行解决方案

1. 先检测人脸再放大处理

利用YOLO等轻量人脸检测器定位远距离人脸,裁剪后放大面部区域,再输入MediaPipe Face Mesh检测关键点,提升面部像素密度,解决低分辨率下关键点检测失效的问题。

2. 优化MediaPipe配置

  • 降低min_detection_confidence和min_tracking_confidence至0.3左右,提升远距离人脸的检测灵敏度;
  • 开启static_image_mode=True,对每一帧重新检测而非跟踪,避免远距离下人脸跟踪丢失。

3. 融合身体与头部姿态推断

当面部关键点检测不可靠时,用身体朝向作为基础,结合头部相对肩膀的偏移量(如鼻子与双肩中点的水平距离)修正人脸朝向,弥补纯面部检测的不足。

代码优化示例

基于你的现有代码,加入YOLO人脸检测+MediaPipe Face Mesh的融合方案:

from cvzone.PoseModule import PoseDetector
import cv2
from ultralytics import YOLO
import math
import numpy as np
import imutils
import mediapipe as mp

# 初始化YOLO人脸检测模型
face_model = YOLO('yolov8n-face.pt')
# 初始化MediaPipe Face Mesh
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(
    static_image_mode=False,
    max_num_faces=1,
    min_detection_confidence=0.3,
    min_tracking_confidence=0.3
)

cap = cv2.VideoCapture(1)

detector = PoseDetector(staticMode=False,
                        modelComplexity=1,
                        smoothLandmarks=True,
                        enableSegmentation=False,
                        smoothSegmentation=True,
                        detectionCon=0.5,
                        trackCon=0.5)

while True:
    success, img = cap.read()
    if not success:
        break
    org_img = img.copy()
    img_h, img_w, _ = org_img.shape
    face_detected = False

    # 第一步:YOLO检测远距离人脸
    face_results = face_model(img, conf=0.3)
    for result in face_results:
        for box in result.boxes:
            x1, y1, x2, y2 = map(int, box.xyxy[0])
            # 裁剪并放大人脸区域
            face_roi = org_img[y1:y2, x1:x2]
            face_roi = cv2.resize(face_roi, (256, 256))
            face_roi_rgb = cv2.cvtColor(face_roi, cv2.COLOR_BGR2RGB)
            
            # Face Mesh检测面部关键点
            mesh_results = face_mesh.process(face_roi_rgb)
            if mesh_results.multi_face_landmarks:
                face_detected = True
                landmarks = mesh_results.multi_face_landmarks[0]
                face_3d = []
                face_2d = []
                # 选取关键姿态关键点:鼻尖、左右眼角、左右耳
                key_indices = [1, 33, 263, 234, 454]
                for idx, lm in enumerate(landmarks.landmark):
                    if idx in key_indices:
                        x, y = int(lm.x * face_roi.shape[1]), int(lm.y * face_roi.shape[0])
                        face_2d.append([x, y])
                        face_3d.append([x, y, lm.z * 3000])
                
                face_2d = np.array(face_2d, dtype=np.float64)
                face_3d = np.array(face_3d, dtype=np.float64)
                
                # 相机矩阵配置
                focal_length = 1 * face_roi.shape[1]
                camera_matrix = np.array([
                    [focal_length, 0, face_roi.shape[1]/2],
                    [0, focal_length, face_roi.shape[0]/2],
                    [0, 0, 1]
                ], dtype=np.float64)
                dist_matrix = np.zeros((4,1), dtype=np.float64)
                
                # 求解3D姿态
                success, rot_vec, trans_vec = cv2.solvePnP(face_3d, face_2d, camera_matrix, dist_matrix)
                r_mat, jac = cv2.Rodrigues(rot_vec)
                angles, _, _, _, _, _ = cv2.RQDecomp3x3(r_mat)
                
                x = angles[0] * 360
                y = angles[1] * 360
                
                # 判断人脸朝向
                if y < -10:
                    text = "Face Left"
                elif y > 10:
                    text = "Face Right"
                else:
                    text = "Face Forward"
                
                # 在原图绘制结果
                cv2.rectangle(img, (x1, y1), (x2, y2), (0,255,0), 2)
                cv2.putText(img, text, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,0), 2)
                cv2.putText(img, f"Y: {round(y,2)}", (x1, y1-40), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,255,0), 2)
    
    # 未检测到人脸时,用身体姿态补充推断
    if not face_detected:
        img = detector.findPose(img, draw=False)
        lmList, bboxInfo = detector.findPosition(img, draw=False, bboxWithHands=False)
        if lmList:
            # 获取身体关键点
            left_shoulder = lmList[11]
            right_shoulder = lmList[12]
            nose = lmList[0]
            
            # 计算双肩中点
            shoulder_mid_x = (left_shoulder[0] + right_shoulder[0]) // 2
            # 判断头部相对身体的偏移
            head_offset = nose[0] - shoulder_mid_x
            if head_offset < -25:
                text = "Face Left (Body-based)"
            elif head_offset > 25:
                text = "Face Right (Body-based)"
            else:
                text = "Face Forward (Body-based)"
            
            cv2.putText(img, text, (20,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)
    
    cv2.imshow("Image", imutils.resize(img, height=480))
    key = cv2.waitKey(1)
    if key == 115:
        break

cap.release()
cv2.destroyAllWindows()

替代方案

  • 专用低分辨率姿态模型:使用HRNet、3DDFA-V2等针对低分辨率人脸优化的头部姿态估计模型,这类模型对小尺寸人脸的鲁棒性更强;
  • 深度摄像头辅助:搭配Intel RealSense等深度摄像头,利用深度数据提升3D姿态估计精度,即使面部像素少,深度信息也能辅助判断朝向。

内容的提问来源于stack exchange,提问作者nadhir hasan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 23:52:04