[Insight-developers] enhancement to itk::GDCMImageIO

Kent Williams norman-k-williams at uiowa.edu
Wed Feb 9 15:44:59 EST 2005


Enclosed is a context diff for a proposed change to itkGDCMImageIO.cxx, 
which sets the ITK_CoordinateOrientation attribute in the 
MetadataDictionary for images read in via GDCM.

I didn't just check it in, partly because it's relatively late in the 
day, and partly because I would like feedback about image orientation in 
ImageIO in general, and the way I've added it to the GDCMImageIO class 
in particular.

I don't think what I've done would break anything but I've been wrong 
before ;-)
-------------- next part --------------
*** itkGDCMImageIO.cxx.~1.54.~	2005-01-25 09:45:48.000000000 -0600
--- itkGDCMImageIO.cxx	2005-02-09 13:39:37.000000000 -0600
***************
*** 18,24 ****
  
  =========================================================================*/
  #include "itkGDCMImageIO.h"
! 
  #include "itkMetaDataObject.h"
  #include <itksys/Base64.h>
  #include "gdcm/src/gdcmValEntry.h" //internal of gdcm
--- 18,24 ----
  
  =========================================================================*/
  #include "itkGDCMImageIO.h"
! #include "itkIOCommon.h"
  #include "itkMetaDataObject.h"
  #include <itksys/Base64.h>
  #include "gdcm/src/gdcmValEntry.h" //internal of gdcm
***************
*** 258,263 ****
--- 258,413 ----
    file.close();
  }
  
+ namespace gdcmOrient
+ {
+ inline float Abs(float x)
+ {
+   if(x < 0)
+     return -x;
+   return x;
+ }
+ 
+ inline unsigned Max3(float x, float y, float z)
+ {
+   if(Abs(x) > Abs(y) && Abs(x) > Abs(z))
+     {
+     return 0;
+     }
+   if(Abs(y) > Abs(x) && Abs(y) > Abs(z))
+     {
+     return 1;
+     }
+   if(Abs(z) > Abs(x) && Abs(z) > Abs(y))
+     {
+     return 2;
+     }
+   // they must all be equal, so just say x
+   return 0;
+ }
+ 
+ inline int Sign(float x)
+ {
+   if(x < 0)
+     return -1;
+   return 1;
+ }
+ 
+ static void getcosines(const std::string &orientstring,float *cosines)
+ {
+   int i = 0;
+   std::string::size_type numstart, numend;
+   numstart = 0;
+   while(numstart != std::string::npos)
+     {
+     numend = orientstring.find("\\",numstart);
+     while(numstart != numend && orientstring[numstart] == ' ')
+       {
+       numstart++;
+       }
+     cosines[i++] = atof(orientstring.substr(numstart,numend-numstart).c_str());
+     numstart = (numend == std::string::npos ? numend : numend + 1);
+     }
+ }
+ //
+ // this is all based on this from the DICOM standard
+ //
+ // C.7.6.2.1.1
+ // Image Orientation (0020,0037) specifies the direction 
+ // cosines of the first row and the first column with 
+ // respect to the patient. These Attributes shall be 
+ // provide as a pair. Row value for the x, y, and z 
+ // axes respectively followed by the Column value for 
+ // the x, y, and z axes respectively. The direction 
+ // of the axes is defined fully by the patient's 
+ // orientation. The x-axis is increasing to the 
+ // left hand side of the patient. The y-axis is increasing 
+ // to the posterior side of the patient. The z-axis is 
+ // increasing toward the head of the patient. The patient 
+ // based coordinate system is a right handed system, 
+ // i.e. the vector cross product of a unit vector 
+ // along the positive x-axis and a unit vector 
+ // along the positive y-axis is equal to a unit 
+ // vector along the positive z-axis.
+ 
+ static SpatialOrientation::ValidCoordinateOrientationFlags 
+ dicomOrient(const std::string &orientstring)
+ {
+   float cosines[6];
+   int axes[9] = {0,0,0,0,0,0,0,0,0};
+   int dominant_axis;
+ 
+   // convert orientation string to floats
+   getcosines(orientstring,cosines);
+ 
+   // figure out the dominant axis of the row
+   dominant_axis = Max3(cosines[0],
+                        cosines[1],
+                        cosines[2]);
+   axes[dominant_axis] = 
+     Sign(cosines[dominant_axis]);
+ 
+   // figure the dominant axis of the column dimension
+   dominant_axis = Max3(cosines[3],
+                        cosines[4],
+                        cosines[5]);
+   axes[dominant_axis + 3] =
+     Sign(cosines[dominant_axis + 3]);
+ 
+   // cross product to get slice direction
+   axes[6] = axes[1] * axes[5] - axes[2] * axes[4];
+   axes[7] = axes[2] * axes[3] - axes[0] * axes[5];
+   axes[8] = axes[0] * axes[4] - axes[1] * axes[3];
+ 
+   //
+   // swizzle up the spatial orientation.
+   // this is based on the idea that SpatialOrientation in the patient's
+   // frame of reference.
+ #define SICTZero static_cast<SpatialOrientation::CoordinateTerms>(0)
+   SpatialOrientation::CoordinateTerms terms[3] = {SICTZero,SICTZero,SICTZero};
+   for(unsigned i = 0; i < 3; i++)
+     {
+     if(axes[(i*3)] == 1)
+       {
+       terms[i] = SpatialOrientation::ITK_COORDINATE_Right;
+       }
+     else if(axes[(i*3)] == -1)
+       {
+       terms[i] = SpatialOrientation::ITK_COORDINATE_Left;
+       }
+     else if(axes[(i*3)+1] == 1)
+       {
+       terms[i] = SpatialOrientation::ITK_COORDINATE_Anterior;
+       }
+     else if(axes[(i*3)+1] == -1)
+       {
+       terms[i] = SpatialOrientation::ITK_COORDINATE_Posterior;
+       }
+     else if(axes[(i*3)+2] == 1)
+       {
+       terms[i] = SpatialOrientation::ITK_COORDINATE_Inferior;
+       }
+     else if(axes[(i*3)+2] == -1)
+       {
+       terms[i] = SpatialOrientation::ITK_COORDINATE_Superior;
+       }
+     }
+   //
+   // all terms must be defined, otherwise just punt
+   if(terms[0] == SICTZero || terms[1] == SICTZero || terms[2] == SICTZero)
+     {
+     return SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIP;
+     }
+   return static_cast<SpatialOrientation::ValidCoordinateOrientationFlags>
+     ((terms[0] << 
+      SpatialOrientation::ITK_COORDINATE_PrimaryMinor) +
+     (terms[1] << 
+      SpatialOrientation::ITK_COORDINATE_SecondaryMinor) +
+     (terms[2] << 
+      SpatialOrientation::ITK_COORDINATE_TertiaryMinor));
+     
+ }
+ }
+ 
  void GDCMImageIO::InternalReadImageInformation(std::ifstream& file)
  {
    //read header
***************
*** 395,400 ****
--- 545,564 ----
  
      d = header.GetNextEntry();
    }
+   //
+   // encode the image orientation, based on Image Orientation (Patient)
+   SpatialOrientation::ValidCoordinateOrientationFlags coord_orient;
+   std::string iop = header.GetEntryByNumber(0x0020,0x0037);
+   if(iop == "gdcm::Unfound")
+     {
+     // total punt, but any value has a 1 in 48 chance of being right.
+     coord_orient = SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIP;
+     }
+   else
+     {
+     coord_orient = gdcmOrient::dicomOrient(iop);
+     }
+     itk::EncapsulateMetaData<SpatialOrientation::ValidCoordinateOrientationFlags>(dico,ITK_CoordinateOrientation, coord_orient);
  }
  
  void GDCMImageIO::ReadImageInformation()


More information about the Insight-developers mailing list