How to apply an existing BSpline transformation to points, TransformPoint not working for me?

Hi, I have an existing BSpline transform as a result of registering a pair of images. Now I want to apply this existing transform to a set of 3D points. My idea is to create a new BSplineTransform and call its TransformPoint() function, but something must be missing, my transferred points are exactly the same as before:

// all information are stored in TransformParameters[1], such as TransformParameters[1]["GridOrigin"] etc
Image coeffImage = new sitk.Image(gridSize, PixelIDValueEnum.sitkVectorFloat32, 3);
coeffImage.SetOrigin(gridOrigin);
coeffImage.SetSpacing(gridSpacing);

// read grid points from TransformParameters[1]
var buffer = coeffImage.GetBufferAsFloat();
var numGridPoints = gridSize[0] * gridSize[1] * gridSize[2] * 3;
var gridPointsVectorString = TransformParameters[1]["TransformParameters"];
for (int i = 0; i < numGridPoints; i++)
{
    gridPoints[i] = float.Parse(gridPointsVectorString[i]);
}
Marshal.Copy(buffer, gridPoints, 0, gridPoints.Length);

VectorUInt32 transformDomainMeshSize = new VectorUInt32(3) { (uint)image.XSize, (uint)image.YSize, (uint)image.ZSize, 2 /* what is this last parameter for? */ };
var bSplineTransform = SimpleITK.BSplineTransformInitializer(coeffImage, transformDomainMeshSize);

// ready to TransformPoint?
var ptTransformed = bSplineTransform.TransformPoint(new VectorDouble(3) { 0, 0, 0 });
ptTransformed = bSplineTransform.TransformPoint(new VectorDouble(3) { 10, 10, 10 });
ptTransformed = bSplineTransform.TransformPoint(new VectorDouble(3) { 300, 200, 6 });
// still the same! Why?

Any help would be appreciated!

If you already have a transform, why do you want to construct another one? For transforming the points, you usually want the inverse of the resampling transform.

I do not want to construct another one, I want to apply the existing transform to a set of 3D points. The original BSpline transform was done by registering a fixed image - moving image pair, and the moving image has been deformed to match the fixed image, this is all good. The transform parameters are all saved into disk for future use. Now if there are some special points or geometry drawn on the moving image, say a manual segmentation of an object, how do I apply the transformation to this segmentation (not an image)? I thought I should create the transform (maybe this is what you mean by “construct”) by loading the already saved transform parameters, then call TransformPoint() to transform my points one-by-one, thus the above code. The code ran but doesn’t really do anything. Do I create the transform the right way, or do I miss something?

I think my question is related to SimpleITK: Using TransformPoint() to Transform Mask Vertices, where in their case the TransformPoint() did output new positions for the points, although initially inverted. In my case the points returned by TransformPoint() is simply the same as the input points.

Instead of saving your transform in some custom format, why not use transform IO?

The transform were done by using Elastix, then SimpleITK.WriteParameterFile() and ParameterMap p = SimpleITK.ReadParameterFile(file) are used to write and read the parameters (currently in .txt format).

Thanks for your question, I found it is different from SimpleITK’s transform format, because calling var transform = SimpleITK.ReadTransform(transformFile); gave me error:
…\itkTxtTransformIO.cxx:160:
ITK ERROR: TxtTransformIOTemplate(00000176365766E0): Tags must be delimited by :’
my input transformFile (by Elastix) looks like this:

(BSplineTransformSplineOrder 3)
(Direction 1 0 0 0 1 0 0 0 1)
(FixedImageDimension 3)
(FixedInternalImagePixelType "float")
(GridDirection 1 0 0 0 1 0 0 0 1)
(GridIndex 0 0 0)
(GridOrigin -108.6132815 -419.105469 -204.75)
(GridSize 15 21 16)
(GridSpacing 15 15 15)
...

Then I just tried to write out my newly created BSpline transfrom:

var bSplineTransform = SimpleITK.BSplineTransformInitializer(coeffImage, transformDomainMeshSize);
SimpleITK.WriteTransform(bSplineTransform, "c:/temp/bSplineTransform.txt");

It gives me these:

#Insight Transform File V1.0
#Transform 0
Transform: BSplineTransform_double_3_3
Parameters: 0 0 0 0 0 0 0 0 0 0 0 0 0 ................
FixedParameters: 515 515 140 -118.43505859375 -429.10302734375 -215.90419708029196 0.44677734375 0.62255859375 1.7791970802919708 1 0 0 0 1 0 0 0 1

So I guess my code couldn’t convert the Elastix based transform file to the SimpleITK.BSplineTransform, although I believe they are closely related.

Is there a way to convert the Elastix based transform to SimpleITK.BSplineTransform?

I don’t know about SimpleITK, but ITKPython has a way, both ITK->Elastix and Elastix->ITK. Both of these ways are imperfect, but they exist.

1 Like