Files
wehub-resource-sync 9194ef5abd
Docs/Test Workflow / Test docs build (push) Failing after 0s
Check links & references / links-check (push) Failing after 1s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.10) (push) Failing after 0s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.11) (push) Failing after 0s
PR Conflict Labeler / main (push) Failing after 2s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.12) (push) Failing after 2s
Pytest/Test Workflow / Import Test and Pytest Run (ubuntu-latest, 3.13) (push) Failing after 0s
Pytest/Test Workflow / Build this Package (push) Failing after 5s
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.10) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.11) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.12) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (macos-latest, 3.13) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.10) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.11) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.12) (push) Has been cancelled
Pytest/Test Workflow / Import Test and Pytest Run (windows-latest, 3.13) (push) Has been cancelled
Pytest/Test Workflow / testing-guardian (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:06:10 +08:00

238 lines
7.0 KiB
Python

import numpy as np
import pytest
from supervision.detection.core import Detections
from supervision.detection.utils.converters import mask_to_rle
SERVERLESS_SAM3_DICT = {
"prompt_results": [
{
"prompt_index": 0,
"echo": {
"prompt_index": 0,
"type": "text",
"text": "person",
"num_boxes": 0,
},
"predictions": [
{
"masks": [[[295, 675], [294, 676]], [[496, 617], [495, 618]]],
"confidence": 0.94921875,
"format": "polygon",
}
],
},
{
"prompt_index": 1,
"echo": {"prompt_index": 1, "type": "text", "text": "dog", "num_boxes": 0},
"predictions": [
{
"masks": [[[316, 561], [316, 562]], [[345, 251], [344, 252]]],
"confidence": 0.89453125,
"format": "polygon",
}
],
},
],
"time": 0.14756996370851994,
}
HOSTED_SAM3_DICT = {
"prompt_results": [
{
"prompt_index": 0,
"echo": {
"prompt_index": 0,
"type": "text",
"text": "bottle",
"num_boxes": 0,
},
"predictions": [
{
"masks": [[[1364, 200], [1365, 201]]],
"confidence": 0.8984375,
"format": "polygon",
},
{
"masks": [[[1140, 171], [1139, 170]]],
"confidence": 0.94140625,
"format": "polygon",
},
],
}
],
"time": 0.7277156260097399,
}
SERVERLESS_SAM3_PVS_DICT = {
"predictions": [
{
"masks": [
[[713, 1276], [713, 1279], [714, 1279], [714, 1277]],
[[711, 1273]],
[[671, 1231], [671, 1234]],
[[523, 1222], [522, 1223]],
],
"confidence": 0.0025782063603401184,
"format": "polygon",
}
],
"time": 0.07825545498053543,
}
@pytest.mark.parametrize(
("sam_result", "expected_xyxy", "expected_mask_shape"),
[
(
[
{
"segmentation": np.ones((10, 10), dtype=bool),
"bbox": [0, 0, 10, 10],
"area": 100,
}
],
np.array([[0, 0, 10, 10]], dtype=np.float32),
(1, 10, 10),
),
([], np.empty((0, 4), dtype=np.float32), None),
],
)
def test_from_sam(
sam_result: list[dict],
expected_xyxy: np.ndarray,
expected_mask_shape: tuple[int, ...] | None,
) -> None:
detections = Detections.from_sam(sam_result=sam_result)
assert np.array_equal(detections.xyxy, expected_xyxy)
if expected_mask_shape is not None:
assert detections.mask.shape == expected_mask_shape
else:
assert detections.mask is None
def test_from_sam_decodes_coco_rle_masks() -> None:
"""COCO RLE SAM outputs are decoded to dense boolean masks."""
small_mask = np.zeros((4, 4), dtype=bool)
small_mask[3, 3] = True
large_mask = np.zeros((4, 4), dtype=bool)
large_mask[:2, :2] = True
sam_result = [
{
"segmentation": {
"size": [4, 4],
"counts": mask_to_rle(small_mask, compressed=True),
},
"bbox": [3, 3, 1, 1],
"area": 1,
},
{
"segmentation": {
"size": [4, 4],
"counts": mask_to_rle(large_mask, compressed=True),
},
"bbox": [0, 0, 2, 2],
"area": 4,
},
]
detections = Detections.from_sam(sam_result=sam_result)
assert len(detections) == 2
assert isinstance(detections.mask, np.ndarray)
assert detections.mask.dtype == bool
assert detections.mask.shape == (2, 4, 4)
np.testing.assert_array_equal(detections.mask, np.stack([large_mask, small_mask]))
np.testing.assert_array_equal(
detections.xyxy,
np.array([[0, 0, 2, 2], [3, 3, 4, 4]], dtype=np.float32),
)
@pytest.mark.parametrize(
(
"sam3_result",
"resolution_wh",
"expected_xyxy",
"expected_confidence",
"expected_class_id",
),
[
(
{
"prompt_results": [
{
"predictions": [
{
"format": "polygon",
"masks": [[[0, 0], [10, 0], [10, 10], [0, 10]]],
"confidence": 0.9,
}
],
"prompt_index": 0,
}
]
},
(100, 100),
np.array([[0, 0, 10, 10]], dtype=np.float32),
np.array([0.9], dtype=np.float32),
np.array([0], dtype=int),
),
(
{"prompt_results": []},
(100, 100),
np.empty((0, 4), dtype=np.float32),
np.empty((0,), dtype=np.float32),
np.empty((0,), dtype=int),
),
(
SERVERLESS_SAM3_DICT,
(1000, 1000),
np.array(
[[294.0, 617.0, 496.0, 676.0], [316.0, 251.0, 345.0, 562.0]],
dtype=np.float32,
),
np.array([0.94921875, 0.89453125], dtype=np.float32),
np.array([0, 1], dtype=int),
),
(
HOSTED_SAM3_DICT,
(2000, 2000),
np.array(
[[1364.0, 200.0, 1365.0, 201.0], [1139.0, 170.0, 1140.0, 171.0]],
dtype=np.float32,
),
np.array([0.898438, 0.941406], dtype=np.float32),
np.array([0, 0], dtype=int),
),
(
SERVERLESS_SAM3_PVS_DICT,
(2000, 2000),
np.array([[522.0, 1222.0, 714.0, 1279.0]], dtype=np.float32),
np.array([0.00257821], dtype=np.float32),
np.array([0], dtype=int),
),
],
)
def test_from_sam3(
sam3_result: dict,
resolution_wh: tuple[int, int],
expected_xyxy: np.ndarray,
expected_confidence: np.ndarray,
expected_class_id: np.ndarray,
) -> None:
detections = Detections.from_sam3(
sam3_result=sam3_result, resolution_wh=resolution_wh
)
np.testing.assert_allclose(detections.xyxy, expected_xyxy, atol=1e-5)
np.testing.assert_allclose(detections.confidence, expected_confidence, atol=1e-5)
np.testing.assert_array_equal(detections.class_id, expected_class_id)
def test_from_sam3_invalid_resolution() -> None:
sam3_result = {"prompt_results": []}
with pytest.raises(
ValueError, match=r"Both dimensions in resolution must be positive\."
):
Detections.from_sam3(sam3_result=sam3_result, resolution_wh=(-100, 100))