
    ^jr<                        d dl mZ d dlmZmZmZ d dlZd dlZd dl	mZ
 d dlmZ 	 	 	 	 	 	 	 	 ddZ	 	 	 	 ddZddZ	 d	 	 	 	 	 ddZddd	Z	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 dd
Zy)    )annotations)AnyLiteralcastN)CompactMaskc                   t        j                  | j                  d   |d   |d   fd      }|d   dk  rM|d    }t        | j                  d   |d   |d   z
        }d}t        |d   | j                  d   |d   z         }n4d}t        | j                  d   |d   |d   z
        }|d   }|d   |z   |z
  }|d   dk  rM|d    }t        | j                  d   |d   |d   z
        }	d}
t        |d   | j                  d   |d   z         }n4d}t        | j                  d   |d   |d   z
        }	|d   }
|d   |	z   |z
  }||kD  r|	|kD  r| dd||	||f   |dd|
|||f<   |S )a  
    Offset the masks in an array by the specified (x, y) amount.

    Args:
        masks: A 3D array of binary masks corresponding to the
            predictions. Shape: `(N, H, W)`, where N is the number of predictions, and
            H, W are the dimensions of each mask.
        offset: An array of shape `(2,)` containing int values
            `[dx, dy]`. Supports both positive and negative values for bidirectional
            movement.
        resolution_wh: The width and height of the desired mask
            resolution.

    Returns:
        Repositioned masks, optionally padded to the specified shape.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> mask = np.array([[[False, False, False, False],
        ...                   [False, True,  True,  False],
        ...                   [False, True,  True,  False],
        ...                   [False, False, False, False]]], dtype=bool)
        >>> offset = np.array([1, 1])
        >>> sv.move_masks(mask, offset, resolution_wh=(4, 4))
        array([[[False, False, False, False],
                [False, False, False, False],
                [False, False,  True,  True],
                [False, False,  True,  True]]])
        >>> offset = np.array([-2, 2])
        >>> sv.move_masks(mask, offset, resolution_wh=(4, 4))
        array([[[False, False, False, False],
                [False, False, False, False],
                [False, False, False, False],
                [ True, False, False, False]]])

        ```
    r      F   N)npfullshapemin)masksoffsetresolution_wh
mask_arraysource_x_startsource_x_enddestination_x_startdestination_x_endsource_y_startsource_y_enddestination_y_startdestination_y_ends               l/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/supervision/detection/utils/masks.py
move_masksr      s   X %++a.-*:M!<LMuUJay1} )5;;q>=+;fQi+GHa 0%++a.6!92LM5;;q>=+;fQi+GH$Qi"1I4~Eay1} )5;;q>=+;fQi+GHa 0%++a.6!92LM5;;q>=+;fQi+GH$Qi"1I4~En$)F
 !^L0.2MMN	 	 11 113	
     c                "    t         t              rt               }|dk(  rDt        t        j
                  t        j                     t        j                  dt                    S t        j                  |dft        j                        }t        |      D ]  } j                  |      }|j                  \  }}t         j                  |df         }t         j                  |df         }t        |j!                               }	|	dk(  rddg||<   }t        j"                  ||f      \  }
}t%        t        j                   |dz   |               |	z  |z   }t%        t        j                   |
dz   |               |	z  |z   }||g||<    t        t        j
                  t        j                     |j'                  t                    S  j                  \  }}} j!                  d	      }t        j"                  ||f      dz   \  }}d||dk(  <   	 	 	 	 	 	 d fd
}ddgddgf} |||      |z  } |||      |z  }t        t        j
                  t        j                     t        j(                  ||f      j'                  t                    S )a  
    Calculate the centroids of binary masks in a tensor.

    Args:
        masks: A 3D NumPy array of shape (num_masks, height, width).
            Each 2D array in the tensor represents a binary mask.
            Also accepts a :class:`~supervision.detection.compact_mask.CompactMask`.

    Returns:
        A 2D NumPy array of shape (num_masks, 2), where each row contains the x and y
            coordinates (in that order) of the centroid of the corresponding mask.
    r   )r   r
   dtyper
   r	   g        g      ?)r	   r
   axisc                    t        t        j                  t        j                     t        j
                  | |            S )N)axes)r   nptNDArrayr   floating	tensordot)indicesr"   r   s     r   sum_over_maskz0calculate_masks_centroids.<locals>.sum_over_mask   s-     CKK,bll5'PT.UVVr   )r)   npt.NDArray[np.floating]r"   ztuple[list[int], list[int]]returnr+   )
isinstancer   lenr   r%   r&   r   int_emptyintzerosfloat64rangecropr   offsetssumr)   floatastypecolumn_stack)r   n	centroidsir5   crop_hcrop_wx1y1total	crop_rows	crop_colscxcy
_num_masksheightwidthtotal_pixelsvertical_indiceshorizontal_indicesr*   aggregation_axis
centroid_x
centroid_ys   `                       r   calculate_masks_centroidsrP   Z   sX    %%J6BGG,bhhvS.IJJ-/XXq!fBJJ-O	q 	$A::a=D!ZZNFFU]]1a4()BU]]1a4()B
OEz #Sz	!#%::vv.>#? Iyrvvy3567%?"DBrvvy3567%?"DB8IaL	$ CKK()*:*:3*?@@ %J99&9)L ,.::vuo+F+L((&'L"#W)W1LW	!W
 78VaV4D13CD|SJ/1AB\QJBGGbooz:.FGNNsS r   c                    | j                  t        j                        }t        j                  |t        j
                  t        j                        \  }}|d}|d   D ]  }||   dk7  s y y)a>  
    Checks if the binary mask contains holes (background pixels fully enclosed by
    foreground pixels).

    Args:
        mask: 2D binary mask where `True` indicates foreground
            object and `False` indicates background.

    Returns:
        True if holes are detected, False otherwise.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> mask = np.array([
        ...     [0, 0, 0, 0, 0],
        ...     [0, 1, 1, 1, 0],
        ...     [0, 1, 0, 1, 0],
        ...     [0, 1, 1, 1, 0],
        ...     [0, 0, 0, 0, 0]
        ... ]).astype(bool)
        >>> sv.contains_holes(mask=mask)
        True
        >>> mask = np.array([
        ...     [0, 0, 0, 0, 0],
        ...     [0, 1, 1, 1, 0],
        ...     [0, 1, 1, 1, 0],
        ...     [0, 1, 1, 1, 0],
        ...     [0, 0, 0, 0, 0]
        ... ]).astype(bool)
        >>> sv.contains_holes(mask=mask)
        False

        ```

    ![contains_holes](https://media.roboflow.com/supervision-docs/contains-holes.png){ align=center width="800" }
       r   TF)r9   r   uint8cv2findContours
RETR_CCOMPCHAIN_APPROX_SIMPLE)mask
mask_uint8_	hierarchyparent_contour_indexhs         r   contains_holesr_      sn    N RXX&J##J@W@WXLAy 1 	A%&",	 r   c                   |dk7  r|dk7  rt        d      | j                  t        j                        }t        j                  |t        j
                        }t        j                  |||      \  }}t        |dkD        S )a  
    Checks if the binary mask contains multiple unconnected foreground segments.

    Args:
        mask: 2D binary mask where `True` indicates foreground
            object and `False` indicates background.
        connectivity: Default: 4 is 4-way connectivity, which means that
            foreground pixels are the part of the same segment/component
            if their edges touch.
            Alternatively: 8 for 8-way connectivity, when foreground pixels are
            connected by their edges or corners touch.

    Returns:
        True when the mask contains multiple not connected components, False otherwise.

    Raises:
        ValueError: If connectivity(int) parameter value is not 4 or 8.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> mask = np.array([
        ...     [0, 0, 0, 0, 0, 0],
        ...     [0, 1, 1, 0, 1, 1],
        ...     [0, 1, 1, 0, 1, 1],
        ...     [0, 0, 0, 0, 0, 0],
        ...     [0, 1, 1, 1, 0, 0],
        ...     [0, 1, 1, 1, 0, 0]
        ... ]).astype(bool)
        >>> sv.contains_multiple_segments(mask=mask, connectivity=4)
        True
        >>> mask = np.array([
        ...     [0, 0, 0, 0, 0, 0],
        ...     [0, 1, 1, 1, 1, 1],
        ...     [0, 1, 1, 1, 1, 1],
        ...     [0, 1, 1, 1, 1, 1],
        ...     [0, 1, 1, 1, 1, 1],
        ...     [0, 0, 0, 0, 0, 0]
        ... ]).astype(bool)
        >>> sv.contains_multiple_segments(mask=mask, connectivity=4)
        False

        ```

    ![contains_multiple_segments](https://media.roboflow.com/supervision-docs/contains-multiple-segments.png){ align=center width="800" }
          zCIncorrect connectivity value. Possible connectivity values: 4 or 8.r   connectivityr
   )	
ValueErrorr9   r   rT   
zeros_likeint32rU   connectedComponentsbool)rY   rd   rZ   labelsnumber_of_labelsr[   s         r   contains_multiple_segmentsrl      s|    d q\Q.Q
 	
 RXX&J]]:RXX6F11Fa  1$%%r   c                   | j                   d   }| j                   d   }t        ||z  ||z        }t        ||z        }t        ||z        }t        j                  d|dz
  |      j                  t              }t        j                  d|dz
  |      j                  t              }t        j                  ||      \  }	}
| dd|
|	f   }|j                  | j                   d   ||      S )a.  
    Resize all masks in the array to have a maximum dimension of max_dimension,
    maintaining aspect ratio.

    Args:
        masks: 3D array of binary masks with shape (N, H, W).
        max_dimension: The maximum dimension for the resized masks.

    Returns:
        Array of resized masks.
    r	   r
   r   N)r   r   r1   r   linspacer9   meshgridreshape)r   max_dimension
max_height	max_widthscale
new_height	new_widthxyxvyvresized_maskss               r   resize_masksr|     s     kk!nJ[[^I
*MI,EFEUZ'(JEI%&I
Ay1}i077<A
AzA~z299#>A[[AFB!R)$M  QYGGr   c                   | j                   t        k7  rt        d      | j                  \  }}t	        j
                  |       s| j                         S | j                  t        j                        }t        j                  ||      \  }}	}
}|dk  r| j                         S |
ddt        j                  f   }dt        t	        j                  |            z   }|.t        t	        j                  ||            }t        |      |z  }n|t        |      }nt!        d      t	        j"                  |t              }d||<   |dk(  r`|dd ||   z
  }t	        j$                  t	        j&                  |d	z  d
            }dt	        j(                  ||k        d   z   }d||<   ||	   S |dk(  r|	|k(  j                  t        j                        }d|z
  }t        j*                  |t        j,                  d      }t/        d|      D ]J  }||k(  r	|	|k(  }t	        j
                  |      s$t        ||   j1                               }||k  sFd||<   L ||	   S t!        d      )a  
    Keep the largest connected component and any other components within a distance
    threshold.

    Distance can be absolute in pixels or relative to the image diagonal.

    Args:
        mask: Boolean mask HxW.
        absolute_distance: Max allowed distance in pixels to the main component.
            Ignored if `relative_distance` is provided.
        relative_distance: Fraction of the diagonal. If set, threshold = fraction * sqrt(H^2 + W^2).
        connectivity: Defines which neighboring pixels are considered connected.
            - 4-connectedness: Only orthogonal neighbors.
              ```
              [ ][X][ ]
              [X][O][X]
              [ ][X][ ]
              ```
            - 8-connectedness: Includes diagonal neighbors.
              ```
              [X][X][X]
              [X][O][X]
              [X][X][X]
              ```
            Default is 8.
        mode: Defines how distance between components is measured.
            - "edge": Uses distance between nearest edges (via distance transform).
            - "centroid": Uses distance between component centroids.

    Returns:
        Boolean mask after filtering.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> mask = np.array([
        ...     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        ...     [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
        ...     [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
        ...     [0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0],
        ...     [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
        ...     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        ...     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        ...     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        ...     [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
        ...     [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
        ...     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        ...     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        ... ], dtype=bool)
        >>> sv.filter_segments_by_distance(
        ...     mask,
        ...     absolute_distance=3,
        ...     mode="edge",
        ...     connectivity=8
        ... ).astype(int)
        array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

        ```

        The nearby 2x2 block at columns 6-7 is kept because its edge distance
        is within 3 pixels. The distant block at columns 9-10 is removed.
    zmask must be booleanrc   r	   Nz:Either absolute_distance or relative_distance must be set.r   Tcentroidr
   r!   r   edgerR   z!mode must be 'edge' or 'centroid')r    ri   	TypeErrorr   r   anycopyr9   rT   rU   connectedComponentsWithStatsCC_STAT_AREAr1   argmaxr8   hypotre   r2   sqrtr7   wheredistanceTransformDIST_L2r4   r   )rY   absolute_distancerelative_distancerd   moderH   rI   image
num_labelsrj   statsr<   areas
main_labeldiagonal	thresholdkeep_labelsdifferences	distancesnearby	main_maskinversedistance_transformlabel	componentmin_distances                             r   filter_segments_by_distancer   #  sJ   b zzT.//JJMFE66$<yy{KK!E
 ,/+K+KL,(Jy Qyy{!"c&&&'ES5)**J$&%01+,x7			&+,	UVV)+*D)IK"K
zmi
&;;GGBFF;>:;	RXXi945a88"F" v! 
z)11"((;	i- 227CKKK1j) 	*E
"%I66)$ !3I!>!B!B!DELy(%)E"	* v <==r   )r   npt.NDArray[np.bool_]r   znpt.NDArray[np.int32]r   ztuple[int, int]r,   r   )r   znpt.NDArray[Any] | CompactMaskr,   znpt.NDArray[np.int_])rY   r   r,   ri   )ra   )rY   r   rd   r1   r,   ri   )i  )r   npt.NDArray[Any]rq   r1   r,   r   )g      Y@Nrb   r   )rY   r   r   float | Noner   r   rd   r1   r   zLiteral['edge', 'centroid']r,   r   )
__future__r   typingr   r   r   rU   numpyr   numpy.typingr%   "supervision.detection.compact_maskr   r   rP   r_   rl   r|   r    r   r   <module>r      s    " % % 
   :K K!K #K 	K\:)::z/f 67;&
;&/2;&	;&|H< ',&*(.G
G#G $G 	G
 &G Gr   