Ë
    Fêñi
.  ã                  óÊ   — 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	Z
d dlZ	 d	 	 	 	 	 	 	 	 	 dd„Zdd„Zdd„Zdd	„Zdd
„Z	 	 	 	 	 	 	 	 dd„Zdd„Zdd„Zdd„Zdd„Zdd„Zy)é    )ÚannotationsN)Ú	Generator)Úproduct)ÚAnyc                óÒ  — t        j                  |t         j                  | j                  ¬«      }t        j                  |t         j                  | j                  ¬«      }t	        | |«      j                  «       } t        j
                  | |ddd…f   |d¬«      }t        j
                  | |ddd…f   |d¬«      }t        j                  || «      }t        j                  |d¬«      S )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           ú\/var/www/pod-logistic/pod-ai/venv/lib/python3.12/site-packages/ultralytics/models/sam/amg.pyÚis_box_near_crop_edger      s¯   € ô( —_‘_ X´U·[±[ÈÏÉÔV€NÜ—_‘_ X´U·[±[ÈÏÉÔV€NÜ˜e XÓ.×4Ñ4Ó6€EÜ—]‘] 5¨.¸ºq¸Ñ*AÈÐSTÔU€NÜ—m‘m E¨>¸$Â¸'Ñ+BÈÐTUÔV€OÜ×&Ñ& ~¸Ð7GÓH€NÜ�9‰9�^¨Ô+Ð+ó    c              '  ó  ‡K  — ‰rt        ˆfd„‰D «       «      sJ d«       ‚t        ‰d   «      | z  t        t        ‰d   «      | z  dk7  «      z   }t        |«      D ]   }‰D �cg c]  }||| z  |dz   | z   ‘Œ c}–— Œ" yc c}w ­w)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  óR   •K  — | ]  }t        |«      t        ‰d    «      k(  –— Œ  y­w)r   N)Úlen)Ú.0ÚaÚargss     €r   ú	<genexpr>z!batch_iterator.<locals>.<genexpr>A   s"   øè ø€ Ò=°1œ˜A›¤# d¨1¡g£,Õ.Ñ=ù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³À
Ñ1JÈaÑ1OÓ-PÑP€IÜ�9Óò KˆØEIÖJ¸cˆs�1�z‘> Q¨¡U¨jÑ$8Ò9ÒJÓJñKùÚJùs   ƒABÁ"A?Á7Bc                ó$  — | ||z   kD  j                  dt        j                  ¬«      j                  dt        j                  ¬«      }| ||z
  kD  j                  dt        j                  ¬«      j                  dt        j                  ¬«      }||z  S )a”  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.

    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)

    Notes:
        - One mask is always contained inside the other.
        - Memory is saved by preventing unnecessary cast to torch.int64.
    éÿÿÿÿ)r   )Úsumr   Úint16Úint32)ÚmasksÚmask_thresholdÚthreshold_offsetÚintersectionsÚunionss        r   Úcalculate_stability_scorer9   G   sŠ   € ð0 ˜nÐ/?Ñ?Ñ@×EÑEÀbÔPU×P[ÑP[ÐEÓ\×`Ñ`ÐacÔkp×kvÑkvÐ`Ów€MØ�~Ð(8Ñ8Ñ9×>Ñ>¸rÌÏÉÐ>ÓU×YÑYÐZ\Ôdi×doÑdoÐYÓp€FØ˜6Ñ!Ð!r   c                ó  — dd| z  z  }t        j                  |d|z
  | «      }t        j                  |ddd…f   | df«      }t        j                  |dd…df   d| f«      }t        j                  ||gd¬«      j	                  dd«      S )zaGenerate a 2D grid of evenly spaced points in the range [0,1]x[0,1] for image segmentation tasks.r   é   Nr0   )Úaxis)ÚnpÚlinspaceÚtileÚstackÚreshape)Ú
n_per_sideÚoffsetÚpoints_one_sideÚpoints_xÚpoints_ys        r   Úbuild_point_gridrG   d   sƒ   € à�!�j‘.Ñ!€FÜ—k‘k &¨!¨f©*°jÓA€OÜ�w‰w� tªQ wÑ/°*¸a°ÓA€HÜ�w‰w�¢q¨$ wÑ/°!°Z°ÓA€HÜ�8‰8�X˜xÐ(¨rÔ2×:Ñ:¸2¸qÓAÐAr   c           
     ót   — t        |dz   «      D �cg c]  }t        t        | ||z  z  «      «      ‘Œ c}S c c}w )zPGenerate point grids for multiple crop layers with varying scales and densities.r   )r)   rG   r(   )rB   Ún_layersÚscale_per_layerÚis       r   Úbuild_all_layer_point_gridsrL   m   s7   € äNSÐT\Ð_`ÑT`ÓNaÖbÈÔœS ¨ÀÑ/AÑ!BÓCÕDÒbÐbùÒbs   ‘!5c           	     óh  — g g }}| \  }}t        ||«      }|j                  dd||g«       |j                  d«       d„ }t        |«      D ]Ù  }	d|	dz   z  }
t        ||z  d|
z  z  «      } |||
|«      } |||
|«      }t        |
«      D �cg c]  }t        ||z
  |z  «      ‘Œ }}t        |
«      D �cg c]  }t        ||z
  |z  «      ‘Œ }}t	        ||«      D ]J  \  }}||t        ||z   |«      t        ||z   |«      g}|j                  |«       |j                  |	dz   «       ŒL ŒÛ ||fS c c}w c c}w )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                óD   — t        j                  ||dz
  z  | z   |z  «      S )zZCalculate the length of each crop given the original length, number of crops, and overlap.r   )ÚmathÚceil)Úorig_lenÚn_cropsÚoverlaps      r   Úcrop_lenz%generate_crop_boxes.<locals>.crop_lenŽ   s$   € ä�y‰y˜' W¨q¡[Ñ1°HÑ<ÀÑGÓHÐHr   r;   r   )ÚminÚappendr)   r(   r   )Úim_sizerI   Úoverlap_ratioÚ
crop_boxesÚ
layer_idxsÚim_hÚim_wÚ
short_siderT   Úi_layerÚn_crops_per_siderS   Úcrop_wÚcrop_hrK   Úcrop_box_x0Úcrop_box_y0Úx0Úy0Úboxs                       r   Úgenerate_crop_boxesrg   r   sp  € ð(   �
€JØ�J€Dˆ$Ü�T˜4“€Jð ×Ñ�q˜!˜T 4Ð(Ô)Ø×Ñ�aÔòIô ˜“?ò +ˆØ ¨1¡Ñ-ÐÜ�m jÑ0°AÐ8HÑ4HÑIÓJˆá˜$Ð 0°'Ó:ˆÙ˜$Ð 0°'Ó:ˆä<AÐBRÓ<SÖT°q”s˜F WÑ,°Ñ1Õ2ÐTˆÐTÜ<AÐBRÓ<SÖT°q”s˜F WÑ,°Ñ1Õ2ÐTˆÐTô ˜k¨;Ó7ò 	+‰FˆB�Ø�rœ3˜r F™{¨DÓ1´3°r¸F±{ÀDÓ3IÐJˆCØ×Ñ˜cÔ"Ø×Ñ˜g¨™kÕ*ñ	+ð+ð  �zÐ!Ð!ùò UùÚTs   Â
D*Â1D/c                ó¸   — |\  }}}}t        j                  ||||gg| j                  ¬«      }t        | j                  «      dk(  r|j                  d«      }| |z   S )zIUncrop bounding boxes by adding the crop box offset to their coordinates.©r	   é   r   ©r   Útensorr	   r"   ÚshapeÚ	unsqueeze)r   r   rd   re   Ú_rC   s         r   r   r   ¥   sZ   € à�L€BˆˆAˆqÜ�\‰\˜B  B¨Ð+Ð,°U·\±\ÔB€Fä
ˆ5�;‰;Ó˜1ÒØ×!Ñ! !Ó$ˆØ�6‰>Ðr   c                ó´   — |\  }}}}t        j                  ||gg| j                  ¬«      }t        | j                  «      dk(  r|j                  d«      }| |z   S )zAUncrop points by adding the crop box offset to their coordinates.ri   rj   r   rk   )Úpointsr   rd   re   ro   rC   s         r   Úuncrop_pointsrr   ¯   sT   € à�L€BˆˆAˆqÜ�\‰\˜B ˜8˜*¨V¯]©]Ô;€Fä
ˆ6�<‰<Ó˜AÒØ×!Ñ! !Ó$ˆØ�F‰?Ðr   c                óÌ   — |\  }}}}|dk(  r|dk(  r||k(  r||k(  r| S |||z
  z
  |||z
  z
  }	}|||z
  ||	|z
  f}
t         j                  j                  j                  | |
d¬«      S )z]Uncrop masks by padding them to the original image size, handling coordinate transformations.r   )Úvalue)r   ÚnnÚ
functionalÚpad)r4   r   Úorig_hÚorig_wrd   re   Úx1Úy1Úpad_xÚpad_yrw   s              r   Úuncrop_masksr~   ¹   s€   € à�N€BˆˆB�Ø	ˆQ‚w�2˜’7˜r Vš|°°f²Øˆà˜R "™WÑ% v°°b±Ñ'9ˆ5€EØˆu�r‰z˜2˜u r™zÐ
*€CÜ�8‰8×Ñ×"Ñ" 5¨#°QÐ"Ó7Ð7r   c                óð  — ddl }|dv sJ d|› d�«       ‚|dk(  }|| z  j                  t        j                  «      }|j	                  |d«      \  }}}}	|dd…df   d	d }
t        |
«      D ��cg c]  \  }}||k  sŒ|d	z   ‘Œ }}}|s| d
fS dg|¢}|sBt        |«      D �cg c]	  }||vsŒ|‘Œ c}xs" t        t        j                  |
«      «      d	z   g}t        j                  ||«      } | dfS c c}}w c c}w )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€   é   r0   r   FT)
Úcv2Úastyper=   Úuint8ÚconnectedComponentsWithStatsÚ	enumerater)   r(   ÚargmaxÚisin)ÚmaskÚarea_threshÚmoderƒ   Úcorrect_holesÚworking_maskÚn_labelsÚregionsÚstatsro   ÚsizesrK   ÚsÚsmall_regionsÚfill_labelss                  r   Úremove_small_regionsr–   Ä   s  € ó& àÐ'Ñ'ÐK¨>¸$¸¸{Ð)KÓKÐ'Ø˜G‘O€MØ! DÑ(×0Ñ0´·±Ó:€LØ"%×"BÑ"BÀ<ÐQRÓ"SÑ€Hˆg�u˜aØ’!�R�%‰L˜˜Ð€EÜ'0°Ó'7×K™t˜q !¸1¸{»?�Q˜“UÐK€MÑKÙØ�Uˆ{ÐØÐ%�}Ð%€KÙä"'¨£/ÖJ˜Q°Q¸kÒ5I’qÒJÒiÌsÔSU×S\ÑS\Ð]bÓScÓOdÐghÑOhÐNiˆÜ�7‰7�7˜KÓ(€DØ�ˆ:Ðùó Lùò Ks   Á,C-Á:C-Â	C3Â(C3c                óð  — t        j                  | «      dk(  r1t        j                  g | j                  dd ¢d‘­d| j                  iŽS | j                  }|dd \  }}t        |«      dkD  r| j                  dd«      n| j                  d«      } t        j                  | d¬	«      \  }}|t        j                  ||j                  ¬
«      ddd…f   z  }t        j                  |d¬	«      \  }}||| z  z   }t        j                  |d¬	«      \  }}t        j                  | d¬	«      \  }	}|	t        j                  ||	j                  ¬
«      ddd…f   z  }
t        j                  |
d¬	«      \  }}|
||	 z  z   }
t        j                  |
d¬	«      \  }}||k  ||k  z  }t        j                  ||||gd¬	«      }|| j                  d«      z  }t        |«      dkD  r |j                  g |dd ¢d‘­Ž S |d   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;   éýÿÿÿr0   r   ri   )r   ÚnumelÚzerosrm   r	   r"   Úflattenrn   ÚmaxÚarangerU   r@   rA   )r4   rm   ÚhÚwÚ	in_heightro   Ú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ÒÜ�{‰{ÐE˜EŸK™K¨¨Ð,ÐE¨aÒE¸¿¹ÑEÐEð �K‰K€EØ��ˆ:�D€A€qÜ$'¨£J°¢NˆE�M‰M˜!˜RÔ ¸¿¹ÈÓ8J€Eä—9‘9˜U¨Ô+�L€IˆqØ ¤5§<¡<°¸)×:JÑ:JÔ#KÈDÒRSÈGÑ#TÑTÐÜ—i‘iÐ 0°bÔ9�O€L�!Ø'¨!°	¨zÑ*:Ñ:ÐÜ—9‘9Ð-°2Ô6�L€Iˆqô —)‘)˜E rÔ*�K€HˆaØ¤§¡¨a¸¿¹Ô!HÈÊqÈÑ!QÑQ€OÜ—Y‘Y˜°BÔ7�N€K�Ø%¨¨h¨Y©Ñ7€OÜ—I‘I˜o°2Ô6�M€J�ð   *Ñ,°À	Ñ1IÑJ€LÜ
�+‰+�z 9¨k¸<ÐHÈbÔ
Q€CØ
�,�×)Ñ)¨"Ó-Ñ
-€Cô +.¨e«*°qª.ˆ;ˆ3�;‰;Ð&˜˜c˜r˜
Ð& AÒ&ÐD¸cÀ!¹fÐDr   )g      4@)
r   útorch.Tensorr   ú	list[int]r   r®   r
   r   Úreturnr­   )r*   r(   r¯   zGenerator[list[Any]])r4   r­   r5   r   r6   r   r¯   r­   )rB   r(   r¯   ú
np.ndarray)rB   r(   rI   r(   rJ   r(   r¯   zlist[np.ndarray])rW   ztuple[int, ...]rI   r(   rX   r   r¯   z!tuple[list[list[int]], list[int]])r   r­   r   r®   r¯   r­   )rq   r­   r   r®   r¯   r­   )
r4   r­   r   r®   rx   r(   ry   r(   r¯   r­   )rŠ   r°   r‹   r   rŒ   Ústrr¯   ztuple[np.ndarray, bool])r4   r­   r¯   r­   )Ú
__future__r   rO   Úcollections.abcr   Ú	itertoolsr   Útypingr   Únumpyr=   r   r   r.   r9   rG   rL   rg   r   rr   r~   r–   r¬   © r   r   ú<module>r¸      s¨   ðõ #ã Ý %Ý Ý ã Û ð RVð,Øð,Ø#,ð,Ø8Að,ØINð,àó,ó:Kó8"ó:Bócð
0"Øð0"Ø(+ð0"Ø<Að0"à&ó0"ófóó8ó"ôJ*Er   