# Copyright 2025 The HunyuanVideo Team and The HuggingFace Team. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import numpy as np from ...configuration_utils import register_to_config from ...video_processor import VideoProcessor # copied from https://github.com/Tencent-Hunyuan/HunyuanVideo-1.5/blob/main/hyvideo/utils/data_utils.py#L20 def generate_crop_size_list(base_size=256, patch_size=16, max_ratio=4.0): num_patches = round((base_size / patch_size) ** 2) assert max_ratio >= 1.0 crop_size_list = [] wp, hp = num_patches, 1 while wp > 0: if max(wp, hp) / min(wp, hp) <= max_ratio: crop_size_list.append((wp * patch_size, hp * patch_size)) if (hp + 1) * wp <= num_patches: hp += 1 else: wp -= 1 return crop_size_list # copied from https://github.com/Tencent-Hunyuan/HunyuanVideo-1.5/blob/main/hyvideo/utils/data_utils.py#L38 def get_closest_ratio(height: float, width: float, ratios: list, buckets: list): """ Get the closest ratio in the buckets. Args: height (float): video height width (float): video width ratios (list): video aspect ratio buckets (list): buckets generated by `generate_crop_size_list` Returns: the closest size in the buckets and the corresponding ratio """ aspect_ratio = float(height) / float(width) diff_ratios = ratios - aspect_ratio if aspect_ratio >= 1: indices = [(index, x) for index, x in enumerate(diff_ratios) if x <= 0] else: indices = [(index, x) for index, x in enumerate(diff_ratios) if x >= 0] closest_ratio_id = min(indices, key=lambda pair: abs(pair[1]))[0] closest_size = buckets[closest_ratio_id] closest_ratio = ratios[closest_ratio_id] return closest_size, closest_ratio class HunyuanVideo15ImageProcessor(VideoProcessor): r""" Image/video processor to preproces/postprocess the reference image/generatedvideo for the HunyuanVideo1.5 model. Args: do_resize (`bool`, *optional*, defaults to `True`): Whether to downscale the image's (height, width) dimensions to multiples of `vae_scale_factor`. Can accept `height` and `width` arguments from [`image_processor.VaeImageProcessor.preprocess`] method. vae_scale_factor (`int`, *optional*, defaults to `16`): VAE (spatial) scale factor. If `do_resize` is `True`, the image is automatically resized to multiples of this factor. vae_latent_channels (`int`, *optional*, defaults to `32`): VAE latent channels. do_convert_rgb (`bool`, *optional*, defaults to `True`): Whether to convert the image to RGB. """ @register_to_config def __init__( self, do_resize: bool = True, vae_scale_factor: int = 16, vae_latent_channels: int = 32, do_convert_rgb: bool = True, ): super().__init__( do_resize=do_resize, vae_scale_factor=vae_scale_factor, vae_latent_channels=vae_latent_channels, do_convert_rgb=do_convert_rgb, ) def calculate_default_height_width(self, height: int, width: int, target_size: int): crop_size_list = generate_crop_size_list(base_size=target_size, patch_size=self.config.vae_scale_factor) aspect_ratios = np.array([round(float(h) / float(w), 5) for h, w in crop_size_list]) height, width = get_closest_ratio(height, width, aspect_ratios, crop_size_list)[0] return height, width