From bae5414239c50f04e50736768e027f02e61f053c Mon Sep 17 00:00:00 2001 From: Dipet Date: Thu, 17 Jun 2021 10:29:52 +0300 Subject: [PATCH 1/2] Convert to and from YOLO format without normalization and denormalization to prevent rounding errors --- albumentations/augmentations/bbox_utils.py | 34 ++++++++++++---------- tests/test_bbox.py | 9 ++++-- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/albumentations/augmentations/bbox_utils.py b/albumentations/augmentations/bbox_utils.py index 9a2d50d59..962d3afed 100644 --- a/albumentations/augmentations/bbox_utils.py +++ b/albumentations/augmentations/bbox_utils.py @@ -233,20 +233,23 @@ def convert_bbox_to_albumentations(bbox, source_format, rows, cols, check_validi # https://github.com/pjreddie/darknet/blob/f6d861736038da22c9eb0739dca84003c5a5e275/scripts/voc_label.py#L12 bbox, tail = bbox[:4], tuple(bbox[4:]) _bbox = np.array(bbox[:4]) - if np.any((_bbox <= 0) | (_bbox > 1)): - raise ValueError("In YOLO format all labels must be float and in range (0, 1]") + if check_validity and np.any((_bbox <= 0) | (_bbox > 1)): + raise ValueError("In YOLO format all coordinates must be float and in range (0, 1]") - x, y, width, height = denormalize_bbox(bbox, rows, cols) + x, y, w, h = bbox - x_min = int(x - width / 2 + 1) - x_max = int(x_min + width) - y_min = int(y - height / 2 + 1) - y_max = int(y_min + height) + w_half, h_half = w / 2, h / 2 + x_min = x - w_half + y_min = y - h_half + x_max = x_min + w + y_max = y_min + h else: (x_min, y_min, x_max, y_max), tail = bbox[:4], tuple(bbox[4:]) bbox = (x_min, y_min, x_max, y_max) + tail - bbox = normalize_bbox(bbox, rows, cols) + + if source_format != "yolo": + bbox = normalize_bbox(bbox, rows, cols) if check_validity: check_bbox(bbox) return bbox @@ -280,20 +283,21 @@ def convert_bbox_from_albumentations(bbox, target_format, rows, cols, check_vali ) if check_validity: check_bbox(bbox) - bbox = denormalize_bbox(bbox, rows, cols) + + if target_format != "yolo": + bbox = denormalize_bbox(bbox, rows, cols) if target_format == "coco": (x_min, y_min, x_max, y_max), tail = bbox[:4], tuple(bbox[4:]) width = x_max - x_min height = y_max - y_min bbox = (x_min, y_min, width, height) + tail elif target_format == "yolo": - # https://github.com/pjreddie/darknet/blob/f6d861736038da22c9eb0739dca84003c5a5e275/scripts/voc_label.py#L12 (x_min, y_min, x_max, y_max), tail = bbox[:4], bbox[4:] - x = int((x_min + x_max) / 2 - 1) - y = int((y_min + y_max) / 2 - 1) - width = x_max - x_min - height = y_max - y_min - bbox = normalize_bbox((x, y, width, height) + tail, rows, cols) + x = (x_min + x_max) / 2.0 + y = (y_min + y_max) / 2.0 + w = x_max - x_min + h = y_max - y_min + bbox = (x, y, w, h) + tail return bbox diff --git a/tests/test_bbox.py b/tests/test_bbox.py index c6cf3d5d5..fd7f84d86 100644 --- a/tests/test_bbox.py +++ b/tests/test_bbox.py @@ -77,8 +77,11 @@ def test_calculate_bbox_area(bbox, rows, cols, expected): ((20, 30, 40, 50, 99), "coco", (0.2, 0.3, 0.6, 0.8, 99)), ((20, 30, 60, 80), "pascal_voc", (0.2, 0.3, 0.6, 0.8)), ((20, 30, 60, 80, 99), "pascal_voc", (0.2, 0.3, 0.6, 0.8, 99)), - ((0.2, 0.3, 0.4, 0.5), "yolo", (0.01, 0.06, 0.41, 0.56)), - ((0.2, 0.3, 0.4, 0.5, 99), "yolo", (0.01, 0.06, 0.41, 0.56, 99)), + ((0.2, 0.3, 0.4, 0.5), "yolo", (0.00, 0.05, 0.40, 0.55)), + ((0.2, 0.3, 0.4, 0.5, 99), "yolo", (0.00, 0.05, 0.40, 0.55, 99)), + ((0.1, 0.1, 0.2, 0.2), "yolo", (0.0, 0.0, 0.2, 0.2)), + ((0.99662423, 0.7520255, 0.00675154, 0.01446759), "yolo", (0.99324846, 0.744791705, 1.0, 0.759259295)), + ((0.9375, 0.510416, 0.1234375, 0.97638), "yolo", (0.87578125, 0.022226, 0.999218749, 0.998606)), ], ) def test_convert_bbox_to_albumentations(bbox, source_format, expected): @@ -87,7 +90,7 @@ def test_convert_bbox_to_albumentations(bbox, source_format, expected): converted_bbox = convert_bbox_to_albumentations( bbox, rows=image.shape[0], cols=image.shape[1], source_format=source_format ) - assert converted_bbox == expected + assert np.all(np.isclose(converted_bbox, expected)) @pytest.mark.parametrize( From 867bfa15874eae96b4266ba0e268cd1532dd653c Mon Sep 17 00:00:00 2001 From: Dipet Date: Thu, 17 Jun 2021 10:37:26 +0300 Subject: [PATCH 2/2] Fix yolo tests --- tests/test_bbox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_bbox.py b/tests/test_bbox.py index fd7f84d86..4e4063674 100644 --- a/tests/test_bbox.py +++ b/tests/test_bbox.py @@ -100,8 +100,8 @@ def test_convert_bbox_to_albumentations(bbox, source_format, expected): ((0.2, 0.3, 0.6, 0.8, 99), "coco", (20, 30, 40, 50, 99)), ((0.2, 0.3, 0.6, 0.8), "pascal_voc", (20, 30, 60, 80)), ((0.2, 0.3, 0.6, 0.8, 99), "pascal_voc", (20, 30, 60, 80, 99)), - ((0.01, 0.06, 0.41, 0.56), "yolo", (0.2, 0.3, 0.4, 0.5)), - ((0.01, 0.06, 0.41, 0.56, 99), "yolo", (0.2, 0.3, 0.4, 0.5, 99)), + ((0.00, 0.05, 0.40, 0.55), "yolo", (0.2, 0.3, 0.4, 0.5)), + ((0.00, 0.05, 0.40, 0.55, 99), "yolo", (0.2, 0.3, 0.4, 0.5, 99)), ], ) def test_convert_bbox_from_albumentations(bbox, target_format, expected):