vitronedit / hyvideo /utils /multitask_utils.py
multimodalart's picture
multimodalart HF Staff
Initial VitronEdit demo
886038b verified
Raw History Blame Contribute Delete
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