Affine transforms using clesperanto#

This notebook demonstrates how to apply affine transforms to 3D images.

import pyclesperanto_prototype as cle

cle.select_device('TX')
<NVIDIA GeForce GTX 1650 with Max-Q Design on Platform: NVIDIA CUDA (1 refs)>
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from skimage.io import imread
# Laod example data
np_array = imread('../../data/Haase_MRT_tfl3d1.tif')
np_array.shape
(192, 256, 256)
# push it to GPU memory
input_image = cle.push_zyx(np_array)

cle.imshow(input_image)
../_images/affine_transforms_clesperanto_4_0.png

Rotation#

For rotating an image, you need to provide angles corresponding to axes.

rotated = cle.rotate(input_image, angle_around_z_in_degrees=45)
cle.imshow(rotated)
../_images/affine_transforms_clesperanto_6_0.png

Images are rotated around their center by default. You can change this by providing an additional parameter. The image will then be rotated around the origin.

rotated = cle.rotate(input_image, angle_around_z_in_degrees=15, rotate_around_center=False)
cle.imshow(rotated)
../_images/affine_transforms_clesperanto_8_0.png

Translation#

Images can be translate by providing translation distances along axes:

translated = cle.translate(input_image, translate_x=50, translate_y=-50)
cle.imshow(translated)
../_images/affine_transforms_clesperanto_10_0.png

Scaling#

You can scale the image by providing scaling factors.

scaled = cle.scale(input_image, factor_x=0.5, factor_y=2)
cle.imshow(scaled)
../_images/affine_transforms_clesperanto_12_0.png

In this context, the auto_size parameter might be useful:

scaled_auto_size = cle.scale(input_image, factor_x=0.5, factor_y=2, auto_size=True)
cle.imshow(scaled_auto_size)
../_images/affine_transforms_clesperanto_14_0.png

Rigid transform#

Rigid transforms allow to do translations and rotations in one shot

rigid_transformed = cle.rigid_transform(input_image, translate_x=50, angle_around_z_in_degrees=45)
cle.imshow(rigid_transformed)
../_images/affine_transforms_clesperanto_16_0.png

Affine transforms#

To do translation, rotation and scaling in one shot, use affine transforms. Shearing will be implemented in a future release.

To setup an affine transform, you can do this using a 4x4 transform matrix:

transform_matrix = np.asarray([
    [1, 0, 0, 50],
    [0, 2, 0, 0],
    [0, 0, 0.5, 0],
    [0, 0, 0, 1]
])
transformed_image = cle.affine_transform(input_image, transform=transform_matrix)
cle.imshow(transformed_image)
../_images/affine_transforms_clesperanto_18_0.png

Alternatively, you can configure a transform object and pass it:

transform = cle.AffineTransform3D()
transform.translate(50)
transform.scale(1, 2, 0.5)

transformed_image = cle.affine_transform(input_image, transform=transform)
cle.imshow(transformed_image)
../_images/affine_transforms_clesperanto_20_0.png

Shearing#

Providing the shear angle will shear the image in the desired plane

The shear is calculated using the shear angle by the following equation:

1.0/ tan(shear_angle_in_degrees * pi / 180)

#For example, to shear the image in the Y axis along YZ plane using a shear angle of 30 degrees

shear_angle = 30.0

transform = cle.AffineTransform3D()
shear_transform= transform.shear_in_z_plane(angle_y_in_degrees=shear_angle)

transformed_image = cle.affine_transform(input_image, transform=shear_transform)

##display images in each plane
print("yz")
cle.imshow(cle.maximum_x_projection(transformed_image))
print("xz")
cle.imshow(cle.maximum_y_projection(transformed_image))
print("xy")
cle.imshow(cle.maximum_z_projection(transformed_image))
yz
../_images/affine_transforms_clesperanto_22_1.png
xz
../_images/affine_transforms_clesperanto_22_3.png
xy
../_images/affine_transforms_clesperanto_22_5.png

Linear interpolation versus nearest neighbor interpolation#

Let’s crop the nose and transform it using different interpolation modes.

crop = input_image[50,125:150,45:70]

cle.imshow(crop)
../_images/affine_transforms_clesperanto_24_0.png

Nearest neighbor interpolation#

# create a larger image
rescaled = cle.create(np.asarray(crop.shape) * 10)

# fill it with a scaled version of the image; 
cle.scale(crop, rescaled, factor_x=10, factor_y=10, factor_z=10, linear_interpolation=False)
cle.imshow(rescaled)
../_images/affine_transforms_clesperanto_26_0.png

Linear interpolation#

# fill it with a scaled version of the image; 
cle.scale(crop, rescaled, factor_x=10, factor_y=10, factor_z=10, linear_interpolation=True)
cle.imshow(rescaled)
../_images/affine_transforms_clesperanto_28_0.png