EyeLock-Timelapse / eye_lock.py
NeuralFalcon's picture
Create eye_lock.py
888242a verified
import mediapipe as mp
import cv2
import numpy as np
import os
import shutil
import subprocess
import uuid
model_path = "./face_landmarker_v2_with_blendshapes.task"
BaseOptions = mp.tasks.BaseOptions
FaceLandmarker = mp.tasks.vision.FaceLandmarker
FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions
VisionRunningMode = mp.tasks.vision.RunningMode
options = FaceLandmarkerOptions(
base_options=BaseOptions(model_asset_path=model_path),
running_mode=VisionRunningMode.IMAGE,
num_faces=3
)
landmarker = FaceLandmarker.create_from_options(options)
def align_to_fixed_eyes(image, lm, ref_left_eye, ref_right_eye, canvas_size=1024):
"""Align a face to fixed eye positions on a canvas."""
h, w, _ = image.shape
# Current eyes
left_eye = np.array([lm[468].x * w, lm[468].y * h])
right_eye = np.array([lm[473].x * w, lm[473].y * h])
# Compute rotation
dx = right_eye[0] - left_eye[0]
dy = right_eye[1] - left_eye[1]
angle = np.degrees(np.arctan2(dy, dx))
# Compute scale to match reference eye distance
eye_dist = np.linalg.norm(right_eye - left_eye)
ref_eye_dist = np.linalg.norm(np.array(ref_right_eye) - np.array(ref_left_eye))
scale = ref_eye_dist / eye_dist
# Midpoints
eye_center = (left_eye + right_eye) / 2
ref_center = (np.array(ref_left_eye) + np.array(ref_right_eye)) / 2
# Transformation: rotate + scale + translate
M = cv2.getRotationMatrix2D(tuple(eye_center), angle, scale)
M[0,2] += (ref_center[0] - eye_center[0])
M[1,2] += (ref_center[1] - eye_center[1])
# Optional: place on large canvas
offset_x = canvas_size//2 - int(ref_center[0])
offset_y = canvas_size//2 - int(ref_center[1])
M[0,2] += offset_x
M[1,2] += offset_y
aligned = cv2.warpAffine(image, M, (canvas_size, canvas_size), flags=cv2.INTER_CUBIC)
return aligned
def process_images_fixed_eyes(files, output_folder="./aligned_fixed_eyes", canvas_size=1024):
"""Process a list of image files and align faces with fixed eyes."""
if os.path.exists(output_folder):
shutil.rmtree(output_folder)
os.makedirs(output_folder, exist_ok=True)
ref_left_eye, ref_right_eye = None, None
for idx, in_path in enumerate(files):
image = cv2.imread(in_path)
if image is None:
continue
mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=image)
result = landmarker.detect(mp_image)
# Skip if no face or multiple faces
if not result.face_landmarks:
continue
if len(result.face_landmarks) > 1:
continue
lm = result.face_landmarks[0]
# First frame: define reference eyes
if ref_left_eye is None or ref_right_eye is None:
h, w, _ = image.shape
ref_left_eye = (int(lm[468].x * w), int(lm[468].y * h))
ref_right_eye = (int(lm[473].x * w), int(lm[473].y * h))
aligned = align_to_fixed_eyes(image, lm, ref_left_eye, ref_right_eye, canvas_size)
out_path = os.path.join(output_folder, f"{idx:04d}.png")
cv2.imwrite(out_path, aligned)
import os
import uuid
import subprocess
def create_timelapse(input_folder="./aligned_fixed_eyes", output_folder="./download", fps_in=10, fps_out=30):
"""
Create a timelapse video using FFmpeg and a file list (handles missing numbers)
Output is hidden unless FFmpeg fails.
"""
os.makedirs(output_folder, exist_ok=True)
# Get all image files sorted
images = sorted([
f for f in os.listdir(input_folder)
if f.lower().endswith((".png", ".jpg", ".jpeg"))
])
if not images:
print("No images found in folder:", input_folder)
return None
# Create temporary file list for FFmpeg
file_list_path = "./file_list.txt"
with open(file_list_path, "w") as f:
for img in images:
f.write(f"file '{os.path.join(input_folder, img)}'\n")
random_str = str(uuid.uuid4())[:6]
output_path = os.path.join(output_folder, f"{random_str}.mp4")
# FFmpeg command using file list
command = [
"ffmpeg",
"-y",
"-r", str(fps_in), # input frame rate
"-f", "concat",
"-safe", "0",
"-i", file_list_path,
"-c:v", "libx264",
"-r", str(fps_out), # output frame rate
"-pix_fmt", "yuv420p",
output_path
]
# Run FFmpeg, hide output
result = subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
os.remove(file_list_path) # clean up
if result.returncode == 0:
return output_path
else:
print("FFmpeg failed. Command was:")
print(" ".join(command))
return None
def EyeLock_Timelapse(selfies_folder, aligned_folder="./aligned_fixed_eyes", output_folder="./download",image_duraion=0.1):
"""Wrapper: process selfies from a folder and create a timelapse."""
files = sorted([
os.path.join(selfies_folder, f)
for f in os.listdir(selfies_folder)
if f.lower().endswith((".jpg", ".png", ".jpeg"))
])
process_images_fixed_eyes(files, aligned_folder, canvas_size=1024)
output_video = create_timelapse(aligned_folder, output_folder,fps_in=image_duraion*100)
print("Final video:", output_video)
return output_video
# if __name__ == "__main__":
# timelapse_video = EyeLock_Timelapse("./selfies")
# print("Timelapse video saved at:", timelapse_video)