Spaces:
Running on Zero
Running on Zero
| import io | |
| import urllib.request | |
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| from config import ( | |
| MAX_DIM, MIN_DIM, SQUARE_DIM, MULTIPLE_OF, | |
| FIXED_FPS, MIN_FRAMES_MODEL, MAX_FRAMES_MODEL | |
| ) | |
| def load_image_from_url(url: str) -> Image.Image: | |
| if not url or not str(url).strip(): | |
| raise ValueError("Masukkan URL gambar terlebih dahulu.") | |
| url = str(url).strip() | |
| headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"} | |
| req = urllib.request.Request(url, headers=headers) | |
| with urllib.request.urlopen(req, timeout=15) as resp: | |
| img_bytes = resp.read() | |
| img = Image.open(io.BytesIO(img_bytes)) | |
| return img.convert("RGB") | |
| get_timestamp_js = """ | |
| function(video, timestamp) { | |
| const videoElem = document.querySelector('#generated-video video'); | |
| let currentTime = 0; | |
| if (videoElem) { | |
| currentTime = videoElem.currentTime; | |
| console.log("Video found! Time: " + currentTime); | |
| } else { | |
| console.log("No video element found."); | |
| } | |
| return [video, currentTime]; | |
| } | |
| """ | |
| def extract_frame(video_path, timestamp): | |
| if not video_path: | |
| return None, 0 | |
| print(f"Extracting frame at timestamp: {timestamp}") | |
| cap = cv2.VideoCapture(video_path) | |
| if not cap.isOpened(): | |
| return None, timestamp | |
| fps = cap.get(cv2.CAP_PROP_FPS) | |
| if fps <= 0: | |
| fps = 16.0 | |
| target_frame_num = int(float(timestamp) * fps) | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| if total_frames > 0 and target_frame_num >= total_frames: | |
| target_frame_num = total_frames - 1 | |
| cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame_num) | |
| ret, frame = cap.read() | |
| cap.release() | |
| if ret: | |
| return cv2.cvtColor(frame, cv2.COLOR_BGR2RGB), timestamp | |
| return None, timestamp | |
| def resize_image(image: Image.Image) -> Image.Image: | |
| width, height = image.size | |
| if width == height: | |
| return image.resize((SQUARE_DIM, SQUARE_DIM), Image.LANCZOS) | |
| aspect_ratio = width / height | |
| MAX_ASPECT_RATIO = MAX_DIM / MIN_DIM | |
| MIN_ASPECT_RATIO = MIN_DIM / MAX_DIM | |
| image_to_resize = image | |
| if aspect_ratio > MAX_ASPECT_RATIO: | |
| target_w, target_h = MAX_DIM, MIN_DIM | |
| crop_width = int(round(height * MAX_ASPECT_RATIO)) | |
| left = (width - crop_width) // 2 | |
| image_to_resize = image.crop((left, 0, left + crop_width, height)) | |
| elif aspect_ratio < MIN_ASPECT_RATIO: | |
| target_w, target_h = MIN_DIM, MAX_DIM | |
| crop_height = int(round(width / MIN_ASPECT_RATIO)) | |
| top = (height - crop_height) // 2 | |
| image_to_resize = image.crop((0, top, width, top + crop_height)) | |
| else: | |
| if width > height: | |
| target_w = MAX_DIM | |
| target_h = int(round(target_w / aspect_ratio)) | |
| else: | |
| target_h = MAX_DIM | |
| target_w = int(round(target_h * aspect_ratio)) | |
| final_w = round(target_w / MULTIPLE_OF) * MULTIPLE_OF | |
| final_h = round(target_h / MULTIPLE_OF) * MULTIPLE_OF | |
| final_w = max(MIN_DIM, min(MAX_DIM, final_w)) | |
| final_h = max(MIN_DIM, min(MAX_DIM, final_h)) | |
| return image_to_resize.resize((final_w, final_h), Image.LANCZOS) | |
| def resize_and_crop_to_match(target_image, reference_image): | |
| ref_width, ref_height = reference_image.size | |
| target_width, target_height = target_image.size | |
| scale = max(ref_width / target_width, ref_height / target_height) | |
| new_width, new_height = int(target_width * scale), int(target_height * scale) | |
| resized = target_image.resize((new_width, new_height), Image.Resampling.LANCZOS) | |
| left, top = (new_width - ref_width) // 2, (new_height - ref_height) // 2 | |
| return resized.crop((left, top, left + ref_width, top + ref_height)) | |
| def get_num_frames(duration_seconds: float): | |
| raw = int(round(duration_seconds * FIXED_FPS)) | |
| raw = max(MIN_FRAMES_MODEL, min(MAX_FRAMES_MODEL, raw)) | |
| return ((raw - 1) // 4) * 4 + 1 | |