BSplineTransform object has no attribute SetCoefficientImages

I used SimpleITK v1.2 to perform a BSpline image registation. I used BSplineTransformInitializer to initialize the registration:

MeshSize = [NumControlPts] * MovIm.GetDimension()

InitialTx = sitk.BSplineTransformInitializer(FixIm, MeshSize)

I set the metric, optimizer, interpolator, etc. then get the final transform:

FinalTx = RegMethod.Execute(FixIm, MovIm)

The result looks fine. I want to store the transform parameters and deformation field in a DICOM registration object (DRO). The idea being that the DRO will be stored and when the same pair of FixIm and MovIm come about, I can avoid repeating the time-consuming deformable registration by parsing the DRO for the required parameters, create a BSpline transformation, apply the parsed parameters, and resample MovIm.

I have access to the grid size, spacing, origin and direction already but need the coefficient images. It seemed reasonable to get it from the final transform:

CoeffImX, CoeffImY, CoeffImZ = FinalTx.GetCoefficientImages()

but I got the error:

‘Transform’ object has no attribute ‘GetCoefficientImages’

I tried using the initial transform instead:

CoeffImX, CoeffImY, CoeffImZ = InitialTx.GetCoefficientImages()

which worked. I was puzzled by this result since both InitialTx and FinalTx are BSplineTransforms:

print(InitialTx)

itk::simple::BSplineTransform
BSplineTransform (00000267BA4D7330)
RTTI typeinfo: class itk::BSplineTransform<double,3,3>
Reference Count: 3
Modified Time: 19499183
Debug: Off
Object Name:
Observers:
none
CoefficientImage: [ 00000267B2E2FEA0, 00000267B2E2F3A0, 00000267B8BA8430 ]
TransformDomainOrigin: [-220.461, -137.269, -102.056]
TransformDomainPhysicalDimensions: [260.253, 260.253, 181.5]
TransformDomainDirection: 0.998543 -0.0277357 -0.046297
0.0277059 0.999615 -0.00128451
0.0463148 0 0.998927

GridSize: [11, 11, 11]
GridOrigin: [-250.992, -170.661, -126.226]
GridSpacing: [32.5316, 32.5316, 22.6875]
GridDirection: 0.998543 -0.0277357 -0.046297
0.0277059 0.999615 -0.00128451
0.0463148 0 0.998927

print(FinalTx)

itk::simple::Transform
BSplineTransform (00000267BA4D7330)
RTTI typeinfo: class itk::BSplineTransform<double,3,3>
Reference Count: 3
Modified Time: 19499183
Debug: Off
Object Name:
Observers:
none
CoefficientImage: [ 00000267B2E2FEA0, 00000267B2E2F3A0, 00000267B8BA8430 ]
TransformDomainOrigin: [-220.461, -137.269, -102.056]
TransformDomainPhysicalDimensions: [260.253, 260.253, 181.5]
TransformDomainDirection: 0.998543 -0.0277357 -0.046297
0.0277059 0.999615 -0.00128451
0.0463148 0 0.998927

GridSize: [11, 11, 11]
GridOrigin: [-250.992, -170.661, -126.226]
GridSpacing: [32.5316, 32.5316, 22.6875]
GridDirection: 0.998543 -0.0277357 -0.046297
0.0277059 0.999615 -0.00128451
0.0463148 0 0.998927

I acknowledge that the first lines are different, i.e. “itk::simple::BSplineTransform” for InitialTx and “itk::simple::Transform” for FinalTx - perhaps suggesting that they are of different classes. Yet “BSplineTransform” is on the next line for both. I’m not sure how to interpret these differences.

I’d like to know why I was unable to get the coefficient images from FinalTx, and whether it even makes sense to be getting it from the pre-registered transform InitialTx. In any case I thought I would proceed with what I have and see what it gets me.

I created a new BSpline transform, NewBsplineTx, using BSplineTransformInitializer as before. Then I tried to set the coefficient images:

NewBsplineTx.SetCoefficientImages((CoeffsImX_new, CoeffsImY_new, CoeffsImZ_new))

but got the error:

‘BSplineTransform’ object has no attribute ‘SetCoefficientImages’

After some searching I realised that SetCoefficientImages only became possible in SimpleITK v2.0 (although that release note contains “SetCoefficientImage”, i.e. missing “s”, which I assume to be a typo).

I created a new virtual environment and installed SimpleITK v2.0.2 yet to my surprise, I get the exact same error as before (I also tried SetCoefficientImage just to be sure but got the same error).

Any ideas on where I’m going wrong?

Thanks.

Check the results of type(FinalTx). The return type is sitk::Transform it needs to be converted to sitk::BSplineTransform:

FinalTx = sitk.BSplineTransform(FinalTx)

@blowekamp : Thanks for the tip on converting from sitk::Transform to sitk::BSplineTransform.

Interestingly, there was no difference between the arrays from the coefficient images obtained from InitialTx and FinalTx (after converting FinalTx as above).

Anyhow, what still remains is the question of why I get the error:

‘BSplineTransform’ object has no attribute ‘SetCoefficientImages’

when I try to set the coefficient images that I got from FinalTx to a new BSpline transform:

NewBsplineTx = sitk.BSplineTransformInitializer(FixIm, MeshSize)

that I can confirm is of type sitk::BSplineTransform.

My take on this and this is that it should be possible.

I tried both:

NewBsplineTx.SetCoefficientImages((CoeffImX, CoeffImY, CoeffImZ))

and

NewBsplineTx.m_pfSetCoefficientImages((CoeffImX, CoeffImY, CoeffImZ))

(not understanding what the “m_pf” is meant to mean).

Any clues on what I’m getting wrong?

This can be done with the constructor:

sitk.BSplineTransform([CoeffImX, CoeffImY, CoeffImZ])

@blowekamp: Thanks very much.

I was getting tripped up on trying SetCoefficientImages, meanwhile the answer was there all along - ironically at the same two places I linked above: BSplineTransform( const std::vector &coefficientImages, unsigned int order=3 ) :man_facepalming: