GetDirection and GetOrigin for SimpleITK C# implementation

Hi,

I am using the C# implementation for SimpleITK to display MRI data in the Unity game engine and I am running into issues with orientations and IJK to world transform matrices.

My data is a nifti file in RAS coordinates with 1mm isotropic voxels and :
origin = (-127, -96, -110)
direction = identity matrix
dimensions = (256, 256, 208)

From my understanding, when loading an image file in SimpleITK, it converts it to LPS format, meaning that subsequent calls to the GetOrigin and GetDirection functions should be returning these values:
origin = (127, 158, -110)
direction = (-1, 0, 0; 0, -1, 0; 0, 0, 1)

However I am getting a different origin value of (127, 96, 110).

I confirmed the LPS orientation values by converting the original RAS scan into LPS and I am getting the proper numbers in 3DSlicer. But when I load the corrected LPS scan into SimpleITK I get yet again different values :
origin = (-127, -158, -110)
direction = (1, 0, 0; 0, 1, 0; 0, 0, 1)

I get the feeling that SimpleITK is just inverting the x and y origin/direction values regardless of the initial orientation. Am I missing something? I don’t know if this is expected behavior and how I should correct for it.

Thank you for your help!
Guillaume D.

Hello @Guilmer,

I’m a bit confused. What you specify as the origin in RAS is (-127, -96, -110) but you expect it to be (127, 158, -110) in LPS? Is the -96 to 158 a typo?

I would expect a negation of the x, and y coordinates and z is unchanged. As SimpleITK is using the ITK reader the conversion from RAS to LPS should be valid (Slicer uses RAS). Possibly visualize and look at the image information using ITK-SNAP (under the Tools->Image Information, Info tab) you can compare the voxel, world (ITK/SimpleITK) and world (nifti) coordinates.

I was unable to replicate the issue with the nifti files I have. If the issue isn’t clarified after you look at the image via ITK-SNAP, possibly share the image?

Hi!

Sorry if my initial message is a bit confusing, I’m really new to ITK. I’ll try to explain better here.

In our processing pipeline, the conversion from DICOM to NIfTI also handles the transformation from the LPS (DICOM) to the RAS (NIfTI) coordinates. I therefore have a T1 scan in RAS coordinates with the aforementioned details (1mm isotropic, 256x256x208 voxels). The entire scan occupies world space from the origin (-127, -96, -110), to the end point (-127, -96, -110) + (256, 256, 208) * 1mm = (127, 158, 144) mm.

Now assuming that I want to revert the transformation matrix back to LPS, I would begin at the end points for the x and y coordinates (i.e. 127 and 158 mm) and count 255 steps downward to -127 and -96. This implies that the volume occupies the same space regardless of coordinate system and that the volume’s central voxel is not centered on (0,0,0). In that case, a simple inversion of the x and y coordinates does not work.

Looking into the file meta data as returned by ITK, I have qform_code=NIFTI_XFORM_SCANNER_ANAT and qoffsets and quaternion values. If I compute the IJK to world transformation matrix from these values I get the proper values (R = identity matrix with -127, -96, -110 origin). But if I use the Image.GetDirection or Image.GetOrigin functions, the x and y axes are inverted (e.g. origin = 127, 96, -110). Which is wrong.

Considering that the NifTI headers contain information about the qform_[x,y,z]orient, my question is simply: Is ITK always assuming a LPS coordinate system for a volume centered at 0, regardless of the NIfTI headers? Looking at the code here: https://github.com/InsightSoftwareConsortium/ITK/blob/631aeaebf82d2ce8a7d7e3b0165940c5c2f1a586/Modules/IO/NIFTI/src/itkNiftiImageIO.cxx#L1975-L2029 it seems like it, but I am not familiar enough with the code to be certain about it.

It is not a big issue for a single file since I can always manually parse the qform data, but I get an error (volumes not occupying the same space) when I try to combine two NIfTI files of the same scan, one in RAS and one converted to LPS.

I hope that this is clearer. Thanks again for the help!
Guillaume D.

Just as a follow up, I have installed ITK-SNAP and opened the T1 scan in it. I have attached 4 files:

  • The result from calling fslhd on the file, specifying the axes orientation, origin, qform and sform matrices with the correct values.
  • Screenshots from the metadata read when importing a file, again with the proper values.
  • Screenshot from the Tools / Image information / info tab showing improper orientation (LPI) and origin.

fslhd_result.txt (1.8 KB)


ITK_Snap_ImageInfo

info tab showing improper orientation (LPI)

I don’t know internals of Nifti and can not comment the issue, specially, are negative x, y values or origin correct or not, but itksnap uses so called RAI-codes for orientation, where identity is RAI, the same as DICOM LPS, there is a difference in terminology (from direction vs to direction).
unnamed

So I understand now that ITK uses the FROM direction terminology and the the TO that I am using. This clarifies a lot of things. I just have a single issue.

To explain it I will use the FROM terminology that ITK uses. I have the exact same scan it four coordinate systems: LPI, LPS, RAI and RAS. However, if I load the data and call the GetOrigin, GetDirection or TransformIndexToPhysicalPoint functions, the X and Y axes are inverted (i.e. -1) but the Z axis is left unchanged, compared to the NIfTI header, regardless of the coordinate system used.

Is the ITK world space not the same as the NIfTI world space?

Because a scan already in the FROM RAI (DICOM LPS in your above example) direction should not have any axes changed when querying the Origin and Direction.

Also, our scans are not symmetrical in world space (e.g. -96 to + 158 mm in the Y axis) so inverting the axes shifts the data in space. This is just terribly confusing.

@hjmjohnson has dabbled in NIFTI library, he might have further insight.

I do not have time to give an in-depth response, so please excuse the shortness of this response that does not precisely review the above situation.

What I can say is the following (which I hope is helpful):

  1. ITK follows the DICOM standard as the primary representation of mapping the voxel lattice computer memory layout to physical space (using origin, spacing, and direction).

  2. DICOM is defined using LPS conventions, so therefore ITK also uses LPS conventions.

  3. DICOM dictates that the the origin is physical location the CENTER of the first voxel stored in memory.

  4. Any file loaded from disk (irregardless of the on disk format or on disk conventions), is converted with best effort into a DICOM compatible physical space in memory representation.

  5. Any in memory ITK representation of an image is converted (again best effort) to the conventions of the particular file format on disk.

  6. NIFTI has a different internal representation than ITK. You may want to read the nifti header https://nifti.nimh.nih.gov/nifti-1/documentation/faq. and “3D IMAGE (VOLUME) ORIENTATION AND LOCATION IN SPACE:” from https://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h

I hope this helps you understand the process a bit further. I don’t think your question is a nifti-specific, but your example is given in nifti so I have provided nifti references.

Best,
Hans

3 Likes

This is just terribly confusing.

I have to admit i also sometimes don’t understand what happens with origin during interchange with apps using different reference coordinate systems. Anyway, once imported in ITK, if you apply ‘change orientation filter’ (identity/reference is always DICOM LPS in ITK, of course), e.g. (in RAI-codes) RAI -> LPI, the origin will be updated exactly as you imagine.