Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how the entire function used to work. Basically if it's not a tag, bbox, or polygon, simply return the structure that we used to

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 @@ -730,11 +730,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 @@ -749,13 +749,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 @@ -764,22 +768,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 @@ -800,6 +808,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 @@ -861,11 +870,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",
}