Skip to content

Commit

Permalink
[DAR-4140][External] Fixed NifTI import orientation (#953)
Browse files Browse the repository at this point in the history
* Fixed NifTI import orientation

* Simpler implementation

* Update tests/darwin/importer/formats/import_nifti_test.py

Co-authored-by: dorfmanrobert <[email protected]>

---------

Co-authored-by: dorfmanrobert <[email protected]>
  • Loading branch information
JBWilkie and dorfmanrobert authored Nov 8, 2024
1 parent ea72b6c commit 1d6eb59
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 7 deletions.
10 changes: 4 additions & 6 deletions darwin/importer/formats/nifti.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def _parse_nifti(
is_mpr: bool,
legacy: bool = False,
) -> dt.AnnotationFile:
img, pixdims = process_nifti(nib.load(nifti_path), legacy=legacy)
img, pixdims = process_nifti(nib.load(nifti_path))

processed_class_map = process_class_map(class_map)
video_annotations = []
Expand Down Expand Up @@ -513,11 +513,10 @@ def correct_nifti_header_if_necessary(img_nii):
def process_nifti(
input_data: nib.nifti1.Nifti1Image,
ornt: Optional[List[List[float]]] = [[0.0, -1.0], [1.0, -1.0], [2.0, -1.0]],
legacy: bool = False,
) -> Tuple[np.ndarray, Tuple[float]]:
"""
Function that converts a nifti object to RAS orientation (if legacy), then converts to the passed ornt orientation.
The default ornt is for LPI.
Function that converts a nifti object to the RAS orientation, then converts to the passed ornt orientation.
The default ornt is LPI.
Args:
input_data: nibabel nifti object.
Expand All @@ -530,8 +529,7 @@ def process_nifti(
pixdims: tuple of nifti header zoom values.
"""
img = correct_nifti_header_if_necessary(input_data)
if legacy:
img = nib.funcs.as_closest_canonical(img)
img = nib.funcs.as_closest_canonical(img)
data_array = nib.orientations.apply_orientation(img.get_fdata(), ornt)
pixdims = img.header.get_zooms()
return data_array, pixdims
Expand Down
67 changes: 66 additions & 1 deletion tests/darwin/importer/formats/import_nifti_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import numpy as np
import pytest
from scipy import ndimage
import nibabel as nib

from darwin.datatypes import (
Annotation,
Expand All @@ -17,7 +18,7 @@
SubAnnotation,
VideoAnnotation,
)
from darwin.importer.formats.nifti import get_new_axial_size, parse_path
from darwin.importer.formats.nifti import get_new_axial_size, parse_path, process_nifti
from tests.fixtures import *
from darwin.utils.utils import parse_darwin_json

Expand Down Expand Up @@ -239,6 +240,70 @@ def test_get_new_axial_size_with_isotropic():
assert new_size == (20, 10)


def test_process_nifti_orientation_ras_to_lpi(team_slug_darwin_json_v2):
"""
Test that an input NifTI annotation file in the RAS orientation is correctly
transformed to the LPI orientation.
Do this by emulating the `process_nifti` function, which:
- 1: Transforms the input file into the RAS orientation
- 2: Transforms the transformed RAS file into the LPI orientation
"""
with tempfile.TemporaryDirectory() as tmpdir:
with ZipFile("tests/data.zip") as zfile:
zfile.extractall(tmpdir)
filepath = (
Path(tmpdir)
/ team_slug_darwin_json_v2
/ "nifti"
/ "releases"
/ "latest"
/ "annotations"
/ "vol0_brain.nii.gz"
)
lpi_ornt = [[0.0, -1.0], [1.0, -1.0], [2.0, -1.0]]
ras_file = nib.load(filepath)
ras_transformed_file = nib.funcs.as_closest_canonical(ras_file)
lpi_transformed_file = nib.orientations.apply_orientation(
ras_transformed_file.get_fdata(), lpi_ornt
)
processed_file, _ = process_nifti(input_data=ras_file)
assert not np.array_equal(processed_file, ras_file._dataobj)
assert np.array_equal(processed_file, lpi_transformed_file)


def test_process_nifti_orientation_las_to_lpi(team_slug_darwin_json_v2):
"""
Test that an input NifTI annotation file in the LAS orientation is correctly
transformed to the LPI orientation.
Do this by emulating the `process_nifti` function, which:
- 1: Transforms the input file into the RAS orientation
- 2: Transforms the transformed RAS file into the LPI orientation
"""
with tempfile.TemporaryDirectory() as tmpdir:
with ZipFile("tests/data.zip") as zfile:
zfile.extractall(tmpdir)
filepath = (
Path(tmpdir)
/ team_slug_darwin_json_v2
/ "nifti"
/ "releases"
/ "latest"
/ "annotations"
/ "BRAINIX_NIFTI_ROI.nii.gz"
)
lpi_ornt = [[0.0, -1.0], [1.0, -1.0], [2.0, -1.0]]
las_file = nib.load(filepath)
ras_transformed_file = nib.funcs.as_closest_canonical(las_file)
lpi_transformed_file = nib.orientations.apply_orientation(
ras_transformed_file.get_fdata(), lpi_ornt
)
processed_file, _ = process_nifti(input_data=las_file)
assert not np.array_equal(processed_file, las_file._dataobj)
assert np.array_equal(processed_file, lpi_transformed_file)


def serialise_annotation_file(
annotation_file: AnnotationFile, as_dict
) -> Union[str, dict]:
Expand Down
Binary file modified tests/data.zip
Binary file not shown.

0 comments on commit 1d6eb59

Please sign in to comment.