
    ^jJ                       d dl mZ d dlZd dlZd dlmZ d dlmZmZ d dl	m
Z
 d dlZd dlm	Z d dlmZ d dlmZ d dlmZ d d	lmZmZ d d
lmZmZ d dlmZ d dlmZ d dlm Z m!Z! d dl"m#Z# 	 d	 	 	 	 	 	 	 ddZ$ G d d      Z%y)    )annotationsN)Callable)ThreadPoolExecutoras_completed)Any)ORIENTED_BOX_COORDINATES)CompactMask)
Detections)
move_boxesmove_oriented_boxes)OverlapFilterOverlapMetric)
move_masks)	ImageType)
crop_imageget_image_resolution_wh)SupervisionWarningsc                   t        | j                  |      | _        t        | j                  v r/t	        | j                  t           |      | j                  t        <   | j
                  |t        d      t        | j
                  t              rE| j
                  j                  t        |d         t        |d         |d   |d   f      | _        | S t        | j
                  ||      | _        | S )a^  
    Args:
        detections: Detections object to be moved.
        offset: An array of shape `(2,)` containing offset values in the
            format `[dx, dy]`.
        resolution_wh: The width and height of the desired mask
            resolution. Required for segmentation detections.

    Returns:
        Repositioned Detections object.
    )xyxyoffset)xyxyxyxyr   zResolution width and height are required for moving segmentation detections. This should be the same as (width, height) of image shape.r      )dxdynew_image_shape)masksr   resolution_wh)r   r   r   datar   mask
ValueError
isinstancer	   with_offsetintr   
detectionsr   r   s      w/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/supervision/detection/tools/inference_slicer.pymove_detectionsr'      s      !joofEJO:??24G__%=>v5

01 " Y  joo{3(oo99vay>vay>!.q!1=3C D : JO  ) oofMJO     c                      e Zd ZdZddej
                  dej                  ddf	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZ	dd	Z
e	 	 	 	 dd
       Ze	 	 	 	 dd       Ze	 	 	 	 	 	 	 	 dd       Ze	 	 	 	 	 	 dd       Zy)InferenceSliceruN  
    Perform tiled inference on large images by slicing them into overlapping patches.

    This class divides an input image into overlapping slices of configurable size
    and overlap, runs inference on each slice through a user-provided callback, and
    merges the resulting detections. The slicing process allows efficient processing
    of large images with limited resources while preserving detection accuracy via
    configurable overlap and post-processing of overlaps. Uses multi-threading for
    parallel slice inference.

    Args:
        callback: Inference function that takes a sliced image and returns a
            `Detections` object.
        slice_wh: Size of each slice `(width, height)`. If int, both width and
            height are set to this value.
        overlap_wh: Overlap size `(width, height)` between slices. If int, both
            width and height are set to this value.
        overlap_filter: Strategy to merge overlapping detections
            (`NON_MAX_SUPPRESSION`, `NON_MAX_MERGE`, or `NONE`).
        iou_threshold: IOU threshold used in merging overlap filtering.
        overlap_metric: Metric to compute overlap (`IOU` or `IOS`).
        thread_workers: Number of threads for concurrent slice inference.
            Must be a positive integer. When the first slice returns oriented
            bounding boxes (OBB), Supervision probes additional slices until a
            non-empty result is found, then falls back to sequential processing
            for all remaining slices to avoid thread-safety issues in common OBB
            inference backends. Note: the first slice always runs synchronously
            regardless of this setting, so for grids with few slices
            (e.g. two-slice images) effective parallelism is reduced.
        compact_masks: If ``True``, dense ``(N, H, W)`` boolean mask
            arrays returned by the callback are immediately converted to a
            :class:`~supervision.detection.compact_mask.CompactMask`. This
            keeps masks in run-length-encoded form for the entire pipeline —
            merge, NMS, and annotation — avoiding the large ``(N, H, W)``
            allocations that cause OOM on high-resolution images with many
            objects. IoU and NMS are computed directly on the RLE crops
            without ever materialising a full ``(N, H, W)`` array.
            Defaults to ``False`` for backward compatibility.

    Raises:
        ValueError: If `slice_wh`, `overlap_wh`, or `thread_workers` are
            invalid or inconsistent.

    Example:
        ```python
        import cv2
        import supervision as sv
        from rfdetr import RFDETRMedium

        model = RFDETRMedium()

        def callback(tile):
            return model.predict(tile)

        slicer = sv.InferenceSlicer(callback, slice_wh=640, overlap_wh=100)

        image = cv2.imread("example.png")
        detections = slicer(image)
        ```

        ```python
        import supervision as sv
        from PIL import Image
        from ultralytics import YOLO

        model = YOLO("yolo11m.pt")

        def callback(tile):
            results = model(tile)[0]
            return sv.Detections.from_ultralytics(results)

        slicer = sv.InferenceSlicer(callback, slice_wh=640, overlap_wh=100)

        image = Image.open("example.png")
        detections = slicer(image)
        ```
    i  d   g      ?r   Fc	                   | j                  |      }	| j                  |      }
| j                  |	|
       |dk  rt        d|       |	| _        |
| _        || _        t        j                  |      | _	        t        j                  |      | _        || _        || _        || _        d| _        t!        j"                         | _        d| _        t!        j"                         | _        y )N)slice_wh
overlap_whr   z7`thread_workers` must be a positive integer. Received: F)_normalize_slice_wh_normalize_overlap_wh_validate_overlapr    r-   r.   iou_thresholdr   
from_valueoverlap_metricr   overlap_filtercallbackthread_workerscompact_masks_out_of_slice_bounds_warned	threadingLock_out_of_slice_bounds_lock_obb_thread_workers_warned_obb_thread_workers_lock)selfr6   r-   r.   r5   r2   r4   r7   r8   slice_wh_normoverlap_wh_norms              r&   __init__zInferenceSlicer.__init__   s     00:44Z@/RA+,. 
 &)*+66~F+66~F;C,*16()2)9&05'(1(8%r(   c           	        g }t        |      }| j                  || j                  | j                        }|d   }| j	                  ||      }|j                  |       |dd }t        |j                  v }| j                  dk  xs |}	d}
|	s~t        |      dk(  rp|
t        |      k  rb||
   }| j	                  ||      }|j                  |       |
dz  }
t        |j                  v rd}d}	nt        |      dkD  rn|
t        |      k  rb||
d }|	r~| j                  dkD  rF|rD| j                  5  | j                  s#d| _        t        j                  dt        d       ddd       |D ]#  }|j                  | j	                  ||             % nyt        | j                  	      5 }|D cg c]  }|j!                  | j                  ||      ! }}t#        |      D ]!  }|j                  |j%                                # 	 ddd       t'        j(                  |
      }| j*                  t,        j.                  k(  r|S | j*                  t,        j0                  k(  r'|j3                  | j4                  | j6                        S | j*                  t,        j8                  k(  r'|j;                  | j4                  | j6                        S t        j                  d| j*                   t               |S # 1 sw Y   xY wc c}w # 1 sw Y   xY w)a  
        Perform tiled inference on the full image and return merged detections.

        The first slice always runs synchronously so the output type can be
        inspected before committing to a threading strategy. Detections are
        merged in a deterministic order: the first slice is always at index 0,
        followed by any probe slices, then the remaining slices in source order.
        If oriented bounding boxes are detected, all remaining slices are
        processed sequentially and a ``SupervisionWarnings`` warning is emitted
        once per slicer instance.

        Args:
            image: The full image to run inference on.

        Returns:
            Merged detections across all slices.
        )r   r-   r.   r   r   NTzInferenceSlicer detected oriented bounding boxes while `thread_workers > 1`. Remaining slices will be processed sequentially because many OBB inference backends are not thread-safe and can crash when shared across threads.   category
stacklevel)max_workers)detections_list)	thresholdr4   z!Invalid overlap filter strategy: )rF   )r   _generate_offsetr-   r.   _run_callbackappendr   r   r7   lenr>   r=   warningswarnr   r   submitr   resultr
   merger5   r   NONENON_MAX_SUPPRESSIONwith_nmsr2   r4   NON_MAX_MERGEwith_nmm)r?   imagerI   r   offsetsfirst_offsetfirst_detectionsremaining_offsetsobb_detectedshould_run_sequentiallyprobe_indexprobe_offsetprobe_detectionsr   executorfuturesfuturemergeds                     r&   __call__zInferenceSlicer.__call__   s   $ -//6''']] ( 
 qz--e\B/0#ABK/3C3H3HH"&"5"5":"Jl&3/?+@A+E$5 660=#'#5#5e\#J &&'78q +/?/D/DD#'L.2+'(1, $5 66 .kl;"""Q&<22 
:::>7 T &9'(
 , J&&t'9'9%'HIJ $0C0CD < #4 OOD$6$6vF  +73 <F#**6==?;<< !!/B-"4"44M-"C"CC??,,#22 #   -"="==??,,#22 #  
 	/0C0C/DE(	
 Q
 
< <s*   .0K/%L*$K<1L/K9<LLc                   t        ||      }| j                  |      }| j                  rq|j                  et	        |j                  t
        j                        rAt        |      \  }}t        j                  |j                  |j                  ||f      |_        t        |      }| j                   xr t        |      dkD  }|r| j                  5  | j                  st        |      dkD  r|d   |d   z
  }	|d   |d   z
  }
t        j                  |j                  ddddgf   |	kD        }t        j                  |j                  ddddgf   |
kD        }t        j                  |j                  ddddgf   dk        }t        j                  |j                  ddddgf   dk        }|s|s|s|r%d| _        d	}t        j                   |t"        d
       ddd       t%        ||dd |      }|S # 1 sw Y   xY w)aT  
        Run detection callback on a sliced portion of the image and adjust coordinates.

        Args:
            image: The full image.
            offset: Coordinates `(x_min, y_min, x_max, y_max)` defining
                the slice region.

        Returns:
            Detections adjusted to the full image coordinate system.
        )rY   r   N)image_shaper   rD      r   Ta  Detections returned by the callback have coordinates outside the slice bounds. This may be caused by the callback running inference on the full image instead of the provided image slice. Ensure your callback uses the input slice for inference, not the original full-resolution image.rE   r$   )r   r6   r8   r   r!   npndarrayr   r	   
from_denser   r9   rN   r<   anyrO   rP   r   r'   )r?   rY   r   image_slicer%   slice_wslice_hr   needs_warning_checkslice_widthslice_height	x_exceeds	y_exceeds
x_negative
y_negativemsgs                   r&   rL   zInferenceSlicer._run_callback  s    !u6:]];/
 +:??BJJ76{CGW)44$g.JO 06 000HS_q5H 	 // W77C
Oa<O"()fQi"7K#)!9vay#8L "zq1a&y'AK'O PI "zq1a&y'AL'P QI!#
Aq6	(BQ(F!GJ!#
Aq6	(BQ(F!GJ Iz;?85  !c4GTUV'W( %!"1:'


 3W Ws   D
G88Hc                    t        | t              r| dk  rt        d|        | | fS t        | t              r/t	        |       dk(  r!| \  }}|dk  s|dk  rt        d|        ||fS t        d|        )Nr   z1`slice_wh` must be a positive integer. Received: rD   z.`slice_wh` values must be positive. Received: z\`slice_wh` must be an int or a tuple of two positive integers (slice_w, slice_h). Received: r!   r#   r    tuplerN   )r-   widthheights      r&   r/   z#InferenceSlicer._normalize_slice_whQ  s     h$1} GzR  X%%h&3x=A+=$ME6zVq[ DXJO  &= !
$
 	
r(   c                    t        | t              r| dk  rt        d|        | | fS t        | t              r/t	        |       dk(  r!| \  }}|dk  s|dk  rt        d|        ||fS t        d|        )Nr   z7`overlap_wh` must be a non negative integer. Received: rD   z4`overlap_wh` values must be non negative. Received: zf`overlap_wh` must be an int or a tuple of two non negative integers (overlap_w, overlap_h). Received: r{   )r.   	overlap_w	overlap_hs      r&   r0   z%InferenceSlicer._normalize_overlap_whj  s     j#&A~ !!+.  z))j%(S_-A#- Iy1}	A J:,W  i''#&
 	
r(   c                l   |\  }}| \  }}|\  }}||z
  }	||z
  }
	 	 	 	 	 	 	 	 dd} ||||	      } ||||
      }t        j                  ||      \  }}t        j                  ||z   d|      }t        j                  ||z   d|      }t        j                  ||||gd      j	                  dd      }|S )a  
        Generate bounding boxes defining the coordinates of image slices with overlap.

        Args:
            resolution_wh: Image resolution `(width, height)`.
            slice_wh: Size of each slice `(width, height)`.
            overlap_wh: Overlap size between slices `(width, height)`.

        Returns:
            Array of shape `(num_slices, 4)` with each row as
                `(x_min, y_min, x_max, y_max)` coordinates for a slice.
        c                   | |k  rdgS ||k(  r.t        t        j                  d| |      j                               S | |z
  }t        t        j                  d||      j                               }|r|d   |k7  r|j	                  |       |S )Nr   )listrk   arangetolistrM   )
image_size
slice_sizestride
last_startstartss        r&   _compute_axis_startsz>InferenceSlicer._generate_offset.<locals>._compute_axis_starts  s    
 Z's
#BIIaV<CCEFF#j0J $RYYq*f%E%L%L%N OFVBZ:5j)Mr(   )r   r   r   r   r   )axis   )r   r#   r   r#   r   r#   returnz	list[int])rk   meshgridclipstackreshape)r   r-   r.   rs   rt   image_widthimage_heightoverlap_widthoverlap_heightstride_xstride_yr   x_startsy_startsx_miny_minx_maxy_maxrZ   s                      r&   rK   z InferenceSlicer._generate_offset  s   $ %-!\$1!\(2%~..0			 	 		" (""

 (##
 {{8X6u+Q<,a>$&HHE5%(%
 '"a. 	
 r(   c                    |\  }}| \  }}|dk  s|dk  rt        d|       ||k\  s||k\  rt        d| d|  d      y )Nr   z=Overlap values must be greater than or equal to 0. Received: zo`overlap_wh` must be smaller than `slice_wh` in both dimensions to keep a positive stride. Received overlap_wh=z, slice_wh=.)r    )r-   r.   r   r   rp   rq   s         r&   r1   z!InferenceSlicer._validate_overlap  s    
  *	9#q=IM'L* 
 9#7BBL N$:Q(  $8r(   N)r6   z!Callable[[ImageType], Detections]r-   int | tuple[int, int]r.   r   r5   zOverlapFilter | strr2   floatr4   zOverlapMetric | strr7   r#   r8   bool)rY   r   r   r
   )rY   r   r   npt.NDArray[Any]r   r
   )r-   r   r   tuple[int, int])r.   r   r   r   )r   r   r-   r   r.   r   r   r   )r-   r   r.   r   r   None)__name__
__module____qualname____doc__r   rU   r   IOUrB   rg   rL   staticmethodr/   r0   rK   r1    r(   r&   r*   r*   @   s<   Lb +.,/.;.O.O".;.?.?#!93!9 (!9 *	!9
 ,!9 !9 ,!9 !9 !9F_B<| 
'
	
 
0 
)
	
 
2 =&=!= $= 
	= =~ !# 
 r(   r*   )N)r%   r
   r   r   r   ztuple[int, int] | Noner   r
   )&
__future__r   r:   rO   collections.abcr   concurrent.futuresr   r   typingr   numpyrk   numpy.typingnptsupervision.configr   "supervision.detection.compact_maskr	   supervision.detection.corer
   !supervision.detection.utils.boxesr   r   'supervision.detection.utils.iou_and_nmsr   r   !supervision.detection.utils.masksr   supervision.draw.baser   supervision.utils.imager   r   supervision.utils.internalr   r'   r*   r   r(   r&   <module>r      ss    "   $ ?    7 : 1 M P 8 + G : -1&&& *& 	&RW Wr(   