From 85c368e1aafde01f4d8947d4a8875821a46a9b45 Mon Sep 17 00:00:00 2001 From: "Shin, Eunwoo" Date: Fri, 4 Oct 2024 13:20:09 +0900 Subject: [PATCH 1/7] segmentation consider bbox only annotations --- src/otx/core/data/dataset/segmentation.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/otx/core/data/dataset/segmentation.py b/src/otx/core/data/dataset/segmentation.py index 363a15e84cc..61bf35570ea 100644 --- a/src/otx/core/data/dataset/segmentation.py +++ b/src/otx/core/data/dataset/segmentation.py @@ -11,7 +11,7 @@ import cv2 import numpy as np import torch -from datumaro.components.annotation import Ellipse, Image, Mask, Polygon +from datumaro.components.annotation import Ellipse, Image, Mask, Polygon, Bbox, RotatedBbox from torchvision import tv_tensors from otx.core.data.dataset.base import Transforms @@ -99,11 +99,11 @@ def _extract_class_mask(item: DatasetItem, img_shape: tuple[int, int], ignore_in raise ValueError(msg, ignore_index) # fill mask with background label if we have Polygon/Ellipse annotations - fill_value = 0 if isinstance(item.annotations[0], (Ellipse, Polygon)) else ignore_index + fill_value = 0 if isinstance(item.annotations[0], (Ellipse, Polygon, Bbox, RotatedBbox)) else ignore_index class_mask = np.full(shape=img_shape[:2], fill_value=fill_value, dtype=np.uint8) for mask in sorted( - [ann for ann in item.annotations if isinstance(ann, (Mask, Ellipse, Polygon))], + [ann for ann in item.annotations if isinstance(ann, (Mask, Ellipse, Polygon, Bbox, RotatedBbox))], key=lambda ann: ann.z_order, ): index = mask.label @@ -112,7 +112,7 @@ def _extract_class_mask(item: DatasetItem, img_shape: tuple[int, int], ignore_in msg = "Mask's label index should not be None." raise ValueError(msg) - if isinstance(mask, (Ellipse, Polygon)): + if isinstance(mask, (Ellipse, Polygon, Bbox, RotatedBbox)): polygons = np.asarray(mask.as_polygon(), dtype=np.int32).reshape((-1, 1, 2)) class_index = index + 1 # NOTE: disregard the background index. Objects start from index=1 this_class_mask = cv2.drawContours( @@ -194,7 +194,8 @@ def __init__( def has_polygons(self) -> bool: """Check if the dataset has polygons in annotations.""" ann_types = {str(ann_type).split(".")[-1] for ann_type in self.dm_subset.ann_types()} - if ann_types & {"polygon", "ellipse"}: + # all polygon-like format should be considered as polygons + if ann_types & {"polygon", "ellipse", "bbox", "rotated_bbox"}: return True return False From dce9e47209723fe7d0273777df03f3d068828646 Mon Sep 17 00:00:00 2001 From: "Shin, Eunwoo" Date: Fri, 4 Oct 2024 13:39:19 +0900 Subject: [PATCH 2/7] add unit test --- src/otx/core/data/dataset/segmentation.py | 2 +- tests/unit/core/data/conftest.py | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/otx/core/data/dataset/segmentation.py b/src/otx/core/data/dataset/segmentation.py index 61bf35570ea..d415000ef16 100644 --- a/src/otx/core/data/dataset/segmentation.py +++ b/src/otx/core/data/dataset/segmentation.py @@ -11,7 +11,7 @@ import cv2 import numpy as np import torch -from datumaro.components.annotation import Ellipse, Image, Mask, Polygon, Bbox, RotatedBbox +from datumaro.components.annotation import Bbox, Ellipse, Image, Mask, Polygon, RotatedBbox from torchvision import tv_tensors from otx.core.data.dataset.base import Transforms diff --git a/tests/unit/core/data/conftest.py b/tests/unit/core/data/conftest.py index 6c3ca23dde6..c5023788869 100644 --- a/tests/unit/core/data/conftest.py +++ b/tests/unit/core/data/conftest.py @@ -10,7 +10,7 @@ import cv2 import numpy as np import pytest -from datumaro.components.annotation import Bbox, Label, LabelCategories, Mask, Polygon +from datumaro.components.annotation import AnnotationType, Bbox, Label, LabelCategories, Mask, Polygon from datumaro.components.dataset import Dataset as DmDataset from datumaro.components.dataset_base import DatasetItem from datumaro.components.media import Image @@ -133,6 +133,12 @@ def fxt_mock_dm_subset(mocker: MockerFixture, fxt_dm_item: DatasetItem) -> Magic mock_dm_subset.__getitem__.return_value = fxt_dm_item mock_dm_subset.__len__.return_value = 1 mock_dm_subset.categories().__getitem__.return_value = LabelCategories.from_iterable(_LABEL_NAMES) + mock_dm_subset.ann_types.return_value = [ + AnnotationType.label, + AnnotationType.bbox, + AnnotationType.mask, + AnnotationType.polygon, + ] return mock_dm_subset @@ -142,6 +148,7 @@ def fxt_mock_det_dm_subset(mocker: MockerFixture, fxt_dm_item_bbox_only: Dataset mock_dm_subset.__getitem__.return_value = fxt_dm_item_bbox_only mock_dm_subset.__len__.return_value = 1 mock_dm_subset.categories().__getitem__.return_value = LabelCategories.from_iterable(_LABEL_NAMES) + mock_dm_subset.ann_types.return_value = [AnnotationType.bbox] return mock_dm_subset From 473690fb93f66e0c19c7feed8b6c9ce67f00403a Mon Sep 17 00:00:00 2001 From: "Shin, Eunwoo" Date: Fri, 4 Oct 2024 15:45:30 +0900 Subject: [PATCH 3/7] add unit test --- .../core/data/dataset/test_segmentation.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/unit/core/data/dataset/test_segmentation.py diff --git a/tests/unit/core/data/dataset/test_segmentation.py b/tests/unit/core/data/dataset/test_segmentation.py new file mode 100644 index 00000000000..141dc4bf74b --- /dev/null +++ b/tests/unit/core/data/dataset/test_segmentation.py @@ -0,0 +1,36 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +"""Unit tests of classification datasets.""" + +from otx.core.data.dataset.segmentation import OTXSegmentationDataset +from otx.core.data.entity.segmentation import SegDataEntity + + +class TestOTXSegmentationDataset: + def test_get_item( + self, + fxt_mock_dm_subset, + ) -> None: + dataset = OTXSegmentationDataset( + dm_subset=fxt_mock_dm_subset, + transforms=[lambda x: x], + mem_cache_img_max_size=None, + max_refetch=3, + ) + assert isinstance(dataset[0], SegDataEntity) + assert "background" in [label_name.lower() for label_name in dataset.label_info.label_names] + + def test_get_item_from_bbox_dataset( + self, + fxt_mock_det_dm_subset, + ) -> None: + dataset = OTXSegmentationDataset( + dm_subset=fxt_mock_det_dm_subset, + transforms=[lambda x: x], + mem_cache_img_max_size=None, + max_refetch=3, + ) + assert isinstance(dataset[0], SegDataEntity) + # OTXSegmentationDataset should add background when getting a dataset which includes only bbox annotations + assert "background" in [label_name.lower() for label_name in dataset.label_info.label_names] From 398429b740f096f59c872b646e9ef4261c62f98d Mon Sep 17 00:00:00 2001 From: "Shin, Eunwoo" Date: Fri, 4 Oct 2024 16:15:40 +0900 Subject: [PATCH 4/7] update fixture --- tests/unit/core/data/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/core/data/conftest.py b/tests/unit/core/data/conftest.py index c5023788869..e79498a6155 100644 --- a/tests/unit/core/data/conftest.py +++ b/tests/unit/core/data/conftest.py @@ -89,7 +89,7 @@ def fxt_dm_item(request, tmpdir) -> DatasetItem: media=media, annotations=[ Label(label=0), - Bbox(x=0, y=0, w=1, h=1, label=0), + Bbox(x=200, y=200, w=1, h=1, label=0), Mask(label=0, image=np.eye(10, dtype=np.uint8)), Polygon(points=[399.0, 570.0, 397.0, 572.0, 397.0, 573.0, 394.0, 576.0], label=0), ], From 03ca609caff64c01f5a94c283b9d8af8fd486b9f Mon Sep 17 00:00:00 2001 From: "Shin, Eunwoo" Date: Fri, 4 Oct 2024 16:54:48 +0900 Subject: [PATCH 5/7] use name attribute --- src/otx/core/data/dataset/segmentation.py | 3 +-- tox.ini | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/otx/core/data/dataset/segmentation.py b/src/otx/core/data/dataset/segmentation.py index d415000ef16..fbec5c562e5 100644 --- a/src/otx/core/data/dataset/segmentation.py +++ b/src/otx/core/data/dataset/segmentation.py @@ -193,9 +193,8 @@ def __init__( @property def has_polygons(self) -> bool: """Check if the dataset has polygons in annotations.""" - ann_types = {str(ann_type).split(".")[-1] for ann_type in self.dm_subset.ann_types()} # all polygon-like format should be considered as polygons - if ann_types & {"polygon", "ellipse", "bbox", "rotated_bbox"}: + if {ann_type.name for ann_type in self.dm_subset.ann_types()} & {"polygon", "ellipse", "bbox", "rotated_bbox"}: return True return False diff --git a/tox.ini b/tox.ini index fee2ea00e4e..7b1e78537b9 100644 --- a/tox.ini +++ b/tox.ini @@ -52,7 +52,7 @@ commands = --cov-report=xml:{toxworkdir}/coverage_{envname}.xml \ --cov-report=term-missing \ --cov-fail-under=0 \ - {posargs} + {posargs} -- tests/unit/core/data/dataset/test_segmentation.py::TestOTXSegmentationDataset::test_get_item [testenv:integration-test-{all, action, classification, multi_cls_classification, multi_label_classification, hlabel_classification, detection, rotated_detection, keypoint_detection, instance_segmentation, semantic_segmentation, visual_prompting_all, visual_prompting, zero_shot_visual_prompting, anomaly_classification, anomaly_detection, anomaly_segmentation}] From c1cc812e46510fff46cdc1b039c3530c3373ca39 Mon Sep 17 00:00:00 2001 From: "Shin, Eunwoo" Date: Fri, 4 Oct 2024 17:09:05 +0900 Subject: [PATCH 6/7] revert tox file --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 7b1e78537b9..74e20c98e7b 100644 --- a/tox.ini +++ b/tox.ini @@ -52,10 +52,10 @@ commands = --cov-report=xml:{toxworkdir}/coverage_{envname}.xml \ --cov-report=term-missing \ --cov-fail-under=0 \ - {posargs} -- tests/unit/core/data/dataset/test_segmentation.py::TestOTXSegmentationDataset::test_get_item + {posargs} -[testenv:integration-test-{all, action, classification, multi_cls_classification, multi_label_classification, hlabel_classification, detection, rotated_detection, keypoint_detection, instance_segmentation, semantic_segmentation, visual_prompting_all, visual_prompting, zero_shot_visual_prompting, anomaly_classification, anomaly_detection, anomaly_segmentation}] +[testenv:integration-test-{all, action, classification, multi_cls_classification, multi_label_classification, hlabel_classification, detection, rotated_detection, keypoint_detection, instance_segmentation, semantic_segmentation, visual_prompting_all, visual_prompting, zero_shot_visual_prompting, anomaly, anomaly_classification, anomaly_detection, anomaly_segmentation}] setenv = CUBLAS_WORKSPACE_CONFIG=:4096:8 deps = @@ -75,7 +75,7 @@ commands = [testenv:perf-benchmark] deps = - .[base,dev] + .[base,dev,ci_benchmark] commands = pytest -ra --showlocals --csv={toxworkdir}/{envname}-test.csv {posargs:tests/perf} From 2a76349228c1fe2c8806465ffed1668956e55bc7 Mon Sep 17 00:00:00 2001 From: Yunchu Lee Date: Fri, 4 Oct 2024 17:28:54 +0900 Subject: [PATCH 7/7] update for 2.2.0rc4 --- CHANGELOG.md | 2 ++ README.md | 1 + docs/source/guide/release_notes/index.rst | 1 + src/otx/__init__.py | 2 +- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9fa3593381..f25e48e528f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,8 @@ All notable changes to this project will be documented in this file. () - Add type checker in converter for callable functions (optimizer, scheduler) () +- Change sematic segmentation to consider bbox only annotations + () ### Bug fixes diff --git a/README.md b/README.md index 077d7083370..f42741bb689 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,7 @@ In addition to the examples above, please refer to the documentation for tutoria - Include Geti arrow dataset subset names - Include full image with anno in case there's no tile in tile dataset - Add type checker in converter for callable functions (optimizer, scheduler) +- Change sematic segmentation to consider bbox only annotations ### Bug fixes diff --git a/docs/source/guide/release_notes/index.rst b/docs/source/guide/release_notes/index.rst index fbb2ec1e65b..a0e0954c2a8 100644 --- a/docs/source/guide/release_notes/index.rst +++ b/docs/source/guide/release_notes/index.rst @@ -37,6 +37,7 @@ Enhancements - Include Geti arrow dataset subset names - Include full image with anno in case there's no tile in tile dataset - Add type checker in converter for callable functions (optimizer, scheduler) +- Change sematic segmentation to consider bbox only annotations Bug fixes ^^^^^^^^^ diff --git a/src/otx/__init__.py b/src/otx/__init__.py index 5a63dae00ea..15b5d5ff729 100644 --- a/src/otx/__init__.py +++ b/src/otx/__init__.py @@ -3,7 +3,7 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -__version__ = "2.2.0rc3" +__version__ = "2.2.0rc4" import os from pathlib import Path