Repository: InsightSoftwareConsortium/ITK (language: python)

Issue:
ITK's SpatialOrientation and OrientImageFilter have opposite definitions of the DICOM standard
The definitions of the coordinate terms in SpatialOrientationEnums is as follows:
```
Coordinate orientation codes have a place-value organization such that an ImageDimension-al sequence of subcodes says both which varies fastest through which varies slowest, but also which end of the frame of reference is considered zero for each of the coordinates. For example, 'RIP' means Right to Left varies fastest, then Inferior to Superior, and Posterior to Anterior varies the slowest.
```

This is the opposite of the definitions for the DICOM standard:
https://www.slicer.org/wiki/Coordinate_systems

It is interpreted that the preferred way to describe coordinates is in the "TO" direction or the direction of an axes is increasing. See the following DICOM section: C.7.6.2.1.1

ITK is defined as having a LPS coordinate system. However the SpatialOrientation enums and the OrientImageFilters call the RAI coordinates. This is confusing.

UPDATED:

I propose moving `itk::OrientImageFilter` to the deprecated module. Users can using this filter by simply enabling this module as it will be available until least ITK 7.0 ( unplanned ).

The itk::SpatialOrientationEnums and itk::SpatialOrientationAdapters usage should be discouraged. Usage where appropriate will be marked with "ITK_FUTURE_LEGACY_REMOVE", which provides no clear time frame for removal.

The core improvement is the introduction of the "DICOMOrientation" class which contains enum classes to describe spatial orientation as interpreted from DICOM with ITK having "LPS" coordinate. The DICOMOrientation class include the functionality of the legacy SpatialOrientationAdaptor, but with the addition of interpreting string representations. Additionally, this new class provides compatibly with conversion from the legacy SpatialOrientationEnums.

 The [DICOMOrientImageFilter](https://github.com/InsightSoftwareConsortium/ITKSimpleITKFilters/blob/master/include/) from the SimpleITKFilters remote module is introduced to the "filter user" front end api, to clarify the change to the new DICOM based coordinate descriptions.


Discussion / hints:
@dzenanz @lassoan @thewtex Care to chime in on this proposal?
I like it, but there is a lot work there. We should strive to keep the functionality on the same level, including Python accessibility. Also, there are a few examples which should be updated to demonstrate the new recommended syntax and filter names. If you are willing to do this, I am all for it!
The DICOMOrientImageFilter is in the SimpleITKFilters remote module and is available to pip install with "itk_simpleitkfilters".  So please check it out and see if it is already on the same level of accessibility. I am not sure there is much work to do with updating the filter.

Additionally, I don't see examples using the filter. Perhaps because of this discrepancy in the orientation terms.
How is it expected to interact with [SpatialOrientationAdapter](https://github.com/InsightSoftwareConsortium/ITK/blob/master/Modules/Core/Common/include/itkSpatialOrientationAdapter.h)? What about [this test](https://github.com/InsightSoftwareConsortium/ITK/blob/master/Modules/Core/Common/wrapping/test/itkSpatialOrientationAdapterTest.py)? I assume that [DICOMOrientation](https://github.com/InsightSoftwareConsortium/ITKSimpleITKFilters/blob/master/include/itkDICOMOrientation.h) would replace [SpatialOrientation](https://github.com/InsightSoftwareConsortium/ITK/blob/a3d3e53d685b43cf9d07602a8ce4651f2bfc4680/Modules/Core/Common/include/itkSpatialOrientation.h#L46)? Namely, as long as we can accomplish things like [these](https://github.com/InsightSoftwareConsortium/GetYourBrainTogether/blob/main/HCK01_2022_Virtual/Tutorials/MetadataPreservation/Orient_filter.ipynb) using the new filters, we are fine.
@blowekamp sounds good to me :+1: 
I've found the old names very confusing, so this change is very welcome.

To reduce the scope of the change, we could keep the current filters and just add new enum values and method names. For example, ...ITK_COORDINATE_ORIENTATION_RAI=ITK_COORDINATE_ORIENTATION_DICOM_LPS=1...
> I've found the old names very confusing, so this change is very welcome.
> 
> To reduce the scope of the change, we could keep the current filters and just add new enum values and method names. For example, ...ITK_COORDINATE_ORIENTATION_RAI=ITK_COORDINATE_ORIENTATION_DICOM_LPS=1...

I think having classes with both will be rather confusing, and error prone, not to mention more work than the replacement with new classes. Additionally, what is the behavior of the string codes e.g. "RAI"? Runtime legacy options?
@dzenanz Good points. It has been a while since I looked a these details.

> How is it expected to interact with [SpatialOrientationAdapter](https://github.com/InsightSoftwareConsortium/ITK/blob/master/Modules/Core/Common/include/itkSpatialOrientationAdapter.h)? 

So it looks like there are some changes with how the enums are handled, and deserves a review. The new [`DICOMOrientation`](https://github.com/InsightSoftwareConsortium/ITKSimpleITKFilters/blob/cc4f5efcbc603166800bd5d1819702220408016c/include/itkDICOMOrientation.h#L39C31-L39C47) class hold the enums declarations. And instance of DICOMOrientation has a OrientationEnum,  and interfaces to translate between the enum, String, and Direction matrix via constructors and accessors.

Like this:
```

In [10]: lps = itk.DICOMOrientation("LPS")

In [11]: lps.GetAsDirection()
Out[11]: itkMatrixD33 ([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])

In [12]: lps.GetAsOrientation()
Out[12]: 591107

In [13]: lps.GetAsString()
Out[13]: 'LPS'

In [14]: rai = itk.DICOMOrientation(itk.DICOMOrientation.OrientationEnum_RAI)

In [15]: rai.GetAsDirection()
Out[15]: itkMatrixD33 ([[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, -1.0]])
```

> What about [this test](https://github.com/InsightSoftwareConsortium/ITK/blob/master/Modules/Core/Common/wrapping/test/itkSpatialOrientationAdapterTest.py)? 

That can be updated with the new interface above. I have honestly lost track of how Enums should be access and created in C++ ITK much less how SWIG is wrapping the current a legacy enums. This is a good opportunity to review and ensure they are optimized and correct. 

I assume that [DICOMOrientation](https://github.com/InsightSoftwareConsortium/ITKSimpleITKFilters/blob/master/include/itkDICOMOrientation.h) would replace [SpatialOrientation](https://github.com/InsightSoftwareConsortium/ITK/blob/a3d3e53d685b43cf9d07602a8ce4651f2bfc4680/Modules/Core/Common/include/itkSpatialOrientation.h#L46)? Namely, as long as we can accomplish things like [these](https://github.com/InsightSoftwareConsortium/GetYourBrainTogether/blob/main/HCK01_2022_Virtual/Tutorials/MetadataPreservation/Orient_filter.ipynb) using the new filters, we are fine.

As demo'd above I the new "DICOMOrentation" class should provide a consistent interface for switching between the tree orientation representation.


When string code is get/set with the new methods like `Get/SetDICOMOrientation(string code)` then the DICOM definition is used.

Having the old deprecated methods and enum values is less clean now. However, it is a very small and simple development task for ITK developers and very smooth transition for everyone. The deprecated methods and enums can be removed in a couple of years.

Introducing new classes is acceptable, too, it would be immediately more clear solution, it is just signifcantly more work.
> When string code is get/set with the new methods like `Get/SetDICOMOrientation(string code)` then the DICOM definition is used.
> 
> Having the old deprecated methods and enum values is less clean now. However, it is a very small and simple development task for ITK developers and very smooth transition for everyone. The deprecated methods and enums can be removed in a couple of years.
> 
> Introducing new classes is acceptable, too, it would be immediately more clear solution, it is just signifcantly more work.

Let me clarify my proposal and how it will work with compatibility of current usage of the backwards OrientImageFilter's direction labels.

My proposal is to move the current classes and enums to the ITK's Compatibility/Deprecated module as is. This means that for ITK 6.x they can continued to be used without change (maybe a flag will be needed to suppress a warning). At your convince over the next 5 years or so you can migrate to the new DICOMOrientation and DICOMOrientImageFilter, and fix the backwards labels being used with the deprecated class. When ITK 7.0 is released these deprecated classes likely will be removed or place in an unmaintained remote module or some such. I believe this is a smooth, clean and reasonable transition process.

The new classes already exist and are wrapped for ITK Python an are in pypi for ITK 5.4 as show above it further evaluation of the new interface or usage is needed.

https://github.com/InsightSoftwareConsortium/ITKSimpleITKFilters/blob/master/include/itkDICOMOrientation.h
https://github.com/InsightSoftwareConsortium/ITKSimpleITKFilters/blob/master/include/itkDICOMOrientImageFilter.h


> Having the old deprecated methods and enum values is less clean now. However, it is a very small and simple development task for ITK developers and very smooth transition for everyone. The deprecated methods and enums can be removed in a couple of years.

@lassoan I added a constructor to the new DICOMOrientation which takes the legacy SpatialOrientation enums blocked off with "ITK_FUTURE_LEGACY_REMOVE". The proposed DICOMOrientation class/enum has the methods to convert between representation instead of a separate adaptor class. See #4791 for details. Hopefully this will help with a smooth transition.
The new classes proposed in #4791 provide the following unambiguous way to describe a coordinate system:
```
-       itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+         hdr->coordinateOrientation = DICOMOrientation( DICOMOrientation::CoordinateEnum::RightToLeft,
                                                       DICOMOrientation::CoordinateEnum::SuperiorToInferior,
                                                       DICOMOrientation::CoordinateEnum::PosteriorToAnterior);
```


The proposed implementation looks good to me. It is clean and transition should not be difficult.

Maybe `DICOMOrientImageFilter` name could a bit more generic, to allow it to be used for other kinds of coordinate systems. For example, it could be `AntomicalOrientImageFilter` or something even more generic.
@lassoan @seanm @issakomi The propose DICOMOrientationImageFilter and DICOMOrientations appear to have been a straw man and a catalyst to come up with some unambiguous annotations and terminology to describe orientations.

There are two important ITK components being addressed here:
 -  the "enum" or class for representing orientations [itk::SpacialOrientationEnums](https://itk.org/Doxygen/html/classitk_1_1SpatialOrientationEnums.html)
 - the filter used to help convert images between them [itk::OrientImageFilter](https://itk.org/Doxygen/html/classitk_1_1OrientImageFilter.html)

> Maybe `DICOMOrientImageFilter` name could a bit more generic, to allow it to be used for other kinds of coordinate systems. For example, it could be `AntomicalOrientImageFilter` or something even more generic.

Yes, "AnatomicalOrientation" is much clearer, the DICOM notation appears to be in accurate and only lossy inferred from the DICOM specification. Let us apply that to the enum/class first and rename "DICOMOrientation" to "AnotomicalOrientation". 

It is also clear to me the most unambiguous way to describe these anatomical orientations is something like the following:
```
coordinateOrientation = AnatomicalOrientation( AnatomicalOrientation::CoordinateEnum::RightToLeft,
                                                       AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
                                                       AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
```
Which may benefit from some type aliases.

Also these 3 characters enums like "LPS" likely should have a type/space to describe them as "ToCoordinates" and a separate enums with "FromCoordinates".


The propose DICOMOrentation->AnatomicalOrientation class has conversions between type and representations so this might be a smoother transition than initially proposed requiring the disruptive replaced of OrientImageFilter with DICOMOrientImageFilter.

I plan to work on a PR with addition of AnatomicalOrientation and the usage of through ITK as done with the current PR and the DICOMOrientation class. This will not include the introduction of DICOMOrientationImageFilter etc..
Going forward, I should have more time to devote to code reviews, and I should be able to provide early feedback on this effort - should you want it, of course.
It is rather easy to improve the ambiguity  with "from" and "to" notations without deprecation of itkSpatial classes and OrientImageFilter, s. this [post](https://github.com/InsightSoftwareConsortium/ITK/pull/4791#issuecomment-2273695442)

Again, there are no such 3-letter enums and left-handed orientations in DICOM. The name is very misleading. A user may think it is applicable only to DICOM. Yes, "to" notations are more common and there are another orientation codes in DICOM e.g. "L\F": x to left, y to feet, specially for IODs without IPP/IOP, but unrelated to ITK logic.

![dd](https://github.com/user-attachments/assets/57f8a8cf-4b4f-4769-8b01-d16517cf9f61)

**Please don't remove itkSpatial classes and OrientImageFilter, just add new enums with clear names, both "from" and "to", it is easy.**
xref the OME-Zarr anatomical orientation proposal: https://github.com/ome/ngff/pull/253 , which is would be nice to use with this.

Something worth noting that @lassoan pointed out in the discussion is that DICOM uses Head / Foot, H/F instead of Superior / Inferior, S/I:

https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.html#sect_C.7.6.1.1.1
It is really worrying that ITK seems to break this stuff. From practical point of view. There is nothing wrong with it, it is IMO the best implementation. Just clear the ambiguity with enums, please.
> xref the OME-Zarr anatomical orientation proposal: [ome/ngff#253](https://github.com/ome/ngff/pull/253) , which is would be nice to use with this.
> 

> https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.html#sect_C.7.6.1.1.1

What would compatibility or support for that proposal look like for an orientation representation?
> What would compatibility or support for that proposal look like for an orientation representation?

There is one-to-one mapping. Even better, there is direct mapping.

```
coordinateOrientation = AnatomicalOrientation( AnatomicalOrientation::CoordinateEnum::RightToLeft,
                                                       AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
                                                       AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
```

This sounds perfect.
> Please don't remove itkSpatial classes and OrientImageFilter, just add new enums with clear names, both "from" and "to", it is easy.

I agree - when nothing is broken, no new features are added, then changes (even if small ones) are generally not welcome by ITK users. That said, the described deprecation plan (5 years available for application developers to switch to the new classes, detailed documentation will be provided, helpful deprecation messages will tell users they need to update their code and how) should minimize user frustration.

The only thing that bothers me a very little about the current rather heavyweight solution is that this effort could have been spent on more useful, more impactful ITK-related work. For example, reducing the issue and pull requests backlogs, improving OME NGFF file format support, ITK transforms (automatic on-the-fly inversion, extrapolation to entire 3D domain), harmonizing ITK and VTK build systems (keep best parts of both), etc. might have been more useful for the community.
BTW, individual enums can be deprecated like this:

```cpp
enum class MyEnums
{
	X = 1,
	Y [[deprecated]] = X
};

int main()
{
	int x = static_cast<int>(MyEnums::Y);
	return 0;
}
```


pseudo-code
```
{
  ITK_ORIENTATION_NOTATION_FROM_RAI = ... // old def for ITK_ORIENTATION_RAI
  ITK_ORIENTATION_NOTATION_TO_LPS = ITK_ORIENTATION_NOTATION_FROM_RAI,
...
#ifndef LEGACY_REMOVE
  ITK_ORIENTATION_RAI [[deprecated]] = ITK_ORIENTATION_NOTATION_FROM_RAI,
...
#endif
}
```

Fix patch:
diff --git a/Modules/Core/Common/include/itkAnatomicalOrientation.h b/Modules/Core/Common/include/itkAnatomicalOrientation.h
new file mode 100644
index 00000000000..b3678a2bf4a
--- /dev/null
+++ b/Modules/Core/Common/include/itkAnatomicalOrientation.h
@@ -0,0 +1,584 @@
+/*=========================================================================
+ *
+ *  Copyright NumFOCUS
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *         https://www.apache.org/licenses/LICENSE-2.0.txt
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *=========================================================================*/
+#ifndef itkAnatomicalOrientation_h
+#define itkAnatomicalOrientation_h
+
+#include "ITKCommonExport.h"
+#include "itkImageBase.h"
+#ifndef ITK_FUTURE_LEGACY_REMOVE
+#  include "itkSpatialOrientation.h"
+#endif
+#include <map>
+#include <string>
+
+namespace itk
+{
+
+/** \class AnatomicalOrientation
+ * \brief Representations of anatomical orientations and methods to convert between conventions.
+ *
+ *  Defines patient specific anatomical names to the XYZ axes of a 3D image.
+ *
+ * A class instances holds the patient orientation stored as an enumerated type. Conversion to different representations
+ * such as strings and direction cosine matrices are supported.
+ *
+ * The use of unambiguous anatomical orientation names such as "RightToLeft" is preferred, where "Right" is the
+ * "from direction" and the negative direction of the coordinates, while "Left" is the "to direction" and the positive
+ * direction. The following is an unambiguous construction of an AnatomicalOrientation object:
+ *
+ * \code
+ *  AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+ *                        AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+ *                        AnatomicalOrientation::CoordinateEnum::InferiorToSuperior);
+ * \endcode
+ *
+ *
+ * \ingroup ITKCommon
+ */
+class ITKCommon_EXPORT AnatomicalOrientation
+{
+public:
+  static constexpr unsigned int Dimension = 3;
+  using DirectionType = typename ImageBase<Dimension>::DirectionType;
+  static constexpr unsigned int ImageDimension = Dimension;
+
+#ifndef ITK_FUTURE_LEGACY_REMOVE
+  using LegacyOrientationType = SpatialOrientationEnums::ValidCoordinateOrientations;
+#endif
+
+  // Anatomical names for an axis.
+  //
+  enum class CoordinateEnum : uint8_t
+  {
+    UNKNOWN = 0,
+    RightToLeft = 2, ///< 0b0010
+    LeftToRight = 3,
+    PosteriorToAnterior = 4, ///< to front - 0b0100
+    AnteriorToPosterior = 5, ///< to back
+    InferiorToSuperior = 8,  ///< to head - 0b1000
+    SuperiorToInferior = 9,  ///< to foot
+  };
+
+protected:
+  enum class CoordinateMajornessTermsEnum : uint8_t
+  {
+    PrimaryMinor = 0,
+    SecondaryMinor = 8,
+    TertiaryMinor = 16
+  };
+
+  template <CoordinateEnum VPrimary, CoordinateEnum VSecondary, CoordinateEnum VTertiary>
+  static constexpr uint32_t m_OrientationValue =
+    (static_cast<uint32_t>(VPrimary) << static_cast<uint8_t>(CoordinateMajornessTermsEnum::PrimaryMinor)) +
+    (static_cast<uint32_t>(VSecondary) << static_cast<uint8_t>(CoordinateMajornessTermsEnum::SecondaryMinor)) +
+    (static_cast<uint32_t>(VTertiary) << static_cast<uint8_t>(CoordinateMajornessTermsEnum::TertiaryMinor));
+
+  CoordinateEnum
+  GetCoordinateTerm(CoordinateMajornessTermsEnum cmt) const;
+
+public:
+  // Enumerated acronyms based on the positive or "To" direction of the anatomical coordinates.
+  enum class PositiveEnum : uint32_t
+
+  {
+    INVALID = 0,
+
+    RIP = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::AnteriorToPosterior>,
+    LIP = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::AnteriorToPosterior>,
+    RSP = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::AnteriorToPosterior>,
+    LSP = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::AnteriorToPosterior>,
+    RIA = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::PosteriorToAnterior>,
+    LIA = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::PosteriorToAnterior>,
+    RSA = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::PosteriorToAnterior>,
+    LSA = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::PosteriorToAnterior>,
+
+    IRP = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::AnteriorToPosterior>,
+    ILP = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::AnteriorToPosterior>,
+    SRP = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::AnteriorToPosterior>,
+    SLP = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::AnteriorToPosterior>,
+    IRA = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::PosteriorToAnterior>,
+    ILA = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::PosteriorToAnterior>,
+    SRA = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::PosteriorToAnterior>,
+    SLA = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::PosteriorToAnterior>,
+
+    RPI = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::SuperiorToInferior>,
+    LPI = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::SuperiorToInferior>,
+    RAI = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::SuperiorToInferior>,
+    LAI = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::SuperiorToInferior>,
+    RPS = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::InferiorToSuperior>,
+    LPS = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::InferiorToSuperior>,
+    RAS = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::InferiorToSuperior>,
+    LAS = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::InferiorToSuperior>,
+
+    PRI = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::SuperiorToInferior>,
+    PLI = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::SuperiorToInferior>,
+    ARI = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::SuperiorToInferior>,
+    ALI = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::SuperiorToInferior>,
+    PRS = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::InferiorToSuperior>,
+    PLS = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::InferiorToSuperior>,
+    ARS = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::InferiorToSuperior>,
+    ALS = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::InferiorToSuperior>,
+
+    IPR = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::LeftToRight>,
+    SPR = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::LeftToRight>,
+    IAR = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::LeftToRight>,
+    SAR = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::LeftToRight>,
+    IPL = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::RightToLeft>,
+    SPL = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::RightToLeft>,
+    IAL = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::RightToLeft>,
+    SAL = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::RightToLeft>,
+
+    PIR = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::LeftToRight>,
+    PSR = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::LeftToRight>,
+    AIR = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::LeftToRight>,
+    ASR = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::LeftToRight>,
+    PIL = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::RightToLeft>,
+    PSL = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::RightToLeft>,
+    AIL = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::RightToLeft>,
+    ASL = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::RightToLeft>
+  };
+
+  // Enumerated acronyms based on the negative or "From" direction of the anatomical coordinates.
+  enum class NegativeEnum : uint32_t
+
+  {
+    INVALID = 0,
+
+    RIP = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::PosteriorToAnterior>,
+    LIP = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::PosteriorToAnterior>,
+    RSP = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::PosteriorToAnterior>,
+    LSP = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::PosteriorToAnterior>,
+    RIA = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::AnteriorToPosterior>,
+    LIA = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::AnteriorToPosterior>,
+    RSA = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::AnteriorToPosterior>,
+    LSA = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::AnteriorToPosterior>,
+
+    IRP = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::PosteriorToAnterior>,
+    ILP = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::PosteriorToAnterior>,
+    SRP = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::PosteriorToAnterior>,
+    SLP = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::PosteriorToAnterior>,
+    IRA = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::AnteriorToPosterior>,
+    ILA = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::AnteriorToPosterior>,
+    SRA = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::AnteriorToPosterior>,
+    SLA = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::AnteriorToPosterior>,
+
+    RPI = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::InferiorToSuperior>,
+    LPI = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::InferiorToSuperior>,
+    RAI = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::InferiorToSuperior>,
+    LAI = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::InferiorToSuperior>,
+    RPS = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::SuperiorToInferior>,
+    LPS = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::SuperiorToInferior>,
+    RAS = m_OrientationValue<CoordinateEnum::RightToLeft,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::SuperiorToInferior>,
+    LAS = m_OrientationValue<CoordinateEnum::LeftToRight,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::SuperiorToInferior>,
+
+    PRI = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::InferiorToSuperior>,
+    PLI = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::InferiorToSuperior>,
+    ARI = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::InferiorToSuperior>,
+    ALI = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::InferiorToSuperior>,
+    PRS = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::SuperiorToInferior>,
+    PLS = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::SuperiorToInferior>,
+    ARS = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::RightToLeft,
+                             CoordinateEnum::SuperiorToInferior>,
+    ALS = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::LeftToRight,
+                             CoordinateEnum::SuperiorToInferior>,
+
+    IPR = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::RightToLeft>,
+    SPR = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::RightToLeft>,
+    IAR = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::RightToLeft>,
+    SAR = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::RightToLeft>,
+    IPL = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::LeftToRight>,
+    SPL = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::LeftToRight>,
+    IAL = m_OrientationValue<CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::LeftToRight>,
+    SAL = m_OrientationValue<CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::LeftToRight>,
+
+    PIR = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::RightToLeft>,
+    PSR = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::RightToLeft>,
+    AIR = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::RightToLeft>,
+    ASR = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::RightToLeft>,
+    PIL = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::LeftToRight>,
+    PSL = m_OrientationValue<CoordinateEnum::PosteriorToAnterior,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::LeftToRight>,
+    AIL = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::InferiorToSuperior,
+                             CoordinateEnum::LeftToRight>,
+    ASL = m_OrientationValue<CoordinateEnum::AnteriorToPosterior,
+                             CoordinateEnum::SuperiorToInferior,
+                             CoordinateEnum::LeftToRight>
+
+  };
+
+
+  /** \brief Initialize with CoordinateEnum's from separate axes.
+   *
+   * If multiple CoordinateEnums are from the same axes then the Orientation value is INVALID.
+   */
+  constexpr AnatomicalOrientation(CoordinateEnum primary, CoordinateEnum secondary, CoordinateEnum tertiary)
+    : m_Value(
+        SameOrientationAxes(primary, secondary) || SameOrientationAxes(primary, tertiary) ||
+            SameOrientationAxes(secondary, tertiary)
+          ? PositiveEnum::INVALID
+          : static_cast<PositiveEnum>(
+              (static_cast<uint32_t>(primary) << static_cast<uint8_t>(CoordinateMajornessTermsEnum::PrimaryMinor)) +
+              (static_cast<uint32_t>(secondary) << static_cast<uint8_t>(CoordinateMajornessTermsEnum::SecondaryMinor)) +
+              (static_cast<uint32_t>(tertiary) << static_cast<uint8_t>(CoordinateMajornessTermsEnum::TertiaryMinor))))
+  {}
+
+
+  constexpr AnatomicalOrientation(PositiveEnum toOrientation)
+    : m_Value(toOrientation)
+  {}
+
+
+  constexpr AnatomicalOrientation(NegativeEnum fromOrientation)
+    : m_Value(PositiveEnum(static_cast<uint32_t>(fromOrientation)))
+  {}
+
+#ifndef ITK_FUTURE_LEGACY_REMOVE
+  /** \brief Conversion from Legacy SpatialOrientation
+   *
+   * @param legacyOrientation
+   */
+#  if defined(ITK_LEGACY_REMOVE) && !defined(ITK_LEGACY_SILENT)
+  [[deprecated("Use the AnatomicalOrientation::FromEnum type instead.")]]
+#  endif
+  AnatomicalOrientation(LegacyOrientationType legacyOrientation);
+#endif
+
+  /** Conversion for a Direction Cosine Matrix to the closest anatomical orientation. Any partial axis rotations are
+   *  rounded to the nearest axis, and lost in this conversion.
+   */
+  explicit AnatomicalOrientation(const DirectionType & d)
+    : m_Value(ConvertDirectionToPositiveEnum(d))
+  {}
+
+  /** Creates a AnatomicalOrientation from a string with the PositiveEnum encoding. The string is case-insensitive. If
+   * the string is not a valid encoding then the orientation is set to INVALID.
+   */
+  static AnatomicalOrientation
+  CreateFromPositiveStringEncoding(std::string str);
+
+  // Same as CreateFromPositiveStringEncoding but for the NegativeEnum encoding.
+  static AnatomicalOrientation
+  CreateFromNegativeStringEncoding(std::string str);
+
+  operator PositiveEnum() const { return m_Value; }
+
+  /** Returns the PositiveEnum encoding as a string. The string is always upper case. */
+  std::string
+  GetAsPositiveStringEncoding() const;
+
+  /** Returns the NegativeEnum encoding as a string. The string is always upper case. */
+  std::string
+  GetAsNegativeStringEncoding() const;
+
+  /** An involution to convert between "positive" and "negative" single character encoding strings.
+   *
+   * For example the string "RAS" is converted to "LPI" and vice versa.
+   *
+   * The input maybe upper or lower case, while the output is always upper case.
+   * There is no check that the input is a valid encoding.
+   *
+   * */
+  static std::string
+  ConvertStringEncoding(std::string str);
+
+  /** \brief Return the direction cosine matrix for the orientation. */
+  DirectionType
+  GetAsDirection() const
+  {
+    return ConvertPositiveEnumToDirection(m_Value);
+  }
+
+  PositiveEnum
+  GetAsPositiveOrientation() const
+  {
+    return m_Value;
+  }
+
+  NegativeEnum
+  GetAsNegativeOrientation() const
+  {
+    return NegativeEnum(uint32_t(this->m_Value));
+  }
+
+  CoordinateEnum
+  GetPrimaryTerm() const
+  {
+    return GetCoordinateTerm(CoordinateMajornessTermsEnum::PrimaryMinor);
+  }
+
+  CoordinateEnum
+  GetSecondaryTerm() const
+  {
+    return GetCoordinateTerm(CoordinateMajornessTermsEnum::SecondaryMinor);
+  }
+
+  CoordinateEnum
+  GetTertiaryTerm() const
+  {
+    return GetCoordinateTerm(CoordinateMajornessTermsEnum::TertiaryMinor);
+  }
+
+  std::array<CoordinateEnum, 3>
+  GetTerms() const
+  {
+    return { GetPrimaryTerm(), GetSecondaryTerm(), GetTertiaryTerm() };
+  }
+
+  static constexpr bool
+  SameOrientationAxes(CoordinateEnum a, CoordinateEnum b)
+  {
+    const uint8_t AxisField = ~1; // mask the lowest bit
+    return (static_cast<uint8_t>(a) & AxisField) == (static_cast<uint8_t>(b) & AxisField);
+  }
+
+
+  friend ITKCommon_EXPORT std::ostream &
+                          operator<<(std::ostream & out, PositiveEnum value);
+
+protected:
+  /** \brief Return the direction cosine matrix for a orientation. */
+  static DirectionType ConvertPositiveEnumToDirection(PositiveEnum);
+
+
+  /** \brief Return the closest orientation for a direction cosine matrix. */
+  static PositiveEnum
+  ConvertDirectionToPositiveEnum(const DirectionType & dir);
+
+
+  /** \brief Return the global instance of the map from orientation enum to strings.
+   *
+   * The implementation uses a function static local variable so the global is created only if needed, only once.
+   */
+  static const std::map<PositiveEnum, std::string> &
+  GetCodeToString();
+
+  /** \brief Return the global instance of the map from string to orientation enum.
+   */
+  static const std::map<std::string, PositiveEnum> &
+  GetStringToCode();
+
+  PositiveEnum m_Value;
+};
+
+/** Outputs unambiguous anatomical orientation names such as "right-to-left". */
+ITKCommon_EXPORT std::ostream &
+                 operator<<(std::ostream & out, typename AnatomicalOrientation::CoordinateEnum value);
+
+/** Outputs the PositiveEnum encoding as a string such as "LPS". */
+ITKCommon_EXPORT std::ostream &
+                 operator<<(std::ostream & out, typename AnatomicalOrientation::PositiveEnum value);
+
+
+/** Outputs the NegativeEnum encoding as a string such as "RAI" */
+ITKCommon_EXPORT std::ostream &
+                 operator<<(std::ostream & out, typename AnatomicalOrientation::NegativeEnum value);
+
+ITKCommon_EXPORT std::ostream &
+                 operator<<(std::ostream & out, const AnatomicalOrientation & orientation);
+
+
+} // end namespace itk
+
+
+#endif
diff --git a/Modules/Core/Common/src/CMakeLists.txt b/Modules/Core/Common/src/CMakeLists.txt
index 74f031b08d1..8c018b33814 100644
--- a/Modules/Core/Common/src/CMakeLists.txt
+++ b/Modules/Core/Common/src/CMakeLists.txt
@@ -145,7 +145,9 @@ set(ITKCommon_SRCS
     itkFrustumSpatialFunction.cxx
     itkObjectStore.cxx
     itkGaussianDerivativeOperator.cxx
-    itkSpatialOrientation.cxx)
+    itkSpatialOrientation.cxx
+    itkAnatomicalOrientation.cxx
+)
 
 if(WIN32)
   list(APPEND ITKCommon_SRCS itkWin32OutputWindow.cxx)
diff --git a/Modules/Core/Common/src/itkAnatomicalOrientation.cxx b/Modules/Core/Common/src/itkAnatomicalOrientation.cxx
new file mode 100644
index 00000000000..ab13b29c870
--- /dev/null
+++ b/Modules/Core/Common/src/itkAnatomicalOrientation.cxx
@@ -0,0 +1,328 @@
+/*=========================================================================
+ *
+ *  Copyright NumFOCUS
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *         https://www.apache.org/licenses/LICENSE-2.0.txt
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *=========================================================================*/
+#include "itkAnatomicalOrientation.h"
+#ifndef ITK_FUTURE_LEGACY_REMOVE
+#  include "itkSpatialOrientationAdapter.h"
+#endif
+
+namespace itk
+{
+
+
+#ifndef ITK_FUTURE_LEGACY_REMOVE
+AnatomicalOrientation::AnatomicalOrientation(LegacyOrientationType legacyOrientation)
+  : AnatomicalOrientation(SpatialOrientationAdapter().ToDirectionCosines(legacyOrientation))
+{
+  assert(uint32_t(legacyOrientation) == uint32_t(m_Value));
+}
+#endif
+
+
+std::string
+AnatomicalOrientation::GetAsPositiveStringEncoding() const
+{
+
+  // a lambda function to convert a CoordinateEnum to a char
+  auto enumAsChar = [](CoordinateEnum coord) -> char {
+    switch (coord)
+    {
+      case CoordinateEnum::RightToLeft:
+        return 'L';
+      case CoordinateEnum::LeftToRight:
+        return 'R';
+      case CoordinateEnum::AnteriorToPosterior:
+        return 'P';
+      case CoordinateEnum::PosteriorToAnterior:
+        return 'A';
+      case CoordinateEnum::InferiorToSuperior:
+        return 'S';
+      case CoordinateEnum::SuperiorToInferior:
+        return 'I';
+      default:
+        return 'X';
+    }
+  };
+
+  if (m_Value == PositiveEnum::INVALID)
+  {
+    return "INVALID";
+  }
+
+  return std::string({ enumAsChar(GetPrimaryTerm()), enumAsChar(GetSecondaryTerm()), enumAsChar(GetTertiaryTerm()) });
+}
+
+
+std::string
+AnatomicalOrientation::GetAsNegativeStringEncoding() const
+{
+  return ConvertStringEncoding(GetAsPositiveStringEncoding());
+}
+
+
+AnatomicalOrientation
+AnatomicalOrientation::CreateFromPositiveStringEncoding(std::string str)
+{
+  std::transform(str.begin(), str.end(), str.begin(), ::toupper);
+
+  const std::map<std::string, typename AnatomicalOrientation::PositiveEnum> & stringToCode = GetStringToCode();
+  auto                                                                        iter = stringToCode.find(str);
+  if (iter == stringToCode.end())
+  {
+    return AnatomicalOrientation(PositiveEnum::INVALID);
+  }
+  return AnatomicalOrientation(iter->second);
+}
+
+AnatomicalOrientation
+AnatomicalOrientation::CreateFromNegativeStringEncoding(std::string str)
+{
+  return AnatomicalOrientation::CreateFromPositiveStringEncoding(ConvertStringEncoding(str));
+}
+
+
+std::string
+AnatomicalOrientation::ConvertStringEncoding(std::string str)
+{
+
+  auto flip = [](char c) -> char {
+    switch (::toupper(c))
+    {
+      case 'R':
+        return 'L';
+      case 'L':
+        return 'R';
+      case 'A':
+        return 'P';
+      case 'P':
+        return 'A';
+      case 'S':
+        return 'I';
+      case 'I':
+        return 'S';
+      case 'X':
+        return 'X';
+      default:
+        return c;
+    }
+  };
+
+  for (auto & c : str)
+  {
+    c = flip(c);
+  }
+  return str;
+}
+
+
+AnatomicalOrientation::CoordinateEnum
+AnatomicalOrientation::GetCoordinateTerm(CoordinateMajornessTermsEnum cmt) const
+{
+  return static_cast<CoordinateEnum>(static_cast<uint32_t>(m_Value) >> static_cast<uint8_t>(cmt) & 0xff);
+}
+
+
+const std::map<typename AnatomicalOrientation::PositiveEnum, std::string> &
+AnatomicalOrientation::GetCodeToString()
+{
+  auto createCodeToString = []() -> std::map<PositiveEnum, std::string> {
+    std::map<PositiveEnum, std::string> orientToString;
+
+    for (auto code : { PositiveEnum::RIP, PositiveEnum::LIP, PositiveEnum::RSP, PositiveEnum::LSP,    PositiveEnum::RIA,
+                       PositiveEnum::LIA, PositiveEnum::RSA, PositiveEnum::LSA, PositiveEnum::IRP,    PositiveEnum::ILP,
+                       PositiveEnum::SRP, PositiveEnum::SLP, PositiveEnum::IRA, PositiveEnum::ILA,    PositiveEnum::SRA,
+                       PositiveEnum::SLA, PositiveEnum::RPI, PositiveEnum::LPI, PositiveEnum::RAI,    PositiveEnum::LAI,
+                       PositiveEnum::RPS, PositiveEnum::LPS, PositiveEnum::RAS, PositiveEnum::LAS,    PositiveEnum::PRI,
+                       PositiveEnum::PLI, PositiveEnum::ARI, PositiveEnum::ALI, PositiveEnum::PRS,    PositiveEnum::PLS,
+                       PositiveEnum::ARS, PositiveEnum::ALS, PositiveEnum::IPR, PositiveEnum::SPR,    PositiveEnum::IAR,
+                       PositiveEnum::SAR, PositiveEnum::IPL, PositiveEnum::SPL, PositiveEnum::IAL,    PositiveEnum::SAL,
+                       PositiveEnum::PIR, PositiveEnum::PSR, PositiveEnum::AIR, PositiveEnum::ASR,    PositiveEnum::PIL,
+                       PositiveEnum::PSL, PositiveEnum::AIL, PositiveEnum::ASL, PositiveEnum::INVALID })
+    {
+      orientToString[code] = AnatomicalOrientation(code).GetAsPositiveStringEncoding();
+    }
+
+    return orientToString;
+  };
+  static const std::map<PositiveEnum, std::string> codeToString = createCodeToString();
+  return codeToString;
+}
+
+const std::map<std::string, AnatomicalOrientation::PositiveEnum> &
+AnatomicalOrientation::GetStringToCode()
+{
+
+  auto createStringToCode = []() -> std::map<std::string, PositiveEnum> {
+    std::map<std::string, PositiveEnum>         stringToCode;
+    const std::map<PositiveEnum, std::string> & codeToString = GetCodeToString();
+
+    for (const auto & kv : codeToString)
+    {
+      stringToCode[kv.second] = kv.first;
+    }
+    return stringToCode;
+  };
+
+  static const std::map<std::string, AnatomicalOrientation::PositiveEnum> stringToCode = createStringToCode();
+  return stringToCode;
+}
+
+
+AnatomicalOrientation::PositiveEnum
+AnatomicalOrientation::ConvertDirectionToPositiveEnum(const DirectionType & dir)
+{
+  // NOTE: This method was based off of itk::SpatialObjectAdaptor::FromDirectionCosines
+  // but it is DIFFERENT in the meaning of direction in terms of sign-ness.
+  CoordinateEnum terms[3] = { CoordinateEnum::UNKNOWN, CoordinateEnum::UNKNOWN, CoordinateEnum::UNKNOWN };
+
+  std::multimap<double, std::pair<unsigned, unsigned>> value_to_idx;
+  for (unsigned int c = 0; c < 3; ++c)
+  {
+    for (unsigned int r = 0; r < 3; ++r)
+    {
+      value_to_idx.emplace(std::abs(dir[c][r]), std::make_pair(c, r));
+    }
+  }
+
+  for (unsigned i = 0; i < 3; ++i)
+  {
+
+    auto               max_idx = value_to_idx.rbegin()->second;
+    const unsigned int max_c = max_idx.first;
+    const unsigned int max_r = max_idx.second;
+
+    const int max_sgn = Math::sgn(dir[max_c][max_r]);
+
+    for (auto it = value_to_idx.begin(); it != value_to_idx.end();)
+    {
+      if (it->second.first == max_c || it->second.second == max_r)
+      {
+        value_to_idx.erase(it++);
+      }
+      else
+      {
+        ++it;
+      }
+    }
+
+    switch (max_c)
+    {
+      case 0:
+      {
+        // When the dominant axis sign is positive, assign the coordinate for the direction we are increasing towards.
+        // ITK is in LPS, so that is the positive direction
+        terms[max_r] = (max_sgn == 1) ? CoordinateEnum::RightToLeft : CoordinateEnum::LeftToRight;
+        break;
+      }
+      case 1:
+      {
+        terms[max_r] = (max_sgn == 1) ? CoordinateEnum::AnteriorToPosterior : CoordinateEnum::PosteriorToAnterior;
+        break;
+      }
+      case 2:
+      {
+        terms[max_r] = (max_sgn == 1) ? CoordinateEnum::InferiorToSuperior : CoordinateEnum::SuperiorToInferior;
+        break;
+      }
+      default:
+        itkGenericExceptionMacro("Unexpected Axis");
+    }
+  }
+
+  return AnatomicalOrientation(terms[0], terms[1], terms[2]);
+}
+
+
+typename AnatomicalOrientation::DirectionType
+AnatomicalOrientation::ConvertPositiveEnumToDirection(PositiveEnum orientationEnum)
+{
+  const AnatomicalOrientation o(orientationEnum);
+
+  CoordinateEnum terms[Dimension] = { o.GetPrimaryTerm(), o.GetSecondaryTerm(), o.GetTertiaryTerm() };
+  DirectionType  direction;
+  direction.Fill(0.0);
+
+  for (unsigned int i = 0; i < Dimension; ++i)
+  {
+    const int sign = (static_cast<uint8_t>(terms[i]) & 0x1) ? 1 : -1;
+
+    switch (terms[i])
+    {
+      case CoordinateEnum::LeftToRight:
+      case CoordinateEnum::RightToLeft:
+        direction[0][i] = -1 * sign;
+        break;
+      case CoordinateEnum::AnteriorToPosterior:
+      case CoordinateEnum::PosteriorToAnterior:
+        direction[1][i] = 1 * sign;
+        break;
+      case CoordinateEnum::InferiorToSuperior:
+      case CoordinateEnum::SuperiorToInferior:
+        direction[2][i] = -1 * sign;
+        break;
+      case CoordinateEnum::UNKNOWN:
+        break;
+    }
+  }
+  return direction;
+}
+
+std::ostream &
+operator<<(std::ostream & out, typename AnatomicalOrientation::CoordinateEnum value)
+{
+  switch (value)
+  {
+    case AnatomicalOrientation::CoordinateEnum::RightToLeft:
+      return out << "right-to-left";
+    case AnatomicalOrientation::CoordinateEnum::LeftToRight:
+      return out << "left-to-right";
+    case AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior:
+      return out << "anterior-to-posterior";
+    case AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior:
+      return out << "posterior-to-anterior";
+    case AnatomicalOrientation::CoordinateEnum::InferiorToSuperior:
+      return out << "inferior-to-superior";
+    case AnatomicalOrientation::CoordinateEnum::SuperiorToInferior:
+      return out << "superior-to-inferior";
+    case AnatomicalOrientation::CoordinateEnum::UNKNOWN:
+      return out << "unknown";
+    default:
+      return out << "invalid";
+  }
+}
+
+std::ostream &
+operator<<(std::ostream & out, typename AnatomicalOrientation::PositiveEnum value)
+{
+  return (out << AnatomicalOrientation(value).GetAsPositiveStringEncoding());
+}
+
+std::ostream &
+operator<<(std::ostream & out, typename AnatomicalOrientation::NegativeEnum value)
+{
+  return (out << AnatomicalOrientation(value).GetAsNegativeStringEncoding());
+}
+
+std::ostream &
+operator<<(std::ostream & out, const AnatomicalOrientation & orientation)
+{
+  const auto terms = orientation.GetTerms();
+  static_assert(std::tuple_size<decltype(terms)>{} == 3);
+  return out << terms[0] << " " << terms[1] << " " << terms[2];
+}
+
+} // namespace itk
diff --git a/Modules/Core/Common/wrapping/itkAnatomicalOrientation.wrap b/Modules/Core/Common/wrapping/itkAnatomicalOrientation.wrap
new file mode 100644
index 00000000000..9d81865c78e
--- /dev/null
+++ b/Modules/Core/Common/wrapping/itkAnatomicalOrientation.wrap
@@ -0,0 +1,1 @@
+itk_wrap_simple_class("itk::AnatomicalOrientation")
diff --git a/Modules/IO/GE/src/itkGE4ImageIO.cxx b/Modules/IO/GE/src/itkGE4ImageIO.cxx
index 6fa3552585c..d979055dd8e 100644
--- a/Modules/IO/GE/src/itkGE4ImageIO.cxx
+++ b/Modules/IO/GE/src/itkGE4ImageIO.cxx
@@ -144,37 +144,27 @@ GE4ImageIO::ReadHeader(const char * FileNameToRead)
 
   if (strstr(tmpStr, "CORONAL") != nullptr)
   {
-    // hdr->imagePlane =
-    // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_CORONAL;
-    // hdr->origin = itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ORIGIN_SRP;
-    // hdr->origin was SLA in the brains2 filter.
-    hdr->coordinateOrientation =
-      itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+    hdr->coordinateOrientation = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                                       AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
+                                                       AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
   }
   else if (strstr(tmpStr, "SAGITTAL") != nullptr)
   {
-    // hdr->imagePlane =
-    // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_SAGITTAL;
-    // hdr->origin = itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ORIGIN_SRA;
-    // hdr->origin was SLP in the brains2 filter.
-    hdr->coordinateOrientation =
-      itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_AIR;
+    hdr->coordinateOrientation = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                                       AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                                       AnatomicalOrientation::CoordinateEnum::RightToLeft);
   }
   else if (strstr(tmpStr, "AXIAL") != nullptr)
   {
-    // hdr->imagePlane =
-    // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_TRANSVERSE;
-    // hdr->origin = itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ORIGIN_SRA; // was SLP
-    hdr->coordinateOrientation =
-      itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI;
+    hdr->coordinateOrientation = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                                       AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                                       AnatomicalOrientation::CoordinateEnum::InferiorToSuperior);
   }
   else
   {
-    // hdr->imagePlane =
-    // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_CORONAL;
-    // hdr->origin = itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ORIGIN_SRP; // was SLA
-    hdr->coordinateOrientation =
-      itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+    hdr->coordinateOrientation = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                                       AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
+                                                       AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
   }
 
   /* Get the Scan Matrix from the IMAGE Header */
diff --git a/Modules/IO/GE/src/itkGE5ImageIO.cxx b/Modules/IO/GE/src/itkGE5ImageIO.cxx
index cb062050499..33c128867cf 100644
--- a/Modules/IO/GE/src/itkGE5ImageIO.cxx
+++ b/Modules/IO/GE/src/itkGE5ImageIO.cxx
@@ -362,19 +362,27 @@ GE5ImageIO::ReadHeader(const char * FileNameToRead)
   {
     case GE_CORONAL:
       curImage->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+        AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                              AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
+                              AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
       break;
     case GE_SAGITTAL:
       curImage->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_AIR;
+        AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                              AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                              AnatomicalOrientation::CoordinateEnum::RightToLeft);
       break;
     case GE_AXIAL:
       curImage->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI;
+        AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                              AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                              AnatomicalOrientation::CoordinateEnum::InferiorToSuperior);
       break;
     default:
       curImage->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+        AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                              AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
+                              AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
       break;
   }
 
diff --git a/Modules/IO/GE/src/itkGEAdwImageIO.cxx b/Modules/IO/GE/src/itkGEAdwImageIO.cxx
index 6f060293998..75cf01124b8 100644
--- a/Modules/IO/GE/src/itkGEAdwImageIO.cxx
+++ b/Modules/IO/GE/src/itkGEAdwImageIO.cxx
@@ -161,31 +161,24 @@ GEAdwImageIO::ReadHeader(const char * FileNameToRead)
   switch (tmpShort)
   {
     case GE_CORONAL:
-      // hdr->imagePlane = itk::IOCommon::ITK_ANALYZE_ORIENTATION_IRP_CORONAL;
-      // hdr->origin = itk::IOCommon::ITK_ORIGIN_SLA;
-      hdr->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+      hdr->coordinateOrientation = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                                         AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
+                                                         AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
       break;
     case GE_SAGITTAL:
-      // hdr->imagePlane =
-      // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_SAGITTAL;
-      // hdr->origin = itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ORIGIN_SLA;
-      hdr->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_AIR;
+      hdr->coordinateOrientation = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                                         AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                                         AnatomicalOrientation::CoordinateEnum::RightToLeft);
       break;
     case GE_AXIAL:
-      // hdr->imagePlane =
-      // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_TRANSVERSE;
-      // hdr->origin = itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ORIGIN_SLA;
-      hdr->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI;
+      hdr->coordinateOrientation = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                                         AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                                         AnatomicalOrientation::CoordinateEnum::InferiorToSuperior);
       break;
     default:
-      // hdr->imagePlane =
-      // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_CORONAL;
-      // hdr->origin = itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ORIGIN_SLA;
-      hdr->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+      hdr->coordinateOrientation = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                                         AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
+                                                         AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
       break;
   }
   this->GetFloatAt(f, GE_ADW_IM_LOC, &(hdr->sliceLocation));
diff --git a/Modules/IO/IPL/include/itkGEImageHeader.h b/Modules/IO/IPL/include/itkGEImageHeader.h
index 37dd74cec3d..c586941c56d 100644
--- a/Modules/IO/IPL/include/itkGEImageHeader.h
+++ b/Modules/IO/IPL/include/itkGEImageHeader.h
@@ -30,6 +30,7 @@
 #include "ITKIOIPLExport.h"
 
 #include "itkIOCommon.h"
+#include "itkAnatomicalOrientation.h"
 
 enum GE_PANE_STRUCT
 {
@@ -85,13 +86,15 @@ struct GEImageHeader
   short imageYsize;
   float imageXres;
   float imageYres;
-  itk::SpatialOrientationEnums::ValidCoordinateOrientations coordinateOrientation;
-  short                                                     numberOfSlices;
-  short                                                     offset;
-  char                                                      filename[itk::IOCommon::ITK_MAXPATHLEN + 1];
-  char                                                      hospital[35];
-  char                                                      modality[4];
-  short                                                     imagesPerSlice;
+
+  itk::AnatomicalOrientation::PositiveEnum coordinateOrientation; // uint32_t
+
+  short numberOfSlices;
+  short offset;
+  char  filename[itk::IOCommon::ITK_MAXPATHLEN + 1];
+  char  hospital[35];
+  char  modality[4];
+  short imagesPerSlice;
   short turboFactor; // This is only relevant for the geADW image format, but
                      // is put here for convenience
 };
diff --git a/Modules/IO/IPL/src/itkIPLCommonImageIO.cxx b/Modules/IO/IPL/src/itkIPLCommonImageIO.cxx
index b0698c00e55..fdecc38f956 100644
--- a/Modules/IO/IPL/src/itkIPLCommonImageIO.cxx
+++ b/Modules/IO/IPL/src/itkIPLCommonImageIO.cxx
@@ -19,7 +19,7 @@
 #include "itksys/SystemTools.hxx"
 #include "itkIPLCommonImageIO.h"
 #include "itkByteSwapper.h"
-#include "itkSpatialOrientationAdapter.h"
+#include "itkAnatomicalOrientation.h"
 #include "itkDirectory.h"
 #include "itkMetaDataObject.h"
 #include <iostream>
@@ -256,9 +256,8 @@ IPLCommonImageIO::ReadImageInformation()
 
   //
   // set direction cosines
-  using OrientAdapterType = SpatialOrientationAdapter;
-  SpatialOrientationAdapter::DirectionType dir =
-    OrientAdapterType().ToDirectionCosines(m_ImageHeader->coordinateOrientation);
+  AnatomicalOrientation::DirectionType dir =
+    AnatomicalOrientation(m_ImageHeader->coordinateOrientation).GetAsDirection();
   std::vector<double> dirx(3, 0), diry(3, 0), dirz(3, 0);
   dirx[0] = dir[0][0];
   dirx[1] = dir[1][0];
diff --git a/Modules/IO/Meta/src/itkMetaImageIO.cxx b/Modules/IO/Meta/src/itkMetaImageIO.cxx
index f6c2133cc0d..03caa8dc8be 100644
--- a/Modules/IO/Meta/src/itkMetaImageIO.cxx
+++ b/Modules/IO/Meta/src/itkMetaImageIO.cxx
@@ -17,7 +17,7 @@
  *=========================================================================*/
 
 #include "itkMetaImageIO.h"
-#include "itkSpatialOrientationAdapter.h"
+#include "itkAnatomicalOrientation.h"
 #include "itkIOCommon.h"
 #include "itksys/SystemTools.hxx"
 #include "itkMath.h"
@@ -808,11 +808,8 @@ MetaImageIO::Write(const void * buffer)
 
   if (numberOfDimensions == 3)
   {
-    using SpatialOrientations = SpatialOrientationEnums::ValidCoordinateOrientations;
-    SpatialOrientations coordOrient = SpatialOrientations::ITK_COORDINATE_ORIENTATION_INVALID;
-
-    std::vector<double>                      dirx, diry, dirz;
-    SpatialOrientationAdapter::DirectionType dir;
+    std::vector<double>                  dirx, diry, dirz;
+    AnatomicalOrientation::DirectionType dir;
     dirx = this->GetDirection(0);
     diry = this->GetDirection(1);
     dirz = this->GetDirection(2);
@@ -822,238 +819,24 @@ MetaImageIO::Write(const void * buffer)
       dir[ii][1] = diry[ii];
       dir[ii][2] = dirz[ii];
     }
-    coordOrient = SpatialOrientationAdapter().FromDirectionCosines(dir);
-
-    switch (coordOrient)
-    {
-      default:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RPI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RPS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RAI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RAS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RIA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RIP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RSA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RSP:
-      {
-        m_MetaImage.AnatomicalOrientation(0, MET_ORIENTATION_RL);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LPI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LPS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LAI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LAS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LIA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LIP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LSA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LSP:
-      {
-        m_MetaImage.AnatomicalOrientation(0, MET_ORIENTATION_LR);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ALI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ALS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ARI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ARS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_AIL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_AIR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ASL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ASR:
-      {
-        m_MetaImage.AnatomicalOrientation(0, MET_ORIENTATION_AP);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PLI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PLS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PRI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PRS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PIL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PIR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PSL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PSR:
-      {
-        m_MetaImage.AnatomicalOrientation(0, MET_ORIENTATION_PA);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IPL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IPR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IAL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IAR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ILA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ILP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IRA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IRP:
-      {
-        m_MetaImage.AnatomicalOrientation(0, MET_ORIENTATION_IS);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SPL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SPR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SAL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SAR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SLA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SLP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SRA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SRP:
-      {
-        m_MetaImage.AnatomicalOrientation(0, MET_ORIENTATION_SI);
-        break;
-      }
-    }
-    switch (coordOrient)
-    {
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PRI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PRS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ARI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ARS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IRA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IRP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SRA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SRP:
-      {
-        m_MetaImage.AnatomicalOrientation(1, MET_ORIENTATION_RL);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PLI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PLS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ALI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ALS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ILA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ILP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SLA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SLP:
-      {
-        m_MetaImage.AnatomicalOrientation(1, MET_ORIENTATION_LR);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LAI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LAS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RAI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RAS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IAL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IAR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SAL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SAR:
-      {
-        m_MetaImage.AnatomicalOrientation(1, MET_ORIENTATION_AP);
-        break;
-      }
-      default:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LPI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LPS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RPI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RPS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IPL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IPR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SPL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SPR:
-      {
-        m_MetaImage.AnatomicalOrientation(1, MET_ORIENTATION_PA);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PIL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PIR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_AIL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_AIR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LIA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LIP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RIA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RIP:
-      {
-        m_MetaImage.AnatomicalOrientation(1, MET_ORIENTATION_IS);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PSL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PSR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ASL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ASR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LSA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LSP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RSA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RSP:
-      {
-        m_MetaImage.AnatomicalOrientation(1, MET_ORIENTATION_SI);
-        break;
-      }
-    }
-    switch (coordOrient)
-    {
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PIR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PSR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_AIR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ASR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IAR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IPR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SAR:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SPR:
-      {
-        m_MetaImage.AnatomicalOrientation(2, MET_ORIENTATION_RL);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PIL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PSL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_AIL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ASL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IAL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IPL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SAL:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SPL:
-      {
-        m_MetaImage.AnatomicalOrientation(2, MET_ORIENTATION_LR);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LIA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LSA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RIA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RSA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ILA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IRA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SLA:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SRA:
-      {
-        m_MetaImage.AnatomicalOrientation(2, MET_ORIENTATION_AP);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LIP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LSP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RIP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RSP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ILP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_IRP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SLP:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_SRP:
-      {
-        m_MetaImage.AnatomicalOrientation(2, MET_ORIENTATION_PA);
-        break;
-      }
-      default:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PLI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PRI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ALI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ARI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LAI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LPI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RAI:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RPI:
-      {
-        m_MetaImage.AnatomicalOrientation(2, MET_ORIENTATION_IS);
-        break;
-      }
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PLS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_PRS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ALS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_ARS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LAS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_LPS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RAS:
-      case SpatialOrientations::ITK_COORDINATE_ORIENTATION_RPS:
-      {
-        m_MetaImage.AnatomicalOrientation(2, MET_ORIENTATION_SI);
-        break;
-      }
-    }
+    AnatomicalOrientation coordOrient(dir);
+
+    // Mapping from DICOM CoordinateEnum defined as the increasing direction to
+    // the MetaIO enum which has from/to orientation defined.
+    const std::map<AnatomicalOrientation::CoordinateEnum, int> axisToMetOrientation{
+      { AnatomicalOrientation::CoordinateEnum::RightToLeft, MET_ORIENTATION_RL },
+      { AnatomicalOrientation::CoordinateEnum::LeftToRight, MET_ORIENTATION_LR },
+      { AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior, MET_ORIENTATION_AP },
+      { AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior, MET_ORIENTATION_PA },
+      { AnatomicalOrientation::CoordinateEnum::InferiorToSuperior, MET_ORIENTATION_IS },
+      { AnatomicalOrientation::CoordinateEnum::SuperiorToInferior, MET_ORIENTATION_SI }
+    };
+
+    m_MetaImage.AnatomicalOrientation(0, axisToMetOrientation.at(coordOrient.GetPrimaryTerm()));
+    m_MetaImage.AnatomicalOrientation(1, axisToMetOrientation.at(coordOrient.GetSecondaryTerm()));
+    m_MetaImage.AnatomicalOrientation(2, axisToMetOrientation.at(coordOrient.GetTertiaryTerm()));
   }
-  // Propagage direction cosine information.
+  // Propagate direction cosine information.
   auto * transformMatrix = static_cast<double *>(malloc(numberOfDimensions * numberOfDimensions * sizeof(double)));
   if (transformMatrix)
   {
diff --git a/Modules/IO/NIFTI/src/itkNiftiImageIO.cxx b/Modules/IO/NIFTI/src/itkNiftiImageIO.cxx
index 7fde5622799..e5ecf351c6f 100644
--- a/Modules/IO/NIFTI/src/itkNiftiImageIO.cxx
+++ b/Modules/IO/NIFTI/src/itkNiftiImageIO.cxx
@@ -18,7 +18,7 @@
 #include "itkNiftiImageIO.h"
 #include "itkIOCommon.h"
 #include "itkMetaDataObject.h"
-#include "itkSpatialOrientationAdapter.h"
+#include "itkAnatomicalOrientation.h"
 #include <nifti1_io.h>
 #include "itkNiftiImageIOConfigurePrivate.h"
 #include "itkMakeUniqueForOverwrite.h"
@@ -1878,7 +1878,6 @@ IsAffine(const mat44 & nifti_mat)
 void
 NiftiImageIO::SetImageIOOrientationFromNIfTI(unsigned short dims, double spacingscale, double timingscale)
 {
-  typedef SpatialOrientationAdapter OrientAdapterType;
   // in the case of an Analyze75 file, use old analyze orient method.
   // but this could be a nifti file without qform and sform
   if (this->m_NiftiImage->qform_code == NIFTI_XFORM_UNKNOWN && this->m_NiftiImage->sform_code == NIFTI_XFORM_UNKNOWN)
@@ -1897,33 +1896,47 @@ NiftiImageIO::SetImageIOOrientationFromNIfTI(unsigned short dims, double spacing
         this->GetLegacyAnalyze75Mode() != NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4 &&
         this->GetLegacyAnalyze75Mode() != NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4Warning)
     { // only do this for Analyze file format
-      SpatialOrientationAdapter::OrientationType orient;
+      AnatomicalOrientation orient(AnatomicalOrientation::PositiveEnum::INVALID);
       switch (this->m_NiftiImage->analyze75_orient)
       {
         case a75_transverse_unflipped:
-          orient = SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RPI;
+          orient = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                         AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior,
+                                         AnatomicalOrientation::CoordinateEnum::InferiorToSuperior);
           break;
         case a75_sagittal_unflipped:
-          orient = SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PIR;
+          orient = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior,
+                                         AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                         AnatomicalOrientation::CoordinateEnum::RightToLeft);
           break;
         case a75_coronal_unflipped:
-          orient = SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RIP;
+          orient = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                         AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                         AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
           break;
         case a75_transverse_flipped:
-          orient = SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI;
+          orient = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                         AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                         AnatomicalOrientation::CoordinateEnum::InferiorToSuperior);
           break;
         case a75_sagittal_flipped:
-          orient = SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PIL;
+          orient = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior,
+                                         AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                         AnatomicalOrientation::CoordinateEnum::LeftToRight);
           break;
         case a75_coronal_flipped:
-          orient = SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+          orient = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                         AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
+                                         AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
           break;
         case a75_orient_unknown:
-          orient = SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RIP;
+          orient = AnatomicalOrientation(AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                         AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                         AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior);
           break;
       }
-      const SpatialOrientationAdapter::DirectionType dir = OrientAdapterType().ToDirectionCosines(orient);
-      const int                                      max_defined_orientation_dims = (dims > 3) ? 3 : dims;
+      const auto dir = orient.GetAsDirection();
+      const int  max_defined_orientation_dims = (dims > 3) ? 3 : dims;
       for (int d = 0; d < max_defined_orientation_dims; ++d)
       {
         std::vector<double> direction(dims, 0.0);
diff --git a/Modules/IO/PhilipsREC/src/itkPhilipsRECImageIO.cxx b/Modules/IO/PhilipsREC/src/itkPhilipsRECImageIO.cxx
index 4e00f816bce..6ced3046896 100644
--- a/Modules/IO/PhilipsREC/src/itkPhilipsRECImageIO.cxx
+++ b/Modules/IO/PhilipsREC/src/itkPhilipsRECImageIO.cxx
@@ -29,7 +29,7 @@
 #include "itkIOCommon.h"
 #include "itkByteSwapper.h"
 #include "itkMetaDataObject.h"
-#include "itkSpatialOrientationAdapter.h"
+#include "itkAnatomicalOrientation.h"
 #include "itksys/SystemTools.hxx"
 #include "itk_zlib.h"
 #include <fstream>
@@ -710,7 +710,7 @@ PhilipsRECImageIO::ReadImageInformation()
   AffineMatrix spacing;
   spacing.SetIdentity();
 
-  SpatialOrientationEnums::ValidCoordinateOrientations coord_orient;
+  AnatomicalOrientation coord_orient(AnatomicalOrientation::FromEnum::RSA);
 
   switch (par.sliceorient)
   {
@@ -744,7 +744,7 @@ PhilipsRECImageIO::ReadImageInformation()
       spacing[2][2] = par.vox[1];
   }
 
-  SpatialOrientationAdapter::DirectionType dir = SpatialOrientationAdapter().ToDirectionCosines(coord_orient);
+  AnatomicalOrientation::DirectionType dir = coord_orient.GetAsDirection();
 
   AffineMatrix direction;
   direction.SetIdentity();
diff --git a/Modules/IO/Siemens/src/itkSiemensVisionImageIO.cxx b/Modules/IO/Siemens/src/itkSiemensVisionImageIO.cxx
index 5ce05187c89..1e6b52a1290 100644
--- a/Modules/IO/Siemens/src/itkSiemensVisionImageIO.cxx
+++ b/Modules/IO/Siemens/src/itkSiemensVisionImageIO.cxx
@@ -223,8 +223,7 @@ SiemensVisionImageIO::ReadHeader(const char * FileNameToRead)
     if (text_angle_len.empty() || itk::Math::abs(std::stod(text_angle_len)) <= 45.0)
     {
       // hdr->imagePlane = itk::IOCommon::ITK_ANALYZE_ORIENTATION_IRP_CORONAL;
-      hdr->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+      hdr->coordinateOrientation = AnatomicalOrientation(itk::AnatomicalOrientation::NegativeEnum::RSP);
     }
     else
     {
@@ -232,15 +231,13 @@ SiemensVisionImageIO::ReadHeader(const char * FileNameToRead)
       {
         // hdr->imagePlane =
         // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_SAGITTAL;
-        hdr->coordinateOrientation =
-          itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_AIR;
+        hdr->coordinateOrientation = AnatomicalOrientation(itk::AnatomicalOrientation::NegativeEnum::AIR);
       }
       else
       {
         // hdr->imagePlane =
         // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_TRANSVERSE;
-        hdr->coordinateOrientation =
-          itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI;
+        hdr->coordinateOrientation = AnatomicalOrientation(itk::AnatomicalOrientation::NegativeEnum::RAI);
       }
     }
   }
@@ -250,8 +247,7 @@ SiemensVisionImageIO::ReadHeader(const char * FileNameToRead)
     {
       // hdr->imagePlane =
       // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_SAGITTAL;
-      hdr->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_AIR;
+      hdr->coordinateOrientation = AnatomicalOrientation(itk::AnatomicalOrientation::NegativeEnum::AIR);
     }
     else
     {
@@ -259,15 +255,13 @@ SiemensVisionImageIO::ReadHeader(const char * FileNameToRead)
       {
         // hdr->imagePlane =
         // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_CORONAL;
-        hdr->coordinateOrientation =
-          itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+        hdr->coordinateOrientation = AnatomicalOrientation(itk::AnatomicalOrientation::NegativeEnum::RSP);
       }
       else
       {
         // hdr->imagePlane =
         // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_TRANSVERSE;
-        hdr->coordinateOrientation =
-          itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI;
+        hdr->coordinateOrientation = AnatomicalOrientation(itk::AnatomicalOrientation::NegativeEnum::RAI);
       }
     }
   }
@@ -277,8 +271,7 @@ SiemensVisionImageIO::ReadHeader(const char * FileNameToRead)
     {
       // hdr->imagePlane =
       // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_TRANSVERSE;
-      hdr->coordinateOrientation =
-        itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI;
+      hdr->coordinateOrientation = AnatomicalOrientation(itk::AnatomicalOrientation::NegativeEnum::RAI);
     }
     else
     {
@@ -286,15 +279,13 @@ SiemensVisionImageIO::ReadHeader(const char * FileNameToRead)
       {
         // hdr->imagePlane =
         // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_CORONAL;
-        hdr->coordinateOrientation =
-          itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP;
+        hdr->coordinateOrientation = AnatomicalOrientation(itk::AnatomicalOrientation::NegativeEnum::RSP);
       }
       else
       {
         // hdr->imagePlane =
         // itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_ANALYZE_ORIENTATION_IRP_SAGITTAL;
-        hdr->coordinateOrientation =
-          itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_AIR;
+        hdr->coordinateOrientation = AnatomicalOrientation(itk::AnatomicalOrientation::NegativeEnum::AIR);
       }
     }
   }


Test patch:
diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt
index 461b2f96ed7..1bca0535242 100644
--- a/Modules/Core/Common/test/CMakeLists.txt
+++ b/Modules/Core/Common/test/CMakeLists.txt
@@ -1760,7 +1760,9 @@ set(ITKCommonGTests
     itkWeakPointerGTest.cxx
     itkCommonTypeTraitsGTest.cxx
     itkMetaDataDictionaryGTest.cxx
-    itkSpatialOrientationAdaptorGTest.cxx)
+    itkSpatialOrientationAdaptorGTest.cxx
+    itkAnatomicalOrientationGTest.cxx
+)
 creategoogletestdriver(ITKCommon "${ITKCommon-Test_LIBRARIES}" "${ITKCommonGTests}")
 # If `-static` was passed to CMAKE_EXE_LINKER_FLAGS, compilation fails. No need to
 # test this case.
diff --git a/Modules/Core/Common/test/itkAnatomicalOrientationGTest.cxx b/Modules/Core/Common/test/itkAnatomicalOrientationGTest.cxx
new file mode 100644
index 00000000000..f09b5fcf0e8
--- /dev/null
+++ b/Modules/Core/Common/test/itkAnatomicalOrientationGTest.cxx
@@ -0,0 +1,269 @@
+/*=========================================================================
+ *
+ *  Copyright NumFOCUS
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *         https://www.apache.org/licenses/LICENSE-2.0.txt
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *=========================================================================*/
+
+#include <gtest/gtest.h>
+
+#include "itkGTest.h"
+#ifndef ITK_FUTURE_LEGACY_REMOVE
+#  define ITK_LEGACY_SILENT
+#endif
+#include "itkAnatomicalOrientation.h"
+#include "itkImage.h"
+#include <sstream>
+
+
+TEST(AnatomicalOrientation, ConstructionAndValues)
+{
+  using itk::AnatomicalOrientation;
+  using OE = AnatomicalOrientation::PositiveEnum;
+  using NOE = AnatomicalOrientation::NegativeEnum;
+  using CE = AnatomicalOrientation::CoordinateEnum;
+  using ImageType = itk::Image<float, 3>;
+
+  ImageType::DirectionType d;
+
+  AnatomicalOrientation do1(OE::LPS);
+
+  EXPECT_EQ("LPS", do1.GetAsPositiveStringEncoding());
+  EXPECT_EQ(CE::RightToLeft, do1.GetPrimaryTerm());
+  EXPECT_EQ(CE::AnteriorToPosterior, do1.GetSecondaryTerm());
+  EXPECT_EQ(CE::InferiorToSuperior, do1.GetTertiaryTerm());
+  EXPECT_EQ(OE::LPS, do1.GetAsPositiveOrientation());
+  EXPECT_EQ(NOE::RAI, do1.GetAsNegativeOrientation());
+
+  d.SetIdentity();
+  EXPECT_EQ(d, do1.GetAsDirection());
+
+
+  do1 = AnatomicalOrientation::CreateFromPositiveStringEncoding("RAS");
+
+  EXPECT_EQ("RAS", do1.GetAsPositiveStringEncoding());
+  EXPECT_EQ(CE::LeftToRight, do1.GetPrimaryTerm());
+  EXPECT_EQ(CE::PosteriorToAnterior, do1.GetSecondaryTerm());
+  EXPECT_EQ(CE::InferiorToSuperior, do1.GetTertiaryTerm());
+  EXPECT_EQ(OE::RAS, do1.GetAsPositiveOrientation());
+  EXPECT_EQ(NOE::LPI, do1.GetAsNegativeOrientation());
+
+  d.Fill(0.0);
+  d(0, 0) = -1.0;
+  d(1, 1) = -1.0;
+  d(2, 2) = 1.0;
+  EXPECT_EQ(d, do1.GetAsDirection());
+
+
+  do1 = AnatomicalOrientation::CreateFromPositiveStringEncoding("rai");
+
+  EXPECT_EQ("RAI", do1.GetAsPositiveStringEncoding());
+  EXPECT_EQ(CE::LeftToRight, do1.GetPrimaryTerm());
+  EXPECT_EQ(CE::PosteriorToAnterior, do1.GetSecondaryTerm());
+  EXPECT_EQ(CE::SuperiorToInferior, do1.GetTertiaryTerm());
+  EXPECT_EQ(OE::RAI, do1.GetAsPositiveOrientation());
+  EXPECT_EQ(NOE::LPS, do1.GetAsNegativeOrientation());
+
+
+  do1 = AnatomicalOrientation::CreateFromNegativeStringEncoding("LPI");
+
+  EXPECT_EQ("RAS", do1.GetAsPositiveStringEncoding());
+  EXPECT_EQ("LPI", do1.GetAsNegativeStringEncoding());
+  EXPECT_EQ(CE::LeftToRight, do1.GetPrimaryTerm());
+  EXPECT_EQ(CE::PosteriorToAnterior, do1.GetSecondaryTerm());
+  EXPECT_EQ(CE::InferiorToSuperior, do1.GetTertiaryTerm());
+  EXPECT_EQ(OE::RAS, do1.GetAsPositiveOrientation());
+  EXPECT_EQ(NOE::LPI, do1.GetAsNegativeOrientation());
+
+  do1 = AnatomicalOrientation(OE::PIR);
+
+  EXPECT_EQ("PIR", do1.GetAsPositiveStringEncoding());
+  EXPECT_EQ(CE::AnteriorToPosterior, do1.GetPrimaryTerm());
+  EXPECT_EQ(CE::SuperiorToInferior, do1.GetSecondaryTerm());
+  EXPECT_EQ(CE::LeftToRight, do1.GetTertiaryTerm());
+  EXPECT_EQ(OE::PIR, do1.GetAsPositiveOrientation());
+  EXPECT_EQ(NOE::ASL, do1.GetAsNegativeOrientation());
+
+  d.Fill(0.0);
+  d(1, 0) = 1.0;
+  d(2, 1) = -1.0;
+  d(0, 2) = -1.0;
+  EXPECT_EQ(d, do1.GetAsDirection());
+
+  AnatomicalOrientation do2(d);
+
+  EXPECT_EQ("PIR", do2.GetAsPositiveStringEncoding());
+  EXPECT_EQ(CE::AnteriorToPosterior, do2.GetPrimaryTerm());
+  EXPECT_EQ(CE::SuperiorToInferior, do2.GetSecondaryTerm());
+  EXPECT_EQ(CE::LeftToRight, do2.GetTertiaryTerm());
+  EXPECT_EQ(OE::PIR, do2.GetAsPositiveOrientation());
+  EXPECT_EQ(NOE::ASL, do2.GetAsNegativeOrientation());
+
+  EXPECT_EQ(d, do2.GetAsDirection());
+
+  AnatomicalOrientation do3 = AnatomicalOrientation::CreateFromPositiveStringEncoding("something invalid");
+  EXPECT_EQ("INVALID", do3.GetAsPositiveStringEncoding());
+  EXPECT_EQ(CE::UNKNOWN, do3.GetPrimaryTerm());
+  EXPECT_EQ(CE::UNKNOWN, do3.GetSecondaryTerm());
+  EXPECT_EQ(CE::UNKNOWN, do3.GetTertiaryTerm());
+  EXPECT_EQ(OE::INVALID, do3.GetAsPositiveOrientation());
+  EXPECT_EQ(NOE::INVALID, do3.GetAsNegativeOrientation());
+}
+
+
+TEST(AnatomicalOrientation, ConvertDirectionToPositiveEnum)
+{
+  using itk::AnatomicalOrientation;
+  using OE = AnatomicalOrientation::PositiveEnum;
+  using ImageType = itk::Image<float, 3>;
+  ImageType::DirectionType d;
+  d.SetIdentity();
+
+  EXPECT_EQ(OE::LPS, AnatomicalOrientation(d));
+
+  d.Fill(0.0);
+  d(0, 0) = -1.0;
+  d(1, 1) = -1.0;
+  d(2, 2) = -1.0;
+  EXPECT_EQ(OE::RAI, AnatomicalOrientation(d));
+
+  d.Fill(0.0);
+  d(2, 0) = 1;
+  d(0, 1) = 1;
+  d(1, 2) = 1;
+  EXPECT_EQ(OE::SLP, AnatomicalOrientation(d));
+
+  d.Fill(0.0);
+  d(1, 0) = 1;
+  d(2, 1) = 1;
+  d(0, 2) = 1;
+  EXPECT_EQ(OE::PSL, AnatomicalOrientation(d));
+
+  d.Fill(0.0);
+  d(0, 0) = 1;
+  d(2, 1) = 1;
+  d(1, 2) = 1;
+  EXPECT_EQ(OE::LSP, AnatomicalOrientation(d));
+
+  d.Fill(0.0);
+  d(1, 0) = 1;
+  d(0, 1) = 1;
+  d(2, 2) = 1;
+  EXPECT_EQ(OE::PLS, AnatomicalOrientation(d));
+
+  d.Fill(0.0);
+  d(2, 0) = 1;
+  d(1, 1) = 1;
+  d(0, 2) = 1;
+  EXPECT_EQ(OE::SPL, AnatomicalOrientation(d));
+
+  const double                                 data[] = { 0.5986634407395047, 0.22716302314740483, -0.768113953548866,
+                          0.5627936241740271, 0.563067040943212,   0.6051601804419384,
+                          0.5699696670095713, -0.794576911518317,  0.20924175102261847 };
+  ImageType::DirectionType::InternalMatrixType m{ data };
+  d.GetVnlMatrix() = m;
+  EXPECT_EQ(OE::PIR, AnatomicalOrientation(d));
+}
+
+TEST(AnatomicalOrientation, ConvertPositiveEnumToDirection)
+{
+  using itk::AnatomicalOrientation;
+  using ImageType = itk::Image<float, 3>;
+  using OE = AnatomicalOrientation::PositiveEnum;
+
+  ImageType::DirectionType d;
+  d.SetIdentity();
+
+  EXPECT_EQ(d, AnatomicalOrientation(OE::LPS).GetAsDirection());
+
+  d.Fill(0.0);
+  d(0, 0) = -1.0;
+  d(1, 1) = -1.0;
+  d(2, 2) = -1.0;
+  EXPECT_EQ(d, AnatomicalOrientation(OE::RAI).GetAsDirection());
+
+  d.Fill(0.0);
+  d(2, 0) = 1;
+  d(0, 1) = 1;
+  d(1, 2) = 1;
+  EXPECT_EQ(d, AnatomicalOrientation(OE::SLP).GetAsDirection());
+
+  d.Fill(0.0);
+  d(1, 0) = 1;
+  d(2, 1) = 1;
+  d(0, 2) = 1;
+  EXPECT_EQ(d, AnatomicalOrientation(OE::PSL).GetAsDirection());
+
+  d.Fill(0.0);
+  d(0, 0) = 1;
+  d(2, 1) = 1;
+  d(1, 2) = 1;
+  EXPECT_EQ(d, AnatomicalOrientation(OE::LSP).GetAsDirection());
+
+  d.Fill(0.0);
+  d(1, 0) = 1;
+  d(0, 1) = 1;
+  d(2, 2) = 1;
+  EXPECT_EQ(d, AnatomicalOrientation(OE::PLS).GetAsDirection());
+
+  d.Fill(0.0);
+  d(2, 0) = 1;
+  d(1, 1) = 1;
+  d(0, 2) = 1;
+  EXPECT_EQ(d, AnatomicalOrientation(OE::SPL).GetAsDirection());
+}
+
+TEST(AntomicalOrientation, ToFromEnumInteroperability)
+{
+
+  using OE = itk::AnatomicalOrientation::PositiveEnum;
+  using FromOE = itk::AnatomicalOrientation::NegativeEnum;
+  using CE = itk::AnatomicalOrientation::CoordinateEnum;
+
+  static_assert(int(OE::RAI) == int(FromOE::LPS));
+  static_assert(int(OE::LPS) == int(FromOE::RAI));
+  static_assert(int(OE::RAS) == int(FromOE::LPI));
+  static_assert(int(OE::LPI) == int(FromOE::RAS));
+  static_assert(int(OE::PIR) == int(FromOE::ASL));
+  static_assert(int(OE::ASL) == int(FromOE::PIR));
+
+  itk::AnatomicalOrientation itk_rai(FromOE::RAI);
+
+  EXPECT_EQ(itk_rai, itk::AnatomicalOrientation(OE::LPS));
+  EXPECT_EQ(itk_rai.GetAsPositiveOrientation(), OE::LPS);
+  EXPECT_EQ(itk_rai.GetAsPositiveStringEncoding(), "LPS");
+  const std::array<CE, 3> expected_terms = { { CE::RightToLeft, CE::AnteriorToPosterior, CE::InferiorToSuperior } };
+  EXPECT_EQ(itk_rai.GetTerms(), expected_terms);
+}
+
+#ifndef ITK_FUTURE_LEGACY_REMOVE
+#  include "itkSpatialOrientation.h"
+TEST(AnatomicalOrientation, LegacyInteroperability)
+{
+
+  using OE = itk::AnatomicalOrientation::PositiveEnum;
+  using SOE = itk::SpatialOrientationEnums::ValidCoordinateOrientations;
+
+  // byte for byte compatibility, may assist with migration of bindings when types are not strictly enforced.
+  static_assert(int(SOE::ITK_COORDINATE_ORIENTATION_RAI) == int(OE::LPS));
+  static_assert(int(SOE::ITK_COORDINATE_ORIENTATION_LPS) == int(OE::RAI));
+  static_assert(int(SOE::ITK_COORDINATE_ORIENTATION_RSA) == int(OE::LIP));
+  static_assert(int(SOE::ITK_COORDINATE_ORIENTATION_ASL) == int(OE::PIR));
+
+  itk::AnatomicalOrientation itk_rai(SOE::ITK_COORDINATE_ORIENTATION_RAI);
+  EXPECT_EQ(itk_rai, OE::LPS);
+  EXPECT_EQ(itk_rai.GetAsPositiveOrientation(), OE::LPS);
+  EXPECT_EQ(itk_rai.GetAsPositiveStringEncoding(), "LPS");
+}
+#endif
diff --git a/Modules/IO/ImageBase/test/itkReadWriteImageWithDictionaryTest.cxx b/Modules/IO/ImageBase/test/itkReadWriteImageWithDictionaryTest.cxx
index 725025709e3..98aa6330c42 100644
--- a/Modules/IO/ImageBase/test/itkReadWriteImageWithDictionaryTest.cxx
+++ b/Modules/IO/ImageBase/test/itkReadWriteImageWithDictionaryTest.cxx
@@ -19,7 +19,7 @@
 #include "itkImageFileWriter.h"
 #include "itkIOCommon.h"
 #include "itkMetaDataObject.h"
-#include "itkSpatialOrientationAdapter.h"
+#include "itkAnatomicalOrientation.h"
 #include "itkTestingMacros.h"
 
 int
@@ -45,8 +45,7 @@ itkReadWriteImageWithDictionaryTest(int argc, char * argv[])
   inputImage->Allocate();
   inputImage->FillBuffer(0);
 
-  inputImage->SetDirection(itk::SpatialOrientationAdapter().ToDirectionCosines(
-    itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RIP));
+  inputImage->SetDirection(itk::AnatomicalOrientation::CreateFromPositiveStringEncoding("LSA").GetAsDirection());
 
   // Add some metadata in the dictionary
   itk::MetaDataDictionary & inputDictionary = inputImage->GetMetaDataDictionary();
diff --git a/Modules/IO/NIFTI/test/itkNiftiImageIOTest.h b/Modules/IO/NIFTI/test/itkNiftiImageIOTest.h
index 6bf97e9985f..c41dfa71511 100644
--- a/Modules/IO/NIFTI/test/itkNiftiImageIOTest.h
+++ b/Modules/IO/NIFTI/test/itkNiftiImageIOTest.h
@@ -30,7 +30,7 @@
 #include "itkNiftiImageIO.h"
 #include "itkMetaDataObject.h"
 #include "itkIOCommon.h"
-#include "itkSpatialOrientationAdapter.h"
+#include "itkAnatomicalOrientation.h"
 #include "itkDiffusionTensor3D.h"
 #include "itkAffineTransform.h"
 #include "itkVector.h"
@@ -228,8 +228,10 @@ template <typename ImageType>
 typename ImageType::DirectionType
 CORDirCosines()
 {
-  typename itk::SpatialOrientationAdapter::DirectionType CORdir = itk::SpatialOrientationAdapter().ToDirectionCosines(
-    itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RIP);
+  auto CORdir = itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                           itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                           itk::AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior)
+                  .GetAsDirection();
   typename ImageType::DirectionType dir;
   for (unsigned int i = 0; i < ImageType::ImageDimension; ++i)
   {
diff --git a/Modules/IO/NIFTI/test/itkNiftiImageIOTest4.cxx b/Modules/IO/NIFTI/test/itkNiftiImageIOTest4.cxx
index 64408d4e651..5ac8afc1550 100644
--- a/Modules/IO/NIFTI/test/itkNiftiImageIOTest4.cxx
+++ b/Modules/IO/NIFTI/test/itkNiftiImageIOTest4.cxx
@@ -71,7 +71,7 @@ itkNiftiImageIOTest4(int argc, char * argv[])
 
   Test4ImageType::DirectionType dir;
   dir.SetIdentity();
-#if 1
+
   // arbitrarily rotate the unit vectors to pick random direction
   // cosines;
   vnl_random randgen(8775070);
@@ -102,10 +102,6 @@ itkNiftiImageIOTest4(int argc, char * argv[])
     }
   }
 
-#else
-  dir = itk::SpatialOrientationAdapter().ToDirectionCosines(
-    itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PLI);
-#endif
   test4Image->SetDirection(dir);
   std::string fname("directionsTest.nii.gz");
   try
diff --git a/Modules/IO/NIFTI/test/itkNiftiReadAnalyzeTest.cxx b/Modules/IO/NIFTI/test/itkNiftiReadAnalyzeTest.cxx
index 5860d24ba6c..8310b3e354e 100644
--- a/Modules/IO/NIFTI/test/itkNiftiReadAnalyzeTest.cxx
+++ b/Modules/IO/NIFTI/test/itkNiftiReadAnalyzeTest.cxx
@@ -22,7 +22,7 @@
 #include "itkImageFileReader.h"
 #include "itkImageRegionConstIterator.h"
 #include "itkMath.h"
-#include "itkSpatialOrientationAdapter.h"
+#include "itkAnatomicalOrientation.h"
 
 // debug
 #include <map>
@@ -120,59 +120,6 @@ const unsigned char LittleEndian_img[] = {
   0x00, 0x00, 0xe0, 0x42, 0x00, 0x00, 0xe0, 0x42, 0x00, 0x00, 0xe0, 0x42,
 };
 
-// Map between axis string labels and spatial orientation
-std::map<itk::SpatialOrientationEnums::ValidCoordinateOrientations, std::string> codeToString = {
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RIP, "RIP" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LIP, "LIP" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP, "RSP" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LSP, "LSP" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RIA, "RIA" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LIA, "LIA" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSA, "RSA" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LSA, "LSA" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_IRP, "IRP" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_ILP, "ILP" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_SRP, "SRP" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_SLP, "SLP" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_IRA, "IRA" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_ILA, "ILA" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_SRA, "SRA" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_SLA, "SLA" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RPI, "RPI" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LPI, "LPI" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI, "RAI" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LAI, "LAI" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RPS, "RPS" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LPS, "LPS" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAS, "RAS" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LAS, "LAS" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PRI, "PRI" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PLI, "PLI" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_ARI, "ARI" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_ALI, "ALI" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PRS, "PRS" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PLS, "PLS" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_ARS, "ARS" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_ALS, "ALS" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_IPR, "IPR" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_SPR, "SPR" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_IAR, "IAR" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_SAR, "SAR" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_IPL, "IPL" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_SPL, "SPL" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_IAL, "IAL" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_SAL, "SAL" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PIR, "PIR" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PSR, "PSR" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_AIR, "AIR" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_ASR, "ASR" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PIL, "PIL" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PSL, "PSL" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_AIL, "AIL" },
-  { itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_ASL, "ASL" }
-};
-
-
 /** WriteFile
  * Write out a char array as binary
  */
@@ -229,19 +176,19 @@ ReadImage(const std::string &                     fileName,
 
 
 int
-itkNiftiAnalyzeContentsAndCoordinatesTest(char *                                                    argv[],
-                                          unsigned char                                             hist_orient_code,
-                                          itk::SpatialOrientationEnums::ValidCoordinateOrientations expected_code,
-                                          itk::NiftiImageIOEnums::Analyze75Flavor                   analyze_mode,
-                                          bool                                                      flip_x = false)
+itkNiftiAnalyzeContentsAndCoordinatesTest(char *                                  argv[],
+                                          unsigned char                           hist_orient_code,
+                                          itk::AnatomicalOrientation              expected_code,
+                                          itk::NiftiImageIOEnums::Analyze75Flavor analyze_mode,
+                                          bool                                    flip_x = false)
 {
   std::string hdrName(argv[1]);
   hdrName += "/littleEndian_";
-  hdrName += codeToString[expected_code];
+  hdrName += expected_code.GetAsPositiveStringEncoding();
   hdrName += ".hdr";
   std::string imgName(argv[1]);
   imgName += "/littleEndian_";
-  imgName += codeToString[expected_code];
+  imgName += expected_code.GetAsPositiveStringEncoding();
   imgName += ".img";
 
   // hack the header to have proper orientation code
@@ -301,14 +248,13 @@ itkNiftiAnalyzeContentsAndCoordinatesTest(char *
     }
   }
 
-  itk::SpatialOrientationEnums::ValidCoordinateOrientations orientation_code =
-    itk::SpatialOrientationAdapter().FromDirectionCosines(img->GetDirection());
+  const itk::AnatomicalOrientation orientation_code(img->GetDirection());
   // verify the correct orientation :
   if (orientation_code != expected_code)
   {
     std::cerr << "Analyze orientation " << static_cast<int>(hist_orient_code) << std::endl;
-    std::cerr << "expected orientation " << codeToString[expected_code] << " but found "
-              << codeToString[orientation_code] << std::endl;
+    std::cerr << "expected orientation " << expected_code.GetAsPositiveStringEncoding() << " but found "
+              << orientation_code.GetAsPositiveStringEncoding() << std::endl;
     return EXIT_FAILURE;
   }
 
@@ -318,7 +264,7 @@ itkNiftiAnalyzeContentsAndCoordinatesTest(char *
             << "negative x step:" << (flip_x ? "true" : "false") << std::endl
             << "Origin   :" << img->GetOrigin() << std::endl
             << "Spacing  :" << img->GetSpacing() << std::endl
-            << "Code     :" << codeToString[orientation_code] << std::endl
+            << "Code     :" << orientation_code.GetAsPositiveStringEncoding() << std::endl
             << "Direction:" << img->GetDirection() << std::endl;
 
   return EXIT_SUCCESS;
@@ -343,95 +289,129 @@ itkNiftiReadAnalyzeTest(int argc, char * argv[])
   return itkNiftiAnalyzeContentsAndCoordinatesTest(
            argv,
            0,
-           itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RPI,
+           itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                      itk::AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior,
+                                      itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
            itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeReject) != EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                0,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RPI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeSPM) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                1,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RIP,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeSPM) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                2,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PIR,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::RightToLeft),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeSPM) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                3,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeSPM) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                4,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RSP,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::SuperiorToInferior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeSPM) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                5,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_PIL,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::LeftToRight),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeSPM) == EXIT_FAILURE ||
              // ITK4 default behaviour: reader should ignore orientation code and always produce RAI ,
              // there should be a warning on console
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                0,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4Warning) == EXIT_FAILURE ||
              // ITK4 reader should ignore orientation code and always produce RAI
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                0,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                1,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                2,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                3,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                5,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4) == EXIT_FAILURE ||
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                5,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RAI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4) == EXIT_FAILURE ||
              // flip X  axis , SPM reader should respect this
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                0,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LPI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::LeftToRight,
+                                          itk::AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeSPM,
                true) == EXIT_FAILURE ||
              // flip X  axis , ITK4 reader should respect this
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                0,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_LAI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::LeftToRight,
+                                          itk::AnatomicalOrientation::CoordinateEnum::AnteriorToPosterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeITK4,
                true) == EXIT_FAILURE ||
              // flip X  axis , FSL reader should ignore this
              itkNiftiAnalyzeContentsAndCoordinatesTest(
                argv,
                0,
-               itk::SpatialOrientationEnums::ValidCoordinateOrientations::ITK_COORDINATE_ORIENTATION_RPI,
+               itk::AnatomicalOrientation(itk::AnatomicalOrientation::CoordinateEnum::RightToLeft,
+                                          itk::AnatomicalOrientation::CoordinateEnum::PosteriorToAnterior,
+                                          itk::AnatomicalOrientation::CoordinateEnum::InferiorToSuperior),
                itk::NiftiImageIOEnums::Analyze75Flavor::AnalyzeFSL,
                true) == EXIT_FAILURE