diff --git a/darwin/exporter/formats/nifti.py b/darwin/exporter/formats/nifti.py index 396f49743..b7c80854c 100644 --- a/darwin/exporter/formats/nifti.py +++ b/darwin/exporter/formats/nifti.py @@ -58,13 +58,18 @@ class Volume: primary_plane: str +# Unique ID and file suffix for the "All segments" volume +multi_segments_label = "0" +multi_segments_name = "Segments" + + def export( annotation_files: Iterable[dt.AnnotationFile], output_dir: Path, ) -> None: """ Exports the given ``AnnotationFile``\\s into nifti format inside of the given - ``output_dir``. Deletes everything within ``output_dir/masks`` before writting to it. + ``output_dir``. Deletes everything within ``output_dir/masks`` before writing to it. Parameters ---------- @@ -146,6 +151,8 @@ def export( for ann in slot_annotations if ann.annotation_class.annotation_type == "mask" } + # Add a unique ID for the "All segments" volume + mask_id_to_classname[multi_segments_label] = multi_segments_name raster_output_volumes = build_output_volumes( slot, class_names_to_export=list(mask_id_to_classname.values()), @@ -497,6 +504,10 @@ def populate_output_volumes_from_raster_layer( volume[class_name].pixel_array = np.where( multilabel_volume == global_id, 1, volume[class_name].pixel_array ) + elif mask_id == multi_segments_label: + # Unique ID for "All segments": + volume = output_volumes[series_instance_uid] + volume[multi_segments_name].pixel_array = multilabel_volume return volume diff --git a/tests/darwin/data/nifti/multi_segment/axial_RPI_pixdim_1.0_1.0_1.0/darwin.json b/tests/darwin/data/nifti/multi_segment/axial_RPI_pixdim_1.0_1.0_1.0/darwin.json new file mode 100644 index 000000000..7c64e0c0b --- /dev/null +++ b/tests/darwin/data/nifti/multi_segment/axial_RPI_pixdim_1.0_1.0_1.0/darwin.json @@ -0,0 +1,259 @@ +{ + "version": "2.0", + "schema_ref": "https://darwin-public.s3.eu-west-1.amazonaws.com/darwin_json/2.0/schema.json", + "item": { + "name": "axial_RPI_pixdim_1.0_1.0_1.0.dcm", + "path": "/", + "source_info": { + "item_id": "0197ee1d-591e-a61b-82e2-e6f1e5c30cf2", + "dataset": { + "name": "dicom_test_data_new", + "slug": "dicom_test_data_new", + "dataset_management_url": "https://darwin.v7labs.com/datasets/1856922/dataset-management" + }, + "team": { + "name": "V7 John", + "slug": "v7-john" + }, + "workview_url": "https://darwin.v7labs.com/workview?dataset=1856922&item=0197ee1d-591e-a61b-82e2-e6f1e5c30cf2" + }, + "slots": [ + { + "type": "dicom", + "slot_name": "0", + "width": 128, + "height": 128, + "fps": null, + "thumbnail_url": "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/thumbnail?token=590de404-3490-4dde-90f9-d13136b0d14f", + "source_files": [ + { + "file_name": "axial_RPI_pixdim_1.0_1.0_1.0.dcm", + "url": "https://darwin.v7labs.com/api/v2/teams/v7-john/uploads/d4f4e7cd-e8a8-407f-9ff3-0a1f3298c84c?token=590de404-3490-4dde-90f9-d13136b0d14f" + } + ], + "frame_count": 16, + "frame_urls": [ + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/0?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/1?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/2?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/3?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/4?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/5?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/6?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/7?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/8?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/9?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/10?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/11?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/12?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/13?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/14?token=590de404-3490-4dde-90f9-d13136b0d14f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/243d7c36-d767-4e3c-adb0-44324ebd14fe/sections/15?token=590de404-3490-4dde-90f9-d13136b0d14f" + ], + "metadata": { + "handler": "MONAI", + "shape": [ + 1, + 128, + 128, + 16 + ], + "SeriesInstanceUID": "1.2.826.0.1.3680043.8.498.37180825650614764423282910493086149224", + "affine": "[[-1.0, 0.0, 0.0, 127.0], [0.0, -1.0, 0.0, 0.0], [0.0, 0.0, -1.0, 15.0], [0.0, 0.0, 0.0, 1.0]]", + "colorspace": "RG16", + "original_affine": [ + [ + "1.0", + "0.0", + "0.0", + "0.0" + ], + [ + "0.0", + "-1.0", + "0.0", + "0.0" + ], + [ + "0.0", + "0.0", + "1.0", + "0.0" + ], + [ + "0.0", + "0.0", + "0.0", + "1.0" + ] + ], + "pixdim": "(1.0, 1.0, 1.0)", + "plane_map": { + "0": "AXIAL" + }, + "primary_plane": "AXIAL" + } + } + ] + }, + "annotations": [ + { + "frames": { + "15": { + "keyframe": true, + "mask": {} + } + }, + "global_sub_types": {}, + "id": "02c693fa-97f5-4a3c-9c45-e1d9eebb0731", + "interpolate_algorithm": "linear-1.1", + "name": "mask1", + "only_keyframes": true, + "properties": [], + "ranges": [ + [ + 15, + 16 + ] + ], + "slot_names": [ + "0" + ] + }, + { + "frames": { + "15": { + "keyframe": true, + "mask": {} + } + }, + "global_sub_types": {}, + "id": "d212f8a6-8e09-4901-a44b-77745626edc9", + "interpolate_algorithm": "linear-1.1", + "name": "mask2", + "only_keyframes": true, + "properties": [], + "ranges": [ + [ + 15, + 16 + ] + ], + "slot_names": [ + "0" + ] + }, + { + "frames": { + "15": { + "keyframe": true, + "raster_layer": { + "dense_rle": [ + 0, + 2104, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 11816 + ], + "mask_annotation_ids_mapping": { + "02c693fa-97f5-4a3c-9c45-e1d9eebb0731": 1, + "d212f8a6-8e09-4901-a44b-77745626edc9": 2 + }, + "total_pixels": 16384 + } + } + }, + "id": "a15c3b3e-89af-4733-b6c7-10f01e2c0b57", + "name": "__raster_layer__", + "only_keyframes": true, + "properties": [], + "ranges": [ + [ + 0, + 16 + ] + ], + "slot_names": [ + "0" + ] + } + ], + "properties": [] +} \ No newline at end of file diff --git a/tests/darwin/data/nifti/multi_segment/axial_RPI_pixdim_1.0_1.0_1.0/ground_truth.nii.gz b/tests/darwin/data/nifti/multi_segment/axial_RPI_pixdim_1.0_1.0_1.0/ground_truth.nii.gz new file mode 100644 index 000000000..be0895e89 Binary files /dev/null and b/tests/darwin/data/nifti/multi_segment/axial_RPI_pixdim_1.0_1.0_1.0/ground_truth.nii.gz differ diff --git a/tests/darwin/data/nifti/multi_segment/coronal_LAS_pixdim_0.1_0.2_0.5/darwin.json b/tests/darwin/data/nifti/multi_segment/coronal_LAS_pixdim_0.1_0.2_0.5/darwin.json new file mode 100644 index 000000000..e42e9e8d3 --- /dev/null +++ b/tests/darwin/data/nifti/multi_segment/coronal_LAS_pixdim_0.1_0.2_0.5/darwin.json @@ -0,0 +1,259 @@ +{ + "version": "2.0", + "schema_ref": "https://darwin-public.s3.eu-west-1.amazonaws.com/darwin_json/2.0/schema.json", + "item": { + "name": "coronal_LAS_pixdim_0.1_0.2_0.5.dcm", + "path": "/", + "source_info": { + "item_id": "0197ee1d-591e-7d19-bb01-65d27fb0bcdd", + "dataset": { + "name": "dicom_test_data_new", + "slug": "dicom_test_data_new", + "dataset_management_url": "https://darwin.v7labs.com/datasets/1856922/dataset-management" + }, + "team": { + "name": "V7 John", + "slug": "v7-john" + }, + "workview_url": "https://darwin.v7labs.com/workview?dataset=1856922&item=0197ee1d-591e-7d19-bb01-65d27fb0bcdd" + }, + "slots": [ + { + "type": "dicom", + "slot_name": "0", + "width": 128, + "height": 128, + "fps": null, + "thumbnail_url": "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/thumbnail?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "source_files": [ + { + "file_name": "coronal_LAS_pixdim_0.1_0.2_0.5.dcm", + "url": "https://darwin.v7labs.com/api/v2/teams/v7-john/uploads/bbf2147d-e328-4a93-a624-90f9c474a071?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f" + } + ], + "frame_count": 16, + "frame_urls": [ + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/0?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/1?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/2?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/3?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/4?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/5?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/6?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/7?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/8?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/9?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/10?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/11?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/12?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/13?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/14?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/b33547f6-c281-4766-97cf-1623f00353f5/sections/15?token=971b08d7-a0d7-4d95-a22f-f1f7429b207f" + ], + "metadata": { + "handler": "MONAI", + "shape": [ + 1, + 128, + 16, + 128 + ], + "SeriesInstanceUID": "1.2.826.0.1.3680043.8.498.10392093638286046303269310577715221690", + "affine": "[[-0.1, 0.0, 0.0, 0.0], [0.0, -1.0, 0.0, 0.0], [0.0, 0.0, -0.25, 31.75], [0.0, 0.0, 0.0, 1.0]]", + "colorspace": "RG16", + "original_affine": [ + [ + "-0.1", + "0.0", + "0.0", + "0.0" + ], + [ + "0.0", + "0.0", + "-1.0", + "0.0" + ], + [ + "0.0", + "0.25", + "0.0", + "0.0" + ], + [ + "0.0", + "0.0", + "0.0", + "1.0" + ] + ], + "pixdim": "(0.1, 1.0, 0.25)", + "plane_map": { + "0": "CORONAL" + }, + "primary_plane": "CORONAL" + } + } + ] + }, + "annotations": [ + { + "frames": { + "15": { + "keyframe": true, + "mask": {} + } + }, + "global_sub_types": {}, + "id": "0a8b3cfb-d6ff-427a-8b3e-a31410f10331", + "interpolate_algorithm": "linear-1.1", + "name": "mask1", + "only_keyframes": true, + "properties": [], + "ranges": [ + [ + 15, + 16 + ] + ], + "slot_names": [ + "0" + ] + }, + { + "frames": { + "15": { + "keyframe": true, + "mask": {} + } + }, + "global_sub_types": {}, + "id": "0e845870-995b-4cb7-982e-741c1e54109e", + "interpolate_algorithm": "linear-1.1", + "name": "mask2", + "only_keyframes": true, + "properties": [], + "ranges": [ + [ + 15, + 16 + ] + ], + "slot_names": [ + "0" + ] + }, + { + "frames": { + "15": { + "keyframe": true, + "raster_layer": { + "dense_rle": [ + 0, + 6184, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 7736 + ], + "mask_annotation_ids_mapping": { + "0a8b3cfb-d6ff-427a-8b3e-a31410f10331": 1, + "0e845870-995b-4cb7-982e-741c1e54109e": 2 + }, + "total_pixels": 16384 + } + } + }, + "id": "1af4d613-c4c4-41cd-a53a-2e8905f90b95", + "name": "__raster_layer__", + "only_keyframes": true, + "properties": [], + "ranges": [ + [ + 0, + 16 + ] + ], + "slot_names": [ + "0" + ] + } + ], + "properties": [] +} \ No newline at end of file diff --git a/tests/darwin/data/nifti/multi_segment/coronal_LAS_pixdim_0.1_0.2_0.5/ground_truth.nii.gz b/tests/darwin/data/nifti/multi_segment/coronal_LAS_pixdim_0.1_0.2_0.5/ground_truth.nii.gz new file mode 100644 index 000000000..5e0eddacb Binary files /dev/null and b/tests/darwin/data/nifti/multi_segment/coronal_LAS_pixdim_0.1_0.2_0.5/ground_truth.nii.gz differ diff --git a/tests/darwin/data/nifti/multi_segment/sagittal_LPI_pixdim_0.1_0.2_0.5/darwin.json b/tests/darwin/data/nifti/multi_segment/sagittal_LPI_pixdim_0.1_0.2_0.5/darwin.json new file mode 100644 index 000000000..b757dee96 --- /dev/null +++ b/tests/darwin/data/nifti/multi_segment/sagittal_LPI_pixdim_0.1_0.2_0.5/darwin.json @@ -0,0 +1,259 @@ +{ + "version": "2.0", + "schema_ref": "https://darwin-public.s3.eu-west-1.amazonaws.com/darwin_json/2.0/schema.json", + "item": { + "name": "sagittal_LPI_pixdim_0.1_0.2_0.5.dcm", + "path": "/", + "source_info": { + "item_id": "0197ee1d-5920-c9f8-017f-987b38e38f5f", + "dataset": { + "name": "dicom_test_data_new", + "slug": "dicom_test_data_new", + "dataset_management_url": "https://darwin.v7labs.com/datasets/1856922/dataset-management" + }, + "team": { + "name": "V7 John", + "slug": "v7-john" + }, + "workview_url": "https://darwin.v7labs.com/workview?dataset=1856922&item=0197ee1d-5920-c9f8-017f-987b38e38f5f" + }, + "slots": [ + { + "type": "dicom", + "slot_name": "0", + "width": 128, + "height": 128, + "fps": null, + "thumbnail_url": "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/thumbnail?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "source_files": [ + { + "file_name": "sagittal_LPI_pixdim_0.1_0.2_0.5.dcm", + "url": "https://darwin.v7labs.com/api/v2/teams/v7-john/uploads/54adbf48-0129-44ea-978c-313aeb35627b?token=4ca42b77-ad16-42ce-82e1-e9c762085012" + } + ], + "frame_count": 16, + "frame_urls": [ + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/0?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/1?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/2?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/3?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/4?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/5?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/6?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/7?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/8?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/9?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/10?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/11?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/12?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/13?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/14?token=4ca42b77-ad16-42ce-82e1-e9c762085012", + "https://darwin.v7labs.com/api/v2/teams/v7-john/files/c160652a-9d74-4a27-91f5-158bd68eab2c/sections/15?token=4ca42b77-ad16-42ce-82e1-e9c762085012" + ], + "metadata": { + "handler": "MONAI", + "shape": [ + 1, + 16, + 128, + 128 + ], + "SeriesInstanceUID": "1.2.826.0.1.3680043.8.498.16951377570626244557338024182864652772", + "affine": "[[-1.0, 0.0, 0.0, 15.0], [0.0, -0.1, 0.0, 0.0], [0.0, 0.0, -0.25, 0.0], [0.0, 0.0, 0.0, 1.0]]", + "colorspace": "RG16", + "original_affine": [ + [ + "0.0", + "0.0", + "1.0", + "0.0" + ], + [ + "-0.1", + "0.0", + "0.0", + "0.0" + ], + [ + "0.0", + "-0.25", + "0.0", + "0.0" + ], + [ + "0.0", + "0.0", + "0.0", + "1.0" + ] + ], + "pixdim": "(1.0, 0.1, 0.25)", + "plane_map": { + "0": "SAGITTAL" + }, + "primary_plane": "SAGITTAL" + } + } + ] + }, + "annotations": [ + { + "frames": { + "15": { + "keyframe": true, + "mask": {} + } + }, + "global_sub_types": {}, + "id": "2d12dc2e-5cc5-4bb7-89ce-5f010fc0f184", + "interpolate_algorithm": "linear-1.1", + "name": "mask1", + "only_keyframes": true, + "properties": [], + "ranges": [ + [ + 15, + 16 + ] + ], + "slot_names": [ + "0" + ] + }, + { + "frames": { + "15": { + "keyframe": true, + "mask": {} + } + }, + "global_sub_types": {}, + "id": "97117be2-ae2e-4431-bcd3-5dd724121489", + "interpolate_algorithm": "linear-1.1", + "name": "mask2", + "only_keyframes": true, + "properties": [], + "ranges": [ + [ + 15, + 16 + ] + ], + "slot_names": [ + "0" + ] + }, + { + "frames": { + "15": { + "keyframe": true, + "raster_layer": { + "dense_rle": [ + 0, + 2088, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 1, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 96, + 2, + 32, + 0, + 11832 + ], + "mask_annotation_ids_mapping": { + "2d12dc2e-5cc5-4bb7-89ce-5f010fc0f184": 1, + "97117be2-ae2e-4431-bcd3-5dd724121489": 2 + }, + "total_pixels": 16384 + } + } + }, + "id": "c41d3017-793b-41f8-b9be-fa95d2e505ef", + "name": "__raster_layer__", + "only_keyframes": true, + "properties": [], + "ranges": [ + [ + 0, + 16 + ] + ], + "slot_names": [ + "0" + ] + } + ], + "properties": [] +} \ No newline at end of file diff --git a/tests/darwin/data/nifti/multi_segment/sagittal_LPI_pixdim_0.1_0.2_0.5/ground_truth.nii.gz b/tests/darwin/data/nifti/multi_segment/sagittal_LPI_pixdim_0.1_0.2_0.5/ground_truth.nii.gz new file mode 100644 index 000000000..6d281de98 Binary files /dev/null and b/tests/darwin/data/nifti/multi_segment/sagittal_LPI_pixdim_0.1_0.2_0.5/ground_truth.nii.gz differ diff --git a/tests/darwin/exporter/formats/export_darwin_test.py b/tests/darwin/exporter/formats/export_darwin_test.py index 487145269..1c61ee8cd 100644 --- a/tests/darwin/exporter/formats/export_darwin_test.py +++ b/tests/darwin/exporter/formats/export_darwin_test.py @@ -1,13 +1,17 @@ +import shutil import tempfile import zipfile from pathlib import Path +import nibabel as nib +import numpy as np from darwin.datatypes import Annotation, AnnotationClass, AnnotationFile from darwin.exporter.formats.darwin import ( _build_v2_annotation_data, build_image_annotation, ) -from darwin.utils import get_annotation_files_from_dir +from darwin.exporter.formats.nifti import export +from darwin.utils import get_annotation_files_from_dir, parse_darwin_json def test_empty_annotation_file_v2(): @@ -142,3 +146,37 @@ def test_properties_metadata_is_ignored_when_reading_annotations_directory(): for annotation_filepath in annotation_filepaths: assert "./v7/" not in annotation_filepath assert "\\.v7\\" not in annotation_filepath + + +def test_multi_segment_nifti_export(): + root_dir = Path("tests/darwin/data/nifti/multi_segment") + for subdir in root_dir.iterdir(): + if not subdir.is_dir(): + continue + + ground_truth_path = subdir.joinpath("ground_truth.nii.gz") + darwin_json_path = subdir.joinpath("darwin.json") + target_output_directory = subdir.joinpath("output") + volume_name = subdir.parts[-1] + target_output_path = target_output_directory.joinpath( + "darwin", "0", f"{volume_name[:-2]}_Segments_m.nii.gz" + ) + + try: + # Convert darwin json to nifti + annotation_file = parse_darwin_json(darwin_json_path) + assert annotation_file is not None + export([annotation_file], target_output_directory) + + # Compare exported nifti to ground truth + ground_truth = nib.load(ground_truth_path.absolute().as_posix()) + ground_truth_array = ground_truth.get_fdata() + + nifti = nib.load(target_output_path) + nifti_array = nifti.get_fdata() + + assert np.array_equal(nifti_array, ground_truth_array) + + finally: + # Delete produced nifti + shutil.rmtree(target_output_directory.absolute().as_posix()) diff --git a/tests/darwin/importer/formats/import_nifti_test.py b/tests/darwin/importer/formats/import_nifti_test.py index 11632ec58..41dc0cb33 100644 --- a/tests/darwin/importer/formats/import_nifti_test.py +++ b/tests/darwin/importer/formats/import_nifti_test.py @@ -610,3 +610,17 @@ def test_parse_path_nifti_without_legacy_scaling(): parsed_annotation, decimal_places=4 ) assert expected_annotation_rounded == parsed_annotation_rounded + + +def test_image_annotation_nifti_multi_label(): + root_dir = Path("tests/darwin/data/nifti/multi_segment") + for subdir in root_dir.iterdir(): + if not subdir.is_dir(): + continue + + nifti_file_path = subdir.joinpath("ground_truth.nii.gz") + nifti_image = nib.load(nifti_file_path) + data_array = process_nifti(nifti_image) + + # Assert correct conversion with presence of 3 values (background and 2 labels) + assert data_array is not None and len(np.unique(data_array)) == 3