Apply nonlinear transform to point in python

Hello, I have a nonlinear transform which was generated by the CurvedPlanarReformat module. I would like to programmatically find the corresponding point in the original volume space to a point identified in the straightened volume. I can do this in the GUI by creating a fiducial point in the straightened volume and then applying the inverse of the straightening transform to that fiducial node. I want to do the same thing in python. I expected this to just be something like the following:

queryPoint = [5,10,15] # the RAS point coordinate in the straightened volume 
resultPoint = [0]*3 # preallocate to hold the RAS point in the original volume
straighteningTransformNode.TransformPointToWorld(queryPoint, resultPoint)

But when I run this, I always get that resultPoint is equal to queryPoint, even though the straightening transform is definitely not an identity matrix. I haven’t been able to find clear documentation with an example of applying a nonlinear transform to a point (rather than to a node).

It occurs to me as I write this that perhaps the TransformPointToWorld() function is for handling any effects of parent transforms to the given transform, rather than for applying the transform to a point. Since my transform had no parent transform, world coordinate points do not need to be converted to be in the transform’s base coordinate space. So, that would explain why TransformPointToWorld() doesn’t do what I want, but I still don’t see how to actually apply the transform to a point. I’d appreciate any help. Thanks!

Exactly. This is a method of vtkMRMLTransformableNode, so it is not aware of any transform in the current node, it just transforms between the world coordinate system and the node’s coordinate system (determined by all the parent transform nodes).

See an example of how to get transformation between world and a transform node’s children in the script repository.

Please send a pull request with any suggestions for improving the API (more clear documentation, additional helper functions in transform node, etc.).

Thanks for the link. I had looked through the script repository, but didn’t find that example.

This is the code I had figured out as a way to do it last night:

straightToOrigGeneralTransform = vtk.vtkGeneralTransform()
slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(None, straightenTransform, straightToOrigGeneralTransform)
resultPoint = np.zeros(3)
queryPoint = [5.0,10.0,15.0]
straightToOrigGeneralTransform.TransformPoint(queryPoint, resultPoint)

I see from your link that this effect can also be achieved by

straightToOrigGeneralTransform = vtk.vtkGeneralTransform()
straightToOrigGeneralTransform.TransformPoint(queryPoint, resultPoint)

I think what I found confusing was the need to get a transform out of the transform node. I expected that the transform node should be capable of applying its transform to points. I think I didn’t really appreciate the difference between a transform and a transform node. In the Slicer framework, I’m used to thinking of applying a transform as applying a transform node; for example, transforming a volume, model, or markup by applying a transform node. When I wanted to do the same for point coordinates, I was looking for what function in the transform node would allow me to do that, and TransformPointToWorld() and TransformPointFromWorld() sounded just like what I wanted to do, but then I was puzzled by why they didn’t seem to be transforming my query points.

I now understand that TransformPoint<To,From>World() is present for all transformable nodes, and relates to traversing the transform hierarchy only above the given node. Given this generality, it makes sense to keep these functions named as they are, even though they are potentially confusing in the context of a transform node. Would it make sense for vtkMRMLTransformNode to have a function called ApplyTransformToPoint(queryPoint, resultPoint)? And perhaps another called ApplyInverseTransformToPoint(queryPoint, resultPoint)?