00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
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
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
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 ) );
00185 }
00186 else
00187 {
00188 Uint8 *pdata = NULL;
00189 delem->getUint8Array(pdata);
00190 dataArray = TypedArray::SmartPtr( TypedArray::Create( TYPE_CHAR, pdata, totalImageSizePixels, true ) );
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
00208
00209
00210 if ( ! document->getValue( DCM_SpacingBetweenSlices, pixelSize[2] ) )
00211 {
00212 pixelSize[2] = 0;
00213 }
00214
00215
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
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
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
00250
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 }