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.
#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;
}