Composite Transform error

Hello,

I have two transforms: affine and displacementfield. When I apply them affine then df, it works well. I would like to create a composite transform. I read that they are in reverse order with the back being applied first.

My code is as follows:
ct = sitk.CompositeTransform(df_transform)
ct.AddTransform(aff_transform)
sitk.WriteTransform(ct, ‘ct_transform.h5’)

However, I get an error:
RuntimeError: Exception thrown in SimpleITK WriteTransform: [D:\a\1\sitk-build\ITK\Modules\IO\TransformHDF5\src\itkHDF5TransformIO.cxx:389](file:///D:/a/1/sitk-build/ITK/Modules/IO/TransformHDF5/src/itkHDF5TransformIO.cxx:389): ITK ERROR: HDF5TransformIOTemplate(00000194FBD310D0): Composite Transform can only be 1st transform in a file

What does this mean?

Hello @CrownMella,

This means that there is already a transform stored in that file (likely your code is more complex than what you provided). The composite transform has to be the first transform in the file.
The following code works as expected:

import SimpleITK as sitk
import numpy as np

# Create affine and deformation field transformations
dim = 3
aff_transform = sitk.AffineTransform(dim)
df_transform = sitk.DisplacementFieldTransform(dim)
field_size = [10]*dim
field_origin = [-1.0]*dim
field_spacing = [0.8]*dim
field_direction = list(np.identity(dim).ravel())

df_transform.SetFixedParameters(
    field_size + field_origin + field_spacing + field_direction
)
df_transform.SetParameters(np.random.random(len(df_transform.GetParameters())))

# Compose the two transformations and write to file
ct = sitk.CompositeTransform(df_transform)
ct.AddTransform(aff_transform)
sitk.WriteTransform(ct, "ct_transform.h5")

Hi ziv,

Interestingly enough, if I flip the two i.e.
ct = sitk.CompositeTransform(aff_transform)
ct.AddTransform(df_transform)
it works. I’ve tried restarting python, changing the variable name, but it still keeps showing the error.

Hello @CrownMella,

Are you working with the code snippet I provided or your original code? Does the code snippet I provided work? If yes, then there is something else going on with your original code.

Make sure that the type of df_transform is not a CompositeTransform (you end up with a nested CompositeTransform which isn’t supported).

Hi Ziv,

Your code works. In my code, the registration returns sitk.DisplacementFieldTransform(initial_displacement_field) where the initial_displacement_field comes from TransformToDisplacementField(initial_transform) where the initial transform is itk.CenteredTransformInitializer(f,m,sitk.AffineTransform(3), sitk.CenteredTransformInitializerFilter.GEOMETRY)

so no I don’t see any compositetransforms here unless any of those words actually mean composite.

Hello @CrownMella,

Theoretically you are correct, doesn’t sound like you should get a CompositeTransform from that set of steps, but that is a description of the code, not the code itself. Now we know that the transforms are obtained from registration.

My suspicion, the registration using the deformation field isn’t done in-place, and the returned transformation type from the registration is a Transform. If this is the case, you can do the registration in-place or downcast the transform using its Downcast() method.

To see the details of a transform simply print it:

print(df_transform)
1 Like

The results of ImageRegistrationMethods::Execute can be a CompositeTransform. The RegistrationMethods can be configure to modify the displacement field, with the SetInitialTransform(tx, inPlace=True).

Additionally nested Composite transforms can be remote with CompositeTransform::FlattenTransform() method.

Hi Ziv,

What do you mean by done in-place? Also below is the output from print. Looks to be a displacementfieldtransform. The only thing different from the df_transform you made is the reference count (though idk what this even means)

print(dd_transform)
itk::simple::DisplacementFieldTransform
 DisplacementFieldTransform (000002470113D0E0)
   RTTI typeinfo:   class itk::DisplacementFieldTransform<double,3>
   Reference Count: 1
   Modified Time: 124240
   Debug: Off
   Object Name: 
   Observers: 
     none
   DisplacementField: 
     Image (0000024701157910)
       RTTI typeinfo:   class itk::Image<class itk::Vector<double,3>,3>
       Reference Count: 3
       Modified Time: 124236
       Debug: Off
       Object Name: 
       Observers: 
         none
       Source: (none)
       Source output name: (none)
       Release Data: Off
       Data Released: False
       Global Release Data: Off
       PipelineMTime: 0
       UpdateMTime: 0
       RealTimeStamp: 0 seconds 
       LargestPossibleRegion: 
         Dimension: 3
         Index: [0, 0, 0]
         Size: [300, 200, 600]
       BufferedRegion: 
         Dimension: 3
         Index: [0, 0, 0]
         Size: [300, 200, 600]
       RequestedRegion: 
         Dimension: 3
         Index: [0, 0, 0]
         Size: [300, 200, 600]
       Spacing: [1, 1, 1]
       Origin: [0, 0, 0]
       Direction: 
1 0 0
0 1 0
0 0 1

       IndexToPointMatrix: 
1 0 0
0 1 0
0 0 1

       PointToIndexMatrix: 
1 0 0
0 1 0
0 0 1

       Inverse Direction: 
1 0 0
0 1 0
0 0 1

       PixelContainer: 
         ImportImageContainer (0000024700E27F60)
           RTTI typeinfo:   class itk::ImportImageContainer<unsigned __int64,class itk::Vector<double,3> >
           Reference Count: 1
           Modified Time: 124233
           Debug: Off
           Object Name: 
           Observers: 
             none
           Pointer: 00000247B37C6040
           Container manages memory: true
           Size: 36000000
           Capacity: 36000000
   InverseDisplacementField: (null)
   Interpolator: 
     VectorLinearInterpolateImageFunction (0000024747BF2670)
       RTTI typeinfo:   class itk::VectorLinearInterpolateImageFunction<class itk::Image<class itk::Vector<double,3>,3>,double>
       Reference Count: 1
       Modified Time: 124229
       Debug: Off
       Object Name: 
       Observers: 
         none
       InputImage: 0000024701157910
       StartIndex: [0, 0, 0]
       EndIndex: [299, 199, 599]
       StartContinuousIndex: [-0.5, -0.5, -0.5]
       EndContinuousIndex: [299.5, 199.5, 599.5]
   InverseInterpolator: 
     VectorLinearInterpolateImageFunction (0000024747BF2430)
       RTTI typeinfo:   class itk::VectorLinearInterpolateImageFunction<class itk::Image<class itk::Vector<double,3>,3>,double>
       Reference Count: 1
       Modified Time: 124230
       Debug: Off
       Object Name: 
       Observers: 
         none
       InputImage: 0000000000000000
       StartIndex: [0, 0, 0]
       EndIndex: [0, 0, 0]
       StartContinuousIndex: [0, 0, 0]
       EndContinuousIndex: [0, 0, 0]
   DisplacementFieldSetTime: 124240
   m_IdentityJacobian: [1, 0, 0]
[0, 1, 0]
[0, 0, 1]

    CoordinateTolerance: 1e-06
    DirectionTolerance: 1e-06

Hi Bradley, Hi Ziv,

Flattening the transform worked! Thanks to you both. I guess the result of the execute really was a composite transform. Although, I am still confused as to why the order would matter if the compositetransform does not support nesting ie why composite(df), addtransform(aff) didnt work but composite(af),addtransform(df) worked (though the resulting image was not nice)

1 Like