| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import math |
| from typing import Tuple |
|
|
| from PIL import Image |
|
|
| from ...configuration_utils import register_to_config |
| from ...image_processor import VaeImageProcessor |
|
|
|
|
| |
| BUCKETS = { |
| 1024: [ |
| (512, 1792), (512, 1856), (512, 1920), (512, 1984), (512, 2048), |
| (576, 1600), (576, 1664), (576, 1728), (576, 1792), |
| (640, 1472), (640, 1536), (640, 1600), |
| (704, 1344), (704, 1408), (704, 1472), |
| (768, 1216), (768, 1280), (768, 1344), |
| (832, 1152), (832, 1216), |
| (896, 1088), (896, 1152), |
| (960, 1024), (960, 1088), |
| (1024, 960), (1024, 1024), |
| (1088, 896), (1088, 960), |
| (1152, 832), (1152, 896), |
| (1216, 768), (1216, 832), |
| (1280, 768), |
| (1344, 704), (1344, 768), |
| (1408, 704), |
| (1472, 640), (1472, 704), |
| (1536, 640), |
| (1600, 576), (1600, 640), |
| (1664, 576), |
| (1728, 576), |
| (1792, 512), (1792, 576), |
| (1856, 512), |
| (1920, 512), |
| (1984, 512), |
| (2048, 512), |
| ], |
| } |
| |
|
|
|
|
| def find_best_bucket(height: int, width: int, basesize: int) -> Tuple[int, int]: |
| """Return the (h, w) bucket whose aspect ratio is closest to height/width.""" |
| target_ratio = height / width |
| return min( |
| BUCKETS[basesize], |
| key=lambda hw: abs(hw[0] / hw[1] - target_ratio), |
| ) |
|
|
|
|
| class JoyImageEditImageProcessor(VaeImageProcessor): |
| """ |
| Image processor for the JoyImage Edit pipeline. |
| |
| Handles bucket-based resolution selection and resize-center-crop preprocessing. |
| |
| Args: |
| do_resize (`bool`, *optional*, defaults to `True`): |
| Whether to resize the image. |
| vae_scale_factor (`int`, *optional*, defaults to `8`): |
| VAE spatial scale factor. |
| basesize (`int`, *optional*, defaults to `1024`): |
| Base resolution for bucket generation. |
| resample (`str`, *optional*, defaults to `bilinear`): |
| Resampling filter for resizing. |
| do_normalize (`bool`, *optional*, defaults to `True`): |
| Whether to normalize the image to [-1,1]. |
| do_binarize (`bool`, *optional*, defaults to `False`): |
| Whether to binarize the image to 0/1. |
| do_convert_rgb (`bool`, *optional*, defaults to `False`): |
| Whether to convert the images to RGB format. |
| do_convert_grayscale (`bool`, *optional*, defaults to `False`): |
| Whether to convert the images to grayscale format. |
| """ |
|
|
| @register_to_config |
| def __init__( |
| self, |
| do_resize: bool = True, |
| vae_scale_factor: int = 8, |
| basesize: int = 1024, |
| resample: str = "bilinear", |
| do_normalize: bool = True, |
| do_binarize: bool = False, |
| do_convert_rgb: bool = False, |
| do_convert_grayscale: bool = False, |
| ): |
| super().__init__() |
|
|
| def get_default_height_width( |
| self, |
| image: Image.Image, |
| height: int | None = None, |
| width: int | None = None, |
| ) -> Tuple[int, int]: |
| if height is not None and width is not None: |
| src_w, src_h = width, height |
| elif image is None: |
| src_w, src_h = self.config.basesize, self.config.basesize |
| elif isinstance(image, list): |
| src_w, src_h = image[0].size |
| else: |
| src_w, src_h = image.size |
|
|
| return find_best_bucket(src_h, src_w, self.config.basesize) |
|
|
| def resize_center_crop( |
| self, |
| img, |
| target_size: Tuple[int, int], |
| ): |
| """ |
| Scale image to cover target_size, then center-crop. |
| |
| Args: |
| img: Input PIL image or list of PIL images. |
| target_size: (height, width) to crop to. |
| |
| Returns: |
| Resized and center-cropped PIL image(s), matching the input type. |
| """ |
| if isinstance(img, list): |
| return [self.resize_center_crop(i, target_size) for i in img] |
|
|
| w, h = img.size |
| bh, bw = target_size |
| scale = max(bh / h, bw / w) |
| resize_h = math.ceil(h * scale) |
| resize_w = math.ceil(w * scale) |
| img = img.resize((resize_w, resize_h), Image.BILINEAR) |
| left = (resize_w - bw) // 2 |
| top = (resize_h - bh) // 2 |
| img = img.crop((left, top, left + bw, top + bh)) |
| return img |
|
|