cmtkVolumeFromFileDICOM.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 2004-2010 SRI International
00004 //
00005 //  Copyright 1997-2010 Torsten Rohlfing
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2398 $
00026 //
00027 //  $LastChangedDate: 2010-10-05 14:54:37 -0700 (Tue, 05 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkVolumeFromFile.h"
00034 
00035 #include <Base/cmtkTypedArray.h>
00036 #include <System/cmtkConsole.h>
00037 #include <System/cmtkException.h>
00038 
00039 #include <dcmtk/dcmdata/dcdeftag.h>
00040 #include <dcmtk/dcmimgle/didocu.h>
00041 #include <dcmtk/dcmimgle/diutils.h>
00042 
00043 #ifdef CMTK_HAVE_DCMTK_JPEG
00044 #  include <djdecode.h>
00045 #endif
00046 
00047 #ifdef HAVE_SYS_TYPES_H
00048 #  include <sys/types.h>
00049 #endif
00050 
00051 #include <memory>
00052 #include <string.h>
00053 #include <stdio.h>
00054 #include <ctime>
00055 
00056 namespace
00057 cmtk
00058 {
00059 
00060 const UniformVolume::SmartPtr
00061 VolumeFromFile::ReadDICOM( const char *path )
00062 {
00063 #ifdef CMTK_HAVE_DCMTK_JPEG
00064   // register global decompression codecs
00065   static bool decodersRegistered = false;
00066   if ( ! decodersRegistered ) 
00067     {
00068     DJDecoderRegistration::registerCodecs( EDC_photometricInterpretation, EUC_default, EPC_default, 1 );
00069     decodersRegistered = true;
00070     }
00071 #endif
00072     
00073   std::auto_ptr<DcmFileFormat> fileformat( new DcmFileFormat );
00074   if (!fileformat.get()) 
00075     {
00076     throw Exception( "Could not create DICOM file format object." );
00077     }
00078     
00079   fileformat->transferInit();
00080   fileformat->loadFile( path );
00081   fileformat->transferEnd();
00082     
00083   DcmDataset *dataset = fileformat->getAndRemoveDataset();
00084   if ( !dataset ) 
00085     {
00086     throw Exception( "File format has NULL dataset." );
00087     }
00088     
00089   const E_TransferSyntax xfer = dataset->getOriginalXfer();
00090   std::auto_ptr<DiDocument> document( new DiDocument( dataset, xfer, CIF_AcrNemaCompatibility ) );
00091   if ( ! document.get() || ! document->good() ) 
00092     {
00093     throw Exception( "Could not create document representation." );
00094     }
00095     
00096   DcmElement *delem = NULL;
00097   Uint16 tempUint16 = 0;
00098 
00099   int dims[3] = { 0, 0, 0 };
00100   if ( ( delem = document->search( DCM_Rows ) ) ) 
00101     {
00102     delem->getUint16(tempUint16);
00103     dims[1]=(int)tempUint16;
00104     }
00105     
00106   if ( ( delem = document->search( DCM_Columns ) ) ) 
00107     {
00108     delem->getUint16(tempUint16);
00109     dims[0]=(int)tempUint16;
00110     }
00111     
00112   if ( ! document->getValue( DCM_NumberOfFrames, tempUint16 ) ) 
00113     {
00114     tempUint16 = 1;
00115     }
00116   dims[2] = tempUint16;
00117 
00118   unsigned short bytesPerPixel = 0;
00119   unsigned short bitsAllocated = 0;
00120 
00121   if ( ( delem = document->search( DCM_BitsAllocated ) ) ) 
00122     {
00123     delem->getUint16( bitsAllocated );
00124     bytesPerPixel = (((int)bitsAllocated+7)/8);
00125     } 
00126   else
00127     {
00128     // No "BitsAllocated" tag; use "BitsStored" instead.
00129     if ( ( delem = document->search( DCM_BitsStored ) ) ) 
00130       {
00131       delem->getUint16( bitsAllocated );
00132       bytesPerPixel = (((int)bitsAllocated+7)/8);
00133       }
00134     }
00135     
00136   Types::Coordinate pixelSize[3];
00137 
00138   // get calibration from image
00139   const bool hasPixelSpacing = (document->getValue(DCM_PixelSpacing, pixelSize[0], 0) > 0);
00140   if ( hasPixelSpacing )
00141     {
00142     if (document->getValue(DCM_PixelSpacing, pixelSize[1], 1) < 2) 
00143       {
00144       throw Exception( "DICOM file does not have two elements in pixel size tag" );
00145       }
00146     } 
00147   else
00148     throw Exception( "DICOM file does not specify pixel size" );
00149     
00150   const unsigned long totalImageSizePixels = dims[0] * dims[1] * dims[2];
00151     
00152   double rescaleIntercept, rescaleSlope;
00153   const bool haveRescaleIntercept = (0 != document->getValue( DCM_RescaleIntercept, rescaleIntercept ));
00154   if ( ! haveRescaleIntercept )
00155     rescaleIntercept = 0;
00156     
00157   const bool haveRescaleSlope = (0 != document->getValue( DCM_RescaleSlope, rescaleSlope ));
00158   if ( ! haveRescaleSlope )
00159     rescaleSlope = 1;
00160     
00161   bool paddingFlag = false;
00162   Uint16 paddingValue = 0;
00163   if ( (dataset->findAndGetUint16( DCM_PixelPaddingValue, paddingValue )).good() ) 
00164     {
00165     paddingFlag = true;
00166     } 
00167 
00168   TypedArray::SmartPtr dataArray;
00169     
00170 #ifdef DCM_VariablePixelData
00171   delem = document->search( DCM_VariablePixelData );
00172 #else
00173   delem = document->search( DCM_ACR_NEMA_2C_VariablePixelData );
00174 #endif
00175   if (!delem)
00176     delem = document->search( DCM_PixelData );
00177     
00178   if (delem) 
00179     {
00180     if ( (delem->getTag().getEVR() == EVR_OW) || (bitsAllocated > 8) ) 
00181       {
00182       Uint16 *pdata = NULL;
00183       delem->getUint16Array(pdata);
00184       dataArray = TypedArray::SmartPtr( TypedArray::Create( TYPE_SHORT, pdata, totalImageSizePixels, true /*freeArray*/ ) );
00185       } 
00186     else 
00187       {
00188       Uint8 *pdata = NULL;
00189       delem->getUint8Array(pdata);
00190       dataArray = TypedArray::SmartPtr( TypedArray::Create( TYPE_CHAR, pdata, totalImageSizePixels, true /*freeArray*/ ) );
00191       }
00192       
00193     if ( paddingFlag )
00194       dataArray->SetPaddingValue( paddingValue );
00195       
00196     if ( haveRescaleIntercept || haveRescaleSlope ) 
00197       {
00198       dataArray->Rescale( rescaleSlope, rescaleIntercept );
00199       }
00200     delem->detachValueField();
00201     }
00202   else
00203     {
00204     throw( "Could not read pixel data from DICOM file" );
00205     }
00206     
00207   // now some more manual readings...
00208     
00209   // get slice spacing from multi-slice images.
00210   if ( ! document->getValue( DCM_SpacingBetweenSlices, pixelSize[2] ) )
00211     {
00212     pixelSize[2] = 0;
00213     }
00214     
00215   // get original image position from file.
00216   UniformVolume::CoordinateVectorType imageOrigin( UniformVolume::CoordinateVectorType::Init( 0 ) );
00217   const char *image_position_s = NULL;
00218   if ( ! document->getValue( DCM_ImagePositionPatient, image_position_s ) ) 
00219     {
00220     // ImagePositionPatient tag not present, try ImagePosition instead
00221 #ifdef DCM_ImagePosition
00222     document->getValue( DCM_ImagePosition, image_position_s );
00223 #else
00224     document->getValue( DCM_ACR_NEMA_ImagePosition, image_position_s );
00225 #endif
00226     }
00227   if ( image_position_s ) 
00228     {
00229     double xyz[3];
00230     if ( 3 == sscanf( image_position_s,"%lf%*c%lf%*c%lf", xyz, xyz+1, xyz+2 ) ) 
00231       {
00232       imageOrigin = UniformVolume::CoordinateVectorType( xyz );
00233       }
00234     }
00235     
00236   // get original image direction from file.
00237   UniformVolume::CoordinateVectorType imageOrientationX( UniformVolume::CoordinateVectorType::Init( 0 ) );
00238   imageOrientationX[0] = 1;
00239   UniformVolume::CoordinateVectorType imageOrientationY( UniformVolume::CoordinateVectorType::Init( 0 ) );
00240   imageOrientationY[1] = 1;
00241 
00242   const char *image_orientation_s = NULL;
00243 #ifdef DCM_ImageOrientation
00244   if ( ! document->getValue( DCM_ImageOrientation, image_orientation_s ) )
00245 #else
00246     if ( ! document->getValue( DCM_ACR_NEMA_ImageOrientation, image_orientation_s ) )
00247 #endif
00248       {
00249       // ImageOrientation tag not present, try ImageOrientationPatient
00250       // instead
00251       document->getValue( DCM_ImageOrientationPatient, image_orientation_s );
00252       }
00253   if ( image_orientation_s ) 
00254     {
00255     double dx[3], dy[3];
00256     if ( 6 == sscanf( image_orientation_s, "%lf%*c%lf%*c%lf%*c%lf%*c%lf%*c%lf", dx, dx+1, dx+2, dy, dy+1, dy+2 ) ) 
00257       {
00258       imageOrientationX = UniformVolume::CoordinateVectorType( dx );
00259       imageOrientationY = UniformVolume::CoordinateVectorType( dy );
00260       }
00261     }
00262   const Types::Coordinate size[3] = { pixelSize[0] * (dims[0]-1), pixelSize[1] * (dims[1]-1), pixelSize[1] * (dims[1]-1) };  
00263   return UniformVolume::SmartPtr( new UniformVolume( UniformVolume::IndexType( dims ), UniformVolume::CoordinateVectorType( size ), dataArray ) );
00264 }
00265 
00266 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines