CoolFace
Apppublic

DoruC/Grounded-Segment-Anything

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
image_processing_utils.py751 linesDownload Raw Back to transformers_4_35_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