Skip to content

Commit

Permalink
add SimpleITK.Image to ANTsImage conversion (#726)
Browse files Browse the repository at this point in the history
* add sitk_to_ants

* move test to test_utils.py, install SimpleITK so test runs in coverage

---------

Co-authored-by: Bryn Lloyd <12702862+dyollb@users.noreply.github.com>
  • Loading branch information
dyollb and dyollb authored Nov 19, 2024
1 parent db33946 commit 2c624f7
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:
- name: Install coverage
run: python -m pip install coverage

- name: Install optional dependencies
run: python -m pip install SimpleITK

- name: Unit tests
run: tests/run_tests.sh -c

Expand Down
3 changes: 2 additions & 1 deletion ants/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
from .mni2tal import mni2tal
from .ndimage_to_list import ndimage_to_list, list_to_ndimage
from .nifti_to_ants import nifti_to_ants
from .scalar_rgb_vector import rgb_to_vector, vector_to_rgb, scalar_to_rgb
from .scalar_rgb_vector import rgb_to_vector, vector_to_rgb, scalar_to_rgb
from .sitk_to_ants import from_sitk, to_sitk
2 changes: 0 additions & 2 deletions ants/utils/nifti_to_ants.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
__all__ = ["nifti_to_ants"]

import os
from tempfile import mkstemp
import numpy as np
import ants

Expand Down
63 changes: 63 additions & 0 deletions ants/utils/sitk_to_ants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import numpy as np
import ants


def from_sitk(sitk_image: "SimpleITK.Image") -> ants.ANTsImage:
"""
Converts a given SimpleITK image into an ANTsPy image
Parameters
----------
img: SimpleITK.Image
Returns
-------
ants_image: ANTsImage
"""
import SimpleITK as sitk

ndim = sitk_image.GetDimension()

if ndim < 3:
print("Dimensionality is less than 3.")
return None

direction = np.asarray(sitk_image.GetDirection()).reshape((3, 3))
spacing = list(sitk_image.GetSpacing())
origin = list(sitk_image.GetOrigin())

data = sitk.GetArrayViewFromImage(sitk_image)

ants_img: ants.ANTsImage = ants.from_numpy(
data=data.ravel(order="F").reshape(data.shape[::-1]),
origin=origin,
spacing=spacing,
direction=direction,
)

return ants_img


def to_sitk(ants_image: ants.ANTsImage) -> "SimpleITK.Image":
"""
Converts a given ANTsPy image into an SimpleITK image
Parameters
----------
ants_image: ANTsImage
Returns
-------
img: SimpleITK.Image
"""

import SimpleITK as sitk

data = ants_image.view()
shape = ants_image.shape

sitk_img = sitk.GetImageFromArray(data.ravel(order="F").reshape(shape[::-1]))
sitk_img.SetOrigin(ants_image.origin)
sitk_img.SetSpacing(ants_image.spacing)
sitk_img.SetDirection(ants_image.direction.flatten())
return sitk_img
49 changes: 49 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@

import os
import unittest
from tempfile import TemporaryDirectory

from common import run_tests

import numpy.testing as nptest
import numpy as np
import pandas as pd
try:
import SimpleITK as sitk
except ImportError:
sitk = None

import ants

Expand Down Expand Up @@ -994,5 +999,49 @@ def test_channels_first(self):
self.assertTrue(np.allclose(img3.numpy()[:,:,1], img4.numpy()[1,:,:]))


@unittest.skipIf(sitk is None, "SimpleITK is not installed")
class TestModule_sitk_to_ants(unittest.TestCase):
def setUp(self):
shape = (32, 24, 16)
self.img = sitk.GetImageFromArray(np.arange(np.prod(shape), dtype=float).reshape(shape))
self.img.SetSpacing([0.5, 0.5, 2.0])
self.img.SetOrigin([1.2, 5.7, -3.4])
self.img.SetDirection(sitk.VersorTransform([1, 0, 0], 0.5).GetMatrix())

def tearDown(self):
pass

def test_from_sitk(self):
ants_img = ants.from_sitk(self.img)

with TemporaryDirectory() as temp_dir:
temp_fpath = os.path.join(temp_dir, "img.nrrd")
ants.image_write(ants_img, temp_fpath)
img = sitk.ReadImage(temp_fpath)

nptest.assert_equal(
sitk.GetArrayViewFromImage(self.img), sitk.GetArrayViewFromImage(img)
)
nptest.assert_almost_equal(self.img.GetOrigin(), img.GetOrigin())
nptest.assert_almost_equal(self.img.GetSpacing(), img.GetSpacing())
nptest.assert_almost_equal(self.img.GetDirection(), img.GetDirection())

def test_ito_sitk(self):
with TemporaryDirectory() as temp_dir:
temp_fpath = os.path.join(temp_dir, "img.nrrd")
sitk.WriteImage(self.img, temp_fpath)
ants_img = ants.image_read(temp_fpath)

img = ants.to_sitk(ants_img)

nptest.assert_equal(
sitk.GetArrayViewFromImage(self.img), sitk.GetArrayViewFromImage(img)
)
nptest.assert_almost_equal(self.img.GetOrigin(), img.GetOrigin())
nptest.assert_almost_equal(self.img.GetSpacing(), img.GetSpacing())
nptest.assert_almost_equal(self.img.GetDirection(), img.GetDirection())



if __name__ == "__main__":
run_tests()

0 comments on commit 2c624f7

Please sign in to comment.