Spaces:
Running on Zero
Running on Zero
Download hyvideo/utils/multitask_utils.py from hugging-apps/vitronedit: direct link, hf CLI and curl.
- Browser
- Download file 5.11 kB
-
https://huggingface.co/spaces/hugging-apps/vitronedit/resolve/main/hyvideo/utils/multitask_utils.py
- Command line
-
hf download hf://spaces/hugging-apps/vitronedit/hyvideo/utils/multitask_utils.py
-
curl -L -o multitask_utils.py https://huggingface.co/spaces/hugging-apps/vitronedit/resolve/main/hyvideo/utils/multitask_utils.py
5.11 kB
| # Modified by the UniVEdit authors from Tencent-Hunyuan/OmniWeaving (HunyuanVideo-1.5). | |
| import torch | |
| import torchvision.transforms as transforms | |
| import numpy as np | |
| from PIL import Image | |
| from decord import VideoReader | |
| def prepare_custom_video(vr, total_subset=161, nframes=8): | |
| if isinstance(vr, str): | |
| vr = VideoReader(vr) | |
| max_frames = min(len(vr), total_subset) | |
| sample_indices = np.linspace(0, max_frames - 1, nframes).astype(int) | |
| frames = vr.get_batch(sample_indices) | |
| if hasattr(frames, 'asnumpy'): | |
| frames = frames.asnumpy() # decord NDArray | |
| else: | |
| frames = frames.numpy() # PyTorch Tensor | |
| frame_list = [Image.fromarray(frame) for frame in frames] | |
| return frame_list | |
| def get_semantic_images_np(video_path_list, nframes=8): | |
| """ | |
| Extract first frame from each video in video_path_list and return batchified numpy array. | |
| Args: | |
| video_path_list: List of video paths | |
| Returns: | |
| first_images_np: numpy array of shape (B, H, W, C) with dtype uint8 (0-255) | |
| Returns None if video_path_list is None or empty | |
| """ | |
| if video_path_list is None or len(video_path_list) == 0: | |
| return None | |
| first_frames = [] | |
| sampled_frames = [] | |
| for video_path in video_path_list: | |
| # Read first frame from video | |
| if isinstance(video_path, str): | |
| video_reader = VideoReader(video_path) | |
| else: | |
| assert isinstance(video_path, VideoReader), f"video_path must be either str or VideoReader, got {type(video_path)}" | |
| video_reader = video_path | |
| if len(video_reader) == 0: | |
| raise ValueError(f"Video {video_path} has no frames") | |
| sample_frame_list = prepare_custom_video(video_reader, nframes=nframes) | |
| sampled_frames.append(sample_frame_list) | |
| # Get first frame (index 0) | |
| first_frame = video_reader.get_batch([0]) | |
| # Convert to numpy: shape is (1, H, W, C) | |
| if hasattr(first_frame, 'asnumpy'): | |
| first_frame_np = first_frame.asnumpy() # decord NDArray | |
| else: | |
| first_frame_np = first_frame.numpy() # PyTorch Tensor | |
| # Remove batch dimension: shape becomes (H, W, C) | |
| first_frame_np = first_frame_np[0] | |
| first_frames.append(first_frame_np) | |
| del video_reader | |
| # Stack all first frames into batch: shape becomes (B, H, W, C) | |
| first_images_np = np.stack(first_frames, axis=0) | |
| # Ensure uint8 format (0-255) | |
| first_images_np = first_images_np.astype(np.uint8) | |
| return first_images_np, sampled_frames | |
| def get_semantic_images_np2(video_path_list, first_image_pil, vae, F, nframes=8, is_mode=True): | |
| """ | |
| Extract first frame from each video in video_path_list and return batchified numpy array. | |
| Also encode first_image_pil list into cond_latents with values filled at F index=1. | |
| Args: | |
| video_path_list: List of video paths or VideoReader objects | |
| first_image_pil: List of PIL.Image.Image | |
| args: Arguments object containing vae_precision | |
| vae: VAE model | |
| F: Time dimension for cond_latents (must be >= 2) | |
| nframes: Number of frames to sample for each video (default: 8) | |
| is_mode: If True, use mode() for latent distribution, else use sample() | |
| Returns: | |
| first_images_np: numpy array of shape (B, H, W, C) with dtype uint8 (0-255) | |
| sampled_frames: list of sampled frame lists per video | |
| cond_latents: tensor of shape (B, C, F, H, W), values at index=1, others 0 | |
| first_image_pil_np: numpy array of shape (B, H, W, C) with dtype uint8 (0-255) | |
| """ | |
| first_images_np, sampled_frames = get_semantic_images_np(video_path_list, nframes=nframes) | |
| if first_image_pil is None or len(first_image_pil) == 0: | |
| raise ValueError("first_image_pil must be a non-empty list of PIL images") | |
| if F < 2: | |
| raise ValueError(f"F must be >= 2 to fill index=1, got {F}") | |
| first_image_pil_np = np.array([np.array(img, dtype=np.uint8) for img in first_image_pil]) | |
| image_transform = transforms.Compose([ | |
| transforms.ToTensor(), | |
| transforms.Normalize([0.5], [0.5]) | |
| ]) | |
| first_images_pixel_values = [image_transform(image).unsqueeze(0) for image in first_image_pil] | |
| first_images_pixel_values = torch.cat(first_images_pixel_values).unsqueeze(2).to(vae.device) | |
| with torch.autocast(device_type="cuda", dtype=torch.float16, enabled=True): | |
| if is_mode: | |
| encoded_latents = vae.encode(first_images_pixel_values).latent_dist.mode() | |
| else: | |
| encoded_latents = vae.encode(first_images_pixel_values).latent_dist.sample() | |
| encoded_latents.mul_(vae.config.scaling_factor) | |
| B = encoded_latents.shape[0] | |
| C, H, W = encoded_latents.shape[1], encoded_latents.shape[3], encoded_latents.shape[4] | |
| cond_latents = torch.zeros(B, C, F, H, W, dtype=encoded_latents.dtype, device=encoded_latents.device) | |
| cond_latents[:, :, 1, :, :] = encoded_latents.squeeze(2) | |
| return first_images_np, sampled_frames, cond_latents, first_image_pil_np | |