diff --git a/docs/detection/utils.md b/docs/detection/utils.md index 8b9f91f7..0c42a69e 100644 --- a/docs/detection/utils.md +++ b/docs/detection/utils.md @@ -99,4 +99,4 @@ status: new

mask_has_multiple_segments

-:::supervision.detection.utils.mask_has_multiple_segments \ No newline at end of file +:::supervision.detection.utils.mask_has_multiple_segments diff --git a/supervision/__init__.py b/supervision/__init__.py index 7f50a7ad..51b43ef0 100644 --- a/supervision/__init__.py +++ b/supervision/__init__.py @@ -50,6 +50,8 @@ from supervision.detection.utils import ( calculate_masks_centroids, clip_boxes, filter_polygons_by_area, + mask_has_holes, + mask_has_multiple_segments, mask_iou_batch, mask_non_max_suppression, mask_to_polygons, @@ -60,8 +62,6 @@ from supervision.detection.utils import ( polygon_to_mask, polygon_to_xyxy, scale_boxes, - mask_has_holes, - mask_has_multiple_segments, ) from supervision.draw.color import Color, ColorPalette from supervision.draw.utils import ( diff --git a/supervision/detection/utils.py b/supervision/detection/utils.py index 9dd3d734..35510060 100644 --- a/supervision/detection/utils.py +++ b/supervision/detection/utils.py @@ -857,7 +857,7 @@ def mask_has_holes(mask: npt.NDArray[np.bool_]) -> bool: mask_uint8 = mask.astype(np.uint8) _, hierarchy = cv2.findContours(mask_uint8, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) - if hierarchy: # at least one contour was found + if hierarchy: # at least one contour was found parent_countour_index = 3 for h in hierarchy[0]: if h[parent_countour_index] != -1: diff --git a/test/detection/test_utils.py b/test/detection/test_utils.py index b72ca4bf..2821aed2 100644 --- a/test/detection/test_utils.py +++ b/test/detection/test_utils.py @@ -12,13 +12,13 @@ from supervision.detection.utils import ( clip_boxes, filter_polygons_by_area, get_data_item, + mask_has_holes, + mask_has_multiple_segments, mask_non_max_suppression, merge_data, move_boxes, process_roboflow_result, scale_boxes, - mask_has_holes, - mask_has_multiple_segments, ) TEST_MASK = np.zeros((1, 1000, 1000), dtype=bool) @@ -1273,48 +1273,48 @@ def test_get_data_item( @pytest.mark.parametrize( "mask, expected_result, exception", [ - (np.array([[0, 0, 0, 0], - [0, 1, 1, 0], - [0, 1, 0, 0], - [0, 1, 1, 0]]).astype(bool), - False, - DoesNotRaise(), - ), # foreground object in one continuous piece - (np.array([[1, 0, 0, 0], - [1, 0, 0, 0], - [0, 0, 0, 0], - [0, 1, 1, 0]]).astype(bool), - False, - DoesNotRaise(), - ), # foreground object in 2 seperate elements - (np.array([[0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 0, 0]]).astype(bool), - False, - DoesNotRaise(), - ), # no foreground pixels in mask - (np.array([[1, 1, 1, 1], - [1, 1, 1, 1], - [1, 1, 1, 1], - [1, 1, 1, 1]]).astype(bool), - False, - DoesNotRaise(), - ), # only foreground pixels in mask - (np.array([[1, 1, 1, 0], - [1, 0, 1, 0], - [1, 1, 1, 0], - [0, 0, 0, 0]]).astype(bool), - True, - DoesNotRaise(), - ), # foreground object has 1 hole - (np.array([[1, 1, 1, 0], - [1, 0, 1, 1], - [1, 1, 0, 1], - [0, 1, 1, 1]]).astype(bool), - True, - DoesNotRaise(), - ), # foreground object has 2 holes + ( + np.array([[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 1, 1, 0]]).astype( + bool + ), + False, + DoesNotRaise(), + ), # foreground object in one continuous piece + ( + np.array([[1, 0, 0, 0], [1, 0, 0, 0], [0, 0, 0, 0], [0, 1, 1, 0]]).astype( + bool + ), + False, + DoesNotRaise(), + ), # foreground object in 2 seperate elements + ( + np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]).astype( + bool + ), + False, + DoesNotRaise(), + ), # no foreground pixels in mask + ( + np.array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]).astype( + bool + ), + False, + DoesNotRaise(), + ), # only foreground pixels in mask + ( + np.array([[1, 1, 1, 0], [1, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]]).astype( + bool + ), + True, + DoesNotRaise(), + ), # foreground object has 1 hole + ( + np.array([[1, 1, 1, 0], [1, 0, 1, 1], [1, 1, 0, 1], [0, 1, 1, 1]]).astype( + bool + ), + True, + DoesNotRaise(), + ), # foreground object has 2 holes ], ) def test_mask_has_holes( @@ -1322,84 +1322,84 @@ def test_mask_has_holes( ) -> None: with exception: result = mask_has_holes(mask) - assert result == expected_result + assert result == expected_result @pytest.mark.parametrize( "mask, connectivity, expected_result, exception", [ - (np.array([[0, 0, 0, 0], - [0, 1, 1, 0], - [0, 1, 0, 0], - [0, 1, 1, 0]]).astype(bool), - 4, - False, - DoesNotRaise(), - ), # foreground object in one continuous piece - (np.array([[1, 0, 0, 0], - [1, 0, 0, 0], - [0, 0, 0, 0], - [0, 1, 1, 0]]).astype(bool), - 4, - True, - DoesNotRaise(), - ), # foreground object in 2 seperate elements - (np.array([[0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 0, 0]]).astype(bool), - 4, - False, - DoesNotRaise(), - ), # no foreground pixels in mask - (np.array([[1, 1, 1, 1], - [1, 1, 1, 1], - [1, 1, 1, 1], - [1, 1, 1, 1]]).astype(bool), - 4, - False, - DoesNotRaise(), - ), # only foreground pixels in mask - (np.array([[1, 1, 1, 0], - [1, 0, 1, 1], - [1, 1, 0, 1], - [0, 1, 1, 1]]).astype(bool), - 4, - False, - DoesNotRaise(), - ), # foreground object has 2 holes, but is in single piece - (np.array([[1, 1, 0, 0], - [1, 1, 0, 1], - [1, 0, 1, 1], - [0, 0, 1, 1]]).astype(bool), - 4, - True, - DoesNotRaise(), - ), # foreground object in 2 elements with respect to 4-way connectivity - (np.array([[1, 1, 0, 0], - [1, 1, 0, 1], - [1, 0, 1, 1], - [0, 0, 1, 1]]).astype(bool), - 8, - False, - DoesNotRaise(), - ), # foreground object in single piece with respect to 8-way connectivity - (np.array([[1, 1, 0, 0], - [1, 1, 0, 1], - [1, 0, 1, 1], - [0, 0, 1, 1]]).astype(bool), - 5, - None, - pytest.raises(ValueError), - ), # Incorrect connectivity parameter value, raises ValueError + ( + np.array([[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 1, 1, 0]]).astype( + bool + ), + 4, + False, + DoesNotRaise(), + ), # foreground object in one continuous piece + ( + np.array([[1, 0, 0, 0], [1, 0, 0, 0], [0, 0, 0, 0], [0, 1, 1, 0]]).astype( + bool + ), + 4, + True, + DoesNotRaise(), + ), # foreground object in 2 seperate elements + ( + np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]).astype( + bool + ), + 4, + False, + DoesNotRaise(), + ), # no foreground pixels in mask + ( + np.array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]).astype( + bool + ), + 4, + False, + DoesNotRaise(), + ), # only foreground pixels in mask + ( + np.array([[1, 1, 1, 0], [1, 0, 1, 1], [1, 1, 0, 1], [0, 1, 1, 1]]).astype( + bool + ), + 4, + False, + DoesNotRaise(), + ), # foreground object has 2 holes, but is in single piece + ( + np.array([[1, 1, 0, 0], [1, 1, 0, 1], [1, 0, 1, 1], [0, 0, 1, 1]]).astype( + bool + ), + 4, + True, + DoesNotRaise(), + ), # foreground object in 2 elements with respect to 4-way connectivity + ( + np.array([[1, 1, 0, 0], [1, 1, 0, 1], [1, 0, 1, 1], [0, 0, 1, 1]]).astype( + bool + ), + 8, + False, + DoesNotRaise(), + ), # foreground object in single piece with respect to 8-way connectivity + ( + np.array([[1, 1, 0, 0], [1, 1, 0, 1], [1, 0, 1, 1], [0, 0, 1, 1]]).astype( + bool + ), + 5, + None, + pytest.raises(ValueError), + ), # Incorrect connectivity parameter value, raises ValueError ], ) def test_mask_has_multiple_segments( mask: npt.NDArray[np.bool_], - connectivity: int, - expected_result: bool, - exception: Exception + connectivity: int, + expected_result: bool, + exception: Exception, ) -> None: with exception: - result = mask_has_multiple_segments(mask = mask, connectivity=connectivity) - assert result == expected_result + result = mask_has_multiple_segments(mask=mask, connectivity=connectivity) + assert result == expected_result