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

Difficulties with unigradicon-warp #18

Open
russchua opened this issue Jul 30, 2024 · 7 comments · Fixed by #20
Open

Difficulties with unigradicon-warp #18

russchua opened this issue Jul 30, 2024 · 7 comments · Fixed by #20
Assignees

Comments

@russchua
Copy link

russchua commented Jul 30, 2024

Hi, thanks for making uniGradICON.

The instructions look simple enough and unigradicon-register works fine. However I'm having trouble with unigradicon-warp when trying to warp labels.

This works fine:
unigradicon-register --fixed=$fixed_image_file --fixed_modality=mri --moving=$moving_image_file --moving_modality=mri --transform_out=$transform_path --warped_moving_out=$warped_image_path --io_iterations None

This has issues:
unigradicon-warp --fixed $fixed_image_file --moving $moving_label_file --transform $transform_path --warped_moving_out $warped_label_path --nearest_neighbor

Issues:
File "/unigradicon_testing_space/github_pip/uniGradICON/src/unigradicon/init.py", line 312, in wa
rp_command
interpolator = itk.NearestNeighborInterpolateImageFunction.New(moving)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/unigradicon_conda/lib/python3.11/site-packages/itk/support/template_class.py", line 734, in New
raise itk.TemplateTypeError(self, input_type)
itk.support.extras.TemplateTypeError: itk.NearestNeighborInterpolateImageFunction is not wrapped for input type None.

To limit the size of the package, only a limited number of
types are available in ITK Python. To print the supported
types, run the following command in your python environment:

itk.NearestNeighborInterpolateImageFunction.GetTypes()

Possible solutions:

  • If you are an application user:
    ** Convert your input image into a supported format (see below).
    ** Contact developer to report the issue.

  • If you are an application developer, force input images to be
    loaded in a supported pixel type.

    e.g.: instance = itk.NearestNeighborInterpolateImageFunction[itk.Image[itk.SS,2], itk.D].New(my_input)

  • (Advanced) If you are an application developer, build ITK Python yourself and
    turned to ON the corresponding CMake option to wrap the pixel type or image
    dimension you need. When configuring ITK with CMake, you can set
    ITK_WRAP_${type} (replace ${type} with appropriate pixel type such as
    double). If you need to support images with 4 or 5 dimensions, you can add
    these dimensions to the list of dimensions in the CMake variable
    ITK_WRAP_IMAGE_DIMS.

Supported input types:

itk.Image[itk.SS,2]
itk.Image[itk.UC,2]
itk.Image[itk.US,2]
itk.Image[itk.F,2]
itk.Image[itk.D,2]
itk.Image[itk.Vector[itk.F,2],2]
itk.Image[itk.CovariantVector[itk.F,2],2]
itk.Image[itk.RGBPixel[itk.UC],2]
itk.Image[itk.RGBAPixel[itk.UC],2]
itk.Image[itk.SS,3]
itk.Image[itk.UC,3]
itk.Image[itk.US,3]
itk.Image[itk.F,3]
itk.Image[itk.D,3]
itk.Image[itk.Vector[itk.F,3],3]
itk.Image[itk.CovariantVector[itk.F,3],3]
itk.Image[itk.RGBPixel[itk.UC],3]
itk.Image[itk.RGBAPixel[itk.UC],3]
itk.Image[itk.SS,4]
itk.Image[itk.UC,4]
itk.Image[itk.US,4]
itk.Image[itk.F,4]
itk.Image[itk.D,4]
itk.Image[itk.Vector[itk.F,4],4]
itk.Image[itk.CovariantVector[itk.F,4],4]
itk.Image[itk.RGBPixel[itk.UC],4]
itk.Image[itk.RGBAPixel[itk.UC],4]
itk.PhasedArray3DSpecialCoordinatesImage[itk.F]
itk.PhasedArray3DSpecialCoordinatesImage[itk.UC]

@HastingsGreer
Copy link
Collaborator

Thank you for the detailed report! We will work on this

@HastingsGreer
Copy link
Collaborator

Hi! I have added a test to verify that unigradicon-warp works as expected on labelmaps, see #20 . I haven't been able to replicate your issue on a generic label map, so I need more information on the labelmap that is causing the code to break for you.

Could you post the output of this code on your labelmap?

python

import itk
label = itk.imread("your-labelmap-here.nrrd")
print(label)
print(label.GetLargestPossibleRegion().GetSize())

@russchua
Copy link
Author

russchua commented Jul 31, 2024

Thank you, I am actually working with a NIFTI file. Here it is.

Image (0x8288290)
  RTTI typeinfo:   itk::Image<int, 3u>
  Reference Count: 1
  Modified Time: 786
  Debug: Off
  Object Name: 
  Observers: 
    none
  Source: (none)
  Source output name: (none)
  Release Data: Off
  Data Released: False
  Global Release Data: Off
  PipelineMTime: 604
  UpdateMTime: 785
  RealTimeStamp: 0 seconds 
  LargestPossibleRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  BufferedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  RequestedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  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 (0x8288520)
      RTTI typeinfo:   itk::ImportImageContainer<unsigned long, int>
      Reference Count: 1
      Modified Time: 782
      Debug: Off
      Object Name: 
      Observers: 
        none
      Pointer: 0x8497cd0
      Container manages memory: true
      Size: 4915200
      Capacity: 4915200

itkSize3 ([160, 160, 192])

@HastingsGreer
Copy link
Collaborator

Ok! The test now fails, matching your report. It looks like itk doesn't support warping signed int labelmaps, which is surprising but knowing ITK, not that surprising haha. A first pass at a solution is to add a flag for casting int labelmaps to a type that the InterpolateImageFilters support, such as float or double- perhaps with a cast back before saving the image- I will look in to this

@HastingsGreer
Copy link
Collaborator

HastingsGreer commented Aug 1, 2024

Hi! Your issues should now be fixed in the linked pull request. Until we merge it to main and update the pypi package, you can use it locally with

pip install git+https://github.com/uncbiag/unigradicon.git@test-unigradicon-warp-issue

@russchua
Copy link
Author

russchua commented Aug 1, 2024

image
When I do this, the label mask is not seen.

Is this likely because of the meta data contained in an image not otherwise captured in the label data? If so, how can I rectify this?

A print of the fixed_image, moving mask and the fixed_label is shown below

fixed_image:

Image (0xce6f340)
  RTTI typeinfo:   itk::Image<unsigned char, 3u>
  Reference Count: 1
  Modified Time: 3034
  Debug: Off
  Object Name: 
  Observers: 
    none
  Source: (none)
  Source output name: (none)
  Release Data: Off
  Data Released: False
  Global Release Data: Off
  PipelineMTime: 2850
  UpdateMTime: 3033
  RealTimeStamp: 0 seconds 
  LargestPossibleRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  BufferedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  RequestedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  Spacing: [1, 1, 1]
  Origin: [-77.6102, 71.9206, 72.2747]
  Direction: 
1 -1.11759e-08 8.46921e-09
-1.03464e-08 2.32831e-10 -1
1.11759e-08 -1 4.65661e-10

  IndexToPointMatrix: 
1 -1.11759e-08 8.46921e-09
-1.03464e-08 2.32831e-10 -1
1.11759e-08 -1 4.65661e-10

  PointToIndexMatrix: 
1 8.46921e-09 -1.11759e-08
1.11759e-08 -4.65661e-10 -1
-1.03464e-08 -1 -2.32831e-10

  Inverse Direction: 
1 8.46921e-09 -1.11759e-08
1.11759e-08 -4.65661e-10 -1
-1.03464e-08 -1 -2.32831e-10

  PixelContainer: 
    ImportImageContainer (0xce69460)
      RTTI typeinfo:   itk::ImportImageContainer<unsigned long, unsigned char>
      Reference Count: 1
      Modified Time: 3030
      Debug: Off
      Object Name: 
      Observers: 
        none
      Pointer: 0xd717d70
      Container manages memory: true
      Size: 4915200
      Capacity: 4915200

moving_label:

Image (0xd16fae0)
  RTTI typeinfo:   itk::Image<int, 3u>
  Reference Count: 1
  Modified Time: 3782
  Debug: Off
  Object Name: 
  Observers: 
    none
  Source: (none)
  Source output name: (none)
  Release Data: Off
  Data Released: False
  Global Release Data: Off
  PipelineMTime: 3600
  UpdateMTime: 3781
  RealTimeStamp: 0 seconds 
  LargestPossibleRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  BufferedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  RequestedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  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 (0xd16c8e0)
      RTTI typeinfo:   itk::ImportImageContainer<unsigned long, int>
      Reference Count: 1
      Modified Time: 3778
      Debug: Off
      Object Name: 
      Observers: 
        none
      Pointer: 0xe077d90
      Container manages memory: true
      Size: 4915200
      Capacity: 4915200

fixed_label (as shown before):

Image (0xd05c300)
  RTTI typeinfo:   itk::Image<int, 3u>
  Reference Count: 1
  Modified Time: 4155
  Debug: Off
  Object Name: 
  Observers: 
    none
  Source: (none)
  Source output name: (none)
  Release Data: Off
  Data Released: False
  Global Release Data: Off
  PipelineMTime: 3973
  UpdateMTime: 4154
  RealTimeStamp: 0 seconds 
  LargestPossibleRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  BufferedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  RequestedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [160, 160, 192]
  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 (0xd05c590)
      RTTI typeinfo:   itk::ImportImageContainer<unsigned long, int>
      Reference Count: 1
      Modified Time: 4151
      Debug: Off
      Object Name: 
      Observers: 
        none
      Pointer: 0xf337da0
      Container manages memory: true
      Size: 4915200
      Capacity: 4915200

@HastingsGreer
Copy link
Collaborator

HastingsGreer commented Aug 2, 2024

Yes, most likely the spacing, origin and direction of the segmentation mask should match the image- since they appear to have the same Size. Ideally this could be fixed in whatever software produced the mask, as whenever images get separated from their spatial metadata, bugs lurk. However, in this case just copying the image metadata onto the mask should work- just verify that they align after you do this operation, by for example opening both images in 3D Slicer which is a metadata-aware image viewer. to copy the metadata, something like

In [8]: mask = itk.imread('mask'), img = itk.imread('img')

In [9]: mask.SetOrigin(img.GetOrigin())

In [10]: mask.SetDirection(img.GetDirection())

In [11]: mask.SetSpacing(img.GetSpacing())

In [12]: itk.imwrite(mask, "mask_with_metadata.nrrd")

@lintian-a lintian-a assigned lintian-a and unassigned lintian-a Nov 20, 2024
@lintian-a lintian-a linked a pull request Nov 20, 2024 that will close this issue
@lintian-a lintian-a self-assigned this Nov 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants