Bug in vtkNIFTIImageReader's handling of left-handed images?

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Bug in vtkNIFTIImageReader's handling of left-handed images?

mbrown
Is the following behaviour a bug in vtkNIFTImageReader ?

If you load SPM8's EPI.nii MNI template file using vtkNIFTIImageReader, it produces different q-form and s-form matrices. Note that the EPI.nii file obeys radiological convention (i.e. left-right flipped, qfac=-1 and left-handed s-form matrix), and vtkNIFTIImageReader flips the slice order and changes the q-form and s-form matrices as described in vtkNIFTIImageReader.cxx. To reproduce, in Python 2.7.3, running on Ubuntu 12.04, using vtk 6.2.0, do this:

import vtk
file_path = '<path/to/SPM8>/templates/EPI.nii'
r = vtk.vtkNIFTIImageReader()
r.SetFileName(file_path)
r.Update()
print(r.GetNIFTIHeader()) # original header values
print(r.GetQFormMatrix()) # q-form matrix, with modifications by vtkNIFTIImageReader
print(r.GetSFormMatrix()) # s-form matrix, with modifications by vtkNIFTIImageReader

The last three lines produce ...

original NIFTI header values (unnecessary fields not shown):
Dim: 3 91 109 91 1 1 1 1
PixDim: -1 2 2 2 0 0 0 0
QFormCode: 4
SFormCode: 4
QuaternB: 0
QuaternC: 1
QuaternD: 0
QoffsetX: 90
QoffsetY: -126
QoffsetZ: -72
SRowX: -2 0 0  90
SRowY:  0 2 0 -126
SRowZ:  0 0 2 -72

q-form matrix
-1  0  0   90
 0 -1  0 -126
 0  0 -1  108
 0  0  0  1

s-form matrix
-1  0  0   90
 0 -1  0 -126
 0  0 -1 -252
 0  0  0  1

I.e. the z-offset number in the fourth column is different between the q-form and s-form matrices. I tracked down the cause. In vtkNIFTIImageReader.cxx (accessed from https://github.com/Kitware/VTK/blob/master/IO/Image/vtkNIFTIImageReader.cxx on 2015-05-06):

lines 974-976, where it adjusts the q-form matrix when qfac<0:
      mmat[3] -= rmat[0][2]*hdr2->pixdim[3]*(hdr2->dim[3] - 1);
      mmat[7] -= rmat[1][2]*hdr2->pixdim[3]*(hdr2->dim[3] - 1);
      mmat[11] -= rmat[2][2]*hdr2->pixdim[3]*(hdr2->dim[3] - 1);

versus lines 1031-1033, where it adjusts the s-form matrix when qfac<0:
      mmat[3] -= hdr2->srow_x[2]*(hdr2->dim[3] - 1);
      mmat[7] -= hdr2->srow_y[2]*(hdr2->dim[3] - 1);
      mmat[11] -= hdr2->srow_z[2]*(hdr2->dim[3] - 1);

Importantly, the rmat matrix (computed on line 926) used in lines 974-976 is positive definite whereas the matrix defined by srow_x,y,z and used in lines 1031-1033 has negative determinant, in the case of SPM8's EPI.nii file. This means that rmat[2,2]=-1 and line 976 adds 180 to mmat[11] taking it from -72 to 108 in the case of EPI.nii. In contrast, srow_z[2]=2, and line 1033 subtracts 180 from mmat[11] taking it from -72 to -252.

Is this difference in behaviour intentional? If so, why?

Other tests suggest that the q-form code is correct and the s-form code is incorrect. A possible fix would be to replace lines 1031-1033 with:
      mmat[3] += hdr2->srow_x[2]*(hdr2->dim[3] - 1);
      mmat[7] += hdr2->srow_y[2]*(hdr2->dim[3] - 1);
      mmat[11] += hdr2->srow_z[2]*(hdr2->dim[3] - 1);

What do you think? Thanks.
Matt

----------
Matthew Brown, PhD
Department of Psychiatry, University of Alberta
Edmonton, Canada

Reply | Threaded
Open this post in threaded view
|

Re: Bug in vtkNIFTIImageReader's handling of left-handed images?

David Gobbi
Hi Matthew,

I have confirmed that when qfac=-1, the z-offset in the qform and sform
differ when they should be exactly the same.  It is a very good thing that
you found this problem.  I'll get to work on verifying your fix.

 - David


On Wed, May 6, 2015 at 9:25 AM, mbrown <[hidden email]> wrote:
Is the following behaviour a bug in vtkNIFTImageReader ?

If you load SPM8's EPI.nii MNI template file using vtkNIFTIImageReader, it
produces different q-form and s-form matrices. Note that the EPI.nii file
obeys radiological convention (i.e. left-right flipped, qfac=-1 and
left-handed s-form matrix), and vtkNIFTIImageReader flips the slice order
and changes the q-form and s-form matrices as described in
vtkNIFTIImageReader.cxx. To reproduce, in Python 2.7.3, running on Ubuntu
12.04, using vtk 6.2.0, do this:

import vtk
file_path = '<path/to/SPM8>/templates/EPI.nii'
r = vtk.vtkNIFTIImageReader()
r.SetFileName(file_path)
r.Update()
print(r.GetNIFTIHeader()) # original header values
print(r.GetQFormMatrix()) # q-form matrix, with modifications by
vtkNIFTIImageReader
print(r.GetSFormMatrix()) # s-form matrix, with modifications by
vtkNIFTIImageReader

The last three lines produce ...

original NIFTI header values (unnecessary fields not shown):
Dim: 3 91 109 91 1 1 1 1
PixDim: -1 2 2 2 0 0 0 0
QFormCode: 4
SFormCode: 4
QuaternB: 0
QuaternC: 1
QuaternD: 0
QoffsetX: 90
QoffsetY: -126
QoffsetZ: -72
SRowX: -2 0 0  90
SRowY:  0 2 0 -126
SRowZ:  0 0 2 -72

q-form matrix
-1  0  0   90
 0 -1  0 -126
 0  0 -1  108
 0  0  0  1

s-form matrix
-1  0  0   90
 0 -1  0 -126
 0  0 -1 -252
 0  0  0  1

I.e. the z-offset number in the fourth column is different between the
q-form and s-form matrices. I tracked down the cause. In
vtkNIFTIImageReader.cxx (accessed from
https://github.com/Kitware/VTK/blob/master/IO/Image/vtkNIFTIImageReader.cxx
on 2015-05-06):

lines 974-976, where it adjusts the q-form matrix when qfac<0:
      mmat[3] -= rmat[0][2]*hdr2->pixdim[3]*(hdr2->dim[3] - 1);
      mmat[7] -= rmat[1][2]*hdr2->pixdim[3]*(hdr2->dim[3] - 1);
      mmat[11] -= rmat[2][2]*hdr2->pixdim[3]*(hdr2->dim[3] - 1);

versus lines 1031-1033, where it adjusts the s-form matrix when qfac<0:
      mmat[3] -= hdr2->srow_x[2]*(hdr2->dim[3] - 1);
      mmat[7] -= hdr2->srow_y[2]*(hdr2->dim[3] - 1);
      mmat[11] -= hdr2->srow_z[2]*(hdr2->dim[3] - 1);

Importantly, the rmat matrix (computed on line 926) used in lines 974-976 is
positive definite whereas the matrix defined by srow_x,y,z and used in lines
1031-1033 has negative determinant, in the case of SPM8's EPI.nii file. This
means that rmat[2,2]=-1 and line 976 adds 180 to mmat[11] taking it from -72
to 108 in the case of EPI.nii. In contrast, srow_z[2]=2, and line 1033
subtracts 180 from mmat[11] taking it from -72 to -252.

Is this difference in behaviour intentional? If so, why?

Other tests suggest that the q-form code is correct and the s-form code is
incorrect. A possible fix would be to replace lines 1031-1033 with:
      mmat[3] += hdr2->srow_x[2]*(hdr2->dim[3] - 1);
      mmat[7] += hdr2->srow_y[2]*(hdr2->dim[3] - 1);
      mmat[11] += hdr2->srow_z[2]*(hdr2->dim[3] - 1);

What do you think? Thanks.
Matt

----------
Matthew Brown, PhD
Department of Psychiatry, University of Alberta
Edmonton, Canada

_______________________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Search the list archives at: http://markmail.org/search/?q=vtk-developers

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/vtk-developers

Reply | Threaded
Open this post in threaded view
|

Re: Bug in vtkNIFTIImageReader's handling of left-handed images?

David Gobbi
Hi Matthew,

I've written a patch that includes your fix:
https://gitlab.kitware.com/vtk/vtk/merge_requests/181

Hopefully we'll get this merged soon.

 - David



On Wed, May 6, 2015 at 2:10 PM, David Gobbi <[hidden email]> wrote:
Hi Matthew,

I have confirmed that when qfac=-1, the z-offset in the qform and sform
differ when they should be exactly the same.  It is a very good thing that
you found this problem.  I'll get to work on verifying your fix.

 - David


On Wed, May 6, 2015 at 9:25 AM, mbrown <[hidden email]> wrote:
Is the following behaviour a bug in vtkNIFTImageReader ?

If you load SPM8's EPI.nii MNI template file using vtkNIFTIImageReader, it
produces different q-form and s-form matrices. Note that the EPI.nii file
obeys radiological convention (i.e. left-right flipped, qfac=-1 and
left-handed s-form matrix), and vtkNIFTIImageReader flips the slice order
and changes the q-form and s-form matrices as described in
vtkNIFTIImageReader.cxx. To reproduce, in Python 2.7.3, running on Ubuntu
12.04, using vtk 6.2.0, do this:

import vtk
file_path = '<path/to/SPM8>/templates/EPI.nii'
r = vtk.vtkNIFTIImageReader()
r.SetFileName(file_path)
r.Update()
print(r.GetNIFTIHeader()) # original header values
print(r.GetQFormMatrix()) # q-form matrix, with modifications by
vtkNIFTIImageReader
print(r.GetSFormMatrix()) # s-form matrix, with modifications by
vtkNIFTIImageReader

The last three lines produce ...

original NIFTI header values (unnecessary fields not shown):
Dim: 3 91 109 91 1 1 1 1
PixDim: -1 2 2 2 0 0 0 0
QFormCode: 4
SFormCode: 4
QuaternB: 0
QuaternC: 1
QuaternD: 0
QoffsetX: 90
QoffsetY: -126
QoffsetZ: -72
SRowX: -2 0 0  90
SRowY:  0 2 0 -126
SRowZ:  0 0 2 -72

q-form matrix
-1  0  0   90
 0 -1  0 -126
 0  0 -1  108
 0  0  0  1

s-form matrix
-1  0  0   90
 0 -1  0 -126
 0  0 -1 -252
 0  0  0  1

I.e. the z-offset number in the fourth column is different between the
q-form and s-form matrices. I tracked down the cause. In
vtkNIFTIImageReader.cxx (accessed from
https://github.com/Kitware/VTK/blob/master/IO/Image/vtkNIFTIImageReader.cxx
on 2015-05-06):

lines 974-976, where it adjusts the q-form matrix when qfac<0:
      mmat[3] -= rmat[0][2]*hdr2->pixdim[3]*(hdr2->dim[3] - 1);
      mmat[7] -= rmat[1][2]*hdr2->pixdim[3]*(hdr2->dim[3] - 1);
      mmat[11] -= rmat[2][2]*hdr2->pixdim[3]*(hdr2->dim[3] - 1);

versus lines 1031-1033, where it adjusts the s-form matrix when qfac<0:
      mmat[3] -= hdr2->srow_x[2]*(hdr2->dim[3] - 1);
      mmat[7] -= hdr2->srow_y[2]*(hdr2->dim[3] - 1);
      mmat[11] -= hdr2->srow_z[2]*(hdr2->dim[3] - 1);

Importantly, the rmat matrix (computed on line 926) used in lines 974-976 is
positive definite whereas the matrix defined by srow_x,y,z and used in lines
1031-1033 has negative determinant, in the case of SPM8's EPI.nii file. This
means that rmat[2,2]=-1 and line 976 adds 180 to mmat[11] taking it from -72
to 108 in the case of EPI.nii. In contrast, srow_z[2]=2, and line 1033
subtracts 180 from mmat[11] taking it from -72 to -252.

Is this difference in behaviour intentional? If so, why?

Other tests suggest that the q-form code is correct and the s-form code is
incorrect. A possible fix would be to replace lines 1031-1033 with:
      mmat[3] += hdr2->srow_x[2]*(hdr2->dim[3] - 1);
      mmat[7] += hdr2->srow_y[2]*(hdr2->dim[3] - 1);
      mmat[11] += hdr2->srow_z[2]*(hdr2->dim[3] - 1);

What do you think? Thanks.
Matt

----------
Matthew Brown, PhD
Department of Psychiatry, University of Alberta
Edmonton, Canada


_______________________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Search the list archives at: http://markmail.org/search/?q=vtk-developers

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/vtk-developers

Reply | Threaded
Open this post in threaded view
|

Re: Bug in vtkNIFTIImageReader's handling of left-handed images?

mbrown
Great!
Glad this was helpful.
Matt
Reply | Threaded
Open this post in threaded view
|

Re: Bug in vtkNIFTIImageReader's handling of left-handed images?

David Gobbi
The fix has been merged into the master branch and will be in the next release.

 - David

_______________________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Search the list archives at: http://markmail.org/search/?q=vtk-developers

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/vtk-developers