
    |h.                        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
	 d$de
j                  dee   dee   dede
j                  f
d	Zd
edeee   ddf   fdZde
j                  dedede
j                  fdZdede	j"                  fdZdedededee	j"                     fdZdeedf   dededeeee      ee   f   fdZde
j                  dee   de
j                  fdZde
j                  dee   de
j                  fdZde
j                  dee   dedede
j                  f
dZde	j"                  d ed!edee	j"                  ef   fd"Zde
j                  de
j                  fd#Zy)%    N)product)Any	GeneratorListTupleboxescrop_boxorig_boxatolreturnc                    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   )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_edges           Y/var/www/html/test/engine/venv/lib/python3.12/site-packages/ultralytics/models/sam/amg.pyis_box_near_crop_edger       s    * __XU[[VN__XU[[VNeX.446E]]5.q*ASTUNmmE>$'+BTUVO&&~7GHN99^++    
batch_sizec              '     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>@   s"     =1A#d1g,.=s   $'z-Batched iteration must have same-size inputs.r   r   N)allr%   intrange)r"   r(   	n_batchesbargs    `   r   batch_iteratorr0   )   s     . C===n?nn=DG
*ST!W
1Ja1O-PPI9 KEIJcs1z>QUj$89JJKJs   AB"A?7Bmasksmask_thresholdthreshold_offsetc                 $   | ||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.

    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)r1   r2   r3   intersectionsunionss        r   calculate_stability_scorer;   F   s    2 n/??@EEbPUP[P[E\``ackpkvkv`wM~(889>>r>UYYZ\didodoYpF6!!r!   
n_per_sidec                    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      Nr5   )axis)nplinspacetilestackreshape)r<   offsetpoints_one_sidepoints_xpoints_ys        r   build_point_gridrI   d   s    !j.!Fkk&!f*jAOwwtQw/*aAHwwq$w/!ZAH88Xx(r2::2qAAr!   n_layersscale_per_layerc           
      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,   rI   r+   )r<   rJ   rK   is       r   build_all_layer_point_gridsrN   m   s7    NST\_`T`NabS/A!BCDbbbs   !5im_size.overlap_ratioc           	      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                 V    t        t        j                  ||dz
  z  | z   |z              S )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_lenz%generate_crop_boxes.<locals>.crop_len   s)    499g15@GKLMMr!   r>   r   )minappendr,   r+   r   )rO   rJ   rP   
crop_boxes
layer_idxsim_him_w
short_siderX   i_layern_crops_per_siderW   crop_wcrop_hrM   crop_box_x0crop_box_y0x0y0boxs                       r   generate_crop_boxesri   r   sp   *  
JJD$T4J q!T4()aN ? +1-mj0A8H4HIJ$ 0':$ 0':<ABR<STqsFW,12TT<ABR<STqsFW,12TT k;7 	+FBr3rF{D13rF{D3IJC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	   rf   rg   _rE   s         r   r   r      sZ    LBAq\\BB+,U\\BF
5;;1!!!$6>r!   pointsc                     |\  }}}}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.rk   rl   r   rm   )rr   r	   rf   rg   rq   rE   s         r   uncrop_pointsrt      sT    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                  j                  | |
d      S )z]Uncrop masks by padding them to the original image size, handling coordinate transformations.r   )value)r   nn
functionalpad)r1   r	   ru   rv   rf   rg   x1y1pad_xpad_yr{   s              r   uncrop_masksr      s    NBB	Qw27rV|fR"W%vb'95Eurz2urz
*C88""5#Q"77r!   maskarea_threshmodec                    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|z   }|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      r5   r   FT)
cv2astyper@   uint8connectedComponentsWithStats	enumerater,   r+   argmaxisin)r   r   r   r   correct_holesworking_maskn_labelsregionsstatsrq   sizesrM   ssmall_regionsfill_labelss                  r   remove_small_regionsr      s   ( ''K>${)KK'GOM!D(00:L"%"B"B<QR"SHgua!R%LE'0'7Ktq!1{?QUKMKU{#%K"'/JQQk5IqJisSUS\S\]bScOdghOhNi777K(D: L Ks   ,C.:C.	C4)C4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>   r5   r   rk   )r   numelzerosro   r   r%   flattenrp   maxarangerY   rC   rD   )r1   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:DAq$'JNEMM!R 8JE99U+LIq 5<<):J:J#KDRSG#TTii 0b9OL!'!	z*::99-26LIq ))Er*KHaa!Hq!QQOYYB7NK%hY7OIIo26MJ  *,	1IJL
++z9k<Hb
QC
,))"-
-C +.e*q.;3;;&cr
&A&Dc!fDr!   )g      4@)rS   	itertoolsr   typingr   r   r   r   numpyr@   r   Tensorr+   r   r    r0   r;   ndarrayrI   rN   ri   r   rt   r   strboolr   r    r!   r   <module>r      s     . .   RV,<<,#'9,8<S	,IN,
\\,<Ks KiS	48M.N K:"U\\ "5 "\a "fkfrfr "<B B BcC c3 cQT cY]^`^h^hYi c
1"38_1"(+1"<A1"
4S	?DI%&1"hU\\ T#Y 5<< %,, $s)  8 8S	 83 8PS 8X]XdXd 8#rzz # #S #USUS]S]_cScMd #L+Eu|| +E +Er!   