Reading Arbitrary Transforms, Compute Something if Linear

I’m working on trying to extend the antsTransformInfo tool to print the Determinant of a transform if its Linear as part of its summary information.

The existing implementation is very very simple, a copy of an ITK example:

The transform IO seems to not need to know anything about the transform, not the dimension, nor the type, and immediately supports all the ITK transform types, and can print a summary.

I implemented a partial version for linear transforms, and I’ve already had to instantiate 2D and 3D handlers separately, and this doesn’t support unpacking a composite transform at the least, and probably has other corner cases where it will fall over.

Am I going about this the wrong way? Is there a better way? I want this to support reading arbitrary ITK transforms and print the summary object, and if it’s Linear, add the Determinant.

Or, is the better solution to add the Determinant to all Linear transform summaries in ITK?

Thanks for your advice…

I think the 2D vs 3D instantiation can be solved by templating over dimension.

For determining type, maybe this example would help?

https://itk.org/Doxygen/html/Examples_2IO_2TransformReadWrite_8cxx-example.html

  using ReadCompositeTransformType =
    itk::CompositeTransform<ReadScalarType, Dimension>;
  auto it = transforms->begin();
  if (!strcmp((*it)->GetNameOfClass(), "CompositeTransform"))
  {
    ReadCompositeTransformType::Pointer compositeRead =
      static_cast<ReadCompositeTransformType *>((*it).GetPointer());
    compositeRead->Print(std::cout);
  }

You can see the initial logic for loading an arbitrary Transform transforms here:

The SimpleITK Transform constructor ends up doing a dynamic cast to determine what is the concrete transform type.

:edit: Additionally, you probably only need to cast to “MatrixOffsetTransformBase” to support just about all of the linear ITK transforms.

1 Like

Thanks @blowekamp!

1 Like

Thanks everyone. I’ve managed to successfully handle affine vs composite transforms, however, I can’t find a way to “unpack” a composite transform.

I expected it to also be a GetTransformList but that doesn’t seem to be the case.

Is there a way to get an iterator for a CompositeTransform like I do for a list?

 const TransformReaderType::TransformListType * transforms = reader->GetTransformList();
for (auto it = transforms->begin(); it != transforms->end(); ++it)

See a full composite transform reader implementation in 3D Slicer here:

It builds a VTK transformation pipeline from the ITK transform file that can be directly used for visualization (displaying warped images, meshes, segmentations, annotations, etc.).

The answer appears to be that its called a Queue for composite transforms, and I can iterate over it.

Now what remains is that I can’t seem to try/catch a cast of displacement fields into MatrixOffsetTransformBase, instead it segfaults.

Is this a bug, or should I be doing this another way?

          for (auto it2 = compositeTransformQueue.begin(); it2 != compositeTransformQueue.end(); ++it2)
          {
            try
            {
              using TransformType3D = itk::MatrixOffsetTransformBase<double, 3, 3>;
              TransformType3D * itktx3d = dynamic_cast<TransformType3D *>((*it2).GetPointer());
              itktx3d->Print(std::cout);
              std::cout << "Determinant: " << vnl_determinant(itktx3d->GetMatrix().GetVnlMatrix()) << std::endl;
            }
            catch (const itk::ExceptionObject & excp)
            {
              it2->Print(std::cout);
            }
          }

If a dynamic_cast fails the results are null. I don’t see this check.

OK. I was expecting an exception, not a null.

This C++ metamagic is far far outside my programming experience so I’m a copy-paste monkey here.

Thanks all for the help, the final code is a PR for review here

1 Like