CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
image_processing_utils_fast.py834 linesDownload Raw Back to transformers
1# Copyright 2024 The HuggingFace Inc. team.2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7#     http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15from collections.abc import Iterable16from copy import deepcopy17from functools import lru_cache, partial18from typing import Any, Optional, TypedDict, Union19 20import numpy as np21 22from .image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict23from .image_transforms import (24    convert_to_rgb,25    get_resize_output_image_size,26    get_size_with_aspect_ratio,27    group_images_by_shape,28    reorder_images,29)30from .image_utils import (31    ChannelDimension,32    ImageInput,33    ImageType,34    SizeDict,35    get_image_size,36    get_image_size_for_max_height_width,37    get_image_type,38    infer_channel_dimension_format,39    make_flat_list_of_images,40    validate_kwargs,41    validate_preprocess_arguments,42)43from .processing_utils import Unpack44from .utils import (45    TensorType,46    auto_docstring,47    is_torch_available,48    is_torchvision_available,49    is_vision_available,50    logging,51)52from .utils.import_utils import is_rocm_platform53 54 55if is_vision_available():56    from .image_utils import PILImageResampling57 58if is_torch_available():59    import torch60 61if is_torchvision_available():62    from torchvision.transforms.v2 import functional as F63 64    from .image_utils import pil_torch_interpolation_mapping65 66else:67    pil_torch_interpolation_mapping = None68 69 70logger = logging.get_logger(__name__)71 72 73@lru_cache(maxsize=10)74def validate_fast_preprocess_arguments(75    do_rescale: Optional[bool] = None,76    rescale_factor: Optional[float] = None,77    do_normalize: Optional[bool] = None,78    image_mean: Optional[Union[float, list[float]]] = None,79    image_std: Optional[Union[float, list[float]]] = None,80    do_center_crop: Optional[bool] = None,81    crop_size: Optional[SizeDict] = None,82    do_resize: Optional[bool] = None,83    size: Optional[SizeDict] = None,84    interpolation: Optional["F.InterpolationMode"] = None,85    return_tensors: Optional[Union[str, TensorType]] = None,86    data_format: ChannelDimension = ChannelDimension.FIRST,87):88    """89    Checks validity of typically used arguments in an `ImageProcessorFast` `preprocess` method.90    Raises `ValueError` if arguments incompatibility is caught.91    """92    validate_preprocess_arguments(93        do_rescale=do_rescale,94        rescale_factor=rescale_factor,95        do_normalize=do_normalize,96        image_mean=image_mean,97        image_std=image_std,98        do_center_crop=do_center_crop,99        crop_size=crop_size,100        do_resize=do_resize,101        size=size,102        interpolation=interpolation,103    )104    # Extra checks for ImageProcessorFast105    if return_tensors is not None and return_tensors != "pt":106        raise ValueError("Only returning PyTorch tensors is currently supported.")107 108    if data_format != ChannelDimension.FIRST:109        raise ValueError("Only channel first data format is currently supported.")110 111 112def safe_squeeze(tensor: "torch.Tensor", axis: Optional[int] = None) -> "torch.Tensor":113    """114    Squeezes a tensor, but only if the axis specified has dim 1.115    """116    if axis is None:117        return tensor.squeeze()118 119    try:120        return tensor.squeeze(axis=axis)121    except ValueError:122        return tensor123 124 125def max_across_indices(values: Iterable[Any]) -> list[Any]:126    """127    Return the maximum value across all indices of an iterable of values.128    """129    return [max(values_i) for values_i in zip(*values)]130 131 132def get_max_height_width(images: list["torch.Tensor"]) -> tuple[int, ...]:133    """134    Get the maximum height and width across all images in a batch.135    """136 137    _, max_height, max_width = max_across_indices([img.shape for img in images])138 139    return (max_height, max_width)140 141 142def divide_to_patches(143    image: Union[np.ndarray, "torch.Tensor"], patch_size: int144) -> list[Union[np.ndarray, "torch.Tensor"]]:145    """146    Divides an image into patches of a specified size.147 148    Args:149        image (`Union[np.array, "torch.Tensor"]`):150            The input image.151        patch_size (`int`):152            The size of each patch.153    Returns:154        list: A list of Union[np.array, "torch.Tensor"] representing the patches.155    """156    patches = []157    height, width = get_image_size(image, channel_dim=ChannelDimension.FIRST)158    for i in range(0, height, patch_size):159        for j in range(0, width, patch_size):160            patch = image[:, i : i + patch_size, j : j + patch_size]161            patches.append(patch)162 163    return patches164 165 166class DefaultFastImageProcessorKwargs(TypedDict, total=False):167    do_resize: Optional[bool]168    size: Optional[dict[str, int]]169    default_to_square: Optional[bool]170    resample: Optional[Union["PILImageResampling", "F.InterpolationMode"]]171    do_center_crop: Optional[bool]172    crop_size: Optional[dict[str, int]]173    do_rescale: Optional[bool]174    rescale_factor: Optional[Union[int, float]]175    do_normalize: Optional[bool]176    image_mean: Optional[Union[float, list[float]]]177    image_std: Optional[Union[float, list[float]]]178    do_pad: Optional[bool]179    pad_size: Optional[dict[str, int]]180    do_convert_rgb: Optional[bool]181    return_tensors: Optional[Union[str, TensorType]]182    data_format: Optional[ChannelDimension]183    input_data_format: Optional[Union[str, ChannelDimension]]184    device: Optional["torch.device"]185    disable_grouping: Optional[bool]186 187 188@auto_docstring189class BaseImageProcessorFast(BaseImageProcessor):190    resample = None191    image_mean = None192    image_std = None193    size = None194    default_to_square = True195    crop_size = None196    do_resize = None197    do_center_crop = None198    do_pad = None199    pad_size = None200    do_rescale = None201    rescale_factor = 1 / 255202    do_normalize = None203    do_convert_rgb = None204    return_tensors = None205    data_format = ChannelDimension.FIRST206    input_data_format = None207    device = None208    model_input_names = ["pixel_values"]209    valid_kwargs = DefaultFastImageProcessorKwargs210    unused_kwargs = None211 212    def __init__(self, **kwargs: Unpack[DefaultFastImageProcessorKwargs]):213        super().__init__(**kwargs)214        kwargs = self.filter_out_unused_kwargs(kwargs)215        size = kwargs.pop("size", self.size)216        self.size = (217            get_size_dict(size=size, default_to_square=kwargs.pop("default_to_square", self.default_to_square))218            if size is not None219            else None220        )221        crop_size = kwargs.pop("crop_size", self.crop_size)222        self.crop_size = get_size_dict(crop_size, param_name="crop_size") if crop_size is not None else None223        pad_size = kwargs.pop("pad_size", self.pad_size)224        self.pad_size = get_size_dict(size=pad_size, param_name="pad_size") if pad_size is not None else None225 226        for key in self.valid_kwargs.__annotations__:227            kwarg = kwargs.pop(key, None)228            if kwarg is not None:229                setattr(self, key, kwarg)230            else:231                setattr(self, key, deepcopy(getattr(self, key, None)))232 233        # get valid kwargs names234        self._valid_kwargs_names = list(self.valid_kwargs.__annotations__.keys())235 236    @property237    def is_fast(self) -> bool:238        """239        `bool`: Whether or not this image processor is a fast processor (backed by PyTorch and TorchVision).240        """241        return True242 243    def pad(244        self,245        images: "torch.Tensor",246        pad_size: SizeDict = None,247        fill_value: Optional[int] = 0,248        padding_mode: Optional[str] = "constant",249        return_mask: bool = False,250        disable_grouping: Optional[bool] = False,251        **kwargs,252    ) -> "torch.Tensor":253        """254        Pads images to `(pad_size["height"], pad_size["width"])` or to the largest size in the batch.255 256        Args:257            images (`torch.Tensor`):258                Images to pad.259            pad_size (`SizeDict`, *optional*):260                Dictionary in the format `{"height": int, "width": int}` specifying the size of the output image.261            fill_value (`int`, *optional*, defaults to `0`):262                The constant value used to fill the padded area.263            padding_mode (`str`, *optional*, defaults to "constant"):264                The padding mode to use. Can be any of the modes supported by265                `torch.nn.functional.pad` (e.g. constant, reflection, replication).266            return_mask (`bool`, *optional*, defaults to `False`):267                Whether to return a pixel mask to denote padded regions.268            disable_grouping (`bool`, *optional*, defaults to `False`):269                Whether to disable grouping of images by size.270 271        Returns:272            `torch.Tensor`: The resized image.273        """274        if pad_size is not None:275            if not (pad_size.height and pad_size.width):276                raise ValueError(f"Pad size must contain 'height' and 'width' keys only. Got pad_size={pad_size}.")277            pad_size = (pad_size.height, pad_size.width)278        else:279            pad_size = get_max_height_width(images)280 281        grouped_images, grouped_images_index = group_images_by_shape(images, disable_grouping=disable_grouping)282        processed_images_grouped = {}283        processed_masks_grouped = {}284        for shape, stacked_images in grouped_images.items():285            image_size = stacked_images.shape[-2:]286            padding_height = pad_size[0] - image_size[0]287            padding_width = pad_size[1] - image_size[1]288            if padding_height < 0 or padding_width < 0:289                raise ValueError(290                    f"Padding dimensions are negative. Please make sure that the `pad_size` is larger than the "291                    f"image size. Got pad_size={pad_size}, image_size={image_size}."292                )293            if image_size != pad_size:294                padding = (0, 0, padding_width, padding_height)295                stacked_images = F.pad(stacked_images, padding, fill=fill_value, padding_mode=padding_mode)296            processed_images_grouped[shape] = stacked_images297 298            if return_mask:299                # keep only one from the channel dimension in pixel mask300                stacked_masks = torch.zeros_like(stacked_images, dtype=torch.int64)[..., 0, :, :]301                stacked_masks[..., : image_size[0], : image_size[1]] = 1302                processed_masks_grouped[shape] = stacked_masks303 304        processed_images = reorder_images(processed_images_grouped, grouped_images_index)305        if return_mask:306            processed_masks = reorder_images(processed_masks_grouped, grouped_images_index)307            return processed_images, processed_masks308 309        return processed_images310 311    def resize(312        self,313        image: "torch.Tensor",314        size: SizeDict,315        interpolation: Optional["F.InterpolationMode"] = None,316        antialias: bool = True,317        **kwargs,318    ) -> "torch.Tensor":319        """320        Resize an image to `(size["height"], size["width"])`.321 322        Args:323            image (`torch.Tensor`):324                Image to resize.325            size (`SizeDict`):326                Dictionary in the format `{"height": int, "width": int}` specifying the size of the output image.327            interpolation (`InterpolationMode`, *optional*, defaults to `InterpolationMode.BILINEAR`):328                `InterpolationMode` filter to use when resizing the image e.g. `InterpolationMode.BICUBIC`.329 330        Returns:331            `torch.Tensor`: The resized image.332        """333        interpolation = interpolation if interpolation is not None else F.InterpolationMode.BILINEAR334        if size.shortest_edge and size.longest_edge:335            # Resize the image so that the shortest edge or the longest edge is of the given size336            # while maintaining the aspect ratio of the original image.337            new_size = get_size_with_aspect_ratio(338                image.size()[-2:],339                size.shortest_edge,340                size.longest_edge,341            )342        elif size.shortest_edge:343            new_size = get_resize_output_image_size(344                image,345                size=size.shortest_edge,346                default_to_square=False,347                input_data_format=ChannelDimension.FIRST,348            )349        elif size.max_height and size.max_width:350            new_size = get_image_size_for_max_height_width(image.size()[-2:], size.max_height, size.max_width)351        elif size.height and size.width:352            new_size = (size.height, size.width)353        else:354            raise ValueError(355                "Size must contain 'height' and 'width' keys, or 'max_height' and 'max_width', or 'shortest_edge' key. Got"356                f" {size}."357            )358        # This is a workaround to avoid a bug in torch.compile when dealing with uint8 on AMD MI3XX GPUs359        # Tracked in PyTorch issue: https://github.com/pytorch/pytorch/issues/155209360        # TODO: remove this once the bug is fixed (detected with torch==2.7.0+git1fee196, torchvision==0.22.0+9eb57cd)361        if torch.compiler.is_compiling() and is_rocm_platform():362            return self.compile_friendly_resize(image, new_size, interpolation, antialias)363        return F.resize(image, new_size, interpolation=interpolation, antialias=antialias)364 365    @staticmethod366    def compile_friendly_resize(367        image: "torch.Tensor",368        new_size: tuple[int, int],369        interpolation: Optional["F.InterpolationMode"] = None,370        antialias: bool = True,371    ) -> "torch.Tensor":372        """373        A wrapper around `F.resize` so that it is compatible with torch.compile when the image is a uint8 tensor.374        """375        if image.dtype == torch.uint8:376            # 256 is used on purpose instead of 255 to avoid numerical differences377            # see https://github.com/huggingface/transformers/pull/38540#discussion_r2127165652378            image = image.float() / 256379            image = F.resize(image, new_size, interpolation=interpolation, antialias=antialias)380            image = image * 256381            # torch.where is used on purpose instead of torch.clamp to avoid bug in torch.compile382            # see https://github.com/huggingface/transformers/pull/38540#discussion_r2126888471383            image = torch.where(image > 255, 255, image)384            image = torch.where(image < 0, 0, image)385            image = image.round().to(torch.uint8)386        else:387            image = F.resize(image, new_size, interpolation=interpolation, antialias=antialias)388        return image389 390    def rescale(391        self,392        image: "torch.Tensor",393        scale: float,394        **kwargs,395    ) -> "torch.Tensor":396        """397        Rescale an image by a scale factor. image = image * scale.398 399        Args:400            image (`torch.Tensor`):401                Image to rescale.402            scale (`float`):403                The scaling factor to rescale pixel values by.404 405        Returns:406            `torch.Tensor`: The rescaled image.407        """408        return image * scale409 410    def normalize(411        self,412        image: "torch.Tensor",413        mean: Union[float, Iterable[float]],414        std: Union[float, Iterable[float]],415        **kwargs,416    ) -> "torch.Tensor":417        """418        Normalize an image. image = (image - image_mean) / image_std.419 420        Args:421            image (`torch.Tensor`):422                Image to normalize.423            mean (`torch.Tensor`, `float` or `Iterable[float]`):424                Image mean to use for normalization.425            std (`torch.Tensor`, `float` or `Iterable[float]`):426                Image standard deviation to use for normalization.427 428        Returns:429            `torch.Tensor`: The normalized image.430        """431        return F.normalize(image, mean, std)432 433    @lru_cache(maxsize=10)434    def _fuse_mean_std_and_rescale_factor(435        self,436        do_normalize: Optional[bool] = None,437        image_mean: Optional[Union[float, list[float]]] = None,438        image_std: Optional[Union[float, list[float]]] = None,439        do_rescale: Optional[bool] = None,440        rescale_factor: Optional[float] = None,441        device: Optional["torch.device"] = None,442    ) -> tuple:443        if do_rescale and do_normalize:444            # Fused rescale and normalize445            image_mean = torch.tensor(image_mean, device=device) * (1.0 / rescale_factor)446            image_std = torch.tensor(image_std, device=device) * (1.0 / rescale_factor)447            do_rescale = False448        return image_mean, image_std, do_rescale449 450    def rescale_and_normalize(451        self,452        images: "torch.Tensor",453        do_rescale: bool,454        rescale_factor: float,455        do_normalize: bool,456        image_mean: Union[float, list[float]],457        image_std: Union[float, list[float]],458    ) -> "torch.Tensor":459        """460        Rescale and normalize images.461        """462        image_mean, image_std, do_rescale = self._fuse_mean_std_and_rescale_factor(463            do_normalize=do_normalize,464            image_mean=image_mean,465            image_std=image_std,466            do_rescale=do_rescale,467            rescale_factor=rescale_factor,468            device=images.device,469        )470        # if/elif as we use fused rescale and normalize if both are set to True471        if do_normalize:472            images = self.normalize(images.to(dtype=torch.float32), image_mean, image_std)473        elif do_rescale:474            images = self.rescale(images, rescale_factor)475 476        return images477 478    def center_crop(479        self,480        image: "torch.Tensor",481        size: SizeDict,482        **kwargs,483    ) -> "torch.Tensor":484        """485        Note: override torchvision's center_crop to have the same behavior as the slow processor.486        Center crop an image to `(size["height"], size["width"])`. If the input size is smaller than `crop_size` along487        any edge, the image is padded with 0's and then center cropped.488 489        Args:490            image (`"torch.Tensor"`):491                Image to center crop.492            size (`dict[str, int]`):493                Size of the output image.494 495        Returns:496            `torch.Tensor`: The center cropped image.497        """498        if size.height is None or size.width is None:499            raise ValueError(f"The size dictionary must have keys 'height' and 'width'. Got {size.keys()}")500        image_height, image_width = image.shape[-2:]501        crop_height, crop_width = size.height, size.width502 503        if crop_width > image_width or crop_height > image_height:504            padding_ltrb = [505                (crop_width - image_width) // 2 if crop_width > image_width else 0,506                (crop_height - image_height) // 2 if crop_height > image_height else 0,507                (crop_width - image_width + 1) // 2 if crop_width > image_width else 0,508                (crop_height - image_height + 1) // 2 if crop_height > image_height else 0,509            ]510            image = F.pad(image, padding_ltrb, fill=0)  # PIL uses fill value 0511            image_height, image_width = image.shape[-2:]512            if crop_width == image_width and crop_height == image_height:513                return image514 515        crop_top = int((image_height - crop_height) / 2.0)516        crop_left = int((image_width - crop_width) / 2.0)517        return F.crop(image, crop_top, crop_left, crop_height, crop_width)518 519    def convert_to_rgb(520        self,521        image: ImageInput,522    ) -> ImageInput:523        """524        Converts an image to RGB format. Only converts if the image is of type PIL.Image.Image, otherwise returns the image525        as is.526        Args:527            image (ImageInput):528                The image to convert.529 530        Returns:531            ImageInput: The converted image.532        """533        return convert_to_rgb(image)534 535    def filter_out_unused_kwargs(self, kwargs: dict):536        """537        Filter out the unused kwargs from the kwargs dictionary.538        """539        if self.unused_kwargs is None:540            return kwargs541 542        for kwarg_name in self.unused_kwargs:543            if kwarg_name in kwargs:544                logger.warning_once(f"This processor does not use the `{kwarg_name}` parameter. It will be ignored.")545                kwargs.pop(kwarg_name)546        return kwargs547 548    def _prepare_images_structure(549        self,550        images: ImageInput,551        expected_ndims: int = 3,552    ) -> ImageInput:553        """554        Prepare the images structure for processing.555 556        Args:557            images (`ImageInput`):558                The input images to process.559 560        Returns:561            `ImageInput`: The images with a valid nesting.562        """563        # Checks for `str` in case of URL/local path and optionally loads images564        images = self.fetch_images(images)565        return make_flat_list_of_images(images, expected_ndims=expected_ndims)566 567    def _process_image(568        self,569        image: ImageInput,570        do_convert_rgb: Optional[bool] = None,571        input_data_format: Optional[Union[str, ChannelDimension]] = None,572        device: Optional["torch.device"] = None,573    ) -> "torch.Tensor":574        image_type = get_image_type(image)575        if image_type not in [ImageType.PIL, ImageType.TORCH, ImageType.NUMPY]:576            raise ValueError(f"Unsupported input image type {image_type}")577 578        if do_convert_rgb:579            image = self.convert_to_rgb(image)580 581        if image_type == ImageType.PIL:582            image = F.pil_to_tensor(image)583        elif image_type == ImageType.NUMPY:584            # not using F.to_tensor as it doesn't handle (C, H, W) numpy arrays585            image = torch.from_numpy(image).contiguous()586 587        # If the image is 2D, we need to unsqueeze it to add a channel dimension for processing588        if image.ndim == 2:589            image = image.unsqueeze(0)590 591        # Infer the channel dimension format if not provided592        if input_data_format is None:593            input_data_format = infer_channel_dimension_format(image)594 595        if input_data_format == ChannelDimension.LAST:596            # We force the channel dimension to be first for torch tensors as this is what torchvision expects.597            image = image.permute(2, 0, 1).contiguous()598 599        # Now that we have torch tensors, we can move them to the right device600        if device is not None:601            image = image.to(device)602 603        return image604 605    def _prepare_image_like_inputs(606        self,607        images: ImageInput,608        do_convert_rgb: Optional[bool] = None,609        input_data_format: Optional[Union[str, ChannelDimension]] = None,610        device: Optional["torch.device"] = None,611        expected_ndims: int = 3,612    ) -> list["torch.Tensor"]:613        """614        Prepare image-like inputs for processing.615 616        Args:617            images (`ImageInput`):618                The image-like inputs to process.619            do_convert_rgb (`bool`, *optional*):620                Whether to convert the images to RGB.621            input_data_format (`str` or `ChannelDimension`, *optional*):622                The input data format of the images.623            device (`torch.device`, *optional*):624                The device to put the processed images on.625            expected_ndims (`int`, *optional*):626                The expected number of dimensions for the images. (can be 2 for segmentation maps etc.)627 628        Returns:629            List[`torch.Tensor`]: The processed images.630        """631 632        # Get structured images (potentially nested)633        images = self._prepare_images_structure(images, expected_ndims=expected_ndims)634 635        process_image_partial = partial(636            self._process_image, do_convert_rgb=do_convert_rgb, input_data_format=input_data_format, device=device637        )638 639        # Check if we have nested structure, assuming the nesting is consistent640        has_nested_structure = len(images) > 0 and isinstance(images[0], (list, tuple))641 642        if has_nested_structure:643            processed_images = [[process_image_partial(img) for img in nested_list] for nested_list in images]644        else:645            processed_images = [process_image_partial(img) for img in images]646 647        return processed_images648 649    def _further_process_kwargs(650        self,651        size: Optional[SizeDict] = None,652        crop_size: Optional[SizeDict] = None,653        pad_size: Optional[SizeDict] = None,654        default_to_square: Optional[bool] = None,655        image_mean: Optional[Union[float, list[float]]] = None,656        image_std: Optional[Union[float, list[float]]] = None,657        data_format: Optional[ChannelDimension] = None,658        **kwargs,659    ) -> dict:660        """661        Update kwargs that need further processing before being validated662        Can be overridden by subclasses to customize the processing of kwargs.663        """664        if kwargs is None:665            kwargs = {}666        if size is not None:667            size = SizeDict(**get_size_dict(size=size, default_to_square=default_to_square))668        if crop_size is not None:669            crop_size = SizeDict(**get_size_dict(crop_size, param_name="crop_size"))670        if pad_size is not None:671            pad_size = SizeDict(**get_size_dict(size=pad_size, param_name="pad_size"))672        if isinstance(image_mean, list):673            image_mean = tuple(image_mean)674        if isinstance(image_std, list):675            image_std = tuple(image_std)676        if data_format is None:677            data_format = ChannelDimension.FIRST678 679        kwargs["size"] = size680        kwargs["crop_size"] = crop_size681        kwargs["pad_size"] = pad_size682        kwargs["image_mean"] = image_mean683        kwargs["image_std"] = image_std684        kwargs["data_format"] = data_format685 686        # torch resize uses interpolation instead of resample687        # Check if resample is an int before checking if it's an instance of PILImageResampling688        # because if pillow < 9.1.0, resample is an int and PILImageResampling is a module.689        # Checking PILImageResampling will fail with error `TypeError: isinstance() arg 2 must be a type or tuple of types`.690        resample = kwargs.pop("resample")691        kwargs["interpolation"] = (692            pil_torch_interpolation_mapping[resample] if isinstance(resample, (PILImageResampling, int)) else resample693        )694 695        return kwargs696 697    def _validate_preprocess_kwargs(698        self,699        do_rescale: Optional[bool] = None,700        rescale_factor: Optional[float] = None,701        do_normalize: Optional[bool] = None,702        image_mean: Optional[Union[float, tuple[float]]] = None,703        image_std: Optional[Union[float, tuple[float]]] = None,704        do_resize: Optional[bool] = None,705        size: Optional[SizeDict] = None,706        do_center_crop: Optional[bool] = None,707        crop_size: Optional[SizeDict] = None,708        interpolation: Optional["F.InterpolationMode"] = None,709        return_tensors: Optional[Union[str, TensorType]] = None,710        data_format: Optional[ChannelDimension] = None,711        **kwargs,712    ):713        """714        validate the kwargs for the preprocess method.715        """716        validate_fast_preprocess_arguments(717            do_rescale=do_rescale,718            rescale_factor=rescale_factor,719            do_normalize=do_normalize,720            image_mean=image_mean,721            image_std=image_std,722            do_resize=do_resize,723            size=size,724            do_center_crop=do_center_crop,725            crop_size=crop_size,726            interpolation=interpolation,727            return_tensors=return_tensors,728            data_format=data_format,729        )730 731    def __call__(self, images: ImageInput, *args, **kwargs: Unpack[DefaultFastImageProcessorKwargs]) -> BatchFeature:732        return self.preprocess(images, *args, **kwargs)733 734    @auto_docstring735    def preprocess(self, images: ImageInput, *args, **kwargs: Unpack[DefaultFastImageProcessorKwargs]) -> BatchFeature:736        # args are not validated, but their order in the `preprocess` and `_preprocess` signatures must be the same737        validate_kwargs(captured_kwargs=kwargs.keys(), valid_processor_keys=self._valid_kwargs_names)738        # Set default kwargs from self. This ensures that if a kwarg is not provided739        # by the user, it gets its default value from the instance, or is set to None.740        for kwarg_name in self._valid_kwargs_names:741            kwargs.setdefault(kwarg_name, getattr(self, kwarg_name, None))742 743        # Extract parameters that are only used for preparing the input images744        do_convert_rgb = kwargs.pop("do_convert_rgb")745        input_data_format = kwargs.pop("input_data_format")746        device = kwargs.pop("device")747 748        # Update kwargs that need further processing before being validated749        kwargs = self._further_process_kwargs(**kwargs)750 751        # Validate kwargs752        self._validate_preprocess_kwargs(**kwargs)753 754        # Pop kwargs that are not needed in _preprocess755        kwargs.pop("data_format")756 757        return self._preprocess_image_like_inputs(758            images, *args, do_convert_rgb=do_convert_rgb, input_data_format=input_data_format, device=device, **kwargs759        )760 761    def _preprocess_image_like_inputs(762        self,763        images: ImageInput,764        *args,765        do_convert_rgb: bool,766        input_data_format: ChannelDimension,767        device: Optional[Union[str, "torch.device"]] = None,768        **kwargs: Unpack[DefaultFastImageProcessorKwargs],769    ) -> BatchFeature:770        """771        Preprocess image-like inputs.772        To be overridden by subclasses when image-like inputs other than images should be processed.773        It can be used for segmentation maps, depth maps, etc.774        """775        # Prepare input images776        images = self._prepare_image_like_inputs(777            images=images, do_convert_rgb=do_convert_rgb, input_data_format=input_data_format, device=device778        )779        return self._preprocess(images, *args, **kwargs)780 781    def _preprocess(782        self,783        images: list["torch.Tensor"],784        do_resize: bool,785        size: SizeDict,786        interpolation: Optional["F.InterpolationMode"],787        do_center_crop: bool,788        crop_size: SizeDict,789        do_rescale: bool,790        rescale_factor: float,791        do_normalize: bool,792        image_mean: Optional[Union[float, list[float]]],793        image_std: Optional[Union[float, list[float]]],794        do_pad: Optional[bool],795        pad_size: Optional[SizeDict],796        disable_grouping: Optional[bool],797        return_tensors: Optional[Union[str, TensorType]],798        **kwargs,799    ) -> BatchFeature:800        # Group images by size for batched resizing801        grouped_images, grouped_images_index = group_images_by_shape(images, disable_grouping=disable_grouping)802        resized_images_grouped = {}803        for shape, stacked_images in grouped_images.items():804            if do_resize:805                stacked_images = self.resize(image=stacked_images, size=size, interpolation=interpolation)806            resized_images_grouped[shape] = stacked_images807        resized_images = reorder_images(resized_images_grouped, grouped_images_index)808 809        # Group images by size for further processing810        # Needed in case do_resize is False, or resize returns images with different sizes811        grouped_images, grouped_images_index = group_images_by_shape(resized_images, disable_grouping=disable_grouping)812        processed_images_grouped = {}813        for shape, stacked_images in grouped_images.items():814            if do_center_crop:815                stacked_images = self.center_crop(stacked_images, crop_size)816            # Fused rescale and normalize817            stacked_images = self.rescale_and_normalize(818                stacked_images, do_rescale, rescale_factor, do_normalize, image_mean, image_std819            )820            processed_images_grouped[shape] = stacked_images821        processed_images = reorder_images(processed_images_grouped, grouped_images_index)822 823        if do_pad:824            processed_images = self.pad(processed_images, pad_size=pad_size, disable_grouping=disable_grouping)825 826        processed_images = torch.stack(processed_images, dim=0) if return_tensors else processed_images827        return BatchFeature(data={"pixel_values": processed_images}, tensor_type=return_tensors)828 829    def to_dict(self):830        encoder_dict = super().to_dict()831        encoder_dict.pop("_valid_processor_keys", None)832        encoder_dict.pop("_valid_kwargs_names", None)833        return encoder_dict834 
Aluode/PerceptionLabPortable · CoolFace