Nifti (RPI orientation) file exported to DICOM - wrong orientation

Don’t understand me wrong, ITK handles image orientation ideally, it is not a problem with ITK’s orientation design, it is just required step before exporting to multi-frame DICOM.

If someone cares - link to demo program with required re-orientation step before exporting to multi-frame DICOM . All 48 possible orientations test images (in MHA format with R/L marks) are also inside.

Demo

#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkSpatialOrientation.h>
#include <itkOrientImageFilter.h>
#include <iostream>
#include <string>

int main(int argc, char ** argv)
{
  if (argc < 2)
  {
    std::cout << "File name is required" << std::endl;
    return 0;
  }
  typedef itk::Image<unsigned char, 3> ImageTypeUC;
  typedef itk::ImageFileReader<ImageTypeUC> ReaderType;
  typedef itk::ImageFileWriter<ImageTypeUC> WriterType;
  ReaderType::Pointer reader = ReaderType::New();
  try
  {
    reader->SetFileName(argv[1]);
    reader->Update();
  }
  catch (itk::ExceptionObject & ex)
  {
    std::cout << ex.GetDescription() << std::endl;
    return 1;
  }
  ImageTypeUC::Pointer image = reader->GetOutput();
  itk::SpatialOrientationAdapter adapter;
  unsigned int x = 0;
  const unsigned int orientation = static_cast<unsigned int>(
     adapter.FromDirectionCosines(image->GetDirection()));
  switch (orientation)
  {
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIL:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIR;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ALS:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ALI;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ARI:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ARS;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ASR:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ASL;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IAR:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IAL;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ILA:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ILP;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IPL:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IPR;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IRP:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_IRA;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LAI:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LAS;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LIP:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LIA;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPS:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPI;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LSA:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LSP;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PIR:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PIL;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PLI:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PLS;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PRS:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PRI;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PSL:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_PSR;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAS:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAI;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIA:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIP;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPI:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPS;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RSP:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RSA;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SAL:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SAR;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SLP:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SLA;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SPR:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SPL;
    break;
  case itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SRA:
    x = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_SRP;
    break;
  default:
   break;
  }
  const std::string f = std::string(argv[1]) + std::string(".dcm");
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(f.c_str());
  if (x != 0)
  {
    typedef itk::OrientImageFilter<ImageTypeUC,ImageTypeUC>
      OrientImageFilterType;
    OrientImageFilterType::Pointer filter =
      OrientImageFilterType::New();
    try
    {
      filter->SetInput(image);
      filter->UseImageDirectionOn();
      filter->SetDesiredCoordinateOrientation(
        static_cast
          <itk::SpatialOrientation::ValidCoordinateOrientationFlags>
            (x));
      filter->Update();
      writer->SetInput(filter->GetOutput());
    }
    catch (itk::ExceptionObject & ex)
    {
      std::cout << ex.GetDescription() << std::endl;
      return 1;
    }
  }
  else
  {
    writer->SetInput(image);
  }
  try
  {
    writer->Update();
  }
  catch (itk::ExceptionObject & ex)
  {
    std::cout << ex.GetDescription() << std::endl;
    return 1;
  }
  return 0;
}
1 Like