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 "cmtkDICOM.h"
00034
00035 #include <Base/cmtkTypedArray.h>
00036
00037 #include <System/cmtkConsole.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
00062
00063 ScalarImage*
00064 DICOM::Read
00065 ( const char *path )
00066 {
00067 ScalarImage* image = NULL;
00068
00069 #ifdef CMTK_HAVE_DCMTK_JPEG
00070
00071 static bool decodersRegistered = false;
00072 if ( ! decodersRegistered )
00073 {
00074 DJDecoderRegistration::registerCodecs( EDC_photometricInterpretation, EUC_default, EPC_default, 1 );
00075 decodersRegistered = true;
00076 }
00077 #endif
00078
00079 std::auto_ptr<DcmFileFormat> fileformat( new DcmFileFormat );
00080 if (!fileformat.get())
00081 {
00082 StdErr << "ERROR: Could not create DICOM file format object.\n";
00083 return NULL;
00084 }
00085
00086 fileformat->transferInit();
00087 OFCondition status = fileformat->loadFile( path );
00088 fileformat->transferEnd();
00089
00090 if ( !status.good() )
00091 {
00092 StdErr << "Error: cannot read DICOM file " << path << " (" << status.text() << ")\n";
00093 throw (0);
00094 }
00095
00096 DcmDataset *dataset = fileformat->getAndRemoveDataset();
00097
00098 if ( !dataset )
00099 {
00100 StdErr << "ERROR: File format has NULL dataset.\n";
00101 return NULL;
00102 }
00103
00104 std::auto_ptr<DiDocument> document( new DiDocument( dataset, dataset->getOriginalXfer(), CIF_AcrNemaCompatibility ) );
00105 if ( ! document.get() || ! document->good() )
00106 {
00107 StdErr << "ERROR: Could not create document representation.\n";
00108 return NULL;
00109 }
00110
00111 Uint16 dimsX, dimsY;
00112 if ( ! ( document->getValue( DCM_Columns, dimsX ) && document->getValue( DCM_Rows, dimsY ) ) )
00113 {
00114 StdErr << "ERROR: File " << path << " has no DCM_Columns/DCM_Rows tags.\n";
00115 return NULL;
00116 }
00117
00118 Uint16 numberOfFrames = 1;
00119 if ( ! document->getValue( DCM_NumberOfFrames, numberOfFrames ) )
00120 numberOfFrames = 1;
00121 image = new ScalarImage( dimsX, dimsY, numberOfFrames );
00122
00123
00124 double calibrationX = -1, calibrationY = -1;
00125 bool hasPixelSpacing = (document->getValue(DCM_PixelSpacing, calibrationX, 0) > 0);
00126 if ( hasPixelSpacing )
00127 {
00128 if ( document->getValue(DCM_PixelSpacing, calibrationY, 1) < 2)
00129 calibrationY = calibrationX;
00130 }
00131 else
00132 calibrationX = calibrationY = -1;
00133 image->SetPixelSize( calibrationX, calibrationY );
00134
00135 Uint16 bitsAllocated = 0;
00136 if ( ! document->getValue( DCM_BitsAllocated, bitsAllocated ) )
00137
00138 document->getValue( DCM_BitsStored, bitsAllocated );
00139
00140 bool pixelDataSigned = false;
00141 Uint16 pixelRepresentation = 0;
00142 if ( document->getValue( DCM_PixelRepresentation, pixelRepresentation ) > 0)
00143 pixelDataSigned = (pixelRepresentation == 1);
00144
00145 unsigned long totalImageSizePixels = image->GetDims()[AXIS_X] * image->GetDims()[AXIS_Y] * image->GetNumberOfFrames();
00146
00147 double rescaleIntercept, rescaleSlope;
00148 const bool haveRescaleIntercept = (0 != document->getValue( DCM_RescaleIntercept, rescaleIntercept ));
00149 if ( ! haveRescaleIntercept )
00150 rescaleIntercept = 0;
00151
00152 const bool haveRescaleSlope = (0 != document->getValue( DCM_RescaleSlope, rescaleSlope ));
00153 if ( ! haveRescaleSlope )
00154 rescaleSlope = 1;
00155
00156 pixelDataSigned = pixelDataSigned || (rescaleIntercept < 0);
00157
00158 TypedArray::SmartPtr pixelDataArray;
00159
00160 #ifdef DCM_VariablePixelData
00161 DcmElement *delem = document->search( DCM_VariablePixelData );
00162 #else
00163 DcmElement *delem = document->search( DCM_ACR_NEMA_2C_VariablePixelData );
00164 #endif
00165 if (!delem)
00166 delem = document->search( DCM_PixelData );
00167
00168 if (delem)
00169 {
00170 if ( (delem->getTag().getEVR() == EVR_OW) || (bitsAllocated > 8) )
00171 {
00172 Uint16 *pdata = NULL;
00173 delem->getUint16Array(pdata);
00174 if ( pixelDataSigned )
00175 {
00176 pixelDataArray = TypedArray::Create( TYPE_SHORT, pdata, totalImageSizePixels );
00177 }
00178 else
00179 {
00180 pixelDataArray = TypedArray::Create( TYPE_USHORT, pdata, totalImageSizePixels );
00181 }
00182 }
00183 else
00184 {
00185 Uint8 *pdata = NULL;
00186 delem->getUint8Array(pdata);
00187 if ( pixelDataSigned )
00188 {
00189 pixelDataArray = TypedArray::Create( TYPE_CHAR, pdata, totalImageSizePixels );
00190 }
00191 else
00192 {
00193 pixelDataArray = TypedArray::Create( TYPE_BYTE, pdata, totalImageSizePixels );
00194 }
00195 }
00196 delem->detachValueField();
00197 }
00198
00199 if ( ! pixelDataArray )
00200 {
00201 StdErr.printf( "Could not read pixel data from image file\n%s", path );
00202 }
00203
00204 Uint16 paddingValue = 0;
00205 if ( ( dataset->findAndGetUint16( DCM_PixelPaddingValue, paddingValue )).good() )
00206 pixelDataArray->SetPaddingValue( paddingValue );
00207
00208 if ( haveRescaleIntercept || haveRescaleSlope )
00209 pixelDataArray->Rescale( rescaleSlope, rescaleIntercept );
00210
00211 image->SetPixelData( TypedArray::SmartPtr( pixelDataArray ) );
00212
00213
00214
00215
00216 double frameToFrame = 0;
00217 if ( document->getValue( DCM_SpacingBetweenSlices, frameToFrame ) )
00218 image->SetFrameToFrameSpacing( frameToFrame );
00219
00220
00221 double sliceLocation = 0;
00222 if ( ! document->getValue( DCM_SliceLocation, sliceLocation ) )
00223 {
00224 #ifdef DCM_Location
00225 document->getValue( DCM_Location, sliceLocation );
00226 #else
00227 document->getValue( DCM_ACR_NEMA_Location, sliceLocation );
00228 #endif
00229 }
00230 image->SetImageSlicePosition( sliceLocation );
00231
00232
00233
00234 ScalarImage::SpaceVectorType imageOrigin( ScalarImage::SpaceVectorType::Init( 0 ) );
00235 imageOrigin[2] = sliceLocation;
00236
00237
00238 const char *image_position_s = NULL;
00239 if ( ! document->getValue( DCM_ImagePositionPatient, image_position_s ) )
00240 {
00241
00242 #ifdef DCM_ImagePosition
00243 document->getValue( DCM_ImagePosition, image_position_s );
00244 #else
00245 document->getValue( DCM_ACR_NEMA_ImagePosition, image_position_s );
00246 #endif
00247 }
00248 if ( image_position_s )
00249 {
00250 double xyz[3];
00251 if ( 3 == sscanf( image_position_s,"%lf%*c%lf%*c%lf", xyz, xyz+1, xyz+2 ) )
00252 {
00253 imageOrigin = ScalarImage::SpaceVectorType( xyz );
00254 }
00255 }
00256
00257 image->SetImageOrigin( imageOrigin );
00258
00259
00260 ScalarImage::SpaceVectorType imageDirectionX( ScalarImage::SpaceVectorType::Init(0) );
00261 imageDirectionX[0] = 1;
00262 ScalarImage::SpaceVectorType imageDirectionY( ScalarImage::SpaceVectorType::Init(0) );
00263 imageDirectionY[1] = 1;
00264
00265 const char *image_orientation_s = NULL;
00266 document->getValue( DCM_ImageOrientationPatient, image_orientation_s );
00267 if ( image_orientation_s )
00268 {
00269 double dx[3], dy[3];
00270 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 ) )
00271 {
00272 imageDirectionX = ScalarImage::SpaceVectorType( dx );
00273 imageDirectionY = ScalarImage::SpaceVectorType( dy );
00274 }
00275 }
00276
00277 image->SetImageDirectionX( imageDirectionX );
00278 image->SetImageDirectionY( imageDirectionY );
00279
00280 return image;
00281 }
00282
00284
00285 }