[vtk-developers] vtkNIFTIImageReader coordinates
padraig
padraig.looney at gmail.com
Sun Nov 13 11:50:16 EST 2016
Hi David,
I am still confused by this. Volumes that ITK tells me have the same
bounds, VTK displays in Paraview as not having the same bounds.
Consider this header from
vtkNIFTIImageHeader (0x221e6b0)
Debug: Off
Modified Time: 85
Reference Count: 1
Registered Events: (none)
DimInfo: 0x0
Dim: 3 224 153 52 1 1 1 1
PixDim: 1 0.9195 1.40018 2.89048 0 0 0 0
VoxOffset:352
IntentP1: 0
IntentP2: 0
IntentP3: 0
IntentCode: 0
DataType: 2
BitPix: 8
SliceStart: 0
SclSlope: 1
SclInter: 0
SliceEnd: 0
SliceCode: 0
XYZTUnits: 0x2
CalMax: 0
CalMin: 0
SliceDuration: 0
TOffset: 0
Descrip: ""
AuxFile: ""
QFormCode: 2
SFormCode: 1
QuaternB: 0
QuaternC: 0
QuaternD: 1
QOffsetX: 102.536
QOffsetY: 106.413
QOffsetZ: 30.1491
SRowX: -0.9195 0 0 102.536
SRowY: 0 -1.40018 0 106.413
SRowZ: 0 0 2.89048 30.1491
IntentName: ""
Magic: "n+1"
That is the same as the affine from nibabel
array([[ -0.91949999, 0. , 0. , 102.53600311],
[ 0. , -1.40017998, 0. , 106.41300201],
[ 0. , 0. , 2.89048004, 30.14909935],
[ 0. , 0. , 0. , 1. ]])
If you look at the SForm matrix below shouldn't the bounds be
X: (224-1)*-0.9195 + 102.536 = -102.51249999999999
Y: (153-1)*-1.40018 + 106.413 =--106.41436
Z: (52-1)*2.89048 + 30.1491 = 177.56358
In ITK I have checked the physical coordinates of the image and found
the bounds to be, as expected from the above,
[-102.536, -106.413, 30.1491][102.512, 106.414, 177.564]
In VTK I have checked the centre and origin with
vtkNew<vtkNIFTIImageReader> niiReader;
niiReader->SetFileName(str);
niiReader->Update();
int size[3];
double center[3], spacing[3], bounds[6];
niiReader->GetOutput()->GetDimensions(size);
niiReader->GetOutput()->GetCenter(center);
niiReader->GetOutput()->GetBounds(bounds);
std::vector<double> bounds_vec(&bounds[0],&bounds[6]);
std::cout << bounds[0] << " " << bounds[1] << " " << bounds[2] <<
" " << bounds[3] << " " << bounds[4] << " " << bounds[5] << std::endl;
niiReader->GetOutput()->GetSpacing(spacing);
double center1[3] = { center[0], center[1], center[2] };
double center2[3] = { center[0], center[1], center[2] };
std::cout << center[0] << " " << center[1] << " " << center[2] <<
std::endl;
std::cout << size[0] << " " << size[1] << " " << size[2] << std::endl;
and get
0 205.048 0 212.827 0 147.414
102.524 106.414 73.7072
224 153 52
On 12/11/16 15:39, David Gobbi wrote:
> Hi Padraig,
>
> The "direction" or "orientation" is the 3x3 portion of the 4x4 matrix,
> after dividing out the scale.
>
> So if ITK is giving a direction like the following, it means that ITK
> allows the direction to include a mirror-flip (in this case, it's a
> flip along the z-axis):
>
> 1 0 0
> 0 1 0
> 0 0 -1
>
> The vtkNIFTIImageReader doesn't allow a mirror flip in the
> QFormMatrix, so instead it re-orders the nifti slices in memory to
> undo the flip. When it does this, it also has to adjust the 4th column
> of the QFormMatrix since the 4th column now indicates the position of
> the last slice in the file, instead of the first slice in the file.
> The difference in position between the first slice and the last slice
> is (n - 1)*sz, where n is the number of slices and sz is the slice
> spacing. For your image, we can add (n - 1)*sz to -117.265 in order
> to get 30.149:
>
> -117.265 + (52 - 1)*2.89048 = 30.149
>
> This accounts for the discrepancy.
>
> - David
>
> On Sat, Nov 12, 2016 at 7:42 AM, padraig <padraig.looney at gmail.com
> <mailto:padraig.looney at gmail.com>> wrote:
>
> Hi David,
>
>
> vtkNIFTIImageHeader (0x3346680)
> Debug: Off
> Modified Time: 85
> Reference Count: 1
> Registered Events: (none)
> DimInfo: 0x0
> Dim: 3 224 153 52 1 1 1 1
> PixDim: -1 0.9195 1.40018 2.89048 0 0 0 0
> VoxOffset:352
> IntentP1: 0
> IntentP2: 0
> IntentP3: 0
> IntentCode: 0
> DataType: 2
> BitPix: 8
> SliceStart: 0
> SclSlope: 1
> SclInter: 0
> SliceEnd: 0
> SliceCode: 0
> XYZTUnits: 0x2
> CalMax: 0
> CalMin: 0
> SliceDuration: 0
> TOffset: 0
> Descrip: ""
> AuxFile: ""
> QFormCode: 2
> SFormCode: 1
> QuaternB: 0
> QuaternC: 0
> QuaternD: 1
> QOffsetX: 102.536
> QOffsetY: 106.413
> QOffsetZ: 30.1491
> SRowX: -0.9195 0 -0 102.536
> SRowY: 0 -1.40018 -0 106.413
> SRowZ: 0 0 -2.89048 30.1491
> IntentName: ""
> Magic: "n+1"
>
> The direction in ITK is
>
>
> 1 0 0
> 0 1 0
> 0 0 -1
>
> I don't know how to see the direction in nibabel
>
>
> On 12/11/16 14:10, David Gobbi wrote:
>> Hi Padraig,
>>
>> Can you show us the raw qform and sform fields from the NIFTI
>> header itself? In VTK, you can do this as follows:
>>
>> >>> print(reader.GetNIFTIHeader())
>>
>> The difference you see between nibabel, ITK, and VTK has to do
>> with differences in the way these packages deal with the pixdim
>> and the qfac of the nifti file. If you print the Direction from
>> the ITK image you might find that it differs from nibabel, too.
>>
>> For VTK, you can read all the gory details here:
>>
>> http://gitlab.kitware.com/vtk/vtk/blob/v7.0.0/IO/Image/vtkNIFTIImageReader.cxx#L738
>> <http://gitlab.kitware.com/vtk/vtk/blob/v7.0.0/IO/Image/vtkNIFTIImageReader.cxx#L738>
>>
>> - David
>>
>>
>> On Sat, Nov 12, 2016 at 6:10 AM, padraig
>> <padraig.looney at gmail.com <mailto:padraig.looney at gmail.com>> wrote:
>>
>> I have noticed some inconsistencies in how NIFTI images are
>> handled in VTK, ITK, and NiBabel. ITK and NiBabel are in
>> agreement with each other and differ with VTK on the position
>> of the volume. The VTK output for a file is below.
>>
>> vtkNIFTIImageReader (0x1de67d0)
>> Debug: Off
>> Modified Time: 91
>> Reference Count: 2
>> Registered Events: (none)
>> Executive: 0x1de7720
>> ErrorCode: Success
>> Information: 0x1de6ad0
>> AbortExecute: Off
>> Progress: 1
>> Progress Text: (None)
>> FileName:
>> /home/padraig/Desktop/59674/Seeding/I0000003_59674_sn.nii
>> FileNames: 0
>> FilePrefix: (none)
>> FilePattern: %s.%d
>> FileNameSliceOffset: 0
>> FileNameSliceSpacing: 1
>> DataScalarType: unsigned char
>> NumberOfScalarComponents: 1
>> File Dimensionality: 3
>> File Lower Left: On
>> Swap Bytes: Off
>> DataIncrements: (1, 1)
>> DataExtent: (0, 223, 0, 152, 0, 51)
>> DataSpacing: (0.9195, 1.40018, 2.89048)
>> DataOrigin: (0, 0, 0)
>> HeaderSize: 352
>> Internal File Name: (none)
>> TimeAsVector: Off
>> TimeDimension: 1
>> TimeSpacing: 1
>> RescaleSlope: 1
>> RescaleIntercept: 0
>> QFac: -1
>> QFormMatrix: -1 0 0 102.536 0 -1 0 106.413 0 0 1 -117.265 0
>> 0 0 1
>> SFormMatrix: -1 0 -0 102.536 0 -1 -0 106.413 0 0 1 -117.265
>> 0 0 0 1
>> NIFTIHeader:
>> PlanarRGB: Off
>>
>> the qform given by nibabel is
>>
>> >>> ni_ob.get_qform()
>> array([[ -0.91949999, 0. , 0. , 102.53600311],
>> [ 0. , -1.40017998, 0. ,
>> 106.41300201],
>> [ 0. , 0. , 2.89048004, 30.14909935],
>> [ 0. , 0. , 0. , 1. ]])
>>
>>
>> ITK has the origin at
>>
>> [-102.536, -106.413, 30.1491]
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtk-developers/attachments/20161113/69b55a56/attachment.html>
More information about the vtk-developers
mailing list