ITK: Anatomical orientation in MetaImages ignored in ITK

Description

AnatomicalOrientation tag in MetaImages is ignored. LPS is always assumed.

Steps to Reproduce

Have a .mha image with AnatomicalOrientation tag. Change the orientation e.g. from RAS to RAI. The image should be flipped after this change, but it isn’t.

Additional Information

Direction cosines are read, but AnatomicalOrientation is not read, it is always assumed to be LPS.

What should be done: read AnatomicalOrientation, and if it is different from LPS apply an appropriate correction matrix to direction cosines.

Submitted by: @agirault.

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Comments: 31 (25 by maintainers)

Most upvoted comments

I think an important message from @issakomi is to not break backward compatibility. I think that we should be able to maintain backward compatibility in this case (functionality and API), and it is something we should test heavily.

@issakomi - if I misunderstood your message, please let me know. I greatly appreciate the help that you have already given. Hopefully the end result will be to your liking (e.g., not require changes to your code) and perhaps make moving data between ITK and other applications (e.g., Slicer) more clear/defined/easy.

Thanks!

On Mon, Jun 17, 2019 at 11:54 AM issakomi notifications@github.com wrote:

i my apps i heavily use itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_… enum and full compatibility of ITK and DICOM space, it is great advantage. I don’t understand what is your goal? Rename RAI to LSP? There is no standard for that and i’ve never seen 48 orientation codes like in ITK, here and where is wording “DICOM LPS” (not defined in DICOM) and “Slicer RAS”, nothing else. I also don’t understand what is wrong with direction cosines in MetaImage and why should any additional transforms be applied? I will be not able to updated to newer version of ITK, sorry, i have no time to re-write application, i better stay with old version of ITK and will backport critical bugs… Also i have no time to participate in discussions, for me it is too clear. You are from Kitware, it is you playground, but i leave the discussion. Good luck.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/InsightSoftwareConsortium/ITK/issues/1017?email_source=notifications&email_token=AACEJLY5RHWNF5J43BFSWQTP26XTPA5CNFSM4HX5GQMKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODX3T67I#issuecomment-502742909, or mute the thread https://github.com/notifications/unsubscribe-auth/AACEJL24GQ3G7KMLA6KZEADP26XTPANCNFSM4HX5GQMA .

Stephen R. Aylward, Ph.D. Senior Director of Strategic Initiatives, Kitware, Inc., North Carolina

Kitware: Advancing the frontiers of understanding by developing innovative open-source software platforms and integrating them into research, processes, and products.

Please don’t do this. I don’t want to fight with robots.

Adding a “stale” label is fine. It is also OK to assign it to a “backlog”. However, closing an issue would make it seem that the issue has been fixed or it was not valid in the first place, which is often not true.

I understand the desire to have less open issues, but automatically sweeping them under the rug will not improve quality and discourage community members to spend time with reporting issues.

The only valid use case I see for a stale-bot is to automatically close issues that are labelled as “more-information-needed”. If more information is needed from the reporter but response does not arrive within reasonable time then it makes sense to close the issue (and doing it automatically saves some time for the maintainers).

Agreed. If you need to handle the corner cases, NRRD is the way to go. I like keeping MetaIO simpler and more straightforward.

Thanks for the help with it. If you have ideas for clarifying the descriptions, please post them. Otherwise, I will close this issue in a few days.

Thanks, Stephen

On Mon, Dec 23, 2019 at 1:35 PM Andras Lasso notifications@github.com wrote:

This description is great. It gives a good explanation for all the issues related to this field.

I just brought up the other fields because if you want to invest time into this file format then it is important to add a few basic features. But it is perfectly fine to leave this file format as is, because nrrd can be used instead (similarly simple but defines data axes more clearly).

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/InsightSoftwareConsortium/ITK/issues/1017?email_source=notifications&email_token=AACEJLZU43TIFX5HTRYSZNDQ2EAFHA5CNFSM4HX5GQMKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHRV2BY#issuecomment-568548615, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACEJL7QT57K5UAPGWIS4PDQ2EAFHANCNFSM4HX5GQMA .

– Stephen R. Aylward, Ph.D. Senior Director of Strategic Initiatives

Back on topic…I’ve updated the MetaIO documentation, and hopefully it captures this discussion and provides a path forward…

See https://itk.org/Wiki/ITK/MetaIO/Documentation#Tags_Added_by_MetaImage

Also copied below…

AnatomicalOrientation

  • MET_STRING
  • This is a convenience tag, to be used and maintained by applications. Changing this tag in a MetaIO file or via the MetaIO API will not cause the MetaIO library to resample or change the direction matrix of an image. It is up to an application to correctly read, write, and maintain this tag.
  • The history of the interpretation of this tag is as follows:
    • Labels: The labels used to define a space can be “from” labels or “to” labels, where “from” labels define the relative physical location of the origin of a space and “to” labels define the physical direction of movement of a space - thereby RAI “from” space is the same as LPS “to” space. DICOM, ITK, and nearly every application consider label space to be “to” labels.
    • In an LPS “to” space (“to” space will be assumed in the remainder of this discussion), when moving in the x,y,z-directions of “space”, then you are physically moving to the left.
    • The direction matrix specifies how “index” i,j,k-directions (sometimes referred to as the in-memory directions of an image) map into x,y,z-directions. Changing the direction matrix will never change the fact that you’re in an LPS space, but changing a direction matrix will change how moving along the i-index direction maps to a movement in the LPS space.
    • Originally, AnatomicalOrientation was intended to define the space (LPS, RAS, etc) of an image; however, in early 2000s, its implementation was changed (and its documentation became unclear) to define how a patient was oriented in index space (it assumed an LPS space, and thus it became redundant with the direction matrix). These changes seem to have coincided with ITK’s introduction of a direction matrix (thanks goes to Alexis Girault for hunting down this history!). For the past fifteen years++, ITK writes AnatomicOrientation based on the direction matrix and assumes an LPS space. See the code in itkSpatialOrientation.h that specifies a 3-letter code derived from an image’s direction matrix and that 3-letter code is then used to specify the AnatomicalOrientation tag in MetaIO.
    • Moving forward, when implementing new applications, it is recommended that developers use the definition currently implemented by ITK. It represents the most common use of MetaIO.

Hi,

This is perhaps clearer regarding how things are defined now…

AnatomicalOrientation

  • MET_STRING
  • This is a convenience tag, to be used and maintained by applications. Changing this tag in a MetaIO file or via the MetaIO API will not cause the MetaIO library to resample or change the direction matrix of an image. It is up to an application to correctly read, write, and maintain this tag.
  • The history of the interpretation of this tag is as follows:
    • Labels: The labels used to define a space can be “from” labels or “to” labels, where “from” labels define the relative physical location of the origin of a space and “to” labels define the physical direction of movement of a space - thereby RAI “from” space is the same as LPS “to” space. DICOM, ITK, and nearly every application consider label space to be “to” labels.
    • In an LPS “to” space, when moving in the x,y,z-directions of “space”, then you are physically moving to the left.
    • The direction (cosines) matrix specifies how “index” i,j,k-directions (sometimes referred to as the in-memory directions of an image) map into x,y,z-directions. Changing the direction matrix will never change the fact that you’re in an LPS space, but changing a direction matrix will change how moving along the i-index direction maps to a movement in that LPS space.
    • Originally, AnatomicalOrientation was intended to define the space (LPS, RAS, etc) of an image; however, in early 2000s, its implementation was changed (and its documentation became unclear) to define how a patient was oriented in index space (it assumed an LPS space, and thus it became redundant with the direction matrix). These changes seem to have coincided with ITK’s introduction of a direction matrix (thanks goes to Alexis Girault for hunting down this history!). For the past fifteen years++, ITK writes AnatomicOrientation based on the direction matrix and assumes an LPS “to” space. See the code in itkSpatialOrientation.h that specifies a 3-letter “from” label derived from an image’s direction matrix and that 3-letter code is then used to specify the AnatomicalOrientation tag in MetaIO. Therefore, for example, in a CT scan the AnatomicOrientation is typically RAS or RAI (depending on the direction of the sequential slices).
  • Proper Usage
    • When implementing new applications, developers must follow the convention maintained by ITK for the past 15+ years.
    • MetaIO and ITK are defined in LPS “to” space - the same space used by DICOM images.
    • AnatomicOrientation defines the “from” orientation of an image’s index space, as computed in itkSpatialOrientationAdapter.h. That is, it is derived from the direction (cosines) matrix, under the assumption of an LPS “to” space. Since an axis might not be exactly R/L, A/P, I/S aligned, the labels provides by AnatomicOrientation are approximate, using the algorithm in itkSpatialOrientationAdapter.h::FromDirectionCosines().

Andras makes a valid point. Maybe we could change the bot’s settings? @hjmjohnson @thewtex @blowekamp

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Very interesting to see this issue coming up again. I’ve raised this question 7 years ago and the conclusion at that time was that ITK’s implementation was correct and if the documentation was not consistent then it was because it was not interpreted correctly (see details here).

Current AnatomicalOrientation tag is messed up because axis names are inverted (compared to DICOM, nrrd, … and pretty much everything else) and the tag was present but has been ignored for really long time.

One safe option would be to adopt “space” tag from nrrd.

Another safe (and long-term time-saving) option would be to deprecate metaimage format. Nrrd file format was developed for exactly the same purpose as metaimage, but nrrd has advantages, such as having a clear definition of anatomical orientation/space tag (consistent with documentation), it has standard fields for describing axis kinds (very important for higher-dimensional images), and does not contain complicated and rarely-used features (such as multiple data files for a single header). If the decision is made to keep maintaining/improving metaimage format then it would be important to clean up and improve the specification (to be essentially even more similar to nrrd).

in my apps i heavily use itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_… enum and compatibility of ITK and DICOM space, it is great advantage. I don’t understand what is your goal? Rename RAI to LPS? There is no standard for that and i’ve never seen 48 orientation codes like in ITK, here and there is wording “DICOM LPS” (not defined in DICOM) and “Slicer RAS”, nothing else. I also don’t understand what is wrong with direction cosines in MetaImage and why should any additional transforms be applied? I will be not able to update to newer version of ITK, sorry, i have no time to re-write applications, i better stay with the old version of ITK and will back-port critical bugs… Also i have no time to participate in discussions, for me it is too clear. You are from Kitware, it is your playground, but i leave the discussion. Good luck.

There are two issues being discussed here:

  1. lately, the difference between definitions of 3D basis. We seem to all agree that we need to account for:
  • where to look at on the axis to describe it (“from RAI” = “to LPS”, like for ITK)
  • different coordinate systems (if we go with the “to” definition, Slicer is RAS, ITK is LPS)

For this issue, further discussions can be made to better describe this, as ITK/MetaIO is the only one using the “from” definition, and is prone to a lot of confusion as the last couple comments can confirm. And that’s not new.

  1. originally, the issue of the anatomical orientation tag being redundant with the transform matrix, which doesn’t fit with the initial design. This was already described in comments above, summarized again by @aylward :

The direction cosine matrix exists in a space. That space is defined by the AnatomicalOrientation. That is, when moving in the physical x-direction (or in i-index direction with an identity direction matrix), then you are going toward L when in an LPS anatomic space. Changing the direction matrix will never change the fact that you’re in an LPS space, but it will change how moving along the i-index direction maps to a movement in that space. It tells you that the first i-index pixel you access in memory is to the right of the second pixel.

We’ll draft a well-documented post explaining the ins-and-outs of the issue, suggest a versioning update of the MetaIO format to restore this initial feature while maintaining backward-compatibility with how MetaIO has been used for the last 14 years, then share it in the ITK discourse forum to get feedback from the community.

I agree that the definition is poorly worded.

The direction cosine matrix exists in a space. That space is defined by the AnatomicOrientation. That is, when moving in the physical x-direction (or in i-index direction with an identity direction matrix), then you are going toward L when in an LPS anatomic space. Changing the direction matrix will never change the fact that you’re in an LPS space, but it will change how moving along the i-index direction maps to a movement in that space. It tells you that the first i-index pixel you access in memory is to the right of the second pixel.

The code cited by @issakomi seems to only consider direction cosines, then it is perhaps describing how the ijk-index spans (i.e., is oriented within) a specific (e.g., ILS) space. This is different than telling us how that larger space is oriented (e.g., if it is ILS).

On Fri, Jun 14, 2019 at 3:18 PM issakomi notifications@github.com wrote:

@agirault https://github.com/agirault Thank you for responce. But this issue is marked as “bug”, there is no bug. You interpret the AnatomicalOrientation tag as something related to reference coordinate system, but it is not, this 3 letters code is orientation of matrix according to above definition.

#include <itkSpatialOrientation.h>

ImageType::Pointer image = reader->GetOutput(); itk::SpatialOrientationAdapter adapter; const unsigned int orientation = static_cast<unsigned int>( adapter.FromDirectionCosines(image->GetDirection())); switch (orientation) { case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIL: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ALS: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ARI: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ASR: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IAR: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ILA: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IPL: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IRP: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LAI: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LIP: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPS: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LSA: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PIR: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PLI: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PRS: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PSL: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAS: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIA: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPI: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RSP: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SAL: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SLP: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SPR: break; case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SRA: break; default: break; }

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/InsightSoftwareConsortium/ITK/issues/1017?email_source=notifications&email_token=AACEJL7WT36QCPHNSJ54QETP2PVH3A5CNFSM4HX5GQMKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXXXGUI#issuecomment-502231889, or mute the thread https://github.com/notifications/unsubscribe-auth/AACEJLYSKE2DQIFX2GNK2HLP2PVH3ANCNFSM4HX5GQMA .

Stephen R. Aylward, Ph.D. Senior Director of Strategic Initiatives, Kitware, Inc., North Carolina

Kitware: Advancing the frontiers of understanding by developing innovative open-source software platforms and integrating them into research, processes, and products.

But does this refer to ijk or XYZ origin and vectors? If it refers to ijk (index space), then direction matrix is redundant. If it refers to XYZ (physical space), then another (possible) flip is required to reconcile this with ITK convention that identity matrix corresponds to LPS.

Also:

  • ensure to handle the case where the acronym is invalid in the reader
  • update the Writer which currently infers the anatomical orientation from the direction cosines, to instead always write LPS, since that is the coordinate system associated with the direction matrix