Skip to content

Commit

Permalink
Fixed unhandled annotation types in 1.0 conversion (#773)
Browse files Browse the repository at this point in the history
  • Loading branch information
JBWilkie authored Jan 30, 2024
1 parent b3e52dd commit df1219e
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 13 deletions.
3 changes: 3 additions & 0 deletions darwin/exporter/formats/darwin_1_0.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ def _build_legacy_annotation_data(
# Poygons and complex polygons usually have attached bounding_box annotations
v1_data["bounding_box"] = data["bounding_box"]

if not v1_data:
v1_data[annotation_class.annotation_type] = data

return v1_data


Expand Down
38 changes: 25 additions & 13 deletions darwin/importer/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1032,11 +1032,11 @@ def _get_overwrite_value(append: bool) -> str:


def _parse_empty_masks(
annotation: dt.Annotation,
raster_layer: dt.Annotation,
raster_layer_dense_rle_ids: Optional[Set[str]] = None,
raster_layer_dense_rle_ids_frames: Optional[Dict[int, Set[str]]] = None,
):
annotation: dt.Annotation,
raster_layer: dt.Annotation,
raster_layer_dense_rle_ids: Optional[Set[str]] = None,
raster_layer_dense_rle_ids_frames: Optional[Dict[int, Set[str]]] = None,
):
"""
Check if the mask is empty (i.e. masks that do not have a corresponding raster layer) if so, skip import of the mask.
This function is used for both dt.Annotation and dt.VideoAnnotation objects.
Expand All @@ -1051,13 +1051,17 @@ def _parse_empty_masks(
tuple[Optional[Set[str]], Optional[Dict[int, Set[str]]]]: raster_layer_dense_rle_ids, raster_layer_dense_rle_ids_frames
"""
# For dt.VideoAnnotation, create dense_rle ids for each frame.
if raster_layer_dense_rle_ids_frames is None and isinstance(annotation, dt.VideoAnnotation):
if raster_layer_dense_rle_ids_frames is None and isinstance(
annotation, dt.VideoAnnotation
):
assert isinstance(raster_layer, dt.VideoAnnotation)

# build a dict of frame_index: set of dense_rle_ids (for each frame in VideoAnnotation object)
raster_layer_dense_rle_ids_frames = {}
for frame_index, _rl in raster_layer.frames.items():
raster_layer_dense_rle_ids_frames[frame_index] = set(_rl.data["dense_rle"][::2])
raster_layer_dense_rle_ids_frames[frame_index] = set(
_rl.data["dense_rle"][::2]
)

# check every frame
# - if the 'annotation_class_id' is in raster_layer's mask_annotation_ids_mapping dict
Expand All @@ -1066,22 +1070,26 @@ def _parse_empty_masks(
for frame_index, _annotation in annotation.frames.items():
_annotation_id = _annotation.id
if (
frame_index in raster_layer_dense_rle_ids_frames and
raster_layer.frames[frame_index].data["mask_annotation_ids_mapping"][_annotation_id]
frame_index in raster_layer_dense_rle_ids_frames
and raster_layer.frames[frame_index].data[
"mask_annotation_ids_mapping"
][_annotation_id]
not in raster_layer_dense_rle_ids_frames[frame_index]
):
# skip import of the mask, and remove it from mask_annotation_ids_mapping
logger.warning(
f"Skipping import of mask annotation '{_annotation.annotation_class.name}' as it does not have a corresponding raster layer"
)
del raster_layer.frames[frame_index]["mask_annotation_ids_mapping"][_annotation_id]
del raster_layer.frames[frame_index]["mask_annotation_ids_mapping"][
_annotation_id
]
return raster_layer_dense_rle_ids, raster_layer_dense_rle_ids_frames

# For dt.Annotation, create dense_rle ids.
elif raster_layer_dense_rle_ids is None and isinstance(annotation, dt.Annotation):
assert isinstance(raster_layer, dt.Annotation)

# build a set of dense_rle_ids (for the Annotation object)
# build a set of dense_rle_ids (for the Annotation object)
raster_layer_dense_rle_ids = set(raster_layer.data["dense_rle"][::2])

# check the annotation (i.e. mask)
Expand All @@ -1102,6 +1110,7 @@ def _parse_empty_masks(

return raster_layer_dense_rle_ids, raster_layer_dense_rle_ids_frames


def _import_annotations(
client: "Client", # TODO: This is unused, should it be?
id: Union[str, int],
Expand Down Expand Up @@ -1165,11 +1174,14 @@ def _import_annotations(
None,
)
if raster_layer:
raster_layer_dense_rle_ids, raster_layer_dense_rle_ids_frames = _parse_empty_masks(
(
raster_layer_dense_rle_ids,
raster_layer_dense_rle_ids_frames,
) = _parse_empty_masks(
annotation,
raster_layer,
raster_layer_dense_rle_ids,
raster_layer_dense_rle_ids_frames
raster_layer_dense_rle_ids_frames,
)

actors: List[dt.DictFreeForm] = []
Expand Down
47 changes: 47 additions & 0 deletions tests/darwin/exporter/formats/export_darwin_1_0_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,3 +532,50 @@ def test_tags(self):
"annotations": [{"tag": {}, "name": "tag_test", "slot_names": []}],
"dataset": "None",
}

def test_other_annotation_types(self):
line_path = [
{"x": 230.06, "y": 174.04},
{"x": 226.39, "y": 170.36},
{"x": 224.61, "y": 166.81},
]

annotation_class = dt.AnnotationClass(annotation_type="line", name="line_class")

annotation = dt.Annotation(
annotation_class=annotation_class,
data={"path": line_path},
subs=[],
)

annotation_file = dt.AnnotationFile(
path=Path("test.json"),
filename="test.json",
annotation_classes=[annotation_class],
annotations=[annotation],
image_height=1080,
image_width=1920,
image_url="https://darwin.v7labs.com/image.jpg",
)

assert _build_json(annotation_file) == {
"image": {
"seq": None,
"width": 1920,
"height": 1080,
"filename": "test.json",
"original_filename": "test.json",
"url": "https://darwin.v7labs.com/image.jpg",
"thumbnail_url": None,
"path": None,
"workview_url": None,
},
"annotations": [
{
"line": {"path": line_path},
"name": "line_class",
"slot_names": [],
}
],
"dataset": "None",
}

0 comments on commit df1219e

Please sign in to comment.