o
    Vh*+                     @   s  d dl Z d dlmZ d dlmZmZmZmZ d dlZ	d dl
Z
	d0de
jdee dee ded	e
jf
d
dZded	eee ddf fddZde
jdeded	e
jfddZded	e	jfddZdededed	ee	j fddZdeedf deded	eeee  ee f fddZde
jdee d	e
jfd d!Zd"e
jdee d	e
jfd#d$Zde
jdee d%ed&ed	e
jf
d'd(Zd)e	jd*ed+ed	ee	jef fd,d-Zde
jd	e
jfd.d/ZdS )1    N)product)Any	GeneratorListTuple      4@boxescrop_boxorig_boxatolreturnc                 C   s   t j|t j| jd}t j|t j| jd}t| | } t j| |dddf |dd}t j| |dddf |dd}t || }t j|ddS )zeDetermines if bounding boxes are near the edge of a cropped image region using a specified tolerance.)dtypedeviceNr   )r   rtol   dim)torch	as_tensorfloatr   uncrop_boxes_xyxyiscloselogical_andany)r   r	   r
   r   crop_box_torchorig_box_torchnear_crop_edgenear_image_edge r   N/var/www/vscode/kcb/lib/python3.10/site-packages/ultralytics/models/sam/amg.pyis_box_near_crop_edge   s   r    
batch_sizec                 '   st     rt  fdd D sJ dt d  tt d  dk }t|D ]fdd D V  q*dS )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   s$    | ]}t |t  d  kV  qdS )r   N)len).0a)argsr   r   	<genexpr>/   s   " z!batch_iterator.<locals>.<genexpr>z-Batched iteration must have same-size inputs.r   c                    s$   g | ]}|   d    qS r   r   )r#   arg)br!   r   r   
<listcomp>2   s   $ z"batch_iterator.<locals>.<listcomp>N)allr"   intrange)r!   r%   	n_batchesr   )r%   r)   r!   r   batch_iterator   s   "(r/   masksmask_thresholdthreshold_offsetc                 C   sP   | || kj dtjdj dtjd}| || kj dtjdj dtjd}|| S )a  
    Computes 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)r0   r1   r2   intersectionsunionsr   r   r   calculate_stability_score5   s   $$r9   
n_per_sidec                 C   sp   dd|   }t |d| | }t |dddf | df}t |dddf d| f}t j||gddddS )zaGenerate a 2D grid of evenly spaced points in the range [0,1]x[0,1] for image segmentation tasks.r      Nr3   )axis)nplinspacetilestackreshape)r:   offsetpoints_one_sidepoints_xpoints_yr   r   r   build_point_gridS   s
   rF   n_layersscale_per_layerc                    s    fddt |d D S )zQGenerates point grids for multiple crop layers with varying scales and densities.c                    s    g | ]}t t |  qS r   )rF   r,   r#   ir:   rH   r   r   r*   ^        z/build_all_layer_point_grids.<locals>.<listcomp>r   )r-   )r:   rG   rH   r   rK   r   build_all_layer_point_grids\   s   rM   im_size.overlap_ratioc                    s
  g g }}| \}}t ||}|dd||g |d dd }t|D ]\}	d|	d  }
t|| d|
  |||
|||
 fddt|
D } fddt|
D }t||D ] \}}||t | |t |  |g}|| ||	d  q_q$||fS )	a  
    Generates 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:
        (List[List[int]]): List of crop boxes in [x0, y0, x1, y1] format.
        (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                 S   s   t t||d  |  | S )z[Calculates the length of each crop given the original length, number of crops, and overlap.r   )r,   mathceil)orig_lenn_cropsoverlapr   r   r   crop_len~   s   z%generate_crop_boxes.<locals>.crop_lenr;   r   c                       g | ]
}t   | qS r   r,   rI   )crop_wrT   r   r   r*          z'generate_crop_boxes.<locals>.<listcomp>c                    rV   r   rW   rI   )crop_hrT   r   r   r*      rY   )minappendr-   r,   r   )rN   rG   rO   
crop_boxes
layer_idxsim_him_w
short_siderU   i_layern_crops_per_sidecrop_box_x0crop_box_y0x0y0boxr   )rZ   rX   rT   r   generate_crop_boxesa   s&   


 
ri   c                 C   sF   |\}}}}t j||||gg| jd}t| jdkr|d}| | S )zIUncrop bounding boxes by adding the crop box offset to their coordinates.r      r   r   tensorr   r"   shape	unsqueeze)r   r	   rf   rg   _rB   r   r   r   r      s
   
r   pointsc                 C   sB   |\}}}}t j||gg| jd}t| jdkr|d}| | S )zAUncrop points by adding the crop box offset to their coordinates.rj   rk   r   rl   )rq   r	   rf   rg   rp   rB   r   r   r   uncrop_points   s
   
rr   orig_horig_wc                 C   sr   |\}}}}|dkr|dkr||kr||kr| S |||  |||  }}	||| ||	| f}
t jjj| |
ddS )z]Uncrop masks by padding them to the original image size, handling coordinate transformations.r   )value)r   nn
functionalpad)r0   r	   rs   rt   rf   rg   x1y1pad_xpad_yrx   r   r   r   uncrop_masks   s    r}   maskarea_threshmodec                    s   ddl }|dv sJ d| d|dk}|| A tj}||d\}}}}	|dddf d	d }
 fd
dt|
D }|sC| dfS dg| |s_fddt|D p^tt|
d	 gt	|} | dfS )a  
    Removes 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:
        (np.ndarray): Processed binary mask with small regions removed.
        (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      r3   r   c                    s    g | ]\}}| k r|d  qS r'   r   )r#   rJ   s)r   r   r   r*      rL   z(remove_small_regions.<locals>.<listcomp>Fc                    s   g | ]}| vr|qS r   r   rI   )fill_labelsr   r   r*      s    T)
cv2astyper=   uint8connectedComponentsWithStats	enumerater-   r,   argmaxisin)r~   r   r   r   correct_holesworking_maskn_labelsregionsstatsrp   sizessmall_regionsr   )r   r   r   remove_small_regions   s   
*r   c                 C   s  t | dkrt jg | jdd dR d| jiS | j}|dd \}}t|dkr1| ddn| d} t j| dd	\}}|t j	||jd
dddf  }t j|dd	\}}|||   }t j
|dd	\}}t j| dd	\}	}|	t j	||	jd
dddf  }
t j|
dd	\}}|
||	   }
t j
|
dd	\}}||k ||k B }t j||||gdd	}|| d }t|dkr|jg |dd dR  S |d S )a  
    Calculates 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;   r3   r   rj   )r   numelzerosrn   r   r"   flattenro   maxaranger[   r@   rA   )r0   rn   hw	in_heightrp   in_height_coordsbottom_edges	top_edgesin_widthin_width_coordsright_edges
left_edgesempty_filteroutr   r   r   batched_mask_to_box   s&   &"  0r   )r   )rP   	itertoolsr   typingr   r   r   r   numpyr=   r   Tensorr,   r   r    r/   r9   ndarrayrF   rM   ri   r   rr   r}   strboolr   r   r   r   r   r   <module>   sF   
  	

4
&
&%