NeuralFalcon commited on
Commit
888242a
·
verified ·
1 Parent(s): 1593aa0

Create eye_lock.py

Browse files
Files changed (1) hide show
  1. eye_lock.py +170 -0
eye_lock.py ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import mediapipe as mp
3
+ import cv2
4
+ import numpy as np
5
+ import os
6
+ import shutil
7
+ import subprocess
8
+ import uuid
9
+
10
+
11
+
12
+ model_path = "./face_landmarker_v2_with_blendshapes.task"
13
+
14
+ BaseOptions = mp.tasks.BaseOptions
15
+ FaceLandmarker = mp.tasks.vision.FaceLandmarker
16
+ FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions
17
+ VisionRunningMode = mp.tasks.vision.RunningMode
18
+
19
+ options = FaceLandmarkerOptions(
20
+ base_options=BaseOptions(model_asset_path=model_path),
21
+ running_mode=VisionRunningMode.IMAGE,
22
+ num_faces=3
23
+ )
24
+ landmarker = FaceLandmarker.create_from_options(options)
25
+
26
+
27
+ def align_to_fixed_eyes(image, lm, ref_left_eye, ref_right_eye, canvas_size=1024):
28
+ """Align a face to fixed eye positions on a canvas."""
29
+ h, w, _ = image.shape
30
+
31
+ # Current eyes
32
+ left_eye = np.array([lm[468].x * w, lm[468].y * h])
33
+ right_eye = np.array([lm[473].x * w, lm[473].y * h])
34
+
35
+ # Compute rotation
36
+ dx = right_eye[0] - left_eye[0]
37
+ dy = right_eye[1] - left_eye[1]
38
+ angle = np.degrees(np.arctan2(dy, dx))
39
+
40
+ # Compute scale to match reference eye distance
41
+ eye_dist = np.linalg.norm(right_eye - left_eye)
42
+ ref_eye_dist = np.linalg.norm(np.array(ref_right_eye) - np.array(ref_left_eye))
43
+ scale = ref_eye_dist / eye_dist
44
+
45
+ # Midpoints
46
+ eye_center = (left_eye + right_eye) / 2
47
+ ref_center = (np.array(ref_left_eye) + np.array(ref_right_eye)) / 2
48
+
49
+ # Transformation: rotate + scale + translate
50
+ M = cv2.getRotationMatrix2D(tuple(eye_center), angle, scale)
51
+ M[0,2] += (ref_center[0] - eye_center[0])
52
+ M[1,2] += (ref_center[1] - eye_center[1])
53
+
54
+ # Optional: place on large canvas
55
+ offset_x = canvas_size//2 - int(ref_center[0])
56
+ offset_y = canvas_size//2 - int(ref_center[1])
57
+ M[0,2] += offset_x
58
+ M[1,2] += offset_y
59
+
60
+ aligned = cv2.warpAffine(image, M, (canvas_size, canvas_size), flags=cv2.INTER_CUBIC)
61
+ return aligned
62
+
63
+
64
+ def process_images_fixed_eyes(files, output_folder="./aligned_fixed_eyes", canvas_size=1024):
65
+ """Process a list of image files and align faces with fixed eyes."""
66
+ if os.path.exists(output_folder):
67
+ shutil.rmtree(output_folder)
68
+ os.makedirs(output_folder, exist_ok=True)
69
+
70
+ ref_left_eye, ref_right_eye = None, None
71
+
72
+ for idx, in_path in enumerate(files):
73
+ image = cv2.imread(in_path)
74
+ if image is None:
75
+ continue
76
+
77
+ mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=image)
78
+ result = landmarker.detect(mp_image)
79
+
80
+ # Skip if no face or multiple faces
81
+ if not result.face_landmarks:
82
+ continue
83
+ if len(result.face_landmarks) > 1:
84
+ continue
85
+
86
+ lm = result.face_landmarks[0]
87
+
88
+ # First frame: define reference eyes
89
+ if ref_left_eye is None or ref_right_eye is None:
90
+ h, w, _ = image.shape
91
+ ref_left_eye = (int(lm[468].x * w), int(lm[468].y * h))
92
+ ref_right_eye = (int(lm[473].x * w), int(lm[473].y * h))
93
+
94
+ aligned = align_to_fixed_eyes(image, lm, ref_left_eye, ref_right_eye, canvas_size)
95
+
96
+ out_path = os.path.join(output_folder, f"{idx:04d}.png")
97
+ cv2.imwrite(out_path, aligned)
98
+
99
+ import os
100
+ import uuid
101
+ import subprocess
102
+
103
+ def create_timelapse(input_folder="./aligned_fixed_eyes", output_folder="./download", fps_in=10, fps_out=30):
104
+ """
105
+ Create a timelapse video using FFmpeg and a file list (handles missing numbers)
106
+ Output is hidden unless FFmpeg fails.
107
+ """
108
+ os.makedirs(output_folder, exist_ok=True)
109
+
110
+ # Get all image files sorted
111
+ images = sorted([
112
+ f for f in os.listdir(input_folder)
113
+ if f.lower().endswith((".png", ".jpg", ".jpeg"))
114
+ ])
115
+
116
+ if not images:
117
+ print("No images found in folder:", input_folder)
118
+ return None
119
+
120
+ # Create temporary file list for FFmpeg
121
+ file_list_path = "./file_list.txt"
122
+ with open(file_list_path, "w") as f:
123
+ for img in images:
124
+ f.write(f"file '{os.path.join(input_folder, img)}'\n")
125
+
126
+ random_str = str(uuid.uuid4())[:6]
127
+ output_path = os.path.join(output_folder, f"{random_str}.mp4")
128
+
129
+ # FFmpeg command using file list
130
+ command = [
131
+ "ffmpeg",
132
+ "-y",
133
+ "-r", str(fps_in), # input frame rate
134
+ "-f", "concat",
135
+ "-safe", "0",
136
+ "-i", file_list_path,
137
+ "-c:v", "libx264",
138
+ "-r", str(fps_out), # output frame rate
139
+ "-pix_fmt", "yuv420p",
140
+ output_path
141
+ ]
142
+
143
+ # Run FFmpeg, hide output
144
+ result = subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
145
+ os.remove(file_list_path) # clean up
146
+
147
+ if result.returncode == 0:
148
+ return output_path
149
+ else:
150
+ print("FFmpeg failed. Command was:")
151
+ print(" ".join(command))
152
+ return None
153
+
154
+
155
+ def EyeLock_Timelapse(selfies_folder, aligned_folder="./aligned_fixed_eyes", output_folder="./download",image_duraion=0.1):
156
+ """Wrapper: process selfies from a folder and create a timelapse."""
157
+ files = sorted([
158
+ os.path.join(selfies_folder, f)
159
+ for f in os.listdir(selfies_folder)
160
+ if f.lower().endswith((".jpg", ".png", ".jpeg"))
161
+ ])
162
+ process_images_fixed_eyes(files, aligned_folder, canvas_size=1024)
163
+ output_video = create_timelapse(aligned_folder, output_folder,fps_in=image_duraion*100)
164
+ print("Final video:", output_video)
165
+ return output_video
166
+
167
+
168
+ # if __name__ == "__main__":
169
+ # timelapse_video = EyeLock_Timelapse("./selfies")
170
+ # print("Timelapse video saved at:", timelapse_video)