codingutf8 2023 the huggingface inc team licensed under the apache license version 2 0 the license you may not use this file except in compliance with the license you may obtain a copy of the license at http www apache orglicenseslicense2 0 unless required by applicable law or agreed to in writing software distributed under the license is distributed on an as is basis without warranties or conditions of any kind either express or implied see the license for the specific language governing permissions and limitations under the license image processor class for owlv2 import warnings from typing import dict list optional tuple union import numpy as np from imageprocessingutils import baseimageprocessor batchfeature from imagetransforms import centertocornersformat pad tochanneldimensionformat from imageutils import openaiclipmean openaiclipstd channeldimension imageinput pilimageresampling getimagesize inferchanneldimensionformat isscaledimage makelistofimages tonumpyarray validimages from utils import tensortype isscipyavailable istorchavailable isvisionavailable logging requiresbackends if istorchavailable import torch if isvisionavailable import pil if isscipyavailable from scipy import ndimage as ndi logger logging getloggername copied from transformers models owlvit imageprocessingowlvit upcast def upcastt protects from numerical overflows in multiplications by upcasting to the equivalent higher type if t isfloatingpoint return t if t dtype in torch float32 torch float64 else t float else return t if t dtype in torch int32 torch int64 else t int copied from transformers models owlvit imageprocessingowlvit boxarea def boxareaboxes boxes upcastboxes return boxes 2 boxes 0 boxes 3 boxes 1 copied from transformers models owlvit imageprocessingowlvit boxiou def boxiouboxes1 boxes2 area1 boxareaboxes1 area2 boxareaboxes2 lefttop torch maxboxes1 none 2 boxes2 2 n m 2 rightbottom torch minboxes1 none 2 boxes2 2 n m 2 widthheight rightbottom lefttop clampmin0 n m 2 inter widthheight 0 widthheight 1 n m union area1 none area2 inter iou inter union return iou union def preprocessresizeoutputshapeimage outputshape outputshape tupleoutputshape outputndim lenoutputshape inputshape image shape if outputndim image ndim append dimensions to inputshape inputshape 1 outputndim image ndim image np reshapeimage inputshape elif outputndim image ndim 1 multichannel case append shape of last axis outputshape outputshape image shape1 elif outputndim image ndim raise valueerroroutputshape length cannot be smaller than the image number of dimensions return image outputshape def clipwarpoutputinputimage outputimage minval np mininputimage if np isnanminval nans detected use nansafe minmax minfunc np nanmin maxfunc np nanmax minval minfuncinputimage else minfunc np min maxfunc np max maxval maxfuncinputimage outputimage np clipoutputimage minval maxval return outputimage class owlv2imageprocessorbaseimageprocessor r constructs an owlv2 image processor args dorescale bool optional defaults to true whether to rescale the image by the specified scale rescalefactor can be overriden by dorescale in the preprocess method rescalefactor int or float optional defaults to 1255 scale factor to use if rescaling the image can be overriden by rescalefactor in the preprocess method dopad bool optional defaults to true whether to pad the image to a square with gray pixels on the bottom and the right can be overriden by dopad in the preprocess method doresize bool optional defaults to true controls whether to resize the image s height width dimensions to the specified size can be overriden by doresize in the preprocess method size dictstr int optional defaults to height 960 width 960 size to resize the image to can be overriden by size in the preprocess method resample pilimageresampling optional defaults to resampling bilinear resampling method to use if resizing the image can be overriden by resample in the preprocess method donormalize bool optional defaults to true whether to normalize the image can be overridden by the donormalize parameter in the preprocess method imagemean float or listfloat optional defaults to openaiclipmean mean to use if normalizing the image this is a float or list of floats the length of the number of channels in the image can be overridden by the imagemean parameter in the preprocess method imagestd float or listfloat optional defaults to openaiclipstd standard deviation to use if normalizing the image this is a float or list of floats the length of the number of channels in the image can be overridden by the imagestd parameter in the preprocess method pad an image to a square with gray pixels on the bottom and the right as per the original owlv2 implementation args image np ndarray image to pad dataformat str or channeldimension optional the channel dimension format of the image if not provided it will be the same as the input image inputdataformat channeldimension or str optional the channel dimension format of the input image if not provided it will be inferred from the input image resize an image as per the original implementation args image np ndarray image to resize size dictstr int dictionary containing the height and width to resize the image to antialiasing bool optional defaults to true whether to apply antialiasing when downsampling the image antialiasingsigma float optional defaults to none standard deviation for gaussian kernel when downsampling the image if none it will be calculated automatically dataformat str or channeldimension optional the channel dimension format of the image if not provided it will be the same as the input image inputdataformat channeldimension or str optional the channel dimension format of the input image if not provided it will be inferred from the input image translate modes used by np pad to those used by scipy ndimage preprocess an image or batch of images args images imageinput image to preprocess expects a single or batch of images with pixel values ranging from 0 to 255 if passing in images with pixel values between 0 and 1 set dorescalefalse dopad bool optional defaults to self dopad whether to pad the image to a square with gray pixels on the bottom and the right doresize bool optional defaults to self doresize whether to resize the image size dictstr int optional defaults to self size size to resize the image to dorescale bool optional defaults to self dorescale whether to rescale the image values between 0 1 rescalefactor float optional defaults to self rescalefactor rescale factor to rescale the image by if dorescale is set to true donormalize bool optional defaults to self donormalize whether to normalize the image imagemean float or listfloat optional defaults to self imagemean image mean imagestd float or listfloat optional defaults to self imagestd image standard deviation returntensors str or tensortype optional the type of tensors to return can be one of unset return a list of np ndarray tensortype tensorflow or tf return a batch of type tf tensor tensortype pytorch or pt return a batch of type torch tensor tensortype numpy or np return a batch of type np ndarray tensortype jax or jax return a batch of type jax numpy ndarray dataformat channeldimension or str optional defaults to channeldimension first the channel dimension format for the output image can be one of channelsfirst or channeldimension first image in numchannels height width format channelslast or channeldimension last image in height width numchannels format unset use the channel dimension format of the input image inputdataformat channeldimension or str optional the channel dimension format for the input image if unset the channel dimension format is inferred from the input image can be one of channelsfirst or channeldimension first image in numchannels height width format channelslast or channeldimension last image in height width numchannels format none or channeldimension none image in height width format all transformations expect numpy arrays we assume that all images have the same channel dimension format copied from transformers models owlvit imageprocessingowlvit owlvitimageprocessor postprocessobjectdetection converts the raw output of owlvitforobjectdetection into final bounding boxes in topleftx toplefty bottomrightx bottomrighty format args outputs owlvitobjectdetectionoutput raw outputs of the model threshold float optional score threshold to keep object detection predictions targetsizes torch tensor or listtupleint int optional tensor of shape batchsize 2 or list of tuples tupleint int containing the target size height width of each image in the batch if unset predictions will not be resized returns listdict a list of dictionaries each dictionary containing the scores labels and boxes for an image in the batch as predicted by the model todo amy add support for other frameworks convert to x0 y0 x1 y1 format convert from relative 0 1 to absolute 0 height coordinates copied from transformers models owlvit imageprocessingowlvit owlvitimageprocessor postprocessimageguideddetection converts the output of owlvitforobjectdetection imageguideddetection into the format expected by the coco api args outputs owlvitimageguidedobjectdetectionoutput raw outputs of the model threshold float optional defaults to 0 0 minimum confidence threshold to use to filter out predicted boxes nmsthreshold float optional defaults to 0 3 iou threshold for nonmaximum suppression of overlapping boxes targetsizes torch tensor optional tensor of shape batchsize 2 where each entry is the height width of the corresponding image in the batch if set predicted normalized bounding boxes are rescaled to the target sizes if left to none predictions will not be unnormalized returns listdict a list of dictionaries each dictionary containing the scores labels and boxes for an image in the batch as predicted by the model all labels are set to none as owlvitforobjectdetection imageguideddetection perform oneshot object detection convert to x0 y0 x1 y1 format apply nonmaximum suppression nms convert from relative 0 1 to absolute 0 height coordinates compute box display alphas based on prediction scores select scores for boxes matching the current query apply threshold on scores before scaling scale box alpha such that the best box for each query has alpha 1 0 and the worst box has alpha 0 1 all other boxes will either belong to a different query or will not be shown coding utf 8 2023 the huggingface inc team licensed under the apache license version 2 0 the license you may not use this file except in compliance with the license you may obtain a copy of the license at http www apache org licenses license 2 0 unless required by applicable law or agreed to in writing software distributed under the license is distributed on an as is basis without warranties or conditions of any kind either express or implied see the license for the specific language governing permissions and limitations under the license image processor class for owlv2 copied from transformers models owlvit image_processing_owlvit _upcast protects from numerical overflows in multiplications by upcasting to the equivalent higher type copied from transformers models owlvit image_processing_owlvit box_area computes the area of a set of bounding boxes which are specified by its x1 y1 x2 y2 coordinates args boxes torch floattensor of shape number_of_boxes 4 boxes for which the area will be computed they are expected to be in x1 y1 x2 y2 format with 0 x1 x2 and 0 y1 y2 returns torch floattensor a tensor containing the area for each box copied from transformers models owlvit image_processing_owlvit box_iou n m 2 n m 2 n m 2 n m validate resize output shape according to input image args image np ndarray image to be resized output_shape iterable size of the generated output image rows cols dim if dim is not provided the number of channels is preserved returns image np ndarray the input image but with additional singleton dimensions appended in the case where len output_shape input ndim output_shape tuple the output shape converted to tuple raises valueerror if output_shape length is smaller than the image number of dimensions notes the input image is reshaped if its number of dimensions is not equal to output_shape_length append dimensions to input_shape multichannel case append shape of last axis clip output image to range of values of input image note that this function modifies the values of output_image in place taken from https github com scikit image scikit image blob b4b521d6f0a105aabeaa31699949f78453ca3511 skimage transform _warps py l640 args input_image ndarray input image output_image ndarray output image which is modified in place nans detected use nan safe min max constructs an owlv2 image processor args do_rescale bool optional defaults to true whether to rescale the image by the specified scale rescale_factor can be overriden by do_rescale in the preprocess method rescale_factor int or float optional defaults to 1 255 scale factor to use if rescaling the image can be overriden by rescale_factor in the preprocess method do_pad bool optional defaults to true whether to pad the image to a square with gray pixels on the bottom and the right can be overriden by do_pad in the preprocess method do_resize bool optional defaults to true controls whether to resize the image s height width dimensions to the specified size can be overriden by do_resize in the preprocess method size dict str int optional defaults to height 960 width 960 size to resize the image to can be overriden by size in the preprocess method resample pilimageresampling optional defaults to resampling bilinear resampling method to use if resizing the image can be overriden by resample in the preprocess method do_normalize bool optional defaults to true whether to normalize the image can be overridden by the do_normalize parameter in the preprocess method image_mean float or list float optional defaults to openai_clip_mean mean to use if normalizing the image this is a float or list of floats the length of the number of channels in the image can be overridden by the image_mean parameter in the preprocess method image_std float or list float optional defaults to openai_clip_std standard deviation to use if normalizing the image this is a float or list of floats the length of the number of channels in the image can be overridden by the image_std parameter in the preprocess method pad an image to a square with gray pixels on the bottom and the right as per the original owlv2 implementation args image np ndarray image to pad data_format str or channeldimension optional the channel dimension format of the image if not provided it will be the same as the input image input_data_format channeldimension or str optional the channel dimension format of the input image if not provided it will be inferred from the input image resize an image as per the original implementation args image np ndarray image to resize size dict str int dictionary containing the height and width to resize the image to anti_aliasing bool optional defaults to true whether to apply anti aliasing when downsampling the image anti_aliasing_sigma float optional defaults to none standard deviation for gaussian kernel when downsampling the image if none it will be calculated automatically data_format str or channeldimension optional the channel dimension format of the image if not provided it will be the same as the input image input_data_format channeldimension or str optional the channel dimension format of the input image if not provided it will be inferred from the input image translate modes used by np pad to those used by scipy ndimage preprocess an image or batch of images args images imageinput image to preprocess expects a single or batch of images with pixel values ranging from 0 to 255 if passing in images with pixel values between 0 and 1 set do_rescale false do_pad bool optional defaults to self do_pad whether to pad the image to a square with gray pixels on the bottom and the right do_resize bool optional defaults to self do_resize whether to resize the image size dict str int optional defaults to self size size to resize the image to do_rescale bool optional defaults to self do_rescale whether to rescale the image values between 0 1 rescale_factor float optional defaults to self rescale_factor rescale factor to rescale the image by if do_rescale is set to true do_normalize bool optional defaults to self do_normalize whether to normalize the image image_mean float or list float optional defaults to self image_mean image mean image_std float or list float optional defaults to self image_std image standard deviation return_tensors str or tensortype optional the type of tensors to return can be one of unset return a list of np ndarray tensortype tensorflow or tf return a batch of type tf tensor tensortype pytorch or pt return a batch of type torch tensor tensortype numpy or np return a batch of type np ndarray tensortype jax or jax return a batch of type jax numpy ndarray data_format channeldimension or str optional defaults to channeldimension first the channel dimension format for the output image can be one of channels_first or channeldimension first image in num_channels height width format channels_last or channeldimension last image in height width num_channels format unset use the channel dimension format of the input image input_data_format channeldimension or str optional the channel dimension format for the input image if unset the channel dimension format is inferred from the input image can be one of channels_first or channeldimension first image in num_channels height width format channels_last or channeldimension last image in height width num_channels format none or channeldimension none image in height width format all transformations expect numpy arrays we assume that all images have the same channel dimension format copied from transformers models owlvit image_processing_owlvit owlvitimageprocessor post_process_object_detection converts the raw output of owlvitforobjectdetection into final bounding boxes in top_left_x top_left_y bottom_right_x bottom_right_y format args outputs owlvitobjectdetectionoutput raw outputs of the model threshold float optional score threshold to keep object detection predictions target_sizes torch tensor or list tuple int int optional tensor of shape batch_size 2 or list of tuples tuple int int containing the target size height width of each image in the batch if unset predictions will not be resized returns list dict a list of dictionaries each dictionary containing the scores labels and boxes for an image in the batch as predicted by the model todo amy add support for other frameworks convert to x0 y0 x1 y1 format convert from relative 0 1 to absolute 0 height coordinates copied from transformers models owlvit image_processing_owlvit owlvitimageprocessor post_process_image_guided_detection converts the output of owlvitforobjectdetection image_guided_detection into the format expected by the coco api args outputs owlvitimageguidedobjectdetectionoutput raw outputs of the model threshold float optional defaults to 0 0 minimum confidence threshold to use to filter out predicted boxes nms_threshold float optional defaults to 0 3 iou threshold for non maximum suppression of overlapping boxes target_sizes torch tensor optional tensor of shape batch_size 2 where each entry is the height width of the corresponding image in the batch if set predicted normalized bounding boxes are rescaled to the target sizes if left to none predictions will not be unnormalized returns list dict a list of dictionaries each dictionary containing the scores labels and boxes for an image in the batch as predicted by the model all labels are set to none as owlvitforobjectdetection image_guided_detection perform one shot object detection convert to x0 y0 x1 y1 format apply non maximum suppression nms mask self iou convert from relative 0 1 to absolute 0 height coordinates compute box display alphas based on prediction scores select scores for boxes matching the current query apply threshold on scores before scaling scale box alpha such that the best box for each query has alpha 1 0 and the worst box has alpha 0 1 all other boxes will either belong to a different query or will not be shown
import warnings
from typing import Dict, List, Optional, Tuple, Union

import numpy as np

from ...image_processing_utils import BaseImageProcessor, BatchFeature
from ...image_transforms import (
    center_to_corners_format,
    pad,
    to_channel_dimension_format,
)
from ...image_utils import (
    OPENAI_CLIP_MEAN,
    OPENAI_CLIP_STD,
    ChannelDimension,
    ImageInput,
    PILImageResampling,
    get_image_size,
    infer_channel_dimension_format,
    is_scaled_image,
    make_list_of_images,
    to_numpy_array,
    valid_images,
)
from ...utils import (
    TensorType,
    is_scipy_available,
    is_torch_available,
    is_vision_available,
    logging,
    requires_backends,
)


if is_torch_available():
    import torch


if is_vision_available():
    import PIL

if is_scipy_available():
    from scipy import ndimage as ndi


logger = logging.get_logger(__name__)



def _upcast(t):
    
    if t.is_floating_point():
        return t if t.dtype in (torch.float32, torch.float64) else t.float()
    else:
        return t if t.dtype in (torch.int32, torch.int64) else t.int()



def box_area(boxes):
    
    boxes = _upcast(boxes)
    return (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])



def box_iou(boxes1, boxes2):
    area1 = box_area(boxes1)
    area2 = box_area(boxes2)

    left_top = torch.max(boxes1[:, None, :2], boxes2[:, :2])  
    right_bottom = torch.min(boxes1[:, None, 2:], boxes2[:, 2:])  

    width_height = (right_bottom - left_top).clamp(min=0)  
    inter = width_height[:, :, 0] * width_height[:, :, 1]  

    union = area1[:, None] + area2 - inter

    iou = inter / union
    return iou, union


def _preprocess_resize_output_shape(image, output_shape):
    
    output_shape = tuple(output_shape)
    output_ndim = len(output_shape)
    input_shape = image.shape
    if output_ndim > image.ndim:
        
        input_shape += (1,) * (output_ndim - image.ndim)
        image = np.reshape(image, input_shape)
    elif output_ndim == image.ndim - 1:
        
        output_shape = output_shape + (image.shape[-1],)
    elif output_ndim < image.ndim:
        raise ValueError("output_shape length cannot be smaller than the " "image number of dimensions")

    return image, output_shape


def _clip_warp_output(input_image, output_image):
    
    min_val = np.min(input_image)
    if np.isnan(min_val):
        
        min_func = np.nanmin
        max_func = np.nanmax
        min_val = min_func(input_image)
    else:
        min_func = np.min
        max_func = np.max
    max_val = max_func(input_image)

    output_image = np.clip(output_image, min_val, max_val)

    return output_image


class Owlv2ImageProcessor(BaseImageProcessor):
    r

    model_input_names = ["pixel_values"]

    def __init__(
        self,
        do_rescale: bool = True,
        rescale_factor: Union[int, float] = 1 / 255,
        do_pad: bool = True,
        do_resize: bool = True,
        size: Dict[str, int] = None,
        resample: PILImageResampling = PILImageResampling.BILINEAR,
        do_normalize: bool = True,
        image_mean: Optional[Union[float, List[float]]] = None,
        image_std: Optional[Union[float, List[float]]] = None,
        **kwargs,
    ) -> None:
        super().__init__(**kwargs)

        self.do_rescale = do_rescale
        self.rescale_factor = rescale_factor
        self.do_pad = do_pad
        self.do_resize = do_resize
        self.size = size if size is not None else {"height": 960, "width": 960}
        self.resample = resample
        self.do_normalize = do_normalize
        self.image_mean = image_mean if image_mean is not None else OPENAI_CLIP_MEAN
        self.image_std = image_std if image_std is not None else OPENAI_CLIP_STD

    def pad(
        self,
        image: np.array,
        data_format: Optional[Union[str, ChannelDimension]] = None,
        input_data_format: Optional[Union[str, ChannelDimension]] = None,
    ):
        
        height, width = get_image_size(image)
        size = max(height, width)
        image = pad(
            image=image,
            padding=((0, size - height), (0, size - width)),
            constant_values=0.5,
            data_format=data_format,
            input_data_format=input_data_format,
        )

        return image

    def resize(
        self,
        image: np.ndarray,
        size: Dict[str, int],
        anti_aliasing: bool = True,
        anti_aliasing_sigma=None,
        data_format: Optional[Union[str, ChannelDimension]] = None,
        input_data_format: Optional[Union[str, ChannelDimension]] = None,
        **kwargs,
    ) -> np.ndarray:
        
        requires_backends(self, "scipy")

        output_shape = (size["height"], size["width"])
        image = to_channel_dimension_format(image, ChannelDimension.LAST)
        image, output_shape = _preprocess_resize_output_shape(image, output_shape)
        input_shape = image.shape
        factors = np.divide(input_shape, output_shape)

        
        ndi_mode = "mirror"
        cval = 0
        order = 1
        if anti_aliasing:
            if anti_aliasing_sigma is None:
                anti_aliasing_sigma = np.maximum(0, (factors - 1) / 2)
            else:
                anti_aliasing_sigma = np.atleast_1d(anti_aliasing_sigma) * np.ones_like(factors)
                if np.any(anti_aliasing_sigma < 0):
                    raise ValueError("Anti-aliasing standard deviation must be " "greater than or equal to zero")
                elif np.any((anti_aliasing_sigma > 0) & (factors <= 1)):
                    warnings.warn(
                        "Anti-aliasing standard deviation greater than zero but " "not down-sampling along all axes"
                    )
            filtered = ndi.gaussian_filter(image, anti_aliasing_sigma, cval=cval, mode=ndi_mode)
        else:
            filtered = image

        zoom_factors = [1 / f for f in factors]
        out = ndi.zoom(filtered, zoom_factors, order=order, mode=ndi_mode, cval=cval, grid_mode=True)

        image = _clip_warp_output(image, out)

        image = to_channel_dimension_format(image, input_data_format, ChannelDimension.LAST)
        image = (
            to_channel_dimension_format(image, data_format, input_data_format) if data_format is not None else image
        )
        return image

    def preprocess(
        self,
        images: ImageInput,
        do_pad: bool = None,
        do_resize: bool = None,
        size: Dict[str, int] = None,
        do_rescale: bool = None,
        rescale_factor: float = None,
        do_normalize: bool = None,
        image_mean: Optional[Union[float, List[float]]] = None,
        image_std: Optional[Union[float, List[float]]] = None,
        return_tensors: Optional[Union[str, TensorType]] = None,
        data_format: ChannelDimension = ChannelDimension.FIRST,
        input_data_format: Optional[Union[str, ChannelDimension]] = None,
        **kwargs,
    ) -> PIL.Image.Image:
        
        do_rescale = do_rescale if do_rescale is not None else self.do_rescale
        rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
        do_pad = do_pad if do_pad is not None else self.do_pad
        do_resize = do_resize if do_resize is not None else self.do_resize
        do_normalize = do_normalize if do_normalize is not None else self.do_normalize
        image_mean = image_mean if image_mean is not None else self.image_mean
        image_std = image_std if image_std is not None else self.image_std

        size = size if size is not None else self.size

        images = make_list_of_images(images)

        if not valid_images(images):
            raise ValueError(
                "Invalid image type. Must be of type PIL.Image.Image, numpy.ndarray, "
                "torch.Tensor, tf.Tensor or jax.ndarray."
            )

        if do_resize and size is None:
            raise ValueError("Size must be specified if do_resize is True.")

        if do_rescale and rescale_factor is None:
            raise ValueError("Rescale factor must be specified if do_rescale is True.")

        if do_normalize and (image_mean is None or image_std is None):
            raise ValueError("Image mean and std must be specified if do_normalize is True.")

        
        images = [to_numpy_array(image) for image in images]

        if is_scaled_image(images[0]) and do_rescale:
            logger.warning_once(
                "It looks like you are trying to rescale already rescaled images. If the input"
                " images have pixel values between 0 and 1, set `do_rescale=False` to avoid rescaling them again."
            )

        if input_data_format is None:
            
            input_data_format = infer_channel_dimension_format(images[0])

        if do_rescale:
            images = [
                self.rescale(image=image, scale=rescale_factor, input_data_format=input_data_format)
                for image in images
            ]

        if do_pad:
            images = [self.pad(image=image, input_data_format=input_data_format) for image in images]

        if do_resize:
            images = [
                self.resize(
                    image=image,
                    size=size,
                    input_data_format=input_data_format,
                )
                for image in images
            ]

        if do_normalize:
            images = [
                self.normalize(image=image, mean=image_mean, std=image_std, input_data_format=input_data_format)
                for image in images
            ]

        images = [
            to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format) for image in images
        ]

        data = {"pixel_values": images}
        return BatchFeature(data=data, tensor_type=return_tensors)

    
    def post_process_object_detection(
        self, outputs, threshold: float = 0.1, target_sizes: Union[TensorType, List[Tuple]] = None
    ):
        
        
        logits, boxes = outputs.logits, outputs.pred_boxes

        if target_sizes is not None:
            if len(logits) != len(target_sizes):
                raise ValueError(
                    "Make sure that you pass in as many target sizes as the batch dimension of the logits"
                )

        probs = torch.max(logits, dim=-1)
        scores = torch.sigmoid(probs.values)
        labels = probs.indices

        
        boxes = center_to_corners_format(boxes)

        
        if target_sizes is not None:
            if isinstance(target_sizes, List):
                img_h = torch.Tensor([i[0] for i in target_sizes])
                img_w = torch.Tensor([i[1] for i in target_sizes])
            else:
                img_h, img_w = target_sizes.unbind(1)

            scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(boxes.device)
            boxes = boxes * scale_fct[:, None, :]

        results = []
        for s, l, b in zip(scores, labels, boxes):
            score = s[s > threshold]
            label = l[s > threshold]
            box = b[s > threshold]
            results.append({"scores": score, "labels": label, "boxes": box})

        return results

    
    def post_process_image_guided_detection(self, outputs, threshold=0.0, nms_threshold=0.3, target_sizes=None):
        
        logits, target_boxes = outputs.logits, outputs.target_pred_boxes

        if len(logits) != len(target_sizes):
            raise ValueError("Make sure that you pass in as many target sizes as the batch dimension of the logits")
        if target_sizes.shape[1] != 2:
            raise ValueError("Each element of target_sizes must contain the size (h, w) of each image of the batch")

        probs = torch.max(logits, dim=-1)
        scores = torch.sigmoid(probs.values)

        
        target_boxes = center_to_corners_format(target_boxes)

        
        if nms_threshold < 1.0:
            for idx in range(target_boxes.shape[0]):
                for i in torch.argsort(-scores[idx]):
                    if not scores[idx][i]:
                        continue

                    ious = box_iou(target_boxes[idx][i, :].unsqueeze(0), target_boxes[idx])[0][0]
                    ious[i] = -1.0  
                    scores[idx][ious > nms_threshold] = 0.0

        
        img_h, img_w = target_sizes.unbind(1)
        scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(target_boxes.device)
        target_boxes = target_boxes * scale_fct[:, None, :]

        
        results = []
        alphas = torch.zeros_like(scores)

        for idx in range(target_boxes.shape[0]):
            
            query_scores = scores[idx]
            if not query_scores.nonzero().numel():
                continue

            
            query_scores[query_scores < threshold] = 0.0

            
            
            max_score = torch.max(query_scores) + 1e-6
            query_alphas = (query_scores - (max_score * 0.1)) / (max_score * 0.9)
            query_alphas = torch.clip(query_alphas, 0.0, 1.0)
            alphas[idx] = query_alphas

            mask = alphas[idx] > 0
            box_scores = alphas[idx][mask]
            boxes = target_boxes[idx][mask]
            results.append({"scores": box_scores, "labels": None, "boxes": boxes})

        return results