Ë
    ¼Ó^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ÐMÈuÓU€Jàˆa�y�1‚}Ø  ™)˜ˆÜ˜5Ÿ;™; q™>¨=¸Ñ+;¸fÀQ¹iÑ+GÓHˆØÐÜ ¨aÑ 0°%·+±+¸a±.À6È!Á9Ñ2LÓMÑàˆÜ˜5Ÿ;™; q™>¨=¸Ñ+;¸fÀQ¹iÑ+GÓHˆØ$ Q™iÐØ" 1™I¨Ñ4°~ÑEÐàˆa�y�1‚}Ø  ™)˜ˆÜ˜5Ÿ;™; q™>¨=¸Ñ+;¸fÀQ¹iÑ+GÓHˆØÐÜ ¨aÑ 0°%·+±+¸a±.À6È!Á9Ñ2LÓMÑàˆÜ˜5Ÿ;™; q™>¨=¸Ñ+;¸fÀQ¹iÑ+GÓHˆØ$ Q™iÐØ" 1™I¨Ñ4°~ÑEÐà�nÒ$¨¸Ò)Fð
 ’!�^ LÐ0°.ÀÐ2MÐMÑNð	 	ÚØÐ 1Ð1ØÐ 1Ð1ð3ñ	
ð Ðó    c                ó"  ‡ — t        ‰ t        «      �r¸t        ‰ «      }|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-   ø€ ô ”C—K‘K¤§¡Ñ,¬b¯l©l¸5À'Ð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ÜœŸ™¤B§G¡GÑ,¬b¯h©h°vÄSÔ.IÓJÐJä-/¯X©X°q¸!°fÄBÇJÁJÔ-Oˆ	Ü�q“ò 	$ˆAØ—:‘:˜a“=ˆDØ!ŸZ™Z‰NˆF�FÜ�U—]‘] 1 a 4Ñ(Ó)ˆBÜ�U—]‘] 1 a 4Ñ(Ó)ˆBÜ˜Ÿ™›
“OˆEØ˜ŠzØ # S˜z�	˜!‘Øä#%§:¡:¨v°vÐ.>Ó#?Ñ ˆI�yÜ”r—v‘v˜y¨3™°Ñ5Ó6Ó7¸%Ñ?À"ÑDˆBÜ”r—v‘v˜y¨3™°Ñ5Ó6Ó7¸%Ñ?À"ÑDˆBØ ˜8ˆI�aŠLð	$ô ”C—K‘K¤§¡Ñ(¨)×*:Ñ*:¼3Ó*?Ó@Ð@à %§¡Ñ€J�˜Ø—9‘9 &�9Ó)€Lô ,.¯:©:°v¸u°oÓ+FÈÑ+LÑ(ÐÐ(à&'€L� Ñ"Ñ#ðWØ)ðWØ1LðWà	!õWð
 78¸°V¸aÀ¸VÐ4DÐÙÐ1Ð3CÓDÀ|ÑS€JÙÐ/Ð1AÓBÀ\ÑQ€JäÜ�‰”B—G‘GÑœbŸo™o¨z¸:Ð.FÓG×NÑNÌsÓ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 —‘œRŸX™XÓ&€JÜ×#Ñ# J´·±Ä×@WÑ@WÓX�L€A€yàÐØ ÐØ˜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ó
ð 	
ð —‘œRŸX™XÓ&€JÜ�]‰]˜:¬R¯X©XÔ6€FÜ×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Õ   € ð —k‘k !‘n€JØ—[‘[ ‘^€IÜ� 
Ñ*¨M¸IÑ,EÓF€Eä�U˜ZÑ'Ó(€JÜ�E˜IÑ%Ó&€Iä
�‰�A�y 1‘} iÓ0×7Ñ7¼Ó<€AÜ
�‰�A�z A‘~ zÓ2×9Ñ9¼#Ó>€AÜ�[‰[˜˜AÓ�F€Bˆàš!˜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 ‡z�z”TÒÜÐ.Ó/Ð/à—J‘J�M€FˆEÜ�6‰6�$Œ<Ø�y‰y‹{Ðà�K‰KœŸ™Ó!€Eô
 ,/×+KÑ+KØ˜Lô,Ñ(€J�˜˜yð �Q‚Ø�y‰y‹{Ðà�!‘"”c×&Ñ&Ð&Ñ'€EØ”SœŸ™ 5Ó)Ó*Ñ*€JàÐ$ÜœŸ™ &¨%Ó0Ó1ˆÜÐ+Ó,¨xÑ7‰	Ø	Ð	&ÜÐ+Ó,‰	äÐUÓVÐVä)+¯©°*ÄDÔ)I€KØ"€K�
ÑàˆzÒØ  �m i°
Ñ&;Ñ;ˆÜ—G‘GœBŸF™F ;°¡>¸Ô:Ó;ˆ	Ø”R—X‘X˜i¨9Ñ4Ó5°aÑ8Ñ8ˆØ"ˆ�FÑð" �vÑÐð! 
�ŠØ˜zÑ)×1Ñ1´"·(±(Ó;ˆ	Ø�i‘-ˆÜ ×2Ñ2°7¼C¿K¹KÈÓKÐÜ˜1˜jÓ)ò 	*ˆEØ˜
Ò"ØØ %™ˆIÜ—6‘6˜)Ô$ØÜ Ð!3°IÑ!>×!BÑ!BÓ!DÓEˆLØ˜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   