[ITK] Nifti Image to World Orientation

Nicolas Rannou nicolas at eunate.ch
Fri Apr 15 07:10:28 EDT 2016


Hi all,

Apologizes if it is another duplicate but I couldn’t find any relevant/recent information about my issue.

Is it possible to display image to world transform for an image in ITK?

I am trying to figure out how ITK handles the orientation for this Nifti file:
https://drive.google.com/open?id=0B2-PspfnvPNgY1R2SFFTd3YtaGM

The image to world transform I get if I compute it “manually" from the header or run it in Nibabel does not match Slicer's (which is based on ITK) [1]. Also, if I convert this Nifiti file to NRRD in ITK, the orientation returned by the NRRD header matches Slicer but not Nibabel.

SLICER:
-0.859375 0 0 49.8438
0 -0.859375 0 -67.8906
0 0 0.859375 -53.7109
0 0 0 1

NIBABEL:
array([[ -0.859375 ,   0.       ,   0.       ,  49.84375  ],
       [  0.       ,   0.859375 ,   0.       , -67.890625 ],
       [  0.       ,   0.       ,   0.859375 , -53.7109375],
       [  0.       ,   0.       ,   0.       ,   1.       ]])


NRRD HEADER:
NRRD0004
   2 # Complete NRRD file format specification at:
   3 # http://teem.sourceforge.net/nrrd/format.html
   4 type: float
   5 dimension: 3
   6 space: left-posterior-superior
   7 sizes: 117 159 126
   8 space directions: (0.859375,0,0) (0,0.859375,0) (0,0,0.859375)
   9 kinds: domain domain domain
  10 endian: little
  11 encoding: raw
  12 space origin: (-49.84375,67.890625,-53.7109375)


I understand the RAS/LPS differences but what doesn’t makes sense to me are the space directions in the NRRD header: -0.85 on the second vector would make sense to me:
(0.859375,0,0) (0,-0.859375,0) (0,0,0.859375)
I would also expect slicer [0][0] and [1][1] indices to have opposite signs. (like Nibabel)
-0.859375 0 0 49.8438
0  0.859375 0 -67.8906
0 0 0.859375 -53.7109
0 0 0 1


I couldn’t track down where this modification happens in ITK.
Does ITK do any kind of correction to adjust the orientation somehow?


As a test, I convert my Nifti to NRRD [2] and run the program step by step.

In the Nifti parser, one of the last steps is to set the “Direction” to: (NiftiImageIO::SetImageIOOrientationFromNIfTI - Around line 1700)
Direction 0: [1,-0,0]
Direction 1: [-0,-1,0]
Direction 2: [0,0,1]

Then, when the NRRD parser tries fo fetch the direction it becomes: (NrrdImageIO::Write - Around line 945)
Direction 0 [1,0,0]
Direction 1 [0,1,0]
Direction 2 [0,0,1]

I couldn’t track down where this is happening or if that even makes sense.

Best,
Nicolas

[1]
-------------------------------------------------------
 nifti_1_header :
    sizeof_hdr     = 348
    data_type[10]  = 0x 0 0 0 0 0 0 0 0 0 0
    db_name[18]    = 0x 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    extents        = 0
    session_error  = 0
    regular        = 0x72
    dim_info       = 0x0
    dim[8]         = 4 117 159 126 15 1 1 1
    intent_p1      = 0.000000
    intent_p2      = 0.000000
    intent_p3      = 0.000000
    intent_code    = NIFTI_INTENT_NONE
    datatype       = 16
    bitpix         = 32
    slice_start    = 0
    pixdim[8]      = -1.000000 0.859375 0.859375 0.859375
                     1.000000 0.000000 0.000000 0.000000
    vox_offset     = 352.000000
    scl_slope      = 1.000000
    scl_inter      = 0.000000
    slice_end      = 0
    slice_code     = 0
    xyzt_units     = 0x12
    cal_max        = 0.000000
    cal_min        = 0.000000
    slice_duration = 0.000000
    toffset        = 0.000000
    glmax          = 0
    glmin          = 0
    descrip        = ''
    aux_file       = ''
    qform_code     = 1
    sform_code     = 0
    quatern_b      = 0.000000
    quatern_c      = 1.000000
    quatern_d      = 0.000000
    qoffset_x      = 49.843750
    qoffset_y      = -67.890625
    qoffset_z      = -53.710938
    srow_x[4]      = 0.000000, 0.000000, 0.000000, 0.000000
    srow_y[4]      = 0.000000, 0.000000, 0.000000, 0.000000
    srow_z[4]      = 0.000000, 0.000000, 0.000000, 0.000000
    intent_name    = ''
    magic          = 'n+1'
———————————————————————————


SLICER

>>> import slicer
>>> vol = slicer.util.getNode('template_T2.nii')
>>> IJKToRASMat = vtk.vtkMatrix4x4()
>>> vol.GetIJKToRASMatrix(IJKToRASMat);
>>> print(IJKToRASMat)
vtkMatrix4x4 (0x140294910)
Debug: Off
Modified Time: 980729
Reference Count: 1
Registered Events: (none)
Elements:
-0.859375 0 0 49.8438
0 -0.859375 0 -67.8906
0 0 0.859375 -53.7109
0 0 0 1

NIBABEL

In [2]: example_filename = '/Users/nico/work/gitroot/ami/data/nifti/FetalAtlas/template_T2.nii.gz'

In [3]: import nibabel as nib

In [4]: img = nib.load(example_filename)

In [5]: img.shape
Out[5]: (117, 159, 126, 15)

In [6]: img.affine
Out[6]: 
array([[ -0.859375 ,   0.       ,   0.       ,  49.84375  ],
       [  0.       ,   0.859375 ,   0.       , -67.890625 ],
       [  0.       ,   0.       ,   0.859375 , -53.7109375],
       [  0.       ,   0.       ,   0.       ,   1.       ]])

[2]
  typedef itk::Image<float, 3> InputImageType;
  typedef itk::Image<float, 3> OutputImageType;

  typedef itk::ImageFileReader<InputImageType>  ReaderType;
  typedef itk::ImageFileWriter<OutputImageType> WriterType;

  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer = WriterType::New();

  reader->SetFileName( "/Users/nico/work/gitroot/data/nifti/fetalatlas_brain/t2/template_T2.nii.gz" );

  writer->SetFileName( "test.nrrd" );
  writer->SetInput( reader->GetOutput() );
  writer->Update();




[3]

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/community/attachments/20160415/c593ab59/attachment-0001.html>


More information about the Community mailing list