Skip to content

Commit 6de0be9

Browse files
[AI-1287] fixed the siutation when a user pass only a image (#696)
* fixed the siutation when a user pass only a image * changed the check a bit * black * fixed exporter test * black formatting * added fix for when there are no annoations (empty dict) * added tests and extra logic for when annotations is empty, one option is to throw an error and not let the user include images without annotations * black * refactored for readability, area is it's own check now * black
1 parent 2fc5afe commit 6de0be9

File tree

3 files changed

+192
-42
lines changed

3 files changed

+192
-42
lines changed

darwin/torch/transforms.py

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ class ColorJitter(transforms.ColorJitter):
143143
def __call__(
144144
self, image: PILImage.Image, target: Optional[TargetType] = None
145145
) -> Union[PILImage.Image, Tuple[PILImage.Image, TargetType]]:
146-
transform = self.get_params(self.brightness, self.contrast, self.saturation, self.hue)
146+
transform = self.get_params(
147+
self.brightness, self.contrast, self.saturation, self.hue
148+
)
147149
image = transform(image)
148150
if target is None:
149151
return image
@@ -198,7 +200,9 @@ class ConvertPolygonsToInstanceMasks(object):
198200
Converts given polygon to an ``InstanceMask``.
199201
"""
200202

201-
def __call__(self, image: PILImage.Image, target: TargetType) -> Tuple[PILImage.Image, TargetType]:
203+
def __call__(
204+
self, image: PILImage.Image, target: TargetType
205+
) -> Tuple[PILImage.Image, TargetType]:
202206
w, h = image.size
203207

204208
image_id = target["image_id"]
@@ -255,7 +259,9 @@ class ConvertPolygonsToSemanticMask(object):
255259
Converts given polygon to an ``SemanticMask``.
256260
"""
257261

258-
def __call__(self, image: PILImage.Image, target: TargetType) -> Tuple[PILImage.Image, TargetType]:
262+
def __call__(
263+
self, image: PILImage.Image, target: TargetType
264+
) -> Tuple[PILImage.Image, TargetType]:
259265
w, h = image.size
260266
image_id = target["image_id"]
261267
image_id = torch.tensor([image_id])
@@ -282,7 +288,9 @@ class ConvertPolygonToMask(object):
282288
Converts given polygon to a ``Mask``.
283289
"""
284290

285-
def __call__(self, image: PILImage.Image, annotation: Dict[str, Any]) -> Tuple[PILImage.Image, PILImage.Image]:
291+
def __call__(
292+
self, image: PILImage.Image, annotation: Dict[str, Any]
293+
) -> Tuple[PILImage.Image, PILImage.Image]:
286294
w, h = image.size
287295
segmentations = [obj["segmentation"] for obj in annotation]
288296
cats = [obj["category_id"] for obj in annotation]
@@ -327,10 +335,18 @@ def from_dict(cls, alb_dict: dict) -> "AlbumentationsTransform":
327335
def __call__(self, image, annotation: dict = None) -> tuple:
328336
np_image = np.array(image)
329337
if annotation is None:
330-
annotation = {}
331-
albu_data = self._pre_process(np_image, annotation)
338+
annotation_dict = {}
339+
else:
340+
annotation_dict = annotation
341+
342+
albu_data = self._pre_process(np_image, annotation_dict)
332343
transformed_data = self.transform(**albu_data)
333-
image, transformed_annotation = self._post_process(transformed_data, annotation)
344+
image, transformed_annotation = self._post_process(
345+
transformed_data, annotation_dict
346+
)
347+
348+
if annotation is None:
349+
return image
334350

335351
return image, transformed_annotation
336352

@@ -349,7 +365,10 @@ def _pre_process(self, image: np.ndarray, annotation: dict) -> dict:
349365
albumentation_dict["labels"] = labels.tolist()
350366

351367
masks = annotation.get("masks")
352-
if masks is not None:
368+
if (
369+
masks is not None and masks.numel() > 0
370+
): # using numel() to check if tensor is non-empty
371+
print("WE GOT MASKS")
353372
albumentation_dict["masks"] = masks.numpy()
354373

355374
return albumentation_dict
@@ -364,8 +383,6 @@ def _post_process(self, albumentation_output: dict, annotation: dict) -> tuple:
364383
bboxes = albumentation_output.get("bboxes")
365384
if bboxes is not None:
366385
output_annotation["boxes"] = torch.tensor(bboxes)
367-
if "area" in annotation and "masks" not in albumentation_output:
368-
output_annotation["area"] = output_annotation["boxes"][:, 2] * output_annotation["boxes"][:, 3]
369386

370387
labels = albumentation_output.get("labels")
371388
if labels is not None:
@@ -377,8 +394,20 @@ def _post_process(self, albumentation_output: dict, annotation: dict) -> tuple:
377394
output_annotation["masks"] = torch.tensor(np.array(masks))
378395
else:
379396
output_annotation["masks"] = torch.stack(masks)
380-
if "area" in annotation:
381-
output_annotation["area"] = torch.sum(output_annotation["masks"], dim=[1, 2])
397+
elif "masks" in annotation:
398+
output_annotation["masks"] = torch.tensor([])
399+
400+
if "area" in annotation:
401+
if "masks" in output_annotation and output_annotation["masks"].numel() > 0:
402+
output_annotation["area"] = torch.sum(
403+
output_annotation["masks"], dim=[1, 2]
404+
)
405+
elif "boxes" in output_annotation and len(output_annotation["boxes"]) > 0:
406+
output_annotation["area"] = (
407+
output_annotation["boxes"][:, 2] * output_annotation["boxes"][:, 3]
408+
)
409+
else:
410+
output_annotation["area"] = torch.tensor([])
382411

383412
# Copy other metadata from original annotation
384413
for key, value in annotation.items():

tests/darwin/exporter/formats/export_darwin_1_0_test.py

Lines changed: 90 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
from pathlib import Path
22

3-
43
import darwin.datatypes as dt
54
from darwin.exporter.formats.darwin_1_0 import _build_json
65

76

87
class TestBuildJson:
98
def test_empty_annotation_file(self):
10-
annotation_file = dt.AnnotationFile(path=Path("test.json"), filename="test.json", annotation_classes=[], annotations=[])
9+
annotation_file = dt.AnnotationFile(
10+
path=Path("test.json"),
11+
filename="test.json",
12+
annotation_classes=[],
13+
annotations=[],
14+
)
1115

1216
assert _build_json(annotation_file) == {
1317
"image": {
@@ -58,7 +62,9 @@ def test_complete_annotation_file(self):
5862
]
5963

6064
annotation_class = dt.AnnotationClass(name="test", annotation_type="polygon")
61-
annotation = dt.Annotation(annotation_class=annotation_class, data={"path": polygon_path}, subs=[])
65+
annotation = dt.Annotation(
66+
annotation_class=annotation_class, data={"path": polygon_path}, subs=[]
67+
)
6268

6369
annotation_file = dt.AnnotationFile(
6470
path=Path("test.json"),
@@ -82,14 +88,24 @@ def test_complete_annotation_file(self):
8288
"path": None,
8389
"workview_url": None,
8490
},
85-
"annotations": [{"polygon": {"path": polygon_path}, "name": "test", "slot_names": []}],
91+
"annotations": [
92+
{"polygon": {"path": polygon_path}, "name": "test", "slot_names": []}
93+
],
8694
"dataset": "None",
8795
}
8896

8997
def test_complex_polygon(self):
9098
polygon_path = [
91-
[{"x": 230.06, "y": 174.04}, {"x": 226.39, "y": 170.36}, {"x": 224.61, "y": 166.81}],
92-
[{"x": 238.98, "y": 171.69}, {"x": 236.97, "y": 174.04}, {"x": 238.67, "y": 174.04}],
99+
[
100+
{"x": 230.06, "y": 174.04},
101+
{"x": 226.39, "y": 170.36},
102+
{"x": 224.61, "y": 166.81},
103+
],
104+
[
105+
{"x": 238.98, "y": 171.69},
106+
{"x": 236.97, "y": 174.04},
107+
{"x": 238.67, "y": 174.04},
108+
],
93109
[
94110
{"x": 251.75, "y": 169.77},
95111
{"x": 251.75, "y": 154.34},
@@ -98,8 +114,12 @@ def test_complex_polygon(self):
98114
],
99115
]
100116

101-
annotation_class = dt.AnnotationClass(name="test", annotation_type="complex_polygon")
102-
annotation = dt.Annotation(annotation_class=annotation_class, data={"paths": polygon_path}, subs=[])
117+
annotation_class = dt.AnnotationClass(
118+
name="test", annotation_type="complex_polygon"
119+
)
120+
annotation = dt.Annotation(
121+
annotation_class=annotation_class, data={"paths": polygon_path}, subs=[]
122+
)
103123

104124
annotation_file = dt.AnnotationFile(
105125
path=Path("test.json"),
@@ -123,7 +143,13 @@ def test_complex_polygon(self):
123143
"path": None,
124144
"workview_url": None,
125145
},
126-
"annotations": [{"complex_polygon": {"path": polygon_path}, "name": "test", "slot_names": []}],
146+
"annotations": [
147+
{
148+
"complex_polygon": {"path": polygon_path},
149+
"name": "test",
150+
"slot_names": [],
151+
}
152+
],
127153
"dataset": "None",
128154
}
129155

@@ -137,7 +163,11 @@ def test_polygon_annotation_file_with_bbox(self):
137163
bounding_box = {"x": 557.66, "y": 428.98, "w": 160.76, "h": 315.3}
138164

139165
annotation_class = dt.AnnotationClass(name="test", annotation_type="polygon")
140-
annotation = dt.Annotation(annotation_class=annotation_class, data={"path": polygon_path, "bounding_box": bounding_box}, subs=[])
166+
annotation = dt.Annotation(
167+
annotation_class=annotation_class,
168+
data={"path": polygon_path, "bounding_box": bounding_box},
169+
subs=[],
170+
)
141171

142172
annotation_file = dt.AnnotationFile(
143173
path=Path("test.json"),
@@ -161,14 +191,29 @@ def test_polygon_annotation_file_with_bbox(self):
161191
"path": None,
162192
"workview_url": None,
163193
},
164-
"annotations": [{"polygon": {"path": polygon_path}, "name": "test", "slot_names": [], "bounding_box": bounding_box}],
194+
"annotations": [
195+
{
196+
"polygon": {"path": polygon_path},
197+
"name": "test",
198+
"slot_names": [],
199+
"bounding_box": bounding_box,
200+
}
201+
],
165202
"dataset": "None",
166203
}
167204

168205
def test_complex_polygon_with_bbox(self):
169206
polygon_path = [
170-
[{"x": 230.06, "y": 174.04}, {"x": 226.39, "y": 170.36}, {"x": 224.61, "y": 166.81}],
171-
[{"x": 238.98, "y": 171.69}, {"x": 236.97, "y": 174.04}, {"x": 238.67, "y": 174.04}],
207+
[
208+
{"x": 230.06, "y": 174.04},
209+
{"x": 226.39, "y": 170.36},
210+
{"x": 224.61, "y": 166.81},
211+
],
212+
[
213+
{"x": 238.98, "y": 171.69},
214+
{"x": 236.97, "y": 174.04},
215+
{"x": 238.67, "y": 174.04},
216+
],
172217
[
173218
{"x": 251.75, "y": 169.77},
174219
{"x": 251.75, "y": 154.34},
@@ -179,8 +224,14 @@ def test_complex_polygon_with_bbox(self):
179224

180225
bounding_box = {"x": 557.66, "y": 428.98, "w": 160.76, "h": 315.3}
181226

182-
annotation_class = dt.AnnotationClass(name="test", annotation_type="complex_polygon")
183-
annotation = dt.Annotation(annotation_class=annotation_class, data={"paths": polygon_path, "bounding_box": bounding_box}, subs=[])
227+
annotation_class = dt.AnnotationClass(
228+
name="test", annotation_type="complex_polygon"
229+
)
230+
annotation = dt.Annotation(
231+
annotation_class=annotation_class,
232+
data={"paths": polygon_path, "bounding_box": bounding_box},
233+
subs=[],
234+
)
184235

185236
annotation_file = dt.AnnotationFile(
186237
path=Path("test.json"),
@@ -204,14 +255,25 @@ def test_complex_polygon_with_bbox(self):
204255
"path": None,
205256
"workview_url": None,
206257
},
207-
"annotations": [{"complex_polygon": {"path": polygon_path}, "name": "test", "slot_names": [], "bounding_box": bounding_box}],
258+
"annotations": [
259+
{
260+
"complex_polygon": {"path": polygon_path},
261+
"name": "test",
262+
"slot_names": [],
263+
"bounding_box": bounding_box,
264+
}
265+
],
208266
"dataset": "None",
209267
}
210268

211269
def test_bounding_box(self):
212270
bounding_box_data = {"x": 100, "y": 150, "w": 50, "h": 30}
213-
annotation_class = dt.AnnotationClass(name="bbox_test", annotation_type="bounding_box")
214-
annotation = dt.Annotation(annotation_class=annotation_class, data=bounding_box_data, subs=[])
271+
annotation_class = dt.AnnotationClass(
272+
name="bbox_test", annotation_type="bounding_box"
273+
)
274+
annotation = dt.Annotation(
275+
annotation_class=annotation_class, data=bounding_box_data, subs=[]
276+
)
215277

216278
annotation_file = dt.AnnotationFile(
217279
path=Path("test.json"),
@@ -235,14 +297,22 @@ def test_bounding_box(self):
235297
"path": None,
236298
"workview_url": None,
237299
},
238-
"annotations": [{"bounding_box": bounding_box_data, "name": "bbox_test", "slot_names": []}],
300+
"annotations": [
301+
{
302+
"bounding_box": bounding_box_data,
303+
"name": "bbox_test",
304+
"slot_names": [],
305+
}
306+
],
239307
"dataset": "None",
240308
}
241309

242310
def test_tags(self):
243311
tag_data = "sample_tag"
244312
annotation_class = dt.AnnotationClass(name="tag_test", annotation_type="tag")
245-
annotation = dt.Annotation(annotation_class=annotation_class, data=tag_data, subs=[])
313+
annotation = dt.Annotation(
314+
annotation_class=annotation_class, data=tag_data, subs=[]
315+
)
246316

247317
annotation_file = dt.AnnotationFile(
248318
path=Path("test.json"),

0 commit comments

Comments
 (0)