Перенос лица с изображения на лицо в видео с камеры
Когда я запускаю код и выбираю изображение, лицо переносится с изображения только на секунду, а затем рамка остается такой же, как и при запуске кода.
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):
# Конвертируем изображение в оттенки серого для dlib
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Обнаруживаем лица на изображении
faces = dlib.get_frontal_face_detector()(gray, 0)
# Перебираем все обнаруженные лица
for face in faces:
# Получаем ключевые точки на лице
landmarks = predictor(gray, face)
# Получаем координаты ключевых точек
x1 = min([landmarks.part(i).x for i in range(68)])
y1 = min([landmarks.part(i).y for i in range(68)])
x2 = max([landmarks.part(i).x for i in range(68)])
y2 = max([landmarks.part(i).y for i in range(68)])
# Отрисовываем ключевые точки на изображении
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):
# Конвертируем кадр и изображение в оттенки серого для dlib
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)
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([frame_landmarks.part(i).x for i in range(68)])
frame_y1 = min([frame_landmarks.part(i).y for i in range(68)])
frame_x2 = max([frame_landmarks.part(i).x for i in range(68)])
frame_y2 = max([frame_landmarks.part(i).y for i in range(68)])
image_x1 = min([image_landmarks.part(i).x for i in range(68)])
image_y1 = min([image_landmarks.part(i).y for i in range(68)])
image_x2 = max([image_landmarks.part(i).x for i in range(68)])
image_y2 = max([image_landmarks.part(i).y for i in range(68)])
# Вырезаем область лица из изображения
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.5
roi = frame[frame_y1:frame_y2, frame_x1:frame_x2]
roi_bg = cv2.addWeighted(roi, 1 - alpha, np.zeros_like(roi), 0, 0)
roi_fg = cv2.addWeighted(face_img, alpha, np.zeros_like(face_img), 0, 0)
frame[frame_y1:frame_y2, frame_x1:frame_x2] = cv2.add(roi_bg, roi_fg)
elif prev_face_img is not None and prev_face_roi is not None:
# Если лицо не обнаружено, но есть предыдущий фрейм с перенесенным лицом, используем его
frame[prev_face_roi[1]:prev_face_roi[1]+prev_face_roi[3], prev_face_roi[0]:prev_face_roi[0]+prev_face_roi[2]] = prev_face_img
return frame, face_img, prev_face_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("Detecting faces on image", image_with_landmarks)
return image
finally:
root.destroy()
# Запускаем камеру
video = cv2.VideoCapture(0)
prev_face_img = None
prev_face_roi = None
frame_x1 = frame_y1 = frame_x2 = frame_y2 = 0
while True:
hasFrame, frame = video.read()
if not hasFrame:
cv2.waitKey()
break
# Обнаруживаем лица в кадре и рисуем ключевые точки
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame_faces = dlib.get_frontal_face_detector()(frame_gray, 0)
if len(frame_faces) > 0:
frame_landmarks = predictor(frame_gray, frame_faces[0])
frame_pts = np.array([[p.x, p.y] for p in frame_landmarks.parts()], dtype=np.float32)
for x, y in frame_pts.astype(int):
cv2.circle(frame, (x, y), 2, (0, 0, 255), -1)
frame_x1 = min([frame_landmarks.part(i).x for i in range(68)])
frame_y1 = min([frame_landmarks.part(i).y for i in range(68)])
frame_x2 = max([frame_landmarks.part(i).x for i in range(68)])
frame_y2 = max([frame_landmarks.part(i).y for i in range(68)])
prev_face_roi = (frame_x1, frame_y1, frame_x2 - frame_x1, frame_y2 - frame_y1)
# Выбираем изображение
image = None
key = cv2.waitKey(1) & 0xFF
if key == ord("i"):
image = select_image()
if image is not None:
# Переносим лицо с изображения на кадр
frame, prev_face_img, prev_face_roi = transfer_face(frame, image, prev_face_img, prev_face_roi)
# Выводим итоговую картинку
cv2.imshow("Face Transfer", frame)
Я попробовал использовать аффинное преобразование и триангуляцию Делоне для переноса лица с изображения на видео, но это не сработало. Также я попробовал оптимизировать код, но это тоже не сработало.