Ë
    ¼Ó^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   z‡Resolution 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æ   € ô  ! j§o¡o¸fÔE€J„OÜ :§?¡?Ñ2Ü4GØ—_‘_Ô%=Ñ>Àvô5
ˆ
�‰Ô0Ñ1ð ‡�Ð"ØÐ ÜðYóð ô �j—o‘o¤{Ô3à(Ÿo™o×9Ñ9Ü�v˜a‘y“>Ü�v˜a‘y“>Ø!.¨qÑ!1°=ÀÑ3CÐ Dð :ó ˆJŒOð Ðô )Ø —o‘o¨fÀMôˆJŒOð Ðó    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Ñ4°ZÓ@ˆà×Ñ¨À/ÐÔ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   NTzÞInferenceSlicer 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ˆà×'Ñ'Ø'Ø—]‘]Ø—‘ð (ó 
ˆð ˜q‘zˆØ×-Ñ-¨e°\ÓBÐØ×ÑÐ/Ô0à# A B˜KÐÜ/Ð3C×3HÑ3HÐHˆØ"&×"5Ñ"5¸Ñ":Ò"J¸lÐàˆÙ&¬3Ð/?Ó+@ÀAÒ+EØ¤Ð$5Ó 6Ò6Ø0°Ñ=�Ø#'×#5Ñ#5°e¸\Ó#JÐ Ø×&Ñ&Ð'7Ô8Ø˜qÑ �ä+Ð/?×/DÑ/DÑDØ#'�LØ.2Ð+ØäÐ'Ó(¨1Ò,Øð ¤Ð$5Ó 6Ó6ð .¨k¨lÐ;Ðá"Ø×"Ñ" QÒ&©<Ø×2Ñ2ñ 
Ø×:Ò:Ø:>˜Ô7Ü Ÿ™ðTô &9Ø'(õ÷
ð ,ò J�Ø×&Ñ& t×'9Ñ'9¸%ÀÓ'HÕIñJô $°×0CÑ0CÔDð <Èð #4öàð —O‘O D×$6Ñ$6¸¸vÕFð�ð ô +¨7Ó3ò <�FØ#×*Ñ*¨6¯=©=«?Õ;ñ<÷<ô ×!Ñ!°/ÔBˆØ×Ñ¤-×"4Ñ"4Ò4ØˆMØ×Ñ¤-×"CÑ"CÒCØ—?‘?Ø×,Ñ,Ø#×2Ñ2ð #ó ð ð ×Ñ¤-×"=Ñ"=Ò=Ø—?‘?Ø×,Ñ,Ø#×2Ñ2ð #ó ð ô
 	�‰Ø/°×0CÑ0CÐ/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                  sýt        |«      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ê  € ô ! u°6Ô:ˆØ—]‘] ;Ó/ˆ
ð ×ÒØ—‘Ð+Ü˜:Ÿ?™?¬B¯J©JÔ7ä6°{ÓCÑˆG�WÜ)×4Ñ4Ø—‘Ø—‘Ø$ gÐ.ôˆJŒOô 0°Ó6ˆð ×0Ñ0Ð0ÒH´S¸³_ÀqÑ5Hð 	ò Ø×/Ñ/ñ Wà×7Ò7¼CÀ
»OÈaÒ<OØ"(¨¡)¨f°Q©iÑ"7�KØ#)¨!¡9¨v°a©yÑ#8�LÜ "§¡ z§¡²q¸1¸a¸&°yÑ'AÀKÑ'OÓ P�IÜ "§¡ z§¡²q¸1¸a¸&°yÑ'AÀLÑ'PÓ Q�IÜ!#§¡¨
¯©º¸A¸q¸6¸	Ñ(BÀQÑ(FÓ!G�JÜ!#§¡¨
¯©º¸A¸q¸6¸	Ñ(BÀQÑ(FÓ!G�JÙ ¡I±¹zØ;?˜Ô8ð5ð ô !Ÿ™ cÔ4GÐTUÕ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¤Ô&¬3¨x«=¸AÒ+=Ø$‰MˆE�6Ø˜Šz˜V qš[Ü ØDÀXÀJÐ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Ø#-Ñ ˆI�yØ˜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�
à˜Ò#ÜœBŸI™I a¨°VÓ<×CÑCÓEÓFÐFà# jÑ0ˆJÜ $¤R§Y¡Y¨q°*¸fÓ%E×%LÑ%LÓ%NÓ OˆFÙ˜V B™Z¨:Ò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ˆð	Øð	àð	ð ð	ð ó		ñ" (Ø"Ø"Øô
ˆñ
 (Ø#Ø#Øô
ˆô —{‘{ 8¨XÓ6‰ˆˆuÜ—‘˜ Ñ+¨Q°Ó<ˆÜ—‘˜ Ñ,¨a°Ó>ˆä$&§H¡HØ�E˜5 %Ð(Øô%
÷ ‰'�"�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ð ó!9óF_ó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(   