I'm using Mayavi to render some imaging data that consists of multiple 2D planes within a 3D volume, the position, orientation, and scale of which are defined by 4x4 rigid body affine transformation matrices. Each plane consists of:
mayavi.mlab.imshow
mayavi.mlab.points3d
and mayavi.mlab.plot3d
respectively.I transform my points and line vertices from a 2D reference plane into the 3D space by dotting their coordinates with my affine matrix. Based on my previous question/answer here, I figured out that I could set the positions and orientations of the ImageActor
objects individually, using:
obj = mlab.imshow(img) obj.actor.orientation = [pitch, roll, yaw] # the required orientation (deg) obj.actor.position = [dx, dy, dz] # the required position obj.actor.scale = [sx, sy, sz] # the required scale
Now the plot looks like this:
Everything lines up nicely, but it's very difficult to interpret because the planes are so densely spaced in z. What I'd now like to be able to do is 'stretch out' the z-axis by some scaling factor. In the case of the points and lines, this is very easy to do - all I do is multiply all of the transformed z-coordinates by a scaling factor.
However, I can't figure out how to apply the same transformation to the images. If I just scale the z-position, the rotation and scaling of the images will of course be wrong, and my plotted points/lines will no longer fall on the same plane as the image:
What I need to do is apply a non-rigid affine transformation that incorporates shear as well as rotation, translation, and scaling to my images.
Is there any way I can manually apply shear to an ImageActor
, or even better just directly apply an arbitrary 4x4 affine matrix that I've precomputed?
Affine transformation is a linear mapping method that preserves points, straight lines, and planes. Sets of parallel lines remain parallel after an affine transformation. The affine transformation technique is typically used to correct for geometric distortions or deformations that occur with non-ideal camera angles.
To define a unique affine 2D transformation, we need 3 points in the original position, and 3 points in the corresponding new position, . The elements of matrix M, for are what we need to determine.
Note: you need at least 6 points in the sense that if you get more than that, then your system is overdetermined which means you can find an approximate solution e.g with least squares, which is the point of your article. Save this answer.
The affine transforms scale, rotate and shear are actually linear transforms and can be represented by a matrix multiplication of a point represented as a vector, [x y ] = [ax + by dx + ey ] = [a b d e ][x y ] , or x = Mx, where M is the matrix.
ImageActor
, which ultimately is a wrapper for tvtk.ImageActor
, has a user_matrix
property, which lets you assign a 4D transformation matrix.
Starting with a random image,
import numpy as np from mayavi.mlab import imshow s = np.random.random((10, 10)) image = imshow(s, colormap='gist_earth', interpolate=False)
gives us the following ...
Creating a transformation matrix and setting a term to give it some shear ...
from tvtk.api import tvtk transform_matrix = tvtk.Matrix4x4() transform_matrix.set_element(0, 1, 2.5) image.actor.user_matrix = transform_matrix
gives us ...
set_element
has the signature (row, col, value)
, so you should be able to set elements on that matrix as needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With