
    h-.                        S SK Jr  S SKrS SKJr  S SKJr  S SKJr  S SK	r
S SKr S         SS jjrSS jrSS jrSS	 jrSS
 jr        SS jrSS jrSS jrSS jrSS jrSS jrg)    )annotationsN)	Generator)product)Anyc                   [         R                  " U[         R                  U R                  S9n[         R                  " U[         R                  U R                  S9n[	        X5      R                  5       n [         R
                  " XSSS24   USS9n[         R
                  " XSSS24   USS9n[         R                  " Xg) 5      n[         R                  " USS9$ )a  
Determine if bounding boxes are near the edge of a cropped image region using a specified tolerance.

Args:
    boxes (torch.Tensor): Bounding boxes in XYXY format.
    crop_box (list[int]): Crop box coordinates in [x0, y0, x1, y1] format.
    orig_box (list[int]): Original image box coordinates in [x0, y0, x1, y1] format.
    atol (float, optional): Absolute tolerance for edge proximity detection.

Returns:
    (torch.Tensor): Boolean tensor indicating which boxes are near crop edges.

Examples:
    >>> boxes = torch.tensor([[10, 10, 50, 50], [100, 100, 150, 150]])
    >>> crop_box = [0, 0, 200, 200]
    >>> orig_box = [0, 0, 300, 300]
    >>> near_edge = is_box_near_crop_edge(boxes, crop_box, orig_box, atol=20.0)
)dtypedeviceNr   )atolrtol   dim)torch	as_tensorfloatr	   uncrop_boxes_xyxyiscloselogical_andany)boxescrop_boxorig_boxr
   crop_box_torchorig_box_torchnear_crop_edgenear_image_edges           T/home/james-whalen/.local/lib/python3.13/site-packages/ultralytics/models/sam/amg.pyis_box_near_crop_edger      s    * __XU[[VN__XU[[VNe.446E]]5q*ASTUNmmE$'+BTUVO&&~7GHN99^++    c              '  (  ^#    T(       a  [        U4S jT 5       5      (       d   S5       e[        TS   5      U -  [        [        TS   5      U -  S:g  5      -   n[        U5       H"  nT Vs/ s H  oDX0-  US-   U -   PM     snv   M$     gs  snf 7f)a  
Yield batches of data from input arguments with specified batch size for efficient processing.

This function takes a batch size and any number of iterables, then yields batches of elements from those
iterables. All input iterables must have the same length.

Args:
    batch_size (int): Size of each batch to yield.
    *args (Any): Variable length input iterables to batch. All iterables must have the same length.

Yields:
    (list[Any]): A list of batched elements from each input iterable.

Examples:
    >>> data = [1, 2, 3, 4, 5]
    >>> labels = ["a", "b", "c", "d", "e"]
    >>> for batch in batch_iterator(2, data, labels):
    ...     print(batch)
    [[1, 2], ['a', 'b']]
    [[3, 4], ['c', 'd']]
    [[5], ['e']]
c              3  X   >#    U  H  n[        U5      [        TS    5      :H  v   M!     g7f)r   N)len).0aargss     r   	<genexpr>!batch_iterator.<locals>.<genexpr>C   s"     =1A#d1g,.s   '*z-Batched iteration must have same-size inputs.r   r   N)allr"   intrange)
batch_sizer%   	n_batchesbargs    `   r   batch_iteratorr/   ,   s     . C====n?nn=DG
*ST!W
1Ja1O-PPI9EIJTc1>QUj$89TJJ Js   A*B-BBc                   XU-   :  R                  S[        R                  S9R                  S[        R                  S9nXU-
  :  R                  S[        R                  S9R                  S[        R                  S9nX4-  $ )aQ  
Compute the stability score for a batch of masks.

The stability score is the IoU between binary masks obtained by thresholding the predicted mask logits at
high and low values.

Args:
    masks (torch.Tensor): Batch of predicted mask logits.
    mask_threshold (float): Threshold value for creating binary masks.
    threshold_offset (float): Offset applied to the threshold for creating high and low binary masks.

Returns:
    (torch.Tensor): Stability scores for each mask in the batch.

Notes:
    - One mask is always contained inside the other.
    - Memory is saved by preventing unnecessary cast to torch.int64.

Examples:
    >>> masks = torch.rand(10, 256, 256)  # Batch of 10 masks
    >>> mask_threshold = 0.5
    >>> threshold_offset = 0.1
    >>> stability_scores = calculate_stability_score(masks, mask_threshold, threshold_offset)
)r   )sumr   int16int32)masksmask_thresholdthreshold_offsetintersectionsunionss        r   calculate_stability_scorer:   I   s    2 /??@EEbPUP[P[E\``ackpkvkv`wM(889>>r>UYYZ\didodoYpF!!r   c                   SSU -  -  n[         R                  " USU-
  U 5      n[         R                  " USSS24   U S45      n[         R                  " USS2S4   SU 45      n[         R                  " X4/SS9R	                  SS5      $ )zaGenerate a 2D grid of evenly spaced points in the range [0,1]x[0,1] for image segmentation tasks.r      Nr1   )axis)nplinspacetilestackreshape)
n_per_sideoffsetpoints_one_sidepoints_xpoints_ys        r   build_point_gridrH   g   s    !j.!Fkk&!f*jAOwwtQw/*aAHwwq$w/!ZAH88X(r2::2qAAr   c           
     x    [        US-   5       Vs/ s H  n[        [        XU-  -  5      5      PM     sn$ s  snf )zPGenerate point grids for multiple crop layers with varying scales and densities.r   )r*   rH   r)   )rC   n_layersscale_per_layeris       r   build_all_layer_point_gridsrM   p   s;    NST\_`T`NabNaS/A!BCDNabbbs   #7c           	     h   / / pCU u  pV[        XV5      nUR                  SSXe/5        UR                  S5        S n[        U5       H  n	SU	S-   -  n
[        X'-  SU
-  -  5      nU" XjU5      nU" XZU5      n[        U
5       Vs/ s H  n[        X-
  U-  5      PM     nn[        U
5       Vs/ s H  n[        X-
  U-  5      PM     nn[	        UU5       HK  u  nnUU[        UU-   U5      [        UU-   U5      /nUR                  U5        UR                  U	S-   5        MM     M     X44$ s  snf s  snf )a  
Generate crop boxes of varying sizes for multiscale image processing, with layered overlapping regions.

Args:
    im_size (tuple[int, ...]): Height and width of the input image.
    n_layers (int): Number of layers to generate crop boxes for.
    overlap_ratio (float): Ratio of overlap between adjacent crop boxes.

Returns:
    crop_boxes (list[list[int]]): List of crop boxes in [x0, y0, x1, y1] format.
    layer_idxs (list[int]): List of layer indices corresponding to each crop box.

Examples:
    >>> im_size = (800, 1200)  # Height, width
    >>> n_layers = 3
    >>> overlap_ratio = 0.25
    >>> crop_boxes, layer_idxs = generate_crop_boxes(im_size, n_layers, overlap_ratio)
r   c                V    [        [        R                  " X!S-
  -  U -   U-  5      5      $ )zZCalculate the length of each crop given the original length, number of crops, and overlap.r   )r)   mathceil)orig_lenn_cropsoverlaps      r   crop_len%generate_crop_boxes.<locals>.crop_len   s'    499g15@GKLMMr   r<   r   )minappendr*   r)   r   )im_sizerJ   overlap_ratio
crop_boxes
layer_idxsim_him_w
short_siderU   i_layern_crops_per_siderT   crop_wcrop_hrL   crop_box_x0crop_box_y0x0y0boxs                       r   generate_crop_boxesri   u   sV   *  
JDTJ q!T()aN ?1-m0A8H4HIJ$':$':<ABR<ST<SqsF,12<ST<ABR<ST<SqsF,12<ST k;7FBr3rF{D13rF{D3IJCc"gk* 8 #  !! UTs   D*,D/c                    Uu  p#  n[         R                  " X#X#//U R                  S9n[        U R                  5      S:X  a  UR                  S5      nX-   $ )zIUncrop bounding boxes by adding the crop box offset to their coordinates.r	      r   r   tensorr	   r"   shape	unsqueeze)r   r   rf   rg   _rD   s         r   r   r      sR    LBAq\\BB+,U\\BF
5;;1!!!$>r   c                    Uu  p#  n[         R                  " X#//U R                  S9n[        U R                  5      S:X  a  UR                  S5      nX-   $ )zAUncrop points by adding the crop box offset to their coordinates.rk   rl   r   rm   )pointsr   rf   rg   rq   rD   s         r   uncrop_pointsrt      sN    LBAq\\B8*V]];F
6<<A!!!$?r   c                    Uu  pEpgUS:X  a  US:X  a  Xc:X  a  Xr:X  a  U $ X6U-
  -
  X'U-
  -
  pXHU-
  XYU-
  4n
[         R                  R                  R                  X
SS9$ )z]Uncrop masks by padding them to the original image size, handling coordinate transformations.r   )value)r   nn
functionalpad)r5   r   orig_horig_wrf   rg   x1y1pad_xpad_yry   s              r   uncrop_masksr      sl    NBB	Qw27r|"W%vb'95rz2rz
*C88""5Q"77r   c                    SSK nUS;   d   SU S35       eUS:H  nX@-  R                  [        R                  5      nUR	                  US5      u  pgpUSS2S4   S	S n
[        U
5       VVs/ s H  u  pX:  d  M  US	-   PM     nnnU(       d  U S
4$ S/U-   nU(       dM  [        U5       Vs/ s H  oU;  d  M
  UPM     sn=(       d#    [        [        R                  " U
5      5      S	-   /n[        R                  " X~5      n U S4$ s  snnf s  snf )a  
Remove small disconnected regions or holes in a mask based on area threshold and mode.

Args:
    mask (np.ndarray): Binary mask to process.
    area_thresh (float): Area threshold below which regions will be removed.
    mode (str): Processing mode, either 'holes' to fill small holes or 'islands' to remove small disconnected
        regions.

Returns:
    processed_mask (np.ndarray): Processed binary mask with small regions removed.
    modified (bool): Whether any regions were modified.

Examples:
    >>> mask = np.zeros((100, 100), dtype=np.bool_)
    >>> mask[40:60, 40:60] = True  # Create a square
    >>> mask[45:55, 45:55] = False  # Create a hole
    >>> processed_mask, modified = remove_small_regions(mask, 50, "holes")
r   N>   holesislandszProvided mode z is invalidr      r1   r   FT)
cv2astyper>   uint8connectedComponentsWithStats	enumerater*   r)   argmaxisin)maskarea_threshmoder   correct_holesworking_maskn_labelsregionsstatsrq   sizesrL   ssmall_regionsfill_labelss                  r   remove_small_regionsr      s   ( ''K>${)KK'GOM!(00:L"%"B"B<QR"SHu!R%LE'0'7K'7tq1?UQU'7MKU{#%K"'/J/Qk5Iq/JisSUS\S\]bScOdghOhNi777(D: L Ks   +D:	D+	D8Dc                   [         R                  " U 5      S:X  a2  [         R                  " / U R                  SS QSP7SU R                  06$ U R                  nUSS u  p#[        U5      S:  a  U R                  SS5      OU R                  S5      n [         R                  " U SS	9u  pEU[         R                  " X$R                  S
9SSS24   -  n[         R                  " USS	9u  puXbU) -  -   n[         R                  " USS	9u  p[         R                  " U SS	9u  pU	[         R                  " X9R                  S
9SSS24   -  n
[         R                  " U
SS	9u  pXU	) -  -   n
[         R                  " U
SS	9u  pX:  Xx:  -  n[         R                  " XX/SS	9nX) R                  S5      -  n[        U5      S:  a  UR                  " / USS QSP76 $ US   $ )a`  
Calculate bounding boxes in XYXY format around binary masks.

Args:
    masks (torch.Tensor): Binary masks with shape (B, H, W) or (B, C, H, W).

Returns:
    (torch.Tensor): Bounding boxes in XYXY format with shape (B, 4) or (B, C, 4).

Notes:
    - Handles empty masks by returning zero boxes.
    - Preserves input tensor dimensions in the output.
r   N   r	   r<   r1   r   rk   )r   numelzerosro   r	   r"   flattenrp   maxarangerW   rA   rB   )r5   ro   hw	in_heightrq   in_height_coordsbottom_edges	top_edgesin_widthin_width_coordsright_edges
left_edgesempty_filterouts                  r   batched_mask_to_boxr      s    {{5Q{{EEKK,EaEEE KKE:DA$'JNEMM!R 8JE99U+LI 5<<:J:J#KDRSG#TTii 0b9OL'	z*::99-26LI ))Er*KHa!Hq!QQOYYB7NK%hY7OIIo26MJ  ,1IJL
++zkHb
QC
))"-
-C +.e*q.3;;&cr
&A&Dc!fDr   )g      4@)
r   torch.Tensorr   	list[int]r   r   r
   r   returnr   )r+   r)   r   zGenerator[list[Any]])r5   r   r6   r   r7   r   r   r   )rC   r)   r   
np.ndarray)rC   r)   rJ   r)   rK   r)   r   zlist[np.ndarray])rY   ztuple[int, ...]rJ   r)   rZ   r   r   z!tuple[list[list[int]], list[int]])r   r   r   r   r   r   )rs   r   r   r   r   r   )
r5   r   r   r   rz   r)   r{   r)   r   r   )r   r   r   r   r   strr   ztuple[np.ndarray, bool])r5   r   r   r   )
__future__r   rP   collections.abcr   	itertoolsr   typingr   numpyr>   r   r   r/   r:   rH   rM   ri   r   rt   r   r   r    r   r   <module>r      s    #  %     RV,,#,,8A,IN,,<K:"<Bc
1"1"(+1"<A1"&1"h8#L+Er   