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

人脸迁移代码异常:图片人脸无法持续迁移至摄像头视频帧

人脸迁移仅显示一秒的问题解决方案

问题根源

  1. 代码仅在按下i键的那一帧执行人脸迁移操作,后续视频帧直接跳过迁移逻辑,导致效果只持续一帧
  2. 循环内每次重置image = None,选中的目标人脸图片无法被后续帧复用
  3. transfer_face函数中,备份的prev_face_img未正确保存适配当前视频帧尺寸的人脸图像,且后续帧未触发备份逻辑执行

修复后的完整代码

import cv2
import dlib
import numpy as np
import tkinter as tk
from tkinter import filedialog

# 加载人脸关键点检测模型
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

# 检测并标记图像上的人脸关键点
def highlightFaceOnImage(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    faces = dlib.get_frontal_face_detector()(gray, 0)
    
    for face in faces:
        landmarks = predictor(gray, face)
        for i in range(68):
            cv2.circle(image, (landmarks.part(i).x, landmarks.part(i).y), 2, (0, 0, 255), -1)
    return image

# 人脸迁移核心函数
def transfer_face(frame, image, prev_face_img=None, prev_face_roi=None):
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    frame_faces = dlib.get_frontal_face_detector()(frame_gray, 0)
    image_faces = dlib.get_frontal_face_detector()(image_gray, 0)

    current_face_img = prev_face_img
    current_roi = prev_face_roi

    if len(frame_faces) > 0 and len(image_faces) > 0:
        frame_landmarks = predictor(frame_gray, frame_faces[0])
        image_landmarks = predictor(image_gray, image_faces[0])

        # 获取视频帧中人脸的边界
        frame_x1 = min([p.x for p in frame_landmarks.parts()])
        frame_y1 = min([p.y for p in frame_landmarks.parts()])
        frame_x2 = max([p.x for p in frame_landmarks.parts()])
        frame_y2 = max([p.y for p in frame_landmarks.parts()])

        # 获取目标图片中人脸的边界
        image_x1 = min([p.x for p in image_landmarks.parts()])
        image_y1 = min([p.y for p in image_landmarks.parts()])
        image_x2 = max([p.x for p in image_landmarks.parts()])
        image_y2 = max([p.y for p in image_landmarks.parts()])

        # 裁剪并缩放目标人脸到视频帧人脸尺寸
        face_img = image[image_y1:image_y2, image_x1:image_x2]
        face_img = cv2.resize(face_img, (frame_x2 - frame_x1, frame_y2 - frame_y1))

        # 融合人脸到视频帧
        alpha = 0.7
        roi = frame[frame_y1:frame_y2, frame_x1:frame_x2]
        blended_face = cv2.addWeighted(roi, 1 - alpha, face_img, alpha, 0)
        frame[frame_y1:frame_y2, frame_x1:frame_x2] = blended_face

        current_face_img = blended_face
        current_roi = (frame_x1, frame_y1, frame_x2 - frame_x1, frame_y2 - frame_y1)
    elif prev_face_img is not None and prev_face_roi is not None:
        # 人脸丢失时复用上一帧的迁移结果
        x, y, w, h = prev_face_roi
        frame[y:y+h, x:x+w] = prev_face_img

    return frame, current_face_img, current_roi

# 选择目标人脸图片
def select_image():
    root = tk.Tk()
    root.withdraw()
    try:
        file_path = filedialog.askopenfilename()
        if file_path:
            image = cv2.imread(file_path)
            image_with_landmarks = highlightFaceOnImage(image)
            cv2.imshow("Detected Face Landmarks", image_with_landmarks)
            return image
    finally:
        root.destroy()

# 主程序逻辑
video = cv2.VideoCapture(0)

selected_image = None  # 持久化存储选中的图片
prev_face_img = None
prev_face_roi = None

while True:
    hasFrame, frame = video.read()
    if not hasFrame:
        break

    # 处理按键输入
    key = cv2.waitKey(1) & 0xFF
    if key == ord("i"):
        selected_image = select_image()
    elif key == ord("q"):
        break

    # 每帧都执行人脸迁移(如果已选中图片)
    if selected_image is not None:
        frame, prev_face_img, prev_face_roi = transfer_face(frame, selected_image, prev_face_img, prev_face_roi)

    cv2.imshow("Face Transfer", frame)

video.release()
cv2.destroyAllWindows()

关键修改说明

  • 将selected_image设为全局持久变量,避免每次循环重置
  • 把人脸迁移逻辑移到主循环的每帧处理中,而非仅按键时执行
  • 修正transfer_face函数中current_face_img的赋值逻辑,保存融合后的人脸图像而非原始裁剪图
  • 添加q键退出功能,优化程序交互
  • 调整融合透明度alpha为0.7,提升迁移效果的自然度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 23:05:55