Merge branch 'develop' into fix/docs/track_objects
This commit is contained in:
commit
8a905ce79a
|
|
@ -11,6 +11,12 @@ status: new
|
|||
|
||||
:::supervision.detection.utils.box_iou_batch
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.box_iou_batch_with_jaccard">box_iou_batch_with_jaccard</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.box_iou_batch_with_jaccard
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.mask_iou_batch">mask_iou_batch</a></h2>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,3 +16,9 @@ status: new
|
|||
</div>
|
||||
|
||||
:::supervision.metrics.mean_average_precision.MeanAveragePrecisionResult
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.dataset.formats.coco.get_coco_class_index_mapping">get_coco_class_index_mapping</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.dataset.formats.coco.get_coco_class_index_mapping
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ from supervision.dataset.core import (
|
|||
ClassificationDataset,
|
||||
DetectionDataset,
|
||||
)
|
||||
from supervision.dataset.formats.coco import get_coco_class_index_mapping
|
||||
from supervision.dataset.utils import mask_to_rle, rle_to_mask
|
||||
from supervision.detection.core import Detections
|
||||
from supervision.detection.line_zone import (
|
||||
|
|
@ -58,6 +59,7 @@ from supervision.detection.tools.polygon_zone import PolygonZone, PolygonZoneAnn
|
|||
from supervision.detection.tools.smoother import DetectionsSmoother
|
||||
from supervision.detection.utils import (
|
||||
box_iou_batch,
|
||||
box_iou_batch_with_jaccard,
|
||||
calculate_masks_centroids,
|
||||
clip_boxes,
|
||||
contains_holes,
|
||||
|
|
@ -180,6 +182,7 @@ __all__ = [
|
|||
"VideoInfo",
|
||||
"VideoSink",
|
||||
"box_iou_batch",
|
||||
"box_iou_batch_with_jaccard",
|
||||
"box_non_max_merge",
|
||||
"box_non_max_suppression",
|
||||
"calculate_masks_centroids",
|
||||
|
|
@ -199,6 +202,7 @@ __all__ = [
|
|||
"draw_rectangle",
|
||||
"draw_text",
|
||||
"filter_polygons_by_area",
|
||||
"get_coco_class_index_mapping",
|
||||
"get_polygon_center",
|
||||
"get_video_frames_generator",
|
||||
"letterbox_image",
|
||||
|
|
|
|||
|
|
@ -574,7 +574,6 @@ class DetectionDataset(BaseDataset):
|
|||
force_masks (bool): If True,
|
||||
forces masks to be loaded for all annotations,
|
||||
regardless of whether they are present.
|
||||
|
||||
Returns:
|
||||
DetectionDataset: A DetectionDataset instance containing
|
||||
the loaded images and annotations.
|
||||
|
|
|
|||
|
|
@ -90,7 +90,10 @@ def coco_annotations_to_masks(
|
|||
|
||||
|
||||
def coco_annotations_to_detections(
|
||||
image_annotations: List[dict], resolution_wh: Tuple[int, int], with_masks: bool
|
||||
image_annotations: List[dict],
|
||||
resolution_wh: Tuple[int, int],
|
||||
with_masks: bool,
|
||||
use_iscrowd: bool = True,
|
||||
) -> Detections:
|
||||
if not image_annotations:
|
||||
return Detections.empty()
|
||||
|
|
@ -102,15 +105,26 @@ def coco_annotations_to_detections(
|
|||
xyxy = np.asarray(xyxy)
|
||||
xyxy[:, 2:4] += xyxy[:, 0:2]
|
||||
|
||||
data = dict()
|
||||
if use_iscrowd:
|
||||
iscrowd = [
|
||||
image_annotation["iscrowd"] for image_annotation in image_annotations
|
||||
]
|
||||
area = [image_annotation["area"] for image_annotation in image_annotations]
|
||||
data = dict(
|
||||
iscrowd=np.asarray(iscrowd, dtype=int), area=np.asarray(area, dtype=float)
|
||||
)
|
||||
|
||||
if with_masks:
|
||||
mask = coco_annotations_to_masks(
|
||||
image_annotations=image_annotations, resolution_wh=resolution_wh
|
||||
)
|
||||
return Detections(
|
||||
class_id=np.asarray(class_ids, dtype=int), xyxy=xyxy, mask=mask
|
||||
)
|
||||
else:
|
||||
mask = None
|
||||
|
||||
return Detections(xyxy=xyxy, class_id=np.asarray(class_ids, dtype=int))
|
||||
return Detections(
|
||||
class_id=np.asarray(class_ids, dtype=int), xyxy=xyxy, mask=mask, data=data
|
||||
)
|
||||
|
||||
|
||||
def detections_to_coco_annotations(
|
||||
|
|
@ -159,16 +173,58 @@ def detections_to_coco_annotations(
|
|||
return coco_annotations, annotation_id
|
||||
|
||||
|
||||
def get_coco_class_index_mapping(annotations_path: str) -> Dict[int, int]:
|
||||
"""
|
||||
Generates a mapping from sequential class indices to original COCO class ids.
|
||||
|
||||
This function is essential when working with models that expect class ids to be
|
||||
zero-indexed and sequential (0 to 79), as opposed to the original COCO
|
||||
dataset where category ids are non-contiguous ranging from 1 to 90 but skipping some
|
||||
ids.
|
||||
|
||||
Use Cases:
|
||||
- Evaluating models trained with COCO-style annotations where class ids
|
||||
are sequential ranging from 0 to 79.
|
||||
- Ensuring consistent class indexing across training, inference and evaluation,
|
||||
when using different tools or datasets with COCO format.
|
||||
- Reproducing results from models that assume sequential class ids (0 to 79).
|
||||
|
||||
How it Works:
|
||||
- Reads the COCO annotation file in its original format (`annotations_path`).
|
||||
- Extracts and sorts all class names by their original COCO id (1 to 90).
|
||||
- Builds a mapping from COCO class ids (not sequential with skipped ids) to
|
||||
new class ids (sequential ranging from 0 to 79).
|
||||
- Returns a dictionary mapping: `{new_class_id: original_COCO_class_id}`.
|
||||
|
||||
Args:
|
||||
annotations_path (str): Path to COCO JSON annotations file
|
||||
(e.g., `instances_val2017.json`).
|
||||
|
||||
Returns:
|
||||
Dict[int, int]: A mapping from new class id (sequential ranging from 0 to 79)
|
||||
to original COCO class id (1 to 90 with skipped ids).
|
||||
"""
|
||||
coco_data = read_json_file(annotations_path)
|
||||
classes = coco_categories_to_classes(coco_categories=coco_data["categories"])
|
||||
class_mapping = build_coco_class_index_mapping(
|
||||
coco_categories=coco_data["categories"], target_classes=classes
|
||||
)
|
||||
return {v: k for k, v in class_mapping.items()}
|
||||
|
||||
|
||||
def load_coco_annotations(
|
||||
images_directory_path: str,
|
||||
annotations_path: str,
|
||||
force_masks: bool = False,
|
||||
use_iscrowd: bool = True,
|
||||
) -> Tuple[List[str], List[str], Dict[str, Detections]]:
|
||||
coco_data = read_json_file(file_path=annotations_path)
|
||||
classes = coco_categories_to_classes(coco_categories=coco_data["categories"])
|
||||
|
||||
class_index_mapping = build_coco_class_index_mapping(
|
||||
coco_categories=coco_data["categories"], target_classes=classes
|
||||
)
|
||||
|
||||
coco_images = coco_data["images"]
|
||||
coco_annotations_groups = group_coco_annotations_by_image_id(
|
||||
coco_annotations=coco_data["annotations"]
|
||||
|
|
@ -190,7 +246,9 @@ def load_coco_annotations(
|
|||
image_annotations=image_annotations,
|
||||
resolution_wh=(image_width, image_height),
|
||||
with_masks=force_masks,
|
||||
use_iscrowd=use_iscrowd,
|
||||
)
|
||||
|
||||
annotation = map_detections_class_id(
|
||||
source_to_target_mapping=class_index_mapping,
|
||||
detections=annotation,
|
||||
|
|
|
|||
|
|
@ -1325,3 +1325,103 @@ def spread_out_boxes(
|
|||
xyxy_padded[:, [2, 3]] += force_vectors
|
||||
|
||||
return pad_boxes(xyxy_padded, px=-1)
|
||||
|
||||
|
||||
def _jaccard(box_a: List[float], box_b: List[float], is_crowd: bool) -> float:
|
||||
"""
|
||||
Calculate the Jaccard index (intersection over union) between two bounding boxes.
|
||||
If a gt object is marked as "iscrowd", a dt is allowed to match any subregion
|
||||
of the gt. Choosing gt' in the crowd gt that best matches the dt can be done using
|
||||
gt'=intersect(dt,gt). Since by definition union(gt',dt)=dt, computing
|
||||
iou(gt,dt,iscrowd) = iou(gt',dt) = area(intersect(gt,dt)) / area(dt)
|
||||
|
||||
Args:
|
||||
box_a (List[float]): Box coordinates in the format [x, y, width, height].
|
||||
box_b (List[float]): Box coordinates in the format [x, y, width, height].
|
||||
iscrowd (bool): Flag indicating if the second box is a crowd region or not.
|
||||
|
||||
Returns:
|
||||
float: Jaccard index between the two bounding boxes.
|
||||
"""
|
||||
# Smallest number to avoid division by zero
|
||||
EPS = np.spacing(1)
|
||||
|
||||
xa, ya, x2a, y2a = box_a[0], box_a[1], box_a[0] + box_a[2], box_a[1] + box_a[3]
|
||||
xb, yb, x2b, y2b = box_b[0], box_b[1], box_b[0] + box_b[2], box_b[1] + box_b[3]
|
||||
|
||||
# Innermost left x
|
||||
xi = max(xa, xb)
|
||||
# Innermost right x
|
||||
x2i = min(x2a, x2b)
|
||||
# Same for y
|
||||
yi = max(ya, yb)
|
||||
y2i = min(y2a, y2b)
|
||||
|
||||
# Calculate areas
|
||||
Aa = max(x2a - xa, 0.0) * max(y2a - ya, 0.0)
|
||||
Ab = max(x2b - xb, 0.0) * max(y2b - yb, 0.0)
|
||||
Ai = max(x2i - xi, 0.0) * max(y2i - yi, 0.0)
|
||||
|
||||
if is_crowd:
|
||||
return Ai / (Aa + EPS)
|
||||
|
||||
return Ai / (Aa + Ab - Ai + EPS)
|
||||
|
||||
|
||||
def box_iou_batch_with_jaccard(
|
||||
boxes_true: List[List[float]],
|
||||
boxes_detection: List[List[float]],
|
||||
is_crowd: List[bool],
|
||||
) -> np.ndarray:
|
||||
"""
|
||||
Calculate the intersection over union (IoU) between detection bounding boxes (dt)
|
||||
and ground-truth bounding boxes (gt).
|
||||
Reference: https://github.com/rafaelpadilla/review_object_detection_metrics
|
||||
|
||||
Args:
|
||||
boxes_true (List[List[float]]): List of ground-truth bounding boxes in the \
|
||||
format [x, y, width, height].
|
||||
boxes_detection (List[List[float]]): List of detection bounding boxes in the \
|
||||
format [x, y, width, height].
|
||||
is_crowd (List[bool]): List indicating if each ground-truth bounding box \
|
||||
is a crowd region or not.
|
||||
|
||||
Returns:
|
||||
np.ndarray: Array of IoU values of shape (len(dt), len(gt)).
|
||||
|
||||
Examples:
|
||||
```python
|
||||
import numpy as np
|
||||
import supervision as sv
|
||||
|
||||
boxes_true = [
|
||||
[10, 20, 30, 40], # x, y, w, h
|
||||
[15, 25, 35, 45]
|
||||
]
|
||||
boxes_detection = [
|
||||
[12, 22, 28, 38],
|
||||
[16, 26, 36, 46]
|
||||
]
|
||||
is_crowd = [False, False]
|
||||
|
||||
ious = sv.box_iou_batch_with_jaccard(
|
||||
boxes_true=boxes_true,
|
||||
boxes_detection=boxes_detection,
|
||||
is_crowd=is_crowd
|
||||
)
|
||||
# array([
|
||||
# [0.8866..., 0.4960...],
|
||||
# [0.4000..., 0.8622...]
|
||||
# ])
|
||||
```
|
||||
"""
|
||||
assert len(is_crowd) == len(boxes_true), (
|
||||
"`is_crowd` must have the same length as `boxes_true`"
|
||||
)
|
||||
if len(boxes_detection) == 0 or len(boxes_true) == 0:
|
||||
return np.array([])
|
||||
ious = np.zeros((len(boxes_detection), len(boxes_true)), dtype=np.float64)
|
||||
for g_idx, g in enumerate(boxes_true):
|
||||
for d_idx, d in enumerate(boxes_detection):
|
||||
ious[d_idx, g_idx] = _jaccard(d, g, is_crowd[g_idx])
|
||||
return ious
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -162,12 +162,22 @@ def test_group_coco_annotations_by_image_id(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_annotations, resolution_wh, with_masks, expected_result, exception",
|
||||
"image_annotations, resolution_wh, with_masks, use_iscrowd, "
|
||||
"expected_result, exception",
|
||||
[
|
||||
(
|
||||
[],
|
||||
(1000, 1000),
|
||||
False,
|
||||
False,
|
||||
Detections.empty(),
|
||||
DoesNotRaise(),
|
||||
), # empty image annotations
|
||||
(
|
||||
[],
|
||||
(1000, 1000),
|
||||
False,
|
||||
True,
|
||||
Detections.empty(),
|
||||
DoesNotRaise(),
|
||||
), # empty image annotations
|
||||
|
|
@ -179,12 +189,32 @@ def test_group_coco_annotations_by_image_id(
|
|||
],
|
||||
(1000, 1000),
|
||||
False,
|
||||
False,
|
||||
Detections(
|
||||
xyxy=np.array([[0, 0, 100, 100]], dtype=np.float32),
|
||||
class_id=np.array([0], dtype=int),
|
||||
),
|
||||
DoesNotRaise(),
|
||||
), # single image annotations
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
category_id=0, bbox=(0, 0, 100, 100), area=100 * 100
|
||||
)
|
||||
],
|
||||
(1000, 1000),
|
||||
False,
|
||||
True,
|
||||
Detections(
|
||||
xyxy=np.array([[0, 0, 100, 100]], dtype=np.float32),
|
||||
class_id=np.array([0], dtype=int),
|
||||
data={
|
||||
"iscrowd": np.array([0], dtype=int),
|
||||
"area": np.array([100 * 100]),
|
||||
},
|
||||
),
|
||||
DoesNotRaise(),
|
||||
),
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
|
|
@ -196,6 +226,7 @@ def test_group_coco_annotations_by_image_id(
|
|||
],
|
||||
(1000, 1000),
|
||||
False,
|
||||
False,
|
||||
Detections(
|
||||
xyxy=np.array(
|
||||
[[0, 0, 100, 100], [100, 100, 200, 200]], dtype=np.float32
|
||||
|
|
@ -204,6 +235,30 @@ def test_group_coco_annotations_by_image_id(
|
|||
),
|
||||
DoesNotRaise(),
|
||||
), # two image annotations
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
category_id=0, bbox=(0, 0, 100, 100), area=100 * 100
|
||||
),
|
||||
mock_coco_annotation(
|
||||
category_id=0, bbox=(100, 100, 100, 100), area=100 * 100
|
||||
),
|
||||
],
|
||||
(1000, 1000),
|
||||
False,
|
||||
True,
|
||||
Detections(
|
||||
xyxy=np.array(
|
||||
[[0, 0, 100, 100], [100, 100, 200, 200]], dtype=np.float32
|
||||
),
|
||||
class_id=np.array([0, 0], dtype=int),
|
||||
data={
|
||||
"iscrowd": np.array([0, 0], dtype=int),
|
||||
"area": np.array([100 * 100, 100 * 100]),
|
||||
},
|
||||
),
|
||||
DoesNotRaise(),
|
||||
),
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
|
|
@ -215,6 +270,7 @@ def test_group_coco_annotations_by_image_id(
|
|||
],
|
||||
(5, 5),
|
||||
True,
|
||||
False,
|
||||
Detections(
|
||||
xyxy=np.array([[0, 0, 5, 5]], dtype=np.float32),
|
||||
class_id=np.array([0], dtype=int),
|
||||
|
|
@ -232,6 +288,36 @@ def test_group_coco_annotations_by_image_id(
|
|||
),
|
||||
DoesNotRaise(),
|
||||
), # single image annotations with mask as polygon
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
category_id=0,
|
||||
bbox=(0, 0, 5, 5),
|
||||
area=5 * 5,
|
||||
segmentation=[[0, 0, 2, 0, 2, 2, 4, 2, 4, 4, 0, 4]],
|
||||
)
|
||||
],
|
||||
(5, 5),
|
||||
True,
|
||||
True,
|
||||
Detections(
|
||||
xyxy=np.array([[0, 0, 5, 5]], dtype=np.float32),
|
||||
class_id=np.array([0], dtype=int),
|
||||
mask=np.array(
|
||||
[
|
||||
[
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
]
|
||||
]
|
||||
),
|
||||
data={"iscrowd": np.array([0], dtype=int), "area": np.array([25])},
|
||||
),
|
||||
DoesNotRaise(),
|
||||
),
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
|
|
@ -247,6 +333,7 @@ def test_group_coco_annotations_by_image_id(
|
|||
],
|
||||
(5, 5),
|
||||
True,
|
||||
False,
|
||||
Detections(
|
||||
xyxy=np.array([[0, 0, 5, 5]], dtype=np.float32),
|
||||
class_id=np.array([0], dtype=int),
|
||||
|
|
@ -264,6 +351,40 @@ def test_group_coco_annotations_by_image_id(
|
|||
),
|
||||
DoesNotRaise(),
|
||||
), # single image annotations with mask, RLE segmentation mask
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
category_id=0,
|
||||
bbox=(0, 0, 5, 5),
|
||||
area=5 * 5,
|
||||
segmentation={
|
||||
"size": [5, 5],
|
||||
"counts": [0, 15, 2, 3, 2, 3],
|
||||
},
|
||||
iscrowd=True,
|
||||
)
|
||||
],
|
||||
(5, 5),
|
||||
True,
|
||||
True,
|
||||
Detections(
|
||||
xyxy=np.array([[0, 0, 5, 5]], dtype=np.float32),
|
||||
class_id=np.array([0], dtype=int),
|
||||
mask=np.array(
|
||||
[
|
||||
[
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
]
|
||||
]
|
||||
),
|
||||
data={"iscrowd": np.array([1], dtype=int), "area": np.array([25])},
|
||||
),
|
||||
DoesNotRaise(),
|
||||
),
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
|
|
@ -285,6 +406,7 @@ def test_group_coco_annotations_by_image_id(
|
|||
],
|
||||
(5, 5),
|
||||
True,
|
||||
False,
|
||||
Detections(
|
||||
xyxy=np.array([[0, 0, 5, 5], [3, 0, 5, 2]], dtype=np.float32),
|
||||
class_id=np.array([0, 0], dtype=int),
|
||||
|
|
@ -309,6 +431,57 @@ def test_group_coco_annotations_by_image_id(
|
|||
),
|
||||
DoesNotRaise(),
|
||||
), # two image annotations with mask, one mask as polygon and second as RLE
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
category_id=0,
|
||||
bbox=(0, 0, 5, 5),
|
||||
area=5 * 5,
|
||||
segmentation=[[0, 0, 2, 0, 2, 2, 4, 2, 4, 4, 0, 4]],
|
||||
),
|
||||
mock_coco_annotation(
|
||||
category_id=0,
|
||||
bbox=(3, 0, 2, 2),
|
||||
area=2 * 2,
|
||||
segmentation={
|
||||
"size": [5, 5],
|
||||
"counts": [15, 2, 3, 2, 3],
|
||||
},
|
||||
iscrowd=True,
|
||||
),
|
||||
],
|
||||
(5, 5),
|
||||
True,
|
||||
True,
|
||||
Detections(
|
||||
xyxy=np.array([[0, 0, 5, 5], [3, 0, 5, 2]], dtype=np.float32),
|
||||
class_id=np.array([0, 0], dtype=int),
|
||||
mask=np.array(
|
||||
[
|
||||
[
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
],
|
||||
[
|
||||
[0, 0, 0, 1, 1],
|
||||
[0, 0, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
],
|
||||
]
|
||||
),
|
||||
data={
|
||||
"iscrowd": np.array([0, 1], dtype=int),
|
||||
"area": np.array([25, 4]),
|
||||
},
|
||||
),
|
||||
DoesNotRaise(),
|
||||
), # two image annotations with mask, one mask as polygon with iscrowd,
|
||||
# and second as RLE without iscrowd
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
|
|
@ -330,6 +503,7 @@ def test_group_coco_annotations_by_image_id(
|
|||
],
|
||||
(5, 5),
|
||||
True,
|
||||
False,
|
||||
Detections(
|
||||
xyxy=np.array([[3, 0, 5, 2], [0, 0, 5, 5]], dtype=np.float32),
|
||||
class_id=np.array([0, 1], dtype=int),
|
||||
|
|
@ -354,12 +528,64 @@ def test_group_coco_annotations_by_image_id(
|
|||
),
|
||||
DoesNotRaise(),
|
||||
), # two image annotations with mask, first mask as RLE and second as polygon
|
||||
(
|
||||
[
|
||||
mock_coco_annotation(
|
||||
category_id=0,
|
||||
bbox=(3, 0, 2, 2),
|
||||
area=2 * 2,
|
||||
segmentation={
|
||||
"size": [5, 5],
|
||||
"counts": [15, 2, 3, 2, 3],
|
||||
},
|
||||
iscrowd=True,
|
||||
),
|
||||
mock_coco_annotation(
|
||||
category_id=1,
|
||||
bbox=(0, 0, 5, 5),
|
||||
area=5 * 5,
|
||||
segmentation=[[0, 0, 2, 0, 2, 2, 4, 2, 4, 4, 0, 4]],
|
||||
),
|
||||
],
|
||||
(5, 5),
|
||||
True,
|
||||
True,
|
||||
Detections(
|
||||
xyxy=np.array([[3, 0, 5, 2], [0, 0, 5, 5]], dtype=np.float32),
|
||||
class_id=np.array([0, 1], dtype=int),
|
||||
mask=np.array(
|
||||
[
|
||||
[
|
||||
[0, 0, 0, 1, 1],
|
||||
[0, 0, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
],
|
||||
[
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
],
|
||||
]
|
||||
),
|
||||
data={
|
||||
"iscrowd": np.array([1, 0], dtype=int),
|
||||
"area": np.array([4, 25]),
|
||||
},
|
||||
),
|
||||
DoesNotRaise(),
|
||||
), # two image annotations with mask, first mask as RLE with is crowd,
|
||||
# and second as polygon without iscrowd
|
||||
],
|
||||
)
|
||||
def test_coco_annotations_to_detections(
|
||||
image_annotations: List[dict],
|
||||
resolution_wh: Tuple[int, int],
|
||||
with_masks: bool,
|
||||
use_iscrowd: bool,
|
||||
expected_result: Detections,
|
||||
exception: Exception,
|
||||
) -> None:
|
||||
|
|
@ -368,6 +594,7 @@ def test_coco_annotations_to_detections(
|
|||
image_annotations=image_annotations,
|
||||
resolution_wh=resolution_wh,
|
||||
with_masks=with_masks,
|
||||
use_iscrowd=use_iscrowd,
|
||||
)
|
||||
assert result == expected_result
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue