
    /j
.                        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	 d1d2dZd3dZd4dZd5dZd6dZd7d#Zd8d$Zd9d&Zd:d)Zd;d/Zd<d0ZdS )=    )annotationsN)	Generator)product)Any      4@boxestorch.Tensorcrop_box	list[int]orig_boxatolfloatreturnc                   t          j        |t           j        | j                  }t          j        |t           j        | j                  }t	          | |                                          } 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   )r   rtol   dim)torch	as_tensorr   r   uncrop_boxes_xyxyiscloselogical_andany)r   r
   r   r   crop_box_torchorig_box_torchnear_crop_edgenear_image_edges           _/home/longshao/multi-rider-rag/.venv/lib/python3.11/site-packages/ultralytics/models/sam/amg.pyis_box_near_crop_edger"      s    ( _XU[VVVN_XU[VVVNeX..4466E]5.qqq*ASTUUUNmE>$'+BTUVVVO&~7GHHN9^++++    
batch_sizeintGenerator[list[Any]]c              '  (   K   rt          fdD                       s
J d            t          d                    z  t          t          d                    z  dk              z   }t          |          D ] fdD             V  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  d   K   | ]*}t          |          t          d                    k    V  +dS )r   N)len).0aargss     r!   	<genexpr>z!batch_iterator.<locals>.<genexpr>A   s8      ==1A#d1g,,.======r#   z-Batched iteration must have same-size inputs.r   c                6    g | ]}|z  d z   z           S r    )r*   argbr$   s     r!   
<listcomp>z"batch_iterator.<locals>.<listcomp>D   s0    JJJcs1z>QUj$889JJJr#   N)allr)   r%   range)r$   r,   	n_batchesr2   s   `` @r!   batch_iteratorr7   +   s      , nC=========nn?nnn=DG
*ST!W
1Ja1O-P-PPI9 K KJJJJJTJJJJJJJK Kr#   masksmask_thresholdthreshold_offsetc                (   | ||z   k                         dt          j                                       dt          j                  }| ||z
  k                         dt          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)r8   r9   r:   intersectionsunionss        r!   calculate_stability_scorerB   G   s    0 n/??@EEbPUP[E\\``ackpkv`wwM~(889>>r>UUYYZ\didoYppF6!!r#   
n_per_side
np.ndarrayc                    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                              dd          S )zaGenerate a 2D grid of evenly spaced points in the range [0,1]x[0,1] for image segmentation tasks.r      Nr<   )axis)nplinspacetilestackreshape)rC   offsetpoints_one_sidepoints_xpoints_ys        r!   build_point_gridrQ   d   s    !j.!Fk&!f*jAAOwtQQQw/*aAAHwqqq$w/!ZAAH8Xx(r222::2qAAAr#   n_layersscale_per_layerlist[np.ndarray]c                D      fdt          |dz             D             S )zPGenerate point grids for multiple crop layers with varying scales and densities.c           	     T    g | ]$}t          t          |z  z                      %S r0   )rQ   r%   )r*   irC   rS   s     r!   r3   z/build_all_layer_point_grids.<locals>.<listcomp>o   s4    bbbS/A!BCCDDbbbr#   r   )r5   )rC   rR   rS   s   ` `r!   build_all_layer_point_gridsrX   m   s0    bbbbbeT\_`T`NaNabbbbr#   im_sizetuple[int, ...]overlap_ratio!tuple[list[list[int]], list[int]]c           	        g g }}| \  }}t          ||          }|                    dd||g           |                    d           d }t          |          D ]}	d|	dz   z  }
t          ||z  d|
z  z             |||
           |||
          fdt          |
          D             }fdt          |
          D             }t	          ||          D ]Z\  }}||t          |z   |          t          |z   |          g}|                    |           |                    |	dz              [||fS )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                B    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'Wq[1H<GHHHr#   rF   r   c                :    g | ]}t          z
  |z            S r0   r%   )r*   rW   crop_wrc   s     r!   r3   z'generate_crop_boxes.<locals>.<listcomp>   +    TTTqsFW,122TTTr#   c                :    g | ]}t          z
  |z            S r0   rf   )r*   rW   crop_hrc   s     r!   r3   z'generate_crop_boxes.<locals>.<listcomp>   rh   r#   )minappendr5   r%   r   )rY   rR   r[   
crop_boxes
layer_idxsim_him_w
short_siderd   i_layern_crops_per_sidecrop_box_x0crop_box_y0x0y0boxrj   rg   rc   s                   @@@r!   generate_crop_boxesry   r   s   (  
JJD$T4J q!T4()))aI I I ?? + +1-mj0A8H4HIJJ$ 0'::$ 0'::TTTTTEBR<S<STTTTTTTTEBR<S<STTT k;77 	+ 	+FBr3rF{D113rF{D3I3IJCc"""gk****	+
 z!!r#   c                    |\  }}}}t          j        ||||gg| j                  }t          | j                  dk    r|                    d          }| |z   S )zIUncrop bounding boxes by adding the crop box offset to their coordinates.r      r   r   tensorr   r)   shape	unsqueeze)r   r
   rv   rw   _rM   s         r!   r   r      sc    LBAq\BB+,U\BBBF
5;1!!!$$6>r#   pointsc                    |\  }}}}t          j        ||gg| j                  }t          | j                  dk    r|                    d          }| |z   S )zAUncrop points by adding the crop box offset to their coordinates.r{   r|   r   r}   )r   r
   rv   rw   r   rM   s         r!   uncrop_pointsr      s]    LBAq\B8*V];;;F
6<A!!!$$F?r#   orig_horig_wc                    |\  }}}}|dk    r|dk    r||k    r||k    r| S |||z
  z
  |||z
  z
  }	}|||z
  ||	|z
  f}
t           j        j                            | |
d          S )z]Uncrop masks by padding them to the original image size, handling coordinate transformations.r   )value)r   nn
functionalpad)r8   r
   r   r   rv   rw   x1y1pad_xpad_yr   s              r!   uncrop_masksr      s    NBB	Qww277rV||fR"W%vb'95Eurz2urz
*C8""5#Q"777r#   maskarea_threshmodestrtuple[np.ndarray, bool]c                   ddl }|dv sJ d| d            |dk    }|| z                      t          j                  }|                    |d          \  }}}}	|dddf         d	d         }
fd
t          |
          D             }|s| dfS dg||s@fdt          |          D             p$t          t          j        |
                    d	z   gt          j	        |          } | dfS )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      r<   r   c                ,    g | ]\  }}|k     |d z   S r/   r0   )r*   rW   sr   s      r!   r3   z(remove_small_regions.<locals>.<listcomp>   s&    KKKtq!1{??QU???r#   Fc                    g | ]}|v|	S r0   r0   )r*   rW   fill_labelss     r!   r3   z(remove_small_regions.<locals>.<listcomp>   s#    JJJQQk5I5Iq5I5I5Ir#   T)
cv2astyperH   uint8connectedComponentsWithStats	enumerater5   r%   argmaxisin)r   r   r   r   correct_holesworking_maskn_labelsregionsstatsr   sizessmall_regionsr   s    `          @r!   remove_small_regionsr      s7   & JJJ'''')K$)K)K)K'''GOM!D(00::L"%"B"B<QR"S"SHgua!!!R%LEKKKKy'7'7KKKM U{%}%K jJJJJ%//JJJisSUS\]bScScOdOdghOhNi77K((D:r#   c                   t          j        |           dk    r(t          j        g | j        dd         dR d| j        iS | j        }|dd         \  }}t          |          dk    r|                     dd          n|                     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	          }||                     d          z  }t          |          dk    r |j        g |dd         dR  n|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   rF   r<   r   r{   )r   numelzerosr   r   r)   flattenr   maxarangerk   rK   rL   )r8   r   hw	in_heightr   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{EEK,EaEEEEEE KE:DAq$'JJNNEMM!R   8J8JE9U+++LIq 5<):J#K#K#KDRSRSRSG#TTi 0b999OL!'!	z*::9-2666LIq )Er***KHaa!H!H!Hqqq!QQOYB777NK%hY7OIo2666MJ  *,	1IJL
+z9k<Hb
Q
Q
QC
,))"--
-C +.e**q..;3;&crc
&A&&&&c!fDr#   )r   )
r   r	   r
   r   r   r   r   r   r   r	   )r$   r%   r   r&   )r8   r	   r9   r   r:   r   r   r	   )rC   r%   r   rD   )rC   r%   rR   r%   rS   r%   r   rT   )rY   rZ   rR   r%   r[   r   r   r\   )r   r	   r
   r   r   r	   )r   r	   r
   r   r   r	   )
r8   r	   r
   r   r   r%   r   r%   r   r	   )r   rD   r   r   r   r   r   r   )r8   r	   r   r	   )
__future__r   r_   collections.abcr   	itertoolsr   typingr   numpyrH   r   r"   r7   rB   rQ   rX   ry   r   r   r   r   r   r0   r#   r!   <module>r      ss   # " " " " "  % % % % % %                  RV, , , , ,:K K K K8" " " ":B B B Bc c c c
0" 0" 0" 0"f      8 8 8 8" " " "J*E *E *E *E *E *Er#   