Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support reading 2D transforms #7633

Open
dzenanz opened this issue Mar 15, 2024 · 0 comments
Open

Support reading 2D transforms #7633

dzenanz opened this issue Mar 15, 2024 · 0 comments
Assignees
Labels
Type: Enhancement Improvement to functionality

Comments

@dzenanz
Copy link
Member

dzenanz commented Mar 15, 2024

Is your feature request related to a problem? Please describe.

Slicer does not properly open 2D transforms, which are meant to transform 2D images.

Describe the solution you'd like

I assume it would be too much work to have internal support for 2D transforms, so I suggest the following: Convert 2D transforms to 3D transforms upon loading. The transformation along the 3rd axis should be set to zero. When such a transform gets applied to 2D images, they get deformed the same way as when the original 2D transform is applied to them (e.g. ITK's resample filter). I envision no special handling on saving, so they get saved as regular 3D transforms. In the future, we might consider special checks to recognize 2D transforms and convert them to 2D upon saving.

Describe alternatives you've considered

For debugging purposes, 2D affine transforms can be converted to 3D affines without much trouble. ITK-based code from here (in case of link rot):

template <typename TransformType>
void
WriteTransform(const TransformType * transform, std::string filename)
{
  constexpr unsigned Dimension = TransformType::OutputSpaceDimension;
  using Affine3D = itk::AffineTransform<typename TransformType::ParametersValueType, 3>;
  using Affine2D = itk::AffineTransform<typename TransformType::ParametersValueType, 2>;
  using TransformWriterType = itk::TransformFileWriterTemplate<typename TransformType::ParametersValueType>;
  typename TransformWriterType::Pointer tWriter = TransformWriterType::New();
  tWriter->SetFileName(filename);

  if (Dimension == 2 && std::string(transform->GetNameOfClass()) == "AffineTransform")
  {
    typename Affine2D::ConstPointer t2d = dynamic_cast<const Affine2D *>(transform);
    // convert into affine which Slicer can read
    typename Affine3D::MatrixType      m;
    typename Affine3D::TranslationType t;
    t.Fill(0);
    typename Affine3D::InputPointType c;
    c.Fill(0);
    for (unsigned int i = 0; i < Dimension; i++)
    {
      for (unsigned int j = 0; j < Dimension; j++)
      {
        m[i][j] = t2d->GetMatrix()(i, j);
      }
      t[i] = t2d->GetMatrix()(i, Dimension);
      c[i] = t2d->GetCenter()[i];
    }
    m(Dimension, Dimension) = 1.0;

    typename Affine3D::Pointer aTr = Affine3D::New();
    aTr->SetCenter(c);
    aTr->SetMatrix(m);
    aTr->SetOffset(t);
    tWriter->SetInput(aTr);
  }
  else
  {
    tWriter->SetInput(transform);
  }
  tWriter->Update();
}

But this only benefits the one project in which it exists. It would be much better to have this inside Slicer.

Doing the equivalent for displacement field (DF) transforms is more involved. Also, if DF transforms are converted to 3D upon saving to disk, they result in files which are ~33% bigger.

Additional context

Here are some sample transforms: 2D_transform_examples.zip

The sample transforms can be applied to these images:
https://github.com/ntustison/TemplateBuildingExample/tree/master/Faces

Associated forum thread.

@jcfr jcfr added the Type: Enhancement Improvement to functionality label Mar 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Enhancement Improvement to functionality
Development

No branches or pull requests

2 participants