Npy transform matrix

When saving a transformation matrix in python as .npy or .txt, I get a different position in slicer when applying the transformation to a model node. I assume that there is a problem due to different coordinate system but I thought that slicer would handle itk and thus convert my transform matrix.

I failed to update a segmentation node in slicer using np.load however I have the same matrix also as txt and it did not work.

Do you have any suggestions?

Slicer uses all data in LPS coordinate system in files (following conventions set by DICOM, ITK, and most other modern medical image computing software), while uses RAS in the scene (for backward compatibility). You need to apply LPS<->RAS basis transform if you import an LPS transform as shown here. You also need to be aware of the transform direction (modeling/resampling; from/to parent).

Thank you for your reply!!!
I tried to find a solution for the index error however when I do exactly like in the respository mentioned I get the following:

m = np.array( tfm_file.splitlines()[3].split()[1:], dtype=np.float64 )

Traceback (most recent call last):

File “”, line 1, in

IndexError: list index out of range

Do you know how to fix that?

The example code works for the example transform file. If your transform has a different format then you need to adjust the script. For example, if the parameters are not in the 4th line of the string then change [3].

If you already extracted a 4x4 matrix then skip the transform file parsing (the first few lines) and just call the itktfm_to_slicer method.

The problem was that I linked to the file however did not read the content of tfm file.

But I am still frustrated by the fact that when I copy the 4x4 matrix from cloudcompare (where I aligned two STL models) and import it to slicer, the transformation does not work.

Is a different software using a different coordinate system???

The two main coordinate system conventions in medical image computing are LPS and RAS. LPS has practically won, but for backward compatibility reasons RAS is still used in software that placed its bet on RAS (such as Slicer).

Conversion of a transformation matrix from LPS to RAS is trivial:

transform_ras = np.diag([-1, -1, 1, 1]) @ transform_lps @ np.diag([-1, -1, 1, 1])

A complete example to parse CloudCompare output, convert to RAS, and write it into a new transform node:

registrationInfo="""---------------------------
Register info
---------------------------
Final RMS: 5.11411e-5 (computed on 50000 points)
----------------
Transformation matrix
0.632	0.684	-0.365	-28.784
-0.774	0.576	-0.263	17.832
0.030	0.448	0.893	25.578
0.000	0.000	0.000	1.000
----------------
Scale: fixed (1.0)
----------------
Theoretical overlap: 100%
----------------
This report has been output to Console (F8)
---------------------------
OK   
---------------------------
"""

# Get LPS->LPS registration matrix as numpy array
import numpy as np
transformValues_lps = '\t'.join(registrationInfo.splitlines()[6:10]).split()
transform_lps = np.array(transformValues_lps, dtype=np.float64 ).reshape(4, 4)

# Convert LPS->LPS registration matrix to RAS->RAS registration matrix
transform_ras = np.diag([-1, -1, 1, 1]) @ transform_lps @ np.diag([-1, -1, 1, 1])

# Save transform into a new transform node
transformNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLLinearTransformNode", "RegistrationResult")
transformNode.SetMatrixTransformToParent(slicer.util.vtkMatrixFromArray(transform_ras))

Note that Slicer has lots of registration tools, so it should not be necessary to use CloudCompare. Have a look at this page for a quick overview. There are many other, more specialized registration tools, too. Let us know if you were interested in having your complete workflow implemented in Slicer.