I am currently testing out FastModelAlign for affine transforms.
I see there are 3 transformation matrices created, I assume in this order:

scaling

rigid transformation

affine transformation

The resulting model is the result after these 3 transformations and looks as expected.

However, if I make a copy of the original model and apply the “scaling” transform to it, it already matches the FastModelAlign output.

I.e. selecting the “scaling” transform generated by FastModelAlign to a copy of the original model seems to apply the other two transformations (rigid and affine) as well.

Similarly, if I run the registration without the affine transform, applying the “scaling” transform to the original mesh it also translates/rotates it (seems to include rigid transformation too).

I see on the github repo that there is a comment " #Put affine transform node under scaling transform node, which has been put under the rigid transform node".

Does this mean that the scaling transform also contains the information of the affine transform?
The observed behavior would suggest this, but when I look at the actual values of the scaling transform it is just a scaling transform…

I am aware of the LPS/RAS and to/from parent distinctions in the transforms and the exports work well. I am just confused by the behaviour described above within Slicer.

@evaherbst transforms are nested, and they are nested in the order they are created. Each one only contains the transformation associated only with that specific step. In this example I am aligning small (source) model to a large model (target). First there is a linear scaling transform, then a rigid transform and finally an affine transform. Affine transform by itself probably has very little change associated with it because previous steps already taken care of the much larger scaling and alignment transform.

If you want to have a single transform that contains everything, just right-click and harden the transforms nested in the top transform (in this case small_affine). The resultant affine transform will contain everything. The final output (in this case Model), has all these transforms applied to the small model.

I am not sure what you mean by “select affine”, can you clarify? Selecting where?

What the transforms are doing to the model is that affine transform is transforming the rigid, which in return is transforming the scaling transform. So, if you put your original source model under the scaling transform, all other transforms will be automatically applied in the correct order and you should get the model transformed exactly in the same way as your output model.

Thanks Murat! By select I meant what you did in the subject hierarchy. I should have said “applying the transform”.

What the transforms are doing to the model is that affine transform is transforming the rigid, which in return is transforming the scaling transform

Yes, this makes sense now. I was just thinking the affine transform, being the last one applied, would contain all of the ones ^before and so I should apply that in the subject hierarchy. Now it makes sense why the scaling one does all of the transformations.

I was just initially confused because I thought the scaling transform only included scaling, etc. (as it does when you just look at the numbers under “transforms”). But the nesting structure now makes sense.

Thanks for the clarification!
And thanks for developing this tool, it is proving to be very useful already!
Eva

Glad to hear that the module works! We also have some explanation of the nested transformation matrices in the FastModelAlign tutorial at “4. Investigate and Visualize the scaling and rigid transformation process”: https://github.com/SlicerMorph/Tutorials/tree/main/FastModelAlign

In an example I made, I am transforming a source mesh to a smaller target mesh.
The scale transform has scale factors of .59, and the source mesh is therefore shrunk to align with the target when the scale transform is applied.
All good so far.

My question is, why is the transform labeled “to parent”? I would think that the source mesh is the parent. But if that is the case, I would expect the “to parent” transform to mean “source to target”, which should be the inverse of .59, rather than .59.

Or is the parent referring to the target rather than the source?

Either way I can of course use this transform and export it (and calculate the inverse if needed). But I was just wondering about the conventions regarding what is considered the parent here.

I do not know the history of terminology and where term parent comes. All i that terms like source, target etc may mean different things in related different fields such computer vision and medical image analysis.

Ok, thank you for the quick reply.
I’ll just take it at face value then and not pay attention to the “to parent” labeling but just think of all the transforms as “source to target” within Slicer (with the inverse, so “target to source”, being exported from Slicer)

Also, I noticed using meshes with relatively low res (about 2k) gave inconsistencies in rigid alignment results when rerunning FastModelAlign with the same settings.
Affine alignments were almost identical.

Yes, as we showed empirically in the original ALPACA paper (which fastmodelalign is based on), you need 4000-6000 points for optimum registration. If your meshes are sparse in vertices and the generated point clouds are not hitting that limit, you can use the surface toolbox to increase the vertex density.