Invert elastix transformation

Hi @NicoKiaru @bogovicj,

Do you know how to compute the inverse transformation of an elastix transformation?

In my case the transformation is quite complex, spanning multiple Transformation.txt files, including several BSplines.

And what I would need is not to transform an image, but a list of points. Transforming lists of points is supported using -def in transformix, but this will transform points from the fixed to the moving image, whereas I’d need the opposite direction.

1 Like

I never did this… From the documentation (, p38), apparently this can be done by using the displacement magnitude as the penalty that should be minimized.

From the manual:

The DisplacementMagnitudePenalty is a cost function that penalises ||Tμ(x) − x||2. You can use this
to invert transforms, by setting the transform to be inverted as an initial transform (using -t0), setting
(HowToCombineTransforms “Compose”), and running elastix with this metric, using the original fixed
image set both as fixed (-f) and moving (-m) image. After that you can manually set the initial transform
in the last parameter file to “NoInitialTransform”, and voila, you have the inverse transform!


Yes, I found that, too, but it looked rather obscure to me :slight_smile:
Also, I did not really get how to actually do it…

The main idea is to compose your know initial forward transform A with an unknow transform B (it can be whatever, spline, rigid, affine). But:

  • you set an identical Image for the moving image and the fixed image
  • you set the penalty cost for registration as the composed displacement field magnitude

Then you perform the registration, by launching elastik, but you specify the initial transform -t0 parameterTransformA.txt and the parameters of the inverse transform you’d like to have with -p regParamB.txt

(edit: in the case of multiple chained transforms, normally you just need to specify the last transform file because the chaining is specified in it.)

Because of these parameters, basically doing the registration is equivalent to solve B(A(Image))=Image, so in other terms B = A^-1; the unknown transform will be the invert of your original transformation.

Note that you can try to invert a spline transform with a rigid transform (it won’t be perfect, but it will try to do its best).

I managed to do some simple inverse transform. I can try to come up with some command line example.


I have some code that might be worth trying, but am traveling at the moment, I’ll be a little slow…

1 Like

Hi @Christian_Tischer,

I’ve played a bit with the inverse transform. Here’s a small test case:
So on the first column you can see the blobs, and the image to which it is registered on the second column. The registration is done with the composition of a rigid transform followed by a bspline transform:

elastix -f blobs-warp.tif -m blobs.tif -p euler.txt -p bspline.txt -out folder_out

The third column shows the result of this first registration, which is bad, but that doesn’t matter, it’s actually better to test if the invert computation works. To compute the inverse transform (which I choose to be a spline, as specified in the file invRegParameters.txt), I execute:

elastix -f grid.tif -m grid.tif -t0 TransformParameters.1.txt -p invRegParameters.txt -out folder_out_inv

I believe the choice of the image (grid.tif) is not important. It’s just helpful to specify the region on which the computation will take place. TransformParameters.1.txt is the last transform file generated be the first registration.

This computation yields the file TransformParameters.0.txt. In this file you need to change the initial transform to NoInitialTransform, and then the file can be used to invert the transform given by the first registration: as you can see on the fourth column, this works nicely.

Here’s the files used, just in case you want to reproduce this sequence: (1.1 MB)

1 Like

@bogovicj back from travels? =) I am trying to transform points using the pipeline from @NicoKiaru but unfortunately getting nowhere — not sure whether it’s because I need to fliplr the point coordinates, or am using the wrong transform file, or… A script that automates this whole procedure would be much appreciated!


:slight_smile:, yea back long ago.
Left this since my impression was that the solution above could do the job.

Are you using elastix? And if not, is your transformation stored as displacements in x and y?


back long ago.

Seen any turtles? :joy:

Yes, it’s elastix. A collaborator is using it and has successfully registered her mouse brain to the Allen Mouse Brain Atlas (AMBA). But she also has a bunch of cell detections (points) that she would like to map onto the atlas, and that can’t be done without the inverse transforms. (As far as I can tell.)

1 Like

Hi @jni !


Get ready, lots of stuff coming!

I put together a quick demo. Here’s the data I used.


tp="result/TransformParameters.0.txt" # transform parameters

## Convert the elastix transform to a displacement field
transformix -def all -out result -tp $tp

# A test point
echo "280.0,94.0,50" > ptList.csv

# Apply the inverse transform
$PATH_TO_TEMPLATE_BUILDING_JGO/transformPoints -i ptList.csv \
    -o ptList_invxfm.csv \
    -t result/deformationField.nrrd?i

# Apply the inverse transform
transformPoints -i ptList_invxfm.csv \
    -o ptList_invxfm_fwdxfm.csv \
    -t result/deformationField.nrrd

cat ptList.csv
cat ptList_invxfm_fwdxfm.csv

The output of the last two lines is:


i.e. transforming a point through the inverse and then the forward is off by about half a micron (the points have units of microns)

There are ways to ask for higher precision at the cost of speed. Details here, but one example:

-t a_deformation_field.nrrd?invopts;tolerance=0.01;maxIters=200?i

asks for an inverse with a precision of 0.01 units, but computes for a max of 200 iterations


  • elastix, of course
  • Some of my stuff:
git clone
cd template-building
mvn clean compile install
# set PATH_TO_TEMPLATE_BUILDING variable to the jgo subdirectory
1 Like

@bogovicj Thank you so much for this, and sorry for the long delay in responding. Both I and the student I’m helping have had a rather busy month and we didn’t get a chance to try this out until now. (Actually I think @axtimwalde’s talk, in which you feature prominently, might have prompted her to give this a go again :joy:)

When she tries mvn clean compile install, she gets the following error, which I’ve just reproduced on my machine:

Downloading from saalfeld-lab-maven-repo:
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  05:52 min
[INFO] Finished at: 2019-11-26T12:55:37+11:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project saalfeldlab-template-building: Could not resolve dependencies for project org.scijava:saalfeldlab-template-building:jar:0.1.2-SNAPSHOT: Could not find artifact net.imglib2:imglib2-realtransform:jar:2.2.1-SNAPSHOT in imagej.public ( -> [Help 1]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1]

The allegedly missing package is listed here. I really don’t understand what’s happening… Any hints?

Hi @jni, the imglib2-realtrasform artifact is included as a SNAPSHOT dependency. Please try two things in this sequence:

replace imglib2-realtransform-2.2.1-SNAPSHOT by imglib2-realtransform-2.2.1 and see if that builds. If it doesn’t, then it is possible that you need this long overdue PR, clone it, build it mvn clean install, and then the SNAPSHOT will be available on your computer. It also means that we should clean up…

Hi @jni,

Sorry about that.

I updated that repo - I’d expect things to work for you if you pull and retry

mvn clean compile install

Hope it ends up being helpful for you, and do keep us posted!

1 Like

I forgot to chime in that @axtimwalde’s fix worked! Which is of course the same thing as your fix. =) I’ll post another update once Abi has had a chance to try this. Thank you very much!