-
Notifications
You must be signed in to change notification settings - Fork 0
/
swap.py
115 lines (89 loc) · 4.01 KB
/
swap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import sys
import os
import cv2
import dlib
import numpy as np
import pyvirtualcam
from pyvirtualcam import PixelFormat
# Initialize dlib face detector and predictor
if getattr(sys, 'frozen', False):
LOL_FILE = os.path.join(sys._MEIPASS, 'shape_predictor_68_face_landmarks.dat')
else:
LOL_FILE = 'shape_predictor_68_face_landmarks.dat'
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(LOL_FILE)
def overlay_face(background_frame, face_frame):
gray_background = cv2.cvtColor(background_frame, cv2.COLOR_BGR2GRAY)
gray_face = cv2.cvtColor(face_frame, cv2.COLOR_BGR2GRAY)
faces_background = detector(gray_background)
faces_face = detector(gray_face)
if len(faces_background) == 0 or len(faces_face) == 0:
return background_frame
shape_background = predictor(gray_background, faces_background[0])
shape_face = predictor(gray_face, faces_face[0])
points_background = np.array([[p.x, p.y] for p in shape_background.parts()], np.int32)
points_face = np.array([[p.x, p.y] for p in shape_face.parts()], np.int32)
hull_background = cv2.convexHull(points_background)
hull_face = cv2.convexHull(points_face)
mask_background = np.zeros_like(background_frame, dtype=np.uint8)
cv2.fillConvexPoly(mask_background, hull_background, (255, 255, 255))
rect_background = cv2.boundingRect(hull_background)
rect_face = cv2.boundingRect(hull_face)
rect_face = (
max(0, rect_face[0]),
max(0, rect_face[1]),
min(rect_face[2], face_frame.shape[1] - rect_face[0]),
min(rect_face[3], face_frame.shape[0] - rect_face[1])
)
rect_background = (
max(0, rect_background[0]),
max(0, rect_background[1]),
min(rect_background[2], background_frame.shape[1] - rect_background[0]),
min(rect_background[3], background_frame.shape[0] - rect_background[1])
)
center = (rect_background[0] + rect_background[2] // 2, rect_background[1] + rect_background[3] // 2)
x1, y1, w1, h1 = rect_background
x2, y2, w2, h2 = rect_face
if x2 < 0 or y2 < 0 or x2 + w2 > face_frame.shape[1] or y2 + h2 > face_frame.shape[0]:
return background_frame
face_region = face_frame[y2:y2+h2, x2:x2+w2]
face_region_resized = cv2.resize(face_region, (w1, h1))
if center[0] < 0 or center[1] < 0 or center[0] >= background_frame.shape[1] or center[1] >= background_frame.shape[0]:
return background_frame
mask_face = np.zeros((h1, w1, 3), dtype=np.uint8)
cv2.fillConvexPoly(mask_face, hull_face - np.array([x2, y2]), (255, 255, 255))
alpha = 0.5
blended_face_region = cv2.addWeighted(face_region_resized, alpha, background_frame[y1:y1+h1, x1:x1+w1], 1 - alpha, 0)
background_frame[y1:y1+h1, x1:x1+w1] = blended_face_region
seamless_clone = cv2.seamlessClone(
blended_face_region, background_frame, mask_face[:, :, 0], center, cv2.NORMAL_CLONE
)
return seamless_clone
def main():
cap = cv2.VideoCapture(3)
cap2 = cv2.VideoCapture(0)
if not cap.isOpened() or not cap2.isOpened():
raise RuntimeError('Could not open video sources')
pref_width = 1280
pref_height = 720
pref_fps_in = 60
cap.set(cv2.CAP_PROP_FRAME_WIDTH, pref_width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, pref_height)
cap.set(cv2.CAP_PROP_FPS, pref_fps_in)
cap2.set(cv2.CAP_PROP_FRAME_WIDTH, pref_width)
cap2.set(cv2.CAP_PROP_FRAME_HEIGHT, pref_height)
cap2.set(cv2.CAP_PROP_FPS, pref_fps_in)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = 60
with pyvirtualcam.Camera(width, height, fps, fmt=PixelFormat.BGR, device="Unity Video Capture") as cam:
while True:
ret1, face_frame = cap.read()
ret2, background_frame = cap2.read()
if not ret1 or not ret2:
break
frame = overlay_face(background_frame, face_frame)
cam.send(frame)
cam.sleep_until_next_frame()
if __name__ == "__main__":
main()