Prevent transformix running in Slicer Elastix

Using Slicer 4.10.2

I am writing a runtime sensitive registration module which makes use of the slicer elastix module. As you can imagine elastix registration takes some time to run (about ~2 minutes for the data and parameters I am using). However transformix also runs after every run of elastix, and this takes an additional 30 seconds before the process is finished. How can I prevent transformix from running? I did not specify an output volume in Elastix, and my parameter file also specifies not to write an output image (WriteResultImage "false").

Maybe this is where the issue is:

Since transformix’s purpose is to generate the output transformed volume, perhaps it should only be called when outputVolumeNode exists instead of being called every time?

Yes, that makes sense - would you be able to add that option and provide a pull request?

1 Like

Sure, I’ll do that by this week!

Here is the pull request: https://github.com/lassoan/SlicerElastix/pull/19

Transformix is always necessary now because we need to generate a resampled moving volume and/or a displacement field. Both are provided by Transformix.

We could avoid the need to run Transformix if we could read the proprietary Elastix transformation file format. I’ve started implementing a reader for linear transforms, but did not finish it. I include it below - it would be great if you could finish it and integrate it into SlicerElastix module. We should probably implement bspline reader, too.

# Example input:
transformStr="(TransformParameters 0.022507 0.013835 0.013726 7.760838 4.879223 -0.014589)"

transformParams = transformStr.strip("()").split(" ")
transformParams.pop(0)
transformParams = [ float(x) for x in transformParams ]
(roll, pitch, yaw) = np.array(transformParams)[0:3]
computeZYX=False

[rx,ry,rz]=transformParams[0:3]
[tx,ty,tz]=transformParams[3:6]

from math import sin, cos
rotX = np.array([[1.0, 0.0, 0.0], [0.0, cos(rx), -sin(rx)], [0.0, sin(rx), cos(rx)]])
rotY = np.array([[cos(ry), 0.0, sin(ry)], [0.0, 1.0, 0.0], [-sin(ry), 0.0, cos(ry)]])
rotZ = np.array([[cos(rz), -sin(rz), 0.0], [sin(rz), cos(rz), 0.0], [0.0, 0.0, 1.0]])

if computeZYX:
    # Aply the rotation first around Y then X then Z
    fixedToMovingDirection = np.dot(np.dot(rotZ, rotY), rotX)
else:
    # Like VTK transformation order
    fixedToMovingDirection = np.dot(np.dot(rotZ, rotX), rotY)

fixedToMoving = np.eye(4)
fixedToMoving[0:3,0:3] = fixedToMovingDirection
fixedToMoving[0:3,3] = transformParams[3:6]

# Create Slicer linear transform ("to parent" direction, in RAS)
ras2lps = np.array([[-1,0,0,0],[0,-1,0,0],[0,0,1,0],[0,0,0,1]])
movingToFixed = np.dot(np.dot(ras2lps, np.linalg.inv(fixedToMoving)), ras2lps)
slicer.util.updateTransformMatrixFromArray(getNode('Transform_1'),movingToFixed)

I should have made clear that, in my pull request, transformix is still run but with limited parameters so that only the deformation field is written and not a new output image (unless required by the user). This saves a little of time overall.

I will take a look at your code for the linear transform conversion to see if i can contribute!

1 Like

Have you confirmed that this is the correct transformation from the Euler angles to a linear transform? If so, is the only thing left to read the transform text file and write the transform to Slicer?

Yes, the computation should be correct and the remaining task is to iterate through the transform files and apply this parser on them.

Here is the pull request for parsing linear transformations: https://github.com/lassoan/SlicerElastix/pull/21

I included support for translation only registrations too.

Thank you. I’ve merged this and added reading of bspline transforms, too.