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

Python+OpenCV+MediaPipe面部关键点三角图像叠加位置异常求助

问题解决:人脸三角区图片叠加的位置匹配与透明化处理

核心问题分析

你遇到的两个问题本质是:

  • 位置不匹配:目标图片的三角坐标和摄像头人脸关键点坐标没有做尺寸映射+透视变换,MediaPipe输出的是相对画面的归一化坐标,直接使用会错位;另外人脸三角会随面部姿态变化角度,目标图片的三角是固定形状,必须做透视变形匹配人脸姿态。
  • 无透明度方形:叠加时没处理Alpha通道或蒙版,直接把整个图片区域贴上去,没有抠出三角的透明背景。

分步解决方案

1. 预处理目标图片:提取三角区蒙版

先从目标图片中抠出三角区域的蒙版,确保叠加时只有三角内容显示:

import cv2
import numpy as np
import mediapipe as mp

# 加载目标图片和定义目标三角区(替换成你自己的图片路径和实际提取的坐标)
target_img = cv2.imread("your_target_image.png")
# 示例:目标图片上的三个三角顶点像素坐标
target_tri = np.array([[100, 150], [300, 150], [200, 350]], dtype=np.float32)

# 创建目标三角的蒙版
mask = np.zeros(target_img.shape[:2], dtype=np.uint8)
cv2.fillConvexPoly(mask, target_tri.astype(np.int32), 255)
# 提取带蒙版的目标三角ROI
target_roi = cv2.bitwise_and(target_img, target_img, mask=mask)

2. 摄像头人脸关键点坐标转换

MediaPipe输出的face_landmarks.landmark是相对画面的归一化坐标(x/y范围0-1),需要转换成摄像头画面的像素坐标:

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.5)

cap = cv2.VideoCapture(0)
while cap.isOpened():
    success, frame = cap.read()
    if not success:
        continue
    
    # 镜像翻转画面(可选,符合日常视觉习惯)
    frame = cv2.flip(frame, 1)
    h, w, _ = frame.shape
    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = face_mesh.process(rgb_frame)
    
    if results.multi_face_landmarks:
        for face_landmarks in results.multi_face_landmarks:
            # 替换成你要匹配的人脸三角关键点索引(参考MediaPipe关键点图)
            # 示例:左眼周围的三个关键点索引
            landmark_indices = [159, 145, 133]
            face_tri = []
            for idx in landmark_indices:
                x = int(face_landmarks.landmark[idx].x * w)
                y = int(face_landmarks.landmark[idx].y * h)
                face_tri.append([x, y])
            face_tri = np.array(face_tri, dtype=np.float32)

3. 透视变换匹配人脸三角姿态

计算目标三角到人脸三角的透视变换矩阵,把目标ROI变形到人脸三角的形状:

# 计算仿射变换矩阵(针对三角区域用仿射足够)
            M = cv2.getAffineTransform(target_tri, face_tri)
            # 对目标ROI和蒙版做透视变换
            warped_target = cv2.warpAffine(target_roi, M, (w, h))
            warped_mask = cv2.warpAffine(mask, M, (w, h))

4. Alpha混合叠加到摄像头画面

用蒙版做Alpha混合,避免出现方形背景:

# 将单通道蒙版转为3通道,方便和彩色画面混合
            warped_mask_3ch = cv2.cvtColor(warped_mask, cv2.COLOR_GRAY2BGR) / 255.0
            # 混合计算:目标区域*蒙版权重 + 原画面*(1-蒙版权重)
            frame = (frame * (1 - warped_mask_3ch) + warped_target * warped_mask_3ch).astype(np.uint8)

完整代码整合

import cv2
import numpy as np
import mediapipe as mp

# 初始化MediaPipe人脸网格
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.5)

# 加载目标图片并定义目标三角区(替换成你的实际内容)
target_img = cv2.imread("target_tri_image.png")
target_tri = np.array([[50, 50], [250, 50], [150, 200]], dtype=np.float32)

# 创建目标三角蒙版
mask = np.zeros(target_img.shape[:2], dtype=np.uint8)
cv2.fillConvexPoly(mask, target_tri.astype(np.int32), 255)
target_roi = cv2.bitwise_and(target_img, target_img, mask=mask)

# 开启摄像头
cap = cv2.VideoCapture(0)
while cap.isOpened():
    success, frame = cap.read()
    if not success:
        print("摄像头读取失败")
        continue
    
    frame = cv2.flip(frame, 1)
    h, w, _ = frame.shape
    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = face_mesh.process(rgb_frame)
    
    if results.multi_face_landmarks:
        for face_landmarks in results.multi_face_landmarks:
            # 替换成你需要的人脸三角关键点索引
            landmark_indices = [159, 145, 133]
            face_tri = []
            for idx in landmark_indices:
                x = int(face_landmarks.landmark[idx].x * w)
                y = int(face_landmarks.landmark[idx].y * h)
                face_tri.append([x, y])
            face_tri = np.array(face_tri, dtype=np.float32)
            
            # 透视变换与叠加
            M = cv2.getAffineTransform(target_tri, face_tri)
            warped_target = cv2.warpAffine(target_roi, M, (w, h))
            warped_mask = cv2.warpAffine(mask, M, (w, h))
            
            warped_mask_3ch = cv2.cvtColor(warped_mask, cv2.COLOR_GRAY2BGR) / 255.0
            frame = (frame * (1 - warped_mask_3ch) + warped_target * warped_mask_3ch).astype(np.uint8)
    
    cv2.imshow("Face Triangle Overlay", frame)
    if cv2.waitKey(5) & 0xFF == 27:
        break

cap.release()
cv2.destroyAllWindows()

关键注意事项

  • 关键点索引对应:一定要根据你的需求,从MediaPipe人脸关键点图中选对三个匹配的顶点,选不对必然位置错位。
  • 目标三角坐标:确保你提取的目标图片三角坐标是正确的像素坐标,而非归一化坐标。
  • Alpha通道优化:如果你的目标图片本身是带透明背景的PNG,可以直接用target_img[:, :, 3]作为蒙版,无需手动创建。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 03:10:38