
    .h-.                        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           X/var/www/html/ai-service/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^++    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>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 KEIJcs1z>QUj$89JJKJs   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.

    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_scorer9   I   s    2 n/??@EEbPUP[P[E\``ackpkvkv`wM~(889>>r>UYYZ\didodoYpF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   g   s    !j.!Fkk&!f*jAOwwtQw/*aAHwwq$w/!ZAH88Xx(r2::2q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   p   s7    NST\_`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                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   )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   u   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   rd   re   _rC   s         r   r   r      sZ    LBAq\\BB+,U\\BF
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    LBAq\\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    NBB	Qw27rV|fR"W%vb'95Eurz2urz
*C88""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|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      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'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;   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{{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@)
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:"<Bc
1"1"(+1"<A1"&1"h8#L+Er   