# Applying a 4x4 affine transform to a 3D volume

**URL:** https://discourse.itk.org/t/applying-a-4x4-affine-transform-to-a-3d-volume/4555
**Category:** Algorithms
**Tags:** python
**Created:** [November 5, 2021, 3:01pm UTC](https://discourse.itk.org/t/applying-a-4x4-affine-transform-to-a-3d-volume/4555 "2021-11-05T15:01:46Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![joeykleingers](https://discourse.itk.org/user_avatar/discourse.itk.org/joeykleingers/32/1876_2.png) [@joeykleingers](https://discourse.itk.org/u/joeykleingers)
#### Post date: [November 5, 2021, 3:01pm UTC](https://discourse.itk.org/t/applying-a-4x4-affine-transform-to-a-3d-volume/4555/1 "2021-11-05T15:01:47Z")

</div>

I am trying to apply a 4x4 affine transform to a 3D volume to rotate the volume 1 degree along the Y-axis. This is a very simple example that I am trying to prove works so that I can use a more complicated 4x4 transform matrix later.

In the code below, I have a list of file paths to the 10 image slices of the 3D volume (`img_paths`), and I have a helper module, `imageh`, that can read and write images as numpy arrays to/from the file system.

```auto
import os
import itk
import math
import numpy as np
import imageh

# ==============================================================================
# Read slices and create image volume
# ==============================================================================
img_slices = []
for img_path in img_paths:
    img_slice = imageh.load_image(img_path)
    img_slices.append(img_slice)
img_volume = np.stack(img_slices, axis=0)
itk_img_volume = itk.image_from_array(img_volume)

# ==============================================================================
# Set rotation degrees
# ==============================================================================
degrees = 1

# ==============================================================================
# Create Affine Transform
# ==============================================================================
TransformType = itk.AffineTransform[itk.D, 3]
affine_transform = TransformType.New()

# Convert to radians
rads = degrees * math.pi / 180

# We want to rotate around the Y axis...
params = itk.OptimizerParameters[itk.D](12)
params[0] = math.cos(rads)
params[1] = 0
params[2] = math.sin(rads)
params[3] = 0
params[4] = 1
params[5] = 0
params[6] = -math.sin(rads)
params[7] = 0
params[8] = math.cos(rads)
params[9] = 0
params[10] = 0
params[11] = 0

affine_transform.SetParameters(params)

# ==============================================================================
# Setup the resample filter
# ==============================================================================
Image3d = type(itk_img_volume)
FilterType = itk.ResampleImageFilter[Image3d, Image3d]
filter = FilterType.New()
InterpolatorType = itk.NearestNeighborInterpolateImageFunction[Image3d, itk.D]
interpolator = InterpolatorType.New()
filter.SetInterpolator(interpolator)
filter.SetDefaultPixelValue(0)
filter.SetOutputOrigin(itk_img_volume.GetOrigin())
filter.SetOutputSpacing(itk_img_volume.GetSpacing())
filter.SetSize(itk_img_volume.GetLargestPossibleRegion().GetSize())
filter.SetOutputDirection(itk_img_volume.GetDirection())
filter.SetInput(itk_img_volume)
filter.SetTransform(affine_transform)

# ==============================================================================
# Execute the resample filter and convert result to numpy array
# ==============================================================================
filter.Update()
transformed_itk_img = filter.GetOutput()
transformed_vol = itk.array_from_image(transformed_itk_img)

# ==============================================================================
# Output transformed slices to the file system
# ==============================================================================
for i in range(len(img_paths)):
    img_path = img_paths[i]
    output_path = f'{output_dir}{os.path.basename(img_path)}'
    img = transformed_vol[i, ...]
    imageh.save_image(img, output_path)

```

When I write the 10 transformed image slices out to the file system, here are my results:

[01.tif](https://discourse.itk.org/uploads/short-url/po97Yw3fCCVDK0pJJ7JcP6UN0Fl.tif) (910.1 KB)  
[transformed\_01.tif](https://discourse.itk.org/uploads/short-url/aWmy7iY1oncYpspqoaIq77tvJWr.tif) (29.9 KB)

[02.tif](https://discourse.itk.org/uploads/short-url/74vOEYsMlsbANmnKpZ6n4fnpCtP.tif) (910.2 KB)  
[transformed\_02.tif](https://discourse.itk.org/uploads/short-url/nfmMMpQTdznToHTRdM1pKCcHXmr.tif) (56.0 KB)

[03.tif](https://discourse.itk.org/uploads/short-url/j3DSwCtQUJTNFedtT0NgeZoYkvI.tif) (910.4 KB)  
[transformed\_03.tif](https://discourse.itk.org/uploads/short-url/3QEIZCpVvtKvTavBIMfm0SoLLX6.tif) (83.1 KB)

[04.tif](https://discourse.itk.org/uploads/short-url/xB2e4c04RlD5PXz3fA9YHR7XuwR.tif) (910.4 KB)  
[transformed\_04.tif](https://discourse.itk.org/uploads/short-url/2XCSNGtjLuP6VoYjAUPUDNqYxmq.tif) (108.4 KB)

[05.tif](https://discourse.itk.org/uploads/short-url/wFwd6xBedzTY17AOq227bOuBwfF.tif) (909.9 KB)  
[transformed\_05.tif](https://discourse.itk.org/uploads/short-url/sdv4lea4aDDF6cOOX3kBuvOuyxD.tif) (134.7 KB)

[06.tif](https://discourse.itk.org/uploads/short-url/5VBjUtBitB8XlKWJUhRsfC8H4UQ.tif) (910.5 KB)  
[transformed\_06.tif](https://discourse.itk.org/uploads/short-url/uZZf2C3MHiQ9ce5OHp8qOWNquvd.tif) (161.7 KB)

[07.tif](https://discourse.itk.org/uploads/short-url/qsUBzOlXL0HGTU9j4DitwesF2YH.tif) (910.5 KB)  
[transformed\_07.tif](https://discourse.itk.org/uploads/short-url/142Ov1gh4ocikeyYUNY2nH5TGGy.tif) (189.0 KB)

[08.tif](https://discourse.itk.org/uploads/short-url/36h55rFdNcTgqb2fvHBQYEJ2mp3.tif) (910.3 KB)  
[transformed\_08.tif](https://discourse.itk.org/uploads/short-url/oCPPhr1brRtYtDabZAi5OqLNicE.tif) (213.5 KB)

[09.tif](https://discourse.itk.org/uploads/short-url/1M29iy3PWB2SjUpmUbV6R2awYFk.tif) (909.9 KB)  
[transformed\_09.tif](https://discourse.itk.org/uploads/short-url/bvykP8Y7ShjsDDmNAh7S9QPfweh.tif) (240.9 KB)

[10.tif](https://discourse.itk.org/uploads/short-url/sHafLzoLeVvqlZFRY43jLVfKVmI.tif) (910.2 KB)  
[transformed\_10.tif](https://discourse.itk.org/uploads/short-url/hYfmtZRbB0cXV4ktOFb6iF2rLHU.tif) (268.1 KB)

I would expect to still see most of the image for each image because a 1 degree rotation isn’t very much at all. If I go above 1 degree to maybe 5 degrees, I see complete black for all images.

Does anyone know what I’m doing wrong?

---

<div class="post-metadata">

### Author: ![dzenanz](https://discourse.itk.org/user_avatar/discourse.itk.org/dzenanz/32/1093_2.png) [@dzenanz](https://discourse.itk.org/u/dzenanz)
#### Post date: [November 5, 2021, 3:55pm UTC](https://discourse.itk.org/t/applying-a-4x4-affine-transform-to-a-3d-volume/4555/2 "2021-11-05T15:55:11Z")

</div>

By default, transformation center is the coordinate origin. You probably want to find the physical coordinates of a pixel in the center of your image, and pass that to `CenteredAffineTransform`. Or handle this some other way.

---

<div class="post-metadata">

### Author: ![dzenanz](https://discourse.itk.org/user_avatar/discourse.itk.org/dzenanz/32/1093_2.png) [@dzenanz](https://discourse.itk.org/u/dzenanz)
#### Post date: [November 5, 2021, 7:16pm UTC](https://discourse.itk.org/t/applying-a-4x4-affine-transform-to-a-3d-volume/4555/3 "2021-11-05T19:16:36Z")

</div>

I looked at your images now. When visualizing them in slicer ([in.nrrd](https://discourse.itk.org/uploads/short-url/ezoAgKnzkNQVJTIt7uYNEeCxcRv.nrrd), [transformed.nrrd](https://discourse.itk.org/uploads/short-url/hSDxfKwyfomGphF76Z84RtecnVl.nrrd)), it strikes me immediately: rotating along X or Y will quickly bring this thin 3D volume out of its field of view. If you set the slices to be thicker than 1 (e.g. 10, or 20, or 50), or if you rotate around Z axis, this input will serve debugging purposes better. So far, I don’t think there is anything wrong with your code.

---

<div class="post-metadata">

### Author: ![dzenanz](https://discourse.itk.org/user_avatar/discourse.itk.org/dzenanz/32/1093_2.png) [@dzenanz](https://discourse.itk.org/u/dzenanz)
#### Post date: [November 5, 2021, 7:17pm UTC](https://discourse.itk.org/t/applying-a-4x4-affine-transform-to-a-3d-volume/4555/4 "2021-11-05T19:17:40Z")

</div>

You could also consider using [AffineTransform::Rotate3D](https://itk.org/Doxygen/html/classitk_1_1AffineTransform.html#a9cce5e36f6a4f8f0c60fe54a32f38049) if you are unsure about your math.
