thng292 commited on
Commit
34f7d44
·
verified ·
1 Parent(s): 902b033

Upload selfie_filter.py

Browse files
Files changed (1) hide show
  1. selfie_filter.py +152 -0
selfie_filter.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ import cv2
4
+ import landmark_detection
5
+ import gradio as gr
6
+ from mtcnn_facedetection import detect_faces
7
+
8
+
9
+ def apply_sunglasses(image, landmarks, sunglasses_img):
10
+ # If image loading fails or no landmarks, return original image
11
+ if sunglasses_img is None or not landmarks:
12
+ return image
13
+
14
+ # Create a copy of the image to overlay on
15
+ result = image.copy()
16
+
17
+ # Process each face
18
+ for face_landmarks in landmarks:
19
+ # We need at least the eye landmarks
20
+ if len(face_landmarks) < 5:
21
+ continue
22
+
23
+ # Get eye landmarks
24
+ left_eye_center = np.mean(face_landmarks[36:42], axis=0).astype(int)
25
+ right_eye_center = np.mean(face_landmarks[42:48], axis=0).astype(int)
26
+
27
+ # Calculate eye distance and angle
28
+ eye_distance = np.linalg.norm(right_eye_center - left_eye_center)
29
+ # Negate the angle to correct rotation direction
30
+ angle = -np.degrees(
31
+ np.arctan2(
32
+ right_eye_center[1] - left_eye_center[1],
33
+ right_eye_center[0] - left_eye_center[0],
34
+ )
35
+ )
36
+
37
+ # Size for sunglasses based on eye distance
38
+ width = int(eye_distance * 2.5)
39
+ height = int(width * sunglasses_img.shape[0] / sunglasses_img.shape[1])
40
+
41
+ # Resize sunglasses
42
+ sunglasses_resized = cv2.resize(sunglasses_img, (width, height))
43
+
44
+ # Rotate the sunglasses image
45
+ center = (width // 2, height // 2)
46
+ rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
47
+
48
+ # Calculate new dimensions after rotation
49
+ cos = np.abs(rotation_matrix[0, 0])
50
+ sin = np.abs(rotation_matrix[0, 1])
51
+ new_width = int((height * sin) + (width * cos))
52
+ new_height = int((height * cos) + (width * sin))
53
+
54
+ # Adjust rotation matrix
55
+ rotation_matrix[0, 2] += (new_width / 2) - center[0]
56
+ rotation_matrix[1, 2] += (new_height / 2) - center[1]
57
+
58
+ # Perform the rotation
59
+ rotated_glasses = cv2.warpAffine(
60
+ sunglasses_resized,
61
+ rotation_matrix,
62
+ (new_width, new_height),
63
+ flags=cv2.INTER_LINEAR,
64
+ borderMode=cv2.BORDER_CONSTANT,
65
+ borderValue=(0, 0, 0, 0),
66
+ )
67
+
68
+ # Position the sunglasses
69
+ eye_center = ((left_eye_center + right_eye_center) // 2).astype(int)
70
+ x = eye_center[0] - new_width // 2
71
+ y = eye_center[1] - new_height // 2
72
+
73
+ # Create ROI for overlay
74
+ y1, y2 = max(0, y), min(result.shape[0], y + new_height)
75
+ x1, x2 = max(0, x), min(result.shape[1], x + new_width)
76
+
77
+ # ROI in the glasses image
78
+ g_y1, g_y2 = max(0, -y), max(0, -y) + (y2 - y1)
79
+ g_x1, g_x2 = max(0, -x), max(0, -x) + (x2 - x1)
80
+
81
+ # Check if we have valid regions
82
+ if g_y2 <= rotated_glasses.shape[0] and g_x2 <= rotated_glasses.shape[1]:
83
+ roi = result[y1:y2, x1:x2]
84
+ glasses_roi = rotated_glasses[g_y1:g_y2, g_x1:g_x2]
85
+
86
+ # Apply alpha blending
87
+ if glasses_roi.shape[2] == 4 and roi.shape[:2] == glasses_roi.shape[:2]:
88
+ alpha = glasses_roi[:, :, 3] / 255.0
89
+ for c in range(3):
90
+ roi[:, :, c] = (
91
+ glasses_roi[:, :, c] * alpha + roi[:, :, c] * (1 - alpha)
92
+ ).astype(np.uint8)
93
+ result[y1:y2, x1:x2] = roi
94
+
95
+ return result
96
+
97
+
98
+ def do_facial_landmark_recognition(
99
+ image: np.ndarray, face_boxes: list[landmark_detection.BoundingBox]
100
+ ):
101
+ faces = landmark_detection.get_faces(image, face_boxes)
102
+ landmarks_batch = landmark_detection.get_landmarks(faces)
103
+ return landmarks_batch
104
+
105
+
106
+ def do_facial_landmark_recognition_with_mtcnn(image: np.ndarray, sunglasses_img):
107
+ face_boxes = detect_faces(image)
108
+ landmarks_batch = do_facial_landmark_recognition(image, face_boxes)
109
+ return apply_sunglasses(image, landmarks_batch, sunglasses_img)
110
+
111
+
112
+ def process_video(input_path, sunglasses_img):
113
+ output_path = os.path.join(
114
+ os.path.dirname(input_path), "output_" + os.path.basename(input_path)
115
+ )
116
+ # Open the input video
117
+ cap = cv2.VideoCapture(input_path)
118
+ if not cap.isOpened():
119
+ gr.Error(f"Error opening input video file: {input_path}")
120
+ return
121
+
122
+ # Get video properties
123
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
124
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
125
+ fps = cap.get(cv2.CAP_PROP_FPS)
126
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
127
+
128
+ # Create VideoWriter object
129
+ fourcc = cv2.VideoWriter_fourcc(*"mp4v")
130
+ out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
131
+
132
+ frame_count = 0
133
+
134
+ # Process each frame
135
+ while cap.isOpened():
136
+ ret, frame = cap.read()
137
+ if not ret:
138
+ break
139
+
140
+ # Process the frame
141
+ processed_frame = do_facial_landmark_recognition_with_mtcnn(
142
+ frame, sunglasses_img
143
+ )
144
+
145
+ # Write the frame
146
+ out.write(processed_frame)
147
+
148
+ # Release resources
149
+ cap.release()
150
+ out.release()
151
+ gr.Info(f"Video processing complete. Output saved to: {output_path}")
152
+ return output_path