DoruC/Grounded-Segment-Anything
0
1# coding=utf-82# Copyright 2022 The HuggingFace Inc. team.3#4# Licensed under the Apache License, Version 2.0 (the "License");5# you may not use this file except in compliance with the License.6# You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# distributed under the License is distributed on an "AS IS" BASIS,12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13# See the License for the specific language governing permissions and14# limitations under the License.15 16import copy17import json18import os19import warnings20from io import BytesIO21from typing import Any, Dict, Iterable, List, Optional, Tuple, Union22 23import numpy as np24import requests25 26from .dynamic_module_utils import custom_object_save27from .feature_extraction_utils import BatchFeature as BaseBatchFeature28from .image_transforms import center_crop, normalize, rescale29from .image_utils import ChannelDimension30from .utils import (31 IMAGE_PROCESSOR_NAME,32 PushToHubMixin,33 add_model_info_to_auto_map,34 cached_file,35 copy_func,36 download_url,37 is_offline_mode,38 is_remote_url,39 is_vision_available,40 logging,41)42 43 44if is_vision_available():45 from PIL import Image46 47logger = logging.get_logger(__name__)48 49 50# TODO: Move BatchFeature to be imported by both image_processing_utils and image_processing_utils51# We override the class string here, but logic is the same.52class BatchFeature(BaseBatchFeature):53 r"""54 Holds the output of the image processor specific `__call__` methods.55 56 This class is derived from a python dictionary and can be used as a dictionary.57 58 Args:59 data (`dict`):60 Dictionary of lists/arrays/tensors returned by the __call__ method ('pixel_values', etc.).61 tensor_type (`Union[None, str, TensorType]`, *optional*):62 You can give a tensor_type here to convert the lists of integers in PyTorch/TensorFlow/Numpy Tensors at63 initialization.64 """65 66 67# TODO: (Amy) - factor out the common parts of this and the feature extractor68class ImageProcessingMixin(PushToHubMixin):69 """70 This is an image processor mixin used to provide saving/loading functionality for sequential and image feature71 extractors.72 """73 74 _auto_class = None75 76 def __init__(self, **kwargs):77 """Set elements of `kwargs` as attributes."""78 # Pop "processor_class" as it should be saved as private attribute79 self._processor_class = kwargs.pop("processor_class", None)80 # Additional attributes without default values81 for key, value in kwargs.items():82 try:83 setattr(self, key, value)84 except AttributeError as err:85 logger.error(f"Can't set {key} with value {value} for {self}")86 raise err87 88 def _set_processor_class(self, processor_class: str):89 """Sets processor class as an attribute."""90 self._processor_class = processor_class91 92 @classmethod93 def from_pretrained(94 cls,95 pretrained_model_name_or_path: Union[str, os.PathLike],96 cache_dir: Optional[Union[str, os.PathLike]] = None,97 force_download: bool = False,98 local_files_only: bool = False,99 token: Optional[Union[str, bool]] = None,100 revision: str = "main",101 **kwargs,102 ):103 r"""104 Instantiate a type of [`~image_processing_utils.ImageProcessingMixin`] from an image processor.105 106 Args:107 pretrained_model_name_or_path (`str` or `os.PathLike`):108 This can be either:109 110 - a string, the *model id* of a pretrained image_processor hosted inside a model repo on111 huggingface.co. Valid model ids can be located at the root-level, like `bert-base-uncased`, or112 namespaced under a user or organization name, like `dbmdz/bert-base-german-cased`.113 - a path to a *directory* containing a image processor file saved using the114 [`~image_processing_utils.ImageProcessingMixin.save_pretrained`] method, e.g.,115 `./my_model_directory/`.116 - a path or url to a saved image processor JSON *file*, e.g.,117 `./my_model_directory/preprocessor_config.json`.118 cache_dir (`str` or `os.PathLike`, *optional*):119 Path to a directory in which a downloaded pretrained model image processor should be cached if the120 standard cache should not be used.121 force_download (`bool`, *optional*, defaults to `False`):122 Whether or not to force to (re-)download the image processor files and override the cached versions if123 they exist.124 resume_download (`bool`, *optional*, defaults to `False`):125 Whether or not to delete incompletely received file. Attempts to resume the download if such a file126 exists.127 proxies (`Dict[str, str]`, *optional*):128 A dictionary of proxy servers to use by protocol or endpoint, e.g., `{'http': 'foo.bar:3128',129 'http://hostname': 'foo.bar:4012'}.` The proxies are used on each request.130 token (`str` or `bool`, *optional*):131 The token to use as HTTP bearer authorization for remote files. If `True`, or not specified, will use132 the token generated when running `huggingface-cli login` (stored in `~/.huggingface`).133 revision (`str`, *optional*, defaults to `"main"`):134 The specific model version to use. It can be a branch name, a tag name, or a commit id, since we use a135 git-based system for storing models and other artifacts on huggingface.co, so `revision` can be any136 identifier allowed by git.137 138 139 <Tip>140 141 To test a pull request you made on the Hub, you can pass `revision="refs/pr/<pr_number>".142 143 </Tip>144 145 return_unused_kwargs (`bool`, *optional*, defaults to `False`):146 If `False`, then this function returns just the final image processor object. If `True`, then this147 functions returns a `Tuple(image_processor, unused_kwargs)` where *unused_kwargs* is a dictionary148 consisting of the key/value pairs whose keys are not image processor attributes: i.e., the part of149 `kwargs` which has not been used to update `image_processor` and is otherwise ignored.150 subfolder (`str`, *optional*, defaults to `""`):151 In case the relevant files are located inside a subfolder of the model repo on huggingface.co, you can152 specify the folder name here.153 kwargs (`Dict[str, Any]`, *optional*):154 The values in kwargs of any keys which are image processor attributes will be used to override the155 loaded values. Behavior concerning key/value pairs whose keys are *not* image processor attributes is156 controlled by the `return_unused_kwargs` keyword parameter.157 158 Returns:159 A image processor of type [`~image_processing_utils.ImageProcessingMixin`].160 161 Examples:162 163 ```python164 # We can't instantiate directly the base class *ImageProcessingMixin* so let's show the examples on a165 # derived class: *CLIPImageProcessor*166 image_processor = CLIPImageProcessor.from_pretrained(167 "openai/clip-vit-base-patch32"168 ) # Download image_processing_config from huggingface.co and cache.169 image_processor = CLIPImageProcessor.from_pretrained(170 "./test/saved_model/"171 ) # E.g. image processor (or model) was saved using *save_pretrained('./test/saved_model/')*172 image_processor = CLIPImageProcessor.from_pretrained("./test/saved_model/preprocessor_config.json")173 image_processor = CLIPImageProcessor.from_pretrained(174 "openai/clip-vit-base-patch32", do_normalize=False, foo=False175 )176 assert image_processor.do_normalize is False177 image_processor, unused_kwargs = CLIPImageProcessor.from_pretrained(178 "openai/clip-vit-base-patch32", do_normalize=False, foo=False, return_unused_kwargs=True179 )180 assert image_processor.do_normalize is False181 assert unused_kwargs == {"foo": False}182 ```"""183 kwargs["cache_dir"] = cache_dir184 kwargs["force_download"] = force_download185 kwargs["local_files_only"] = local_files_only186 kwargs["revision"] = revision187 188 use_auth_token = kwargs.pop("use_auth_token", None)189 if use_auth_token is not None:190 warnings.warn(191 "The `use_auth_token` argument is deprecated and will be removed in v5 of Transformers.", FutureWarning192 )193 if token is not None:194 raise ValueError(195 "`token` and `use_auth_token` are both specified. Please set only the argument `token`."196 )197 token = use_auth_token198 199 if token is not None:200 kwargs["token"] = token201 202 image_processor_dict, kwargs = cls.get_image_processor_dict(pretrained_model_name_or_path, **kwargs)203 204 return cls.from_dict(image_processor_dict, **kwargs)205 206 def save_pretrained(self, save_directory: Union[str, os.PathLike], push_to_hub: bool = False, **kwargs):207 """208 Save an image processor object to the directory `save_directory`, so that it can be re-loaded using the209 [`~image_processing_utils.ImageProcessingMixin.from_pretrained`] class method.210 211 Args:212 save_directory (`str` or `os.PathLike`):213 Directory where the image processor JSON file will be saved (will be created if it does not exist).214 push_to_hub (`bool`, *optional*, defaults to `False`):215 Whether or not to push your model to the Hugging Face model hub after saving it. You can specify the216 repository you want to push to with `repo_id` (will default to the name of `save_directory` in your217 namespace).218 kwargs (`Dict[str, Any]`, *optional*):219 Additional key word arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method.220 """221 use_auth_token = kwargs.pop("use_auth_token", None)222 223 if use_auth_token is not None:224 warnings.warn(225 "The `use_auth_token` argument is deprecated and will be removed in v5 of Transformers.", FutureWarning226 )227 if kwargs.get("token", None) is not None:228 raise ValueError(229 "`token` and `use_auth_token` are both specified. Please set only the argument `token`."230 )231 kwargs["token"] = use_auth_token232 233 if os.path.isfile(save_directory):234 raise AssertionError(f"Provided path ({save_directory}) should be a directory, not a file")235 236 os.makedirs(save_directory, exist_ok=True)237 238 if push_to_hub:239 commit_message = kwargs.pop("commit_message", None)240 repo_id = kwargs.pop("repo_id", save_directory.split(os.path.sep)[-1])241 repo_id = self._create_repo(repo_id, **kwargs)242 files_timestamps = self._get_files_timestamps(save_directory)243 244 # If we have a custom config, we copy the file defining it in the folder and set the attributes so it can be245 # loaded from the Hub.246 if self._auto_class is not None:247 custom_object_save(self, save_directory, config=self)248 249 # If we save using the predefined names, we can load using `from_pretrained`250 output_image_processor_file = os.path.join(save_directory, IMAGE_PROCESSOR_NAME)251 252 self.to_json_file(output_image_processor_file)253 logger.info(f"Image processor saved in {output_image_processor_file}")254 255 if push_to_hub:256 self._upload_modified_files(257 save_directory,258 repo_id,259 files_timestamps,260 commit_message=commit_message,261 token=kwargs.get("token"),262 )263 264 return [output_image_processor_file]265 266 @classmethod267 def get_image_processor_dict(268 cls, pretrained_model_name_or_path: Union[str, os.PathLike], **kwargs269 ) -> Tuple[Dict[str, Any], Dict[str, Any]]:270 """271 From a `pretrained_model_name_or_path`, resolve to a dictionary of parameters, to be used for instantiating a272 image processor of type [`~image_processor_utils.ImageProcessingMixin`] using `from_dict`.273 274 Parameters:275 pretrained_model_name_or_path (`str` or `os.PathLike`):276 The identifier of the pre-trained checkpoint from which we want the dictionary of parameters.277 subfolder (`str`, *optional*, defaults to `""`):278 In case the relevant files are located inside a subfolder of the model repo on huggingface.co, you can279 specify the folder name here.280 281 Returns:282 `Tuple[Dict, Dict]`: The dictionary(ies) that will be used to instantiate the image processor object.283 """284 cache_dir = kwargs.pop("cache_dir", None)285 force_download = kwargs.pop("force_download", False)286 resume_download = kwargs.pop("resume_download", False)287 proxies = kwargs.pop("proxies", None)288 token = kwargs.pop("token", None)289 use_auth_token = kwargs.pop("use_auth_token", None)290 local_files_only = kwargs.pop("local_files_only", False)291 revision = kwargs.pop("revision", None)292 subfolder = kwargs.pop("subfolder", "")293 294 from_pipeline = kwargs.pop("_from_pipeline", None)295 from_auto_class = kwargs.pop("_from_auto", False)296 297 if use_auth_token is not None:298 warnings.warn(299 "The `use_auth_token` argument is deprecated and will be removed in v5 of Transformers.", FutureWarning300 )301 if token is not None:302 raise ValueError(303 "`token` and `use_auth_token` are both specified. Please set only the argument `token`."304 )305 token = use_auth_token306 307 user_agent = {"file_type": "image processor", "from_auto_class": from_auto_class}308 if from_pipeline is not None:309 user_agent["using_pipeline"] = from_pipeline310 311 if is_offline_mode() and not local_files_only:312 logger.info("Offline mode: forcing local_files_only=True")313 local_files_only = True314 315 pretrained_model_name_or_path = str(pretrained_model_name_or_path)316 is_local = os.path.isdir(pretrained_model_name_or_path)317 if os.path.isdir(pretrained_model_name_or_path):318 image_processor_file = os.path.join(pretrained_model_name_or_path, IMAGE_PROCESSOR_NAME)319 if os.path.isfile(pretrained_model_name_or_path):320 resolved_image_processor_file = pretrained_model_name_or_path321 is_local = True322 elif is_remote_url(pretrained_model_name_or_path):323 image_processor_file = pretrained_model_name_or_path324 resolved_image_processor_file = download_url(pretrained_model_name_or_path)325 else:326 image_processor_file = IMAGE_PROCESSOR_NAME327 try:328 # Load from local folder or from cache or download from model Hub and cache329 resolved_image_processor_file = cached_file(330 pretrained_model_name_or_path,331 image_processor_file,332 cache_dir=cache_dir,333 force_download=force_download,334 proxies=proxies,335 resume_download=resume_download,336 local_files_only=local_files_only,337 token=token,338 user_agent=user_agent,339 revision=revision,340 subfolder=subfolder,341 )342 except EnvironmentError:343 # Raise any environment error raise by `cached_file`. It will have a helpful error message adapted to344 # the original exception.345 raise346 except Exception:347 # For any other exception, we throw a generic error.348 raise EnvironmentError(349 f"Can't load image processor for '{pretrained_model_name_or_path}'. If you were trying to load"350 " it from 'https://huggingface.co/models', make sure you don't have a local directory with the"351 f" same name. Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a"352 f" directory containing a {IMAGE_PROCESSOR_NAME} file"353 )354 355 try:356 # Load image_processor dict357 with open(resolved_image_processor_file, "r", encoding="utf-8") as reader:358 text = reader.read()359 image_processor_dict = json.loads(text)360 361 except json.JSONDecodeError:362 raise EnvironmentError(363 f"It looks like the config file at '{resolved_image_processor_file}' is not a valid JSON file."364 )365 366 if is_local:367 logger.info(f"loading configuration file {resolved_image_processor_file}")368 else:369 logger.info(370 f"loading configuration file {image_processor_file} from cache at {resolved_image_processor_file}"371 )372 373 if "auto_map" in image_processor_dict and not is_local:374 image_processor_dict["auto_map"] = add_model_info_to_auto_map(375 image_processor_dict["auto_map"], pretrained_model_name_or_path376 )377 378 return image_processor_dict, kwargs379 380 @classmethod381 def from_dict(cls, image_processor_dict: Dict[str, Any], **kwargs):382 """383 Instantiates a type of [`~image_processing_utils.ImageProcessingMixin`] from a Python dictionary of parameters.384 385 Args:386 image_processor_dict (`Dict[str, Any]`):387 Dictionary that will be used to instantiate the image processor object. Such a dictionary can be388 retrieved from a pretrained checkpoint by leveraging the389 [`~image_processing_utils.ImageProcessingMixin.to_dict`] method.390 kwargs (`Dict[str, Any]`):391 Additional parameters from which to initialize the image processor object.392 393 Returns:394 [`~image_processing_utils.ImageProcessingMixin`]: The image processor object instantiated from those395 parameters.396 """397 image_processor_dict = image_processor_dict.copy()398 return_unused_kwargs = kwargs.pop("return_unused_kwargs", False)399 400 # The `size` parameter is a dict and was previously an int or tuple in feature extractors.401 # We set `size` here directly to the `image_processor_dict` so that it is converted to the appropriate402 # dict within the image processor and isn't overwritten if `size` is passed in as a kwarg.403 if "size" in kwargs and "size" in image_processor_dict:404 image_processor_dict["size"] = kwargs.pop("size")405 if "crop_size" in kwargs and "crop_size" in image_processor_dict:406 image_processor_dict["crop_size"] = kwargs.pop("crop_size")407 408 image_processor = cls(**image_processor_dict)409 410 # Update image_processor with kwargs if needed411 to_remove = []412 for key, value in kwargs.items():413 if hasattr(image_processor, key):414 setattr(image_processor, key, value)415 to_remove.append(key)416 for key in to_remove:417 kwargs.pop(key, None)418 419 logger.info(f"Image processor {image_processor}")420 if return_unused_kwargs:421 return image_processor, kwargs422 else:423 return image_processor424 425 def to_dict(self) -> Dict[str, Any]:426 """427 Serializes this instance to a Python dictionary.428 429 Returns:430 `Dict[str, Any]`: Dictionary of all the attributes that make up this image processor instance.431 """432 output = copy.deepcopy(self.__dict__)433 output["image_processor_type"] = self.__class__.__name__434 435 return output436 437 @classmethod438 def from_json_file(cls, json_file: Union[str, os.PathLike]):439 """440 Instantiates a image processor of type [`~image_processing_utils.ImageProcessingMixin`] from the path to a JSON441 file of parameters.442 443 Args:444 json_file (`str` or `os.PathLike`):445 Path to the JSON file containing the parameters.446 447 Returns:448 A image processor of type [`~image_processing_utils.ImageProcessingMixin`]: The image_processor object449 instantiated from that JSON file.450 """451 with open(json_file, "r", encoding="utf-8") as reader:452 text = reader.read()453 image_processor_dict = json.loads(text)454 return cls(**image_processor_dict)455 456 def to_json_string(self) -> str:457 """458 Serializes this instance to a JSON string.459 460 Returns:461 `str`: String containing all the attributes that make up this feature_extractor instance in JSON format.462 """463 dictionary = self.to_dict()464 465 for key, value in dictionary.items():466 if isinstance(value, np.ndarray):467 dictionary[key] = value.tolist()468 469 # make sure private name "_processor_class" is correctly470 # saved as "processor_class"471 _processor_class = dictionary.pop("_processor_class", None)472 if _processor_class is not None:473 dictionary["processor_class"] = _processor_class474 475 return json.dumps(dictionary, indent=2, sort_keys=True) + "\n"476 477 def to_json_file(self, json_file_path: Union[str, os.PathLike]):478 """479 Save this instance to a JSON file.480 481 Args:482 json_file_path (`str` or `os.PathLike`):483 Path to the JSON file in which this image_processor instance's parameters will be saved.484 """485 with open(json_file_path, "w", encoding="utf-8") as writer:486 writer.write(self.to_json_string())487 488 def __repr__(self):489 return f"{self.__class__.__name__} {self.to_json_string()}"490 491 @classmethod492 def register_for_auto_class(cls, auto_class="AutoImageProcessor"):493 """494 Register this class with a given auto class. This should only be used for custom image processors as the ones495 in the library are already mapped with `AutoImageProcessor `.496 497 <Tip warning={true}>498 499 This API is experimental and may have some slight breaking changes in the next releases.500 501 </Tip>502 503 Args:504 auto_class (`str` or `type`, *optional*, defaults to `"AutoImageProcessor "`):505 The auto class to register this new image processor with.506 """507 if not isinstance(auto_class, str):508 auto_class = auto_class.__name__509 510 import transformers.models.auto as auto_module511 512 if not hasattr(auto_module, auto_class):513 raise ValueError(f"{auto_class} is not a valid auto class.")514 515 cls._auto_class = auto_class516 517 def fetch_images(self, image_url_or_urls: Union[str, List[str]]):518 """519 Convert a single or a list of urls into the corresponding `PIL.Image` objects.520 521 If a single url is passed, the return value will be a single object. If a list is passed a list of objects is522 returned.523 """524 headers = {525 "User-Agent": (526 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0"527 " Safari/537.36"528 )529 }530 if isinstance(image_url_or_urls, list):531 return [self.fetch_images(x) for x in image_url_or_urls]532 elif isinstance(image_url_or_urls, str):533 response = requests.get(image_url_or_urls, stream=True, headers=headers)534 response.raise_for_status()535 return Image.open(BytesIO(response.content))536 else:537 raise ValueError(f"only a single or a list of entries is supported but got type={type(image_url_or_urls)}")538 539 540class BaseImageProcessor(ImageProcessingMixin):541 def __init__(self, **kwargs):542 super().__init__(**kwargs)543 544 def __call__(self, images, **kwargs) -> BatchFeature:545 """Preprocess an image or a batch of images."""546 return self.preprocess(images, **kwargs)547 548 def preprocess(self, images, **kwargs) -> BatchFeature:549 raise NotImplementedError("Each image processor must implement its own preprocess method")550 551 def rescale(552 self,553 image: np.ndarray,554 scale: float,555 data_format: Optional[Union[str, ChannelDimension]] = None,556 input_data_format: Optional[Union[str, ChannelDimension]] = None,557 **kwargs,558 ) -> np.ndarray:559 """560 Rescale an image by a scale factor. image = image * scale.561 562 Args:563 image (`np.ndarray`):564 Image to rescale.565 scale (`float`):566 The scaling factor to rescale pixel values by.567 data_format (`str` or `ChannelDimension`, *optional*):568 The channel dimension format for the output image. If unset, the channel dimension format of the input569 image is used. Can be one of:570 - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.571 - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.572 input_data_format (`ChannelDimension` or `str`, *optional*):573 The channel dimension format for the input image. If unset, the channel dimension format is inferred574 from the input image. Can be one of:575 - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.576 - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.577 578 Returns:579 `np.ndarray`: The rescaled image.580 """581 return rescale(image, scale=scale, data_format=data_format, input_data_format=input_data_format, **kwargs)582 583 def normalize(584 self,585 image: np.ndarray,586 mean: Union[float, Iterable[float]],587 std: Union[float, Iterable[float]],588 data_format: Optional[Union[str, ChannelDimension]] = None,589 input_data_format: Optional[Union[str, ChannelDimension]] = None,590 **kwargs,591 ) -> np.ndarray:592 """593 Normalize an image. image = (image - image_mean) / image_std.594 595 Args:596 image (`np.ndarray`):597 Image to normalize.598 mean (`float` or `Iterable[float]`):599 Image mean to use for normalization.600 std (`float` or `Iterable[float]`):601 Image standard deviation to use for normalization.602 data_format (`str` or `ChannelDimension`, *optional*):603 The channel dimension format for the output image. If unset, the channel dimension format of the input604 image is used. Can be one of:605 - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.606 - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.607 input_data_format (`ChannelDimension` or `str`, *optional*):608 The channel dimension format for the input image. If unset, the channel dimension format is inferred609 from the input image. Can be one of:610 - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.611 - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.612 613 Returns:614 `np.ndarray`: The normalized image.615 """616 return normalize(617 image, mean=mean, std=std, data_format=data_format, input_data_format=input_data_format, **kwargs618 )619 620 def center_crop(621 self,622 image: np.ndarray,623 size: Dict[str, int],624 data_format: Optional[Union[str, ChannelDimension]] = None,625 input_data_format: Optional[Union[str, ChannelDimension]] = None,626 **kwargs,627 ) -> np.ndarray:628 """629 Center crop an image to `(size["height"], size["width"])`. If the input size is smaller than `crop_size` along630 any edge, the image is padded with 0's and then center cropped.631 632 Args:633 image (`np.ndarray`):634 Image to center crop.635 size (`Dict[str, int]`):636 Size of the output image.637 data_format (`str` or `ChannelDimension`, *optional*):638 The channel dimension format for the output image. If unset, the channel dimension format of the input639 image is used. Can be one of:640 - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.641 - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.642 input_data_format (`ChannelDimension` or `str`, *optional*):643 The channel dimension format for the input image. If unset, the channel dimension format is inferred644 from the input image. Can be one of:645 - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.646 - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.647 """648 size = get_size_dict(size)649 if "height" not in size or "width" not in size:650 raise ValueError(f"The size dictionary must have keys 'height' and 'width'. Got {size.keys()}")651 return center_crop(652 image,653 size=(size["height"], size["width"]),654 data_format=data_format,655 input_data_format=input_data_format,656 **kwargs,657 )658 659 660VALID_SIZE_DICT_KEYS = ({"height", "width"}, {"shortest_edge"}, {"shortest_edge", "longest_edge"}, {"longest_edge"})661 662 663def is_valid_size_dict(size_dict):664 if not isinstance(size_dict, dict):665 return False666 667 size_dict_keys = set(size_dict.keys())668 for allowed_keys in VALID_SIZE_DICT_KEYS:669 if size_dict_keys == allowed_keys:670 return True671 return False672 673 674def convert_to_size_dict(675 size, max_size: Optional[int] = None, default_to_square: bool = True, height_width_order: bool = True676):677 # By default, if size is an int we assume it represents a tuple of (size, size).678 if isinstance(size, int) and default_to_square:679 if max_size is not None:680 raise ValueError("Cannot specify both size as an int, with default_to_square=True and max_size")681 return {"height": size, "width": size}682 # In other configs, if size is an int and default_to_square is False, size represents the length of683 # the shortest edge after resizing.684 elif isinstance(size, int) and not default_to_square:685 size_dict = {"shortest_edge": size}686 if max_size is not None:687 size_dict["longest_edge"] = max_size688 return size_dict689 # Otherwise, if size is a tuple it's either (height, width) or (width, height)690 elif isinstance(size, (tuple, list)) and height_width_order:691 return {"height": size[0], "width": size[1]}692 elif isinstance(size, (tuple, list)) and not height_width_order:693 return {"height": size[1], "width": size[0]}694 elif size is None and max_size is not None:695 if default_to_square:696 raise ValueError("Cannot specify both default_to_square=True and max_size")697 return {"longest_edge": max_size}698 699 raise ValueError(f"Could not convert size input to size dict: {size}")700 701 702def get_size_dict(703 size: Union[int, Iterable[int], Dict[str, int]] = None,704 max_size: Optional[int] = None,705 height_width_order: bool = True,706 default_to_square: bool = True,707 param_name="size",708) -> dict:709 """710 Converts the old size parameter in the config into the new dict expected in the config. This is to ensure backwards711 compatibility with the old image processor configs and removes ambiguity over whether the tuple is in (height,712 width) or (width, height) format.713 714 - If `size` is tuple, it is converted to `{"height": size[0], "width": size[1]}` or `{"height": size[1], "width":715 size[0]}` if `height_width_order` is `False`.716 - If `size` is an int, and `default_to_square` is `True`, it is converted to `{"height": size, "width": size}`.717 - If `size` is an int and `default_to_square` is False, it is converted to `{"shortest_edge": size}`. If `max_size`718 is set, it is added to the dict as `{"longest_edge": max_size}`.719 720 Args:721 size (`Union[int, Iterable[int], Dict[str, int]]`, *optional*):722 The `size` parameter to be cast into a size dictionary.723 max_size (`Optional[int]`, *optional*):724 The `max_size` parameter to be cast into a size dictionary.725 height_width_order (`bool`, *optional*, defaults to `True`):726 If `size` is a tuple, whether it's in (height, width) or (width, height) order.727 default_to_square (`bool`, *optional*, defaults to `True`):728 If `size` is an int, whether to default to a square image or not.729 """730 if not isinstance(size, dict):731 size_dict = convert_to_size_dict(size, max_size, default_to_square, height_width_order)732 logger.info(733 f"{param_name} should be a dictionary on of the following set of keys: {VALID_SIZE_DICT_KEYS}, got {size}."734 f" Converted to {size_dict}.",735 )736 else:737 size_dict = size738 739 if not is_valid_size_dict(size_dict):740 raise ValueError(741 f"{param_name} must have one of the following set of keys: {VALID_SIZE_DICT_KEYS}, got {size_dict.keys()}"742 )743 return size_dict744 745 746ImageProcessingMixin.push_to_hub = copy_func(ImageProcessingMixin.push_to_hub)747if ImageProcessingMixin.push_to_hub.__doc__ is not None:748 ImageProcessingMixin.push_to_hub.__doc__ = ImageProcessingMixin.push_to_hub.__doc__.format(749 object="image processor", object_class="AutoImageProcessor", object_files="image processor file"750 )751 