File size: 5,497 Bytes
888242a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

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)