o
    e0                     @   s~   d dl mZmZ d dlmZmZmZ d dlZd dl	m
Z
mZ d dlmZ d dlmZ de
dejd	e
fd
dZG dd dZdS )    )ThreadPoolExecutoras_completed)CallableOptionalTupleN)
Detectionsvalidate_inference_callback)
move_boxes)
crop_image
detectionsoffsetreturnc                 C   s   t | j|d| _| S )a	  
    Args:
        detections (sv.Detections): Detections object to be moved.
        offset (np.array): An array of shape `(2,)` containing offset values in format
            is `[dx, dy]`.
    Returns:
        (sv.Detections) repositioned Detections object.
    )xyxyr   )r	   r   r   r    r   [/var/www/myenv/lib/python3.10/site-packages/supervision/detection/tools/inference_slicer.pymove_detections   s   	r   c                   @   s   e Zd ZdZ				ddeejgef dee	e	f dee
e
f d	ee
 d
e	f
ddZdejdefddZdefddZedee	e	f dee	e	f dee
e
f dejfddZdS )InferenceSlicera  
    InferenceSlicer performs slicing-based inference for small target detection. This
    method, often referred to as
    [Slicing Adaptive Inference (SAHI)](https://ieeexplore.ieee.org/document/9897990),
    involves dividing a larger image into smaller slices, performing inference on each
    slice, and then merging the detections.

    Args:
        slice_wh (Tuple[int, int]): Dimensions of each slice in the format
            `(width, height)`.
        overlap_ratio_wh (Tuple[float, float]): Overlap ratio between consecutive
            slices in the format `(width_ratio, height_ratio)`.
        iou_threshold (Optional[float]): Intersection over Union (IoU) threshold
            used for non-max suppression.
        callback (Callable): A function that performs inference on a given image
            slice and returns detections.
        thread_workers (int): Number of threads for parallel execution.

    Note:
        The class ensures that slices do not exceed the boundaries of the original
        image. As a result, the final slices in the row and column dimensions might be
        smaller than the specified slice dimensions if the image's width or height is
        not a multiple of the slice's width or height minus the overlap.
    @  r   皙?r         ?   callbackslice_whoverlap_ratio_whiou_thresholdthread_workersc                 C   s,   || _ || _|| _|| _|| _t|d d S )N)r   )r   r   r   r   r   r   )selfr   r   r   r   r   r   r   r   __init__2   s   zInferenceSlicer.__init__imager   c                    s   g }j d j d f}j|jjd}tjd!  fdd|D }t|D ]	}||  q,W d   n1 s@w   Y  t	j
|djjd	S )
a
  
        Performs slicing-based inference on the provided image using the specified
            callback.

        Args:
            image (np.ndarray): The input image on which inference needs to be
                performed. The image should be in the format
                `(height, width, channels)`.

        Returns:
            Detections: A collection of detections for the entire image after merging
                results from all slices and applying NMS.

        Example:
            ```python
            >>> import cv2
            >>> import supervision as sv
            >>> from ultralytics import YOLO

            >>> image = cv2.imread(SOURCE_IMAGE_PATH)
            >>> model = YOLO(...)

            >>> def callback(image_slice: np.ndarray) -> sv.Detections:
            ...     result = model(image_slice)[0]
            ...     return sv.Detections.from_ultralytics(result)

            >>> slicer = sv.InferenceSlicer(callback = callback)

            >>> detections = slicer(image)
            ```
        r   r   )resolution_whr   r   )max_workersc                    s   g | ]
}  j|qS r   )submit_run_callback).0r   executorr!   r   r   r   
<listcomp>j   s    z,InferenceSlicer.__call__.<locals>.<listcomp>N)detections_list)	threshold)shape_generate_offsetr   r   r   r   r   appendresultr   mergewith_nmsr   )r   r!   r*   r"   offsetsfuturesfuturer   r'   r   __call__A   s$    zInferenceSlicer.__call__c                 C   s.   t ||d}| |}t||dd d}|S )af  
        Run the provided callback on a slice of an image.

        Args:
            image (np.ndarray): The input image on which inference needs to run
            offset (np.ndarray): An array of shape `(4,)` containing coordinates
                for the slice.

        Returns:
            Detections: A collection of detections for the slice.
        )r!   r   N   r   )r
   r   r   )r   r!   r   image_slicer   r   r   r   r%   t   s   
zInferenceSlicer._run_callbackr"   c                 C   s   |\}}| \}}|\}}|t ||  }	|t ||  }
td||	}td||
}t||\}}t|| d|}t|| d|}tj||||gdddd}|S )a  
        Generate offset coordinates for slicing an image based on the given resolution,
        slice dimensions, and overlap ratios.

        Args:
            resolution_wh (Tuple[int, int]): A tuple representing the width and height
                of the image to be sliced.
            slice_wh (Tuple[int, int]): A tuple representing the desired width and
                height of each slice.
            overlap_ratio_wh (Tuple[float, float]): A tuple representing the desired
                overlap ratio for width and height between consecutive slices. Each
                value should be in the range [0, 1), where 0 means no overlap and a
                value close to 1 means high overlap.

        Returns:
            np.ndarray: An array of shape `(n, 4)` containing coordinates for each
                slice in the format `[xmin, ymin, xmax, ymax]`.

        Note:
            The function ensures that slices do not exceed the boundaries of the
                original image. As a result, the final slices in the row and column
                dimensions might be smaller than the specified slice dimensions if the
                image's width or height is not a multiple of the slice's width or
                height minus the overlap.
        r   )axis   )intnparangemeshgridclipstackreshape)r"   r   r   slice_widthslice_heightimage_widthimage_heightoverlap_ratio_widthoverlap_ratio_heightwidth_strideheight_stridewshsxminyminxmaxymaxr2   r   r   r   r-      s   z InferenceSlicer._generate_offsetN)r   r   r   r   )__name__
__module____qualname____doc__r   r<   ndarrayr   r   r;   floatr   r    r5   r%   staticmethodr-   r   r   r   r   r      s:    


3


r   )concurrent.futuresr   r   typingr   r   r   numpyr<   supervision.detection.corer   r   supervision.detection.utilsr	   supervision.utils.imager
   arrayr   r   r   r   r   r   <module>   s    