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

MediaPipe人脸渲染程序纹理输出伪影排查与解决

问题背景

开发简易人脸面具渲染功能时,输出纹理存在多处细小伪影,目前既无法定位伪影产生的根本原因,也没有找到彻底消除伪影的方法,伪影位置已在测试示例图中标注。
当前实现基于开源项目mediapipe_faceswap做小幅修改,依赖项目内triangulation_media_pipe.py文件定义的三角剖分规则,核心逻辑如下:

  • 调用MediaPipe FaceMesh接口提取人脸关键点
  • 将归一化格式的关键点坐标转换为OpenCV可用的像素坐标
  • 逐三角形计算仿射变换矩阵
  • 完成源人脸纹理到目标人脸区域的仿射变换与拼接
完整实现代码
import cv2
import mediapipe as mp
import triangulation_media_pipe as tmp
import numpy as np

mp_drawing = mp.solutions.drawing_utils
mp_face_mesh = mp.solutions.face_mesh
face = "face_textures/yash.jpg"


def load_base_img(face_mesh, image_file_name, ):
    image = cv2.imread(image_file_name)
    results = face_mesh.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    return {"img": image, "landmarks": results}


def transform_landmarks_from_tf_to_ocv(keypoints, face_width, face_height):
    landmark_list = []
    if (keypoints.multi_face_landmarks != None):
        for face_landmarks in keypoints.multi_face_landmarks:
            for l in face_landmarks.landmark:
                pt = mp_drawing._normalized_to_pixel_coordinates(l.x, l.y,
                                                                 face_width, face_height)

                landmark_list.append(pt)
    return landmark_list


def main():

    # 摄像头输入逻辑
    face_mesh = mp_face_mesh.FaceMesh()
    base_face_handler, landmark_base_ocv, base_input_image = process_base_face_mesh(face_mesh, face)
    cap = cv2.VideoCapture(2)

    while cap.isOpened():
        _, webcam_img = cap.read()

        image_rows, image_cols, _ = webcam_img.shape
        results = face_mesh.process(webcam_img)
        landmark_target_ocv = transform_landmarks_from_tf_to_ocv(results, image_cols, image_rows)

        # 绘制人脸网格标注
        image = webcam_img.copy()
        img2_new_face = np.zeros_like(image)

        if results.multi_face_landmarks:
            if True:
                for i in range(0, int(len(tmp.TRIANGULATION) / 3)):
                    triangle_index = [tmp.TRIANGULATION[i * 3],
                                      tmp.TRIANGULATION[i * 3 + 1],
                                      tmp.TRIANGULATION[i * 3 + 2]]
                    tbas1 = landmark_base_ocv[triangle_index[0]]
                    tbas2 = landmark_base_ocv[triangle_index[1]]
                    tbas3 = landmark_base_ocv[triangle_index[2]]
                    triangle1 = np.array([tbas1, tbas2, tbas3])

                    rect1 = cv2.boundingRect(triangle1)
                    (x1, y1, w1, h1) = rect1
                    cropped_triangle = base_input_image[y1: y1 + h1, x1: x1 + w1]
                    cropped_tr1_mask = np.zeros((h1, w1), np.uint8)

                    points = np.array([[tbas1[0] - x1, tbas1[1] - y1],
                                       [tbas2[0] - x1, tbas2[1] - y1],
                                       [tbas3[0] - x1, tbas3[1] - y1]])

                    cv2.fillConvexPoly(cropped_tr1_mask, points, 255)
                    ttar1 = landmark_target_ocv[triangle_index[0]]
                    ttar2 = landmark_target_ocv[triangle_index[1]]
                    ttar3 = landmark_target_ocv[triangle_index[2]]

                    triangle2 = np.array([ttar1, ttar2, ttar3])

                    rect2 = cv2.boundingRect(triangle2)
                    (x2, y2, w2, h2) = rect2

                    cropped_tr2_mask = np.zeros((h2, w2), np.uint8)

                    points2 = np.array([[ttar1[0] - x2, ttar1[1] - y2],
                                        [ttar2[0] - x2, ttar2[1] - y2],
                                        [ttar3[0] - x2, ttar3[1] - y2]])

                    cv2.fillConvexPoly(cropped_tr2_mask, points2, 255)
                    # 三角形仿射变换
                    points = np.float32(points)
                    points2 = np.float32(points2)
                    M = cv2.getAffineTransform(points, points2)
                    warped_triangle = cv2.warpAffine(cropped_triangle, M, (w2, h2))
                    warped_triangle = cv2.bitwise_and(warped_triangle, warped_triangle, mask=cropped_tr2_mask)

                    # 重建目标人脸区域
                    img2_new_face_rect_area = img2_new_face[y2: y2 + h2, x2: x2 + w2]
                    img2_new_face_rect_area_gray = cv2.cvtColor(img2_new_face_rect_area, cv2.COLOR_BGR2GRAY)
                    _, mask_triangles_designed = cv2.threshold(img2_new_face_rect_area_gray, 0, 255,
                                                               cv2.THRESH_BINARY_INV)

                    warped_triangle = cv2.bitwise_and(warped_triangle, warped_triangle,
                                                      mask=mask_triangles_designed)


                    img2_new_face_rect_area = cv2.add(img2_new_face_rect_area, warped_triangle)
                    img2_new_face[y2: y2 + h2, x2: x2 + w2] = img2_new_face_rect_area

                    cv2.imshow('mask', img2_new_face)

        key = cv2.waitKey(5)

    face_mesh.close()
    cap.release()


def process_base_face_mesh(face_mesh,
                           image_file):
    base_face_handler = load_base_img(face_mesh, image_file)
    base_input_image = base_face_handler["img"].copy()
    image_rows, image_cols, _ = base_face_handler["img"].shape
    landmark_base_ocv = transform_landmarks_from_tf_to_ocv(base_face_handler["landmarks"], image_cols, image_rows)
    return base_face_handler, landmark_base_ocv, base_input_image


if __name__ == "__main__":
    main()
现存问题与诉求

之前尝试过用同图像的模糊版本生成掩码覆盖伪影区域,但该方案会导致像素值偏差,达不到输出像素值尽可能贴近真实图像的要求。
需要在保证像素精度的前提下,找到可彻底消除该类渲染伪影的可行方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 11:15:29