Skip to content

Commit 758ea97

Browse files
eunwooshyunchu
andauthored
Change sematic segmentation to consider bbox only annotations. (#3996)
* segmentation consider bbox only annotations * add unit test * add unit test * update fixture * use name attribute * revert tox file * update for 2.2.0rc4 --------- Co-authored-by: Yunchu Lee <[email protected]>
1 parent 45078bc commit 758ea97

File tree

8 files changed

+58
-11
lines changed

8 files changed

+58
-11
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ All notable changes to this project will be documented in this file.
5555
(<https://github.com/openvinotoolkit/training_extensions/pull/3964>)
5656
- Add type checker in converter for callable functions (optimizer, scheduler)
5757
(<https://github.com/openvinotoolkit/training_extensions/pull/3968>)
58+
- Change sematic segmentation to consider bbox only annotations
59+
(<https://github.com/openvinotoolkit/training_extensions/pull/3996>)
5860

5961
### Bug fixes
6062

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ In addition to the examples above, please refer to the documentation for tutoria
196196
- Include Geti arrow dataset subset names
197197
- Include full image with anno in case there's no tile in tile dataset
198198
- Add type checker in converter for callable functions (optimizer, scheduler)
199+
- Change sematic segmentation to consider bbox only annotations
199200

200201
### Bug fixes
201202

docs/source/guide/release_notes/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Enhancements
3737
- Include Geti arrow dataset subset names
3838
- Include full image with anno in case there's no tile in tile dataset
3939
- Add type checker in converter for callable functions (optimizer, scheduler)
40+
- Change sematic segmentation to consider bbox only annotations
4041

4142
Bug fixes
4243
^^^^^^^^^

src/otx/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Copyright (C) 2024 Intel Corporation
44
# SPDX-License-Identifier: Apache-2.0
55

6-
__version__ = "2.2.0rc3"
6+
__version__ = "2.2.0rc4"
77

88
import os
99
from pathlib import Path

src/otx/core/data/dataset/segmentation.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import cv2
1212
import numpy as np
1313
import torch
14-
from datumaro.components.annotation import Ellipse, Image, Mask, Polygon
14+
from datumaro.components.annotation import Bbox, Ellipse, Image, Mask, Polygon, RotatedBbox
1515
from torchvision import tv_tensors
1616

1717
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
9999
raise ValueError(msg, ignore_index)
100100

101101
# fill mask with background label if we have Polygon/Ellipse annotations
102-
fill_value = 0 if isinstance(item.annotations[0], (Ellipse, Polygon)) else ignore_index
102+
fill_value = 0 if isinstance(item.annotations[0], (Ellipse, Polygon, Bbox, RotatedBbox)) else ignore_index
103103
class_mask = np.full(shape=img_shape[:2], fill_value=fill_value, dtype=np.uint8)
104104

105105
for mask in sorted(
106-
[ann for ann in item.annotations if isinstance(ann, (Mask, Ellipse, Polygon))],
106+
[ann for ann in item.annotations if isinstance(ann, (Mask, Ellipse, Polygon, Bbox, RotatedBbox))],
107107
key=lambda ann: ann.z_order,
108108
):
109109
index = mask.label
@@ -112,7 +112,7 @@ def _extract_class_mask(item: DatasetItem, img_shape: tuple[int, int], ignore_in
112112
msg = "Mask's label index should not be None."
113113
raise ValueError(msg)
114114

115-
if isinstance(mask, (Ellipse, Polygon)):
115+
if isinstance(mask, (Ellipse, Polygon, Bbox, RotatedBbox)):
116116
polygons = np.asarray(mask.as_polygon(), dtype=np.int32).reshape((-1, 1, 2))
117117
class_index = index + 1 # NOTE: disregard the background index. Objects start from index=1
118118
this_class_mask = cv2.drawContours(
@@ -193,8 +193,8 @@ def __init__(
193193
@property
194194
def has_polygons(self) -> bool:
195195
"""Check if the dataset has polygons in annotations."""
196-
ann_types = {str(ann_type).split(".")[-1] for ann_type in self.dm_subset.ann_types()}
197-
if ann_types & {"polygon", "ellipse"}:
196+
# all polygon-like format should be considered as polygons
197+
if {ann_type.name for ann_type in self.dm_subset.ann_types()} & {"polygon", "ellipse", "bbox", "rotated_bbox"}:
198198
return True
199199
return False
200200

tests/unit/core/data/conftest.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import cv2
1111
import numpy as np
1212
import pytest
13-
from datumaro.components.annotation import Bbox, Label, LabelCategories, Mask, Polygon
13+
from datumaro.components.annotation import AnnotationType, Bbox, Label, LabelCategories, Mask, Polygon
1414
from datumaro.components.dataset import Dataset as DmDataset
1515
from datumaro.components.dataset_base import DatasetItem
1616
from datumaro.components.media import Image
@@ -89,7 +89,7 @@ def fxt_dm_item(request, tmpdir) -> DatasetItem:
8989
media=media,
9090
annotations=[
9191
Label(label=0),
92-
Bbox(x=0, y=0, w=1, h=1, label=0),
92+
Bbox(x=200, y=200, w=1, h=1, label=0),
9393
Mask(label=0, image=np.eye(10, dtype=np.uint8)),
9494
Polygon(points=[399.0, 570.0, 397.0, 572.0, 397.0, 573.0, 394.0, 576.0], label=0),
9595
],
@@ -133,6 +133,12 @@ def fxt_mock_dm_subset(mocker: MockerFixture, fxt_dm_item: DatasetItem) -> Magic
133133
mock_dm_subset.__getitem__.return_value = fxt_dm_item
134134
mock_dm_subset.__len__.return_value = 1
135135
mock_dm_subset.categories().__getitem__.return_value = LabelCategories.from_iterable(_LABEL_NAMES)
136+
mock_dm_subset.ann_types.return_value = [
137+
AnnotationType.label,
138+
AnnotationType.bbox,
139+
AnnotationType.mask,
140+
AnnotationType.polygon,
141+
]
136142
return mock_dm_subset
137143

138144

@@ -142,6 +148,7 @@ def fxt_mock_det_dm_subset(mocker: MockerFixture, fxt_dm_item_bbox_only: Dataset
142148
mock_dm_subset.__getitem__.return_value = fxt_dm_item_bbox_only
143149
mock_dm_subset.__len__.return_value = 1
144150
mock_dm_subset.categories().__getitem__.return_value = LabelCategories.from_iterable(_LABEL_NAMES)
151+
mock_dm_subset.ann_types.return_value = [AnnotationType.bbox]
145152
return mock_dm_subset
146153

147154

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright (C) 2024 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""Unit tests of classification datasets."""
5+
6+
from otx.core.data.dataset.segmentation import OTXSegmentationDataset
7+
from otx.core.data.entity.segmentation import SegDataEntity
8+
9+
10+
class TestOTXSegmentationDataset:
11+
def test_get_item(
12+
self,
13+
fxt_mock_dm_subset,
14+
) -> None:
15+
dataset = OTXSegmentationDataset(
16+
dm_subset=fxt_mock_dm_subset,
17+
transforms=[lambda x: x],
18+
mem_cache_img_max_size=None,
19+
max_refetch=3,
20+
)
21+
assert isinstance(dataset[0], SegDataEntity)
22+
assert "background" in [label_name.lower() for label_name in dataset.label_info.label_names]
23+
24+
def test_get_item_from_bbox_dataset(
25+
self,
26+
fxt_mock_det_dm_subset,
27+
) -> None:
28+
dataset = OTXSegmentationDataset(
29+
dm_subset=fxt_mock_det_dm_subset,
30+
transforms=[lambda x: x],
31+
mem_cache_img_max_size=None,
32+
max_refetch=3,
33+
)
34+
assert isinstance(dataset[0], SegDataEntity)
35+
# OTXSegmentationDataset should add background when getting a dataset which includes only bbox annotations
36+
assert "background" in [label_name.lower() for label_name in dataset.label_info.label_names]

tox.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ commands =
5555
{posargs}
5656

5757

58-
[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}]
58+
[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}]
5959
setenv =
6060
CUBLAS_WORKSPACE_CONFIG=:4096:8
6161
deps =
@@ -75,7 +75,7 @@ commands =
7575

7676
[testenv:perf-benchmark]
7777
deps =
78-
.[base,dev]
78+
.[base,dev,ci_benchmark]
7979
commands =
8080
pytest -ra --showlocals --csv={toxworkdir}/{envname}-test.csv {posargs:tests/perf}
8181

0 commit comments

Comments
 (0)