Proper way to flip using AffineTransform with SimpleITK

I’m trying to flip a 3d image using AffineTransform (I have to support multiple possible modifications to a 3d image, like rotation and flipping, so I’m trying to represent them as matrices) and it seems that when I apply a flipping affine transform [1,0,0,0,1,0,0,0,-1] - to flip around Z axis, the image direction is not modified. If I use sitk.Flip([False, False, True]) instead, the resulting image direction is correct (z axis is -1). Do I need to update the image direction manually after applying affine transform?

import SimpleITK as sitk


image = sitk.Image(3, 3, 3, sitk.sitkInt16)
image.SetDirection([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])


image.SetPixel(0,0,0, 5)
image.SetPixel(0,1,0, 5)
image.SetPixel(0,2,0, 4)
image.SetPixel(1,0,0, 5)
image.SetPixel(1,1,0, 5)
image.SetPixel(1,2,0, 4)
image.SetPixel(2,0,0, 5)
image.SetPixel(2,1,0, 5)
image.SetPixel(2,2,0, 4)


image.SetPixel(0,0,1, 6)
image.SetPixel(0,1,1, 6)
image.SetPixel(0,2,1, 6)
image.SetPixel(1,0,1, 6)
image.SetPixel(1,1,1, 6)
image.SetPixel(1,2,1, 6)
image.SetPixel(2,0,1, 6)
image.SetPixel(2,1,1, 6)
image.SetPixel(2,2,1, 6)

image.SetPixel(0,0,2, 10)
image.SetPixel(0,1,2, 10)
image.SetPixel(0,2,2, 10)
image.SetPixel(1,0,2, 10)
image.SetPixel(1,1,2, 10)
image.SetPixel(1,2,2, 10)
image.SetPixel(2,0,2, 10)
image.SetPixel(2,1,2, 10)
image.SetPixel(2,2,2, 10)

image.SetOrigin([0,0,0])

print("--------- Original -------------")
print("Direction: {}".format(image.GetDirection()))
print(sitk.GetArrayFromImage(image))

print("--------- Flip via AffineTransform -------------")

affineTrans = sitk.AffineTransform(3)
affineTrans.SetMatrix([1,0,0,0,1,0,0,0,-1])
affineTrans.SetCenter([1,1,1])
flipped = sitk.Resample(image, affineTrans)
print("Direction: {}".format(flipped.GetDirection()))
print(sitk.GetArrayFromImage(flipped))
print("--------- Flip via sitk.Flip ---------------")
flipped = sitk.Flip(image, [False,False,True])
print("Direction: {}".format(flipped.GetDirection()))
print(sitk.GetArrayFromImage(flipped))

results:
--------- Original -------------
Direction: (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
[[[ 5 5 5]
[ 5 5 5]
[ 4 4 4]]

 [[ 6  6  6]
  [ 6  6  6]
  [ 6  6  6]]

 [[10 10 10]
  [10 10 10]
  [10 10 10]]]
--------- Flip via AffineTransform -------------
Direction: (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
[[[10 10 10]
  [10 10 10]
  [10 10 10]]

 [[ 6  6  6]
  [ 6  6  6]
  [ 6  6  6]]

 [[ 5  5  5]
  [ 5  5  5]
  [ 4  4  4]]]
--------- Flip via sitk.Flip ---------------
Direction: (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0)
[[[10 10 10]
  [10 10 10]
  [10 10 10]]

 [[ 6  6  6]
  [ 6  6  6]
  [ 6  6  6]]

 [[ 5  5  5]
  [ 5  5  5]
  [ 4  4  4]]]

You may need to review the SimpleITK’s Fundamental Concepts on Images to get a clear understanding that the ITK Image’s pixels are entities in physical space not just an indexed array.

The Flip filter changes the order of the pixels in the array buffer and the meta-data ( origin and orientation matrix ) such that the physical location of each pixel remains exactly the same. If you use a physical space aware medical image viewer like 3D Slicer to view the “flipped” image before and after it would look exactly the same. However, if you problem the two displayed images you would see different (i,j,k) indexes.

Reimplement the Flip filter with the Resample filter the transformation would be the identity, but the meta-data for the output image would be modifed.

Now if that is understood, the determination for your implementation can be made if you want to change the physical location of your pixels or preserve them.

1 Like

This question was also cross-posted to stack overflow.