人脸迁移代码异常:图片人脸无法持续迁移至摄像头视频帧
人脸迁移仅显示一秒的问题解决方案
问题根源
- 代码仅在按下
i键的那一帧执行人脸迁移操作,后续视频帧直接跳过迁移逻辑,导致效果只持续一帧 - 循环内每次重置
image = None,选中的目标人脸图片无法被后续帧复用 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
相关产品推荐
相关产品推荐

