From 90d5d6ad5d00fe80882394c7e95827edba3e2fcc Mon Sep 17 00:00:00 2001 From: klemen1999 Date: Sat, 26 Oct 2024 00:04:03 +0200 Subject: [PATCH 1/2] Added check for bbox sum in annoations --- luxonis_ml/data/datasets/annotation.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/luxonis_ml/data/datasets/annotation.py b/luxonis_ml/data/datasets/annotation.py index eb139c6b..6862c474 100644 --- a/luxonis_ml/data/datasets/annotation.py +++ b/luxonis_ml/data/datasets/annotation.py @@ -174,6 +174,24 @@ def validate_values(cls, values: Dict[str, Any]) -> Dict[str, Any]: logger.warning( "BBox annotation has values outside of [0, 1] range. Clipping them to [0, 1]." ) + + # cliping done in function instead of separate model validator so + # order of execution is explicitly defined + values = cls.clip_sum(values) + return values + + @classmethod + def clip_sum(cls, values: Dict[str, Any]) -> Dict[str, Any]: + if values["x"] + values["w"] > 1: + values["w"] = 1 - values["x"] + logger.warning( + "BBox annotation has x + width > 1. Clipping width so the sum is 1." + ) + if values["y"] + values["h"] > 1: + values["h"] = 1 - values["y"] + logger.warning( + "BBox annotation has y + height > 1. Clipping height so the sum is 1." + ) return values def to_numpy(self, class_mapping: Dict[str, int]) -> np.ndarray: From 2e656664a11626c14e138654ec5a46e3b70047be Mon Sep 17 00:00:00 2001 From: klemen1999 Date: Sat, 26 Oct 2024 00:04:35 +0200 Subject: [PATCH 2/2] added tests --- tests/test_data/test_ann_creation.py | 82 ++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tests/test_data/test_ann_creation.py diff --git a/tests/test_data/test_ann_creation.py b/tests/test_data/test_ann_creation.py new file mode 100644 index 00000000..6fe266b1 --- /dev/null +++ b/tests/test_data/test_ann_creation.py @@ -0,0 +1,82 @@ +import pydantic +import pytest + +from luxonis_ml.data.datasets.annotation import ( + BBoxAnnotation, + KeypointAnnotation, + PolylineSegmentationAnnotation, +) + + +def test_bbox_no_auto_clip(): + base_dict = {"x": 0, "y": 0, "w": 0, "h": 0} + for k in ["x", "y", "w", "h"]: + for v in [-2.1, 2.3, -3.3, 3]: + with pytest.raises(pydantic.ValidationError): + curr_dict = base_dict.copy() + curr_dict[k] = v + BBoxAnnotation(**curr_dict) + + +def test_bbox_auto_clip(): + base_dict = {"x": 0, "y": 0, "w": 0, "h": 0} + for k in ["x", "y", "w", "h"]: + for v in [-1.1, 1.3, -1.3, 2]: + curr_dict = base_dict.copy() + curr_dict[k] = v + bbox_ann = BBoxAnnotation(**curr_dict) + assert 0 <= bbox_ann.x <= 1 + assert 0 <= bbox_ann.y <= 1 + assert 0 <= bbox_ann.w <= 1 + assert 0 <= bbox_ann.h <= 1 + + +def test_bbox_clip_sum(): + bbox_ann = BBoxAnnotation(**{"x": 0.9, "y": 0, "w": 0.2, "h": 0}) + assert bbox_ann.x + bbox_ann.w <= 1 + bbox_ann = BBoxAnnotation(**{"x": 1.2, "y": 0, "w": 0.2, "h": 0}) + assert bbox_ann.x + bbox_ann.w <= 1 + bbox_ann = BBoxAnnotation(**{"x": 0, "y": 0.9, "w": 0, "h": 0.2}) + assert bbox_ann.y + bbox_ann.h <= 1 + bbox_ann = BBoxAnnotation(**{"x": 0, "y": 1.2, "w": 0, "h": 0.2}) + assert bbox_ann.y + bbox_ann.h <= 1 + + +def test_kpt_no_auto_clip(): + with pytest.raises(pydantic.ValidationError): + KeypointAnnotation(**{"keypoints": [(-2.1, 1.1, 0)]}) + with pytest.raises(pydantic.ValidationError): + KeypointAnnotation(**{"keypoints": [(0.1, 2.1, 1)]}) + with pytest.raises(pydantic.ValidationError): + KeypointAnnotation(**{"keypoints": [(0.1, 1.1, 2), (0.1, 2.1, 1)]}) + + +def test_kpt_auto_clip(): + kpt_ann = KeypointAnnotation(**{"keypoints": [(-1.1, 1.1, 0)]}) + assert ( + 0 <= kpt_ann.keypoints[0][0] <= 1 and 0 <= kpt_ann.keypoints[0][1] <= 1 + ) + kpt_ann = KeypointAnnotation(**{"keypoints": [(0.1, 1.1, 1)]}) + assert ( + 0 <= kpt_ann.keypoints[0][0] <= 1 and 0 <= kpt_ann.keypoints[0][1] <= 1 + ) + kpt_ann = KeypointAnnotation(**{"keypoints": [(-2, 2, 2)]}) + assert ( + 0 <= kpt_ann.keypoints[0][0] <= 1 and 0 <= kpt_ann.keypoints[0][1] <= 1 + ) + + +def test_poly_no_auto_clip(): + with pytest.raises(pydantic.ValidationError): + PolylineSegmentationAnnotation( + **{"points": [(-2.1, 1.1), (-2.1, 2.1), (-0.1, -2.1)]} + ) + + +def test_poly_auto_clip(): + poly_ann = PolylineSegmentationAnnotation( + **{"points": [(-0.1, 1.1), (-2, 2), (-0.1, -1.1)]} + ) + assert 0 <= poly_ann.points[0][0] <= 1 and 0 <= poly_ann.points[0][1] <= 1 + assert 0 <= poly_ann.points[1][0] <= 1 and 0 <= poly_ann.points[1][1] <= 1 + assert 0 <= poly_ann.points[2][0] <= 1 and 0 <= poly_ann.points[2][1] <= 1