# ThinPlateSplineKernelTransform\_double\_3\_3

**URL:** <https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299>\
**Category:** Support\
**Created:** [July 13, 2022, 7:55pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299 "2022-07-13T19:55:40Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jean\_Jacquemier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jean_jacquemier/32/15947_2.png) [@Jean\_Jacquemier](https://discourse.slicer.org/u/Jean_Jacquemier)\
**Post date:** [July 13, 2022, 7:55pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/1 "2022-07-13T19:55:40Z")

</div>

The author of a this paper ([Brain microvasculature has a common topology with local differences in geometry that match metabolic load - ScienceDirect](https://www.sciencedirect.com/science/article/pii/S0896627321000805)) published his data: a mouse brain vasculature and the transormation files needed to aligned the vasculature to an ATLAS.

There are 2 transformation files. I managed to apply it to the vasculature thanks to SimpleITK Python library.

I dit not manage to do the same with the second transformation file.

This second transformation is of type : ThinPlateSplineKernelTransform\_double\_3\_3

I already read some subjects on this forum about this issue but none of the existing solutions seems to work in my case.

1/ The “standard” SimpleITK Python library ('version 2.2.0rc2) can not read the file:

"Could not create an instance of “ThinPlateSplineKernelTransform\_double\_3\_3”

The usual cause of this error is not registering the transform with TransformFactory … "

The SimpleITK python package installed inside Slicer3D (Python interactor) can read it. It returns SimpleITK.SimpleITK.CompositeTransform. But the object cannot execute:

" Only storage methods are implemented for InverseThinPlateSplineKernelTransform"

2/ I managed to invert this transformation thanks to Slicer3D transform tab and save it. Then I can open it with the Python Interactor but I cannot obtain the inverse (what I need) :

“sitk::ERROR: Unable to create inverse!”

3/ I cannot load the vasculature into Slicer3D to apply the transformation because the Dataset is huge ( \> 20 GB)

4/ I tried to convert it to a displacement but without success.

Is there something else that I can try ? Thank you for your help, Jean

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 13, 2022, 10:56pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/2 "2022-07-13T22:56:01Z")

</div>

> [@Jean\_Jacquemier](#):
>
> Only storage methods are implemented for InverseThinPlateSplineKernelTransform

This is due to ITK’s limited support for inverted transforms. You often need a transform and the inverse of that transform, but ITK lacks two features:

1. Save a transform and indicate with a flag that it is an inverse transform.
2. Compute inverse of a transform dynamically, at any position.

We addressed (1) in Slicer by adding special “inverse” transform types (such as `InverseThinPlateSplineKernelTransform`). These transform are only used to allow reading/writing inverse transforms in ITK files. If you try to apply these inverse transform types to an image then you get an error (`Only storage methods are implemented for InverseThinPlateSplineKernelTransform`).

We addressed (2) in Slicer by using VTK to apply transforms to images, meshes, point lists, etc. Unlike ITK, VTK can compute inverse of a transform at any position, in real-time very robustly and efficiently (and it can even do it for composite transforms, i.e., a list of concatenated transforms).

If you want to do everything in ITK then you have to implement inverse transform support yourself.

One option is to not use `Inverse...Transform...` classes, but always store the “forward” transform and if you need an inverse transform then compute it using `InverseDisplacementFieldImageFilter`. It will be very slow and brittle, but if you only do batch processing then it may be acceptable.

Another option is to do something similar that Slicer does (incorporate transform direction flag in transform files and/or use VTK transforms). You can either reimplement these features or you can use Slicer’s implementation. Since Slicer can do everything out of the box, using Slicer would be probably the easiest solution, but of course it would add a dependency to your processing workflow.

---

<div class="post-metadata">

**Author:** ![Jean\_Jacquemier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jean_jacquemier/32/15947_2.png) [@Jean\_Jacquemier](https://discourse.slicer.org/u/Jean_Jacquemier)\
**Post date:** [July 14, 2022, 12:35pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/3 "2022-07-14T12:35:34Z")

</div>

> [@lassoan](#):
>
> using Slicer would be probably the easiest solution, but of course it would add a dependency to your processing workflow.

Thank you for being so helpful. 🙏

Using Slicer Python API would be the perfect solution for me.  
I have been searching for documentation, examples or tutorials on using Slicer Python API for registration/transformation without success.

Could you please provide me with a link to such a material.  
For information, following is the SimpleITK equivalent of what I want to perform with slicer.

```auto
transform = SimpleITK.ReadTransform(path)

registered_vasculature_points = list()
for point in 3d_array.astype(np.double):
   registered_vasculature_points.append(transform.TransformPoint(point))

```

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 14, 2022, 3:59pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/4 "2022-07-14T15:59:08Z")

</div>

You can call `ApplyTransform` method of a node to persistently modify it with a transform (corresponds to “Harden transform” on Slicer GUI).

---

<div class="post-metadata">

**Author:** ![Jean\_Jacquemier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jean_jacquemier/32/15947_2.png) [@Jean\_Jacquemier](https://discourse.slicer.org/u/Jean_Jacquemier)\
**Post date:** [August 2, 2022, 1:07pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/5 "2022-08-02T13:07:19Z")

</div>

> [@lassoan](#):
>
> `ApplyTransform`

What is the Python type of the node on which I can call ApplyTranform ? vtkActor ?

---

<div class="post-metadata">

**Author:** ![cpinter](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/cpinter/32/7995_2.png) [@cpinter](https://discourse.slicer.org/u/cpinter)\
**Post date:** [August 2, 2022, 1:37pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/6 "2022-08-02T13:37:24Z")

</div>

As @lassoan wrote it is a method of a MRML node.

---

<div class="post-metadata">

**Author:** ![Jean\_Jacquemier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jean_jacquemier/32/15947_2.png) [@Jean\_Jacquemier](https://discourse.slicer.org/u/Jean_Jacquemier)\
**Post date:** [August 3, 2022, 9:42am UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/7 "2022-08-03T09:42:53Z")

</div>

I succeed to apply the transformation (and the inverse transform btw) to a vtkMRMLScalarVolumeNode (the mrHead from the sample data).

But I do not figure out how to create a vtkMRMLScalarVolumeNode from my numpy array of 3D cartesian coordiates of shape (N, 3).

Could you provide my any tips or clues ?

---

<div class="post-metadata">

**Author:** ![Jean\_Jacquemier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jean_jacquemier/32/15947_2.png) [@Jean\_Jacquemier](https://discourse.slicer.org/u/Jean_Jacquemier)\
**Post date:** [August 3, 2022, 11:49am UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/8 "2022-08-03T11:49:48Z")

</div>

I managed to create a vtkPoints and a vtkPolyData objects from my numpy 3D array.

---

<div class="post-metadata">

**Author:** ![cpinter](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/cpinter/32/7995_2.png) [@cpinter](https://discourse.slicer.org/u/cpinter)\
**Post date:** [August 3, 2022, 1:38pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/9 "2022-08-03T13:38:27Z")

</div>

> [@Jean\_Jacquemier](#):
>
> numpy array of 3D cartesian coordiates of shape (N, 3)

What do these coordinates represent exactly?

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [August 3, 2022, 7:33pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/10 "2022-08-03T19:33:54Z")

</div>

> [@Jean\_Jacquemier](#):
>
> But I do not figure out how to create a vtkMRMLScalarVolumeNode from my numpy array

You can add a scalar volume node to the scene and then set its voxels from a numpy array using updateVolumeFromArray (see example in the [script repository](https://slicer.readthedocs.io/en/latest/developer_guide/script_repository.html#combine-multiple-volumes-into-one)).

---

<div class="post-metadata">

**Author:** ![Jean\_Jacquemier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jean_jacquemier/32/15947_2.png) [@Jean\_Jacquemier](https://discourse.slicer.org/u/Jean_Jacquemier)\
**Post date:** [August 4, 2022, 5:22am UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/11 "2022-08-04T05:22:44Z")

</div>

A mouse brain vasculature. The numpy array of shape (N, 3) represents X,Y and Z coordinates of the nodes that owned the vasculature

---

<div class="post-metadata">

**Author:** ![Jean\_Jacquemier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jean_jacquemier/32/15947_2.png) [@Jean\_Jacquemier](https://discourse.slicer.org/u/Jean_Jacquemier)\
**Post date:** [August 4, 2022, 5:46am UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/12 "2022-08-04T05:46:06Z")

</div>

My dataset is quite huge (1um resolution for the full mouse brain vasculature). Thus, I cannot convert my numpy array of shape (N, 3) (representing X, Y and Z cartesian 3d coordinates of node) to a Matrix of shape (30000, 40000, 65000) like it is in the script you provided to me.  
Is there a slicer utility function that allows to create or fill) a VolumeNode from 3D points like for vtkPoints for example ?

```auto
    vpoints = vtk.vtkPoints()
    vpoints.SetNumberOfPoints(points.shape[0])
    for i in range(points.shape[0]):
        vpoints.SetPoint(i, points[i])
    vpoly = vtk.vtkPolyData()
    vpoly.SetPoints(vpoints)

```

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [August 4, 2022, 1:34pm UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/13 "2022-08-04T13:34:15Z")

</div>

To work with this data as a volume you could make a more manageable sized array, say 1k^3, and make a kind of histogram of the number of sample points within a given voxel. From there you could volume render or segment the result.

---

<div class="post-metadata">

**Author:** ![Jean\_Jacquemier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jean_jacquemier/32/15947_2.png) [@Jean\_Jacquemier](https://discourse.slicer.org/u/Jean_Jacquemier)\
**Post date:** [August 8, 2022, 7:53am UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/14 "2022-08-08T07:53:04Z")

</div>

Thank you for your answer. If I understand correctly, this solution is a workaround to work with a huge dataset with a quite important loss of precision due to the histogram. It is well noted and I will use it if I cannot find a way to apply the transform without loss of precision.

1/ If I split my “huge” volume into smaller volumes that fit with my memory size and apply the full transform on every sub volume, does the resulting merge of all submodules after transformation provide a correct result ?

2/ ITK allows to apply a transform on 3D points with the following method (itk::simple::Transform::TransformPoint).  
Does a similar method exist in MRML lib ?

---

<div class="post-metadata">

**Author:** ![mau\_igna\_06](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/mau_igna_06/32/9056_2.png) [@mau\_igna\_06](https://discourse.slicer.org/u/mau_igna_06)\
**Post date:** [August 8, 2022, 8:15am UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/15 "2022-08-08T08:15:05Z")

</div>

> [@Jean\_Jacquemier](#):
>
> 1/ If I split my “huge” volume into smaller volumes that fit with my memory size and apply the full transform on every sub volume, does the resulting merge of all submodules after transformation provide a correct result ?

Yes

> 2/ ITK allows to apply a transform on 3D points with the following method (itk::simple::Transform::TransformPoint).  
> Does a similar method exist in MRML lib ?

Once you have created the scalar volume nodes, you will need a linear transform node to do the transformation and then harden it for each parcell… regarding your question about transforming points, you already can do this on Slicer’s python interactor:  
[https://vtk.org/doc/nightly/html/classvtkAbstractTransform.html#a978fb5d88da39f847dbcd562f5eaa433](https://vtk.org/doc/nightly/html/classvtkAbstractTransform.html#a978fb5d88da39f847dbcd562f5eaa433)  
using a vtkTransform and setting it’s matrixToParent

---

<div class="post-metadata">

**Author:** ![Jean\_Jacquemier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jean_jacquemier/32/15947_2.png) [@Jean\_Jacquemier](https://discourse.slicer.org/u/Jean_Jacquemier)\
**Post date:** [August 9, 2022, 11:46am UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/16 "2022-08-09T11:46:10Z")

</div>

After so many tested methods and readed documentation, I finally found the solution to my issue.  
And the solution is so simple …

Thank you very much lassoan, cpinter and mau\_igna\_06 for your time and your help.

The solution In a nutshell

1/ convert my 3d cartesian coordinate to VTK coordinate system (RAS)

2/ Opening my transformation file (the one that contains ThinPlateSplineKernelTransform\_double\_3\_3 transform) with slicer.util.loadTransform() method

3/ Get the vtkThinPlateSplineTransform using the GetTransformFromParent() method

4/ Use the TransformPoint method to apply the transform on each 3D point coordinate.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [August 10, 2022, 9:52am UTC](https://discourse.slicer.org/t/thinplatesplinekerneltransform-double-3-3/24299/17 "2022-08-10T09:52:08Z")

</div>

Thanks for the update. You can also achieve what you described by loading your vasculature model into a model node a s then harden the transform on the model.
