DicomIO.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. #include "DicomIO.h"
  2. #include <dcmtk/config/osconfig.h>
  3. #include <dcmtk/dcmdata/dcfilefo.h>
  4. #include <dcmtk/dcmdata/dcdeftag.h>
  5. #include <dcmtk/dcmdata/dcstack.h>
  6. #include <dcmtk/dcmdata/dcpixel.h>
  7. #include <dcmtk/dcmdata/dcxfer.h>
  8. #include <dcmtk/dcmjpeg/djdecode.h>
  9. #include <dcmtk/dcmimgle/dcmimage.h>
  10. #include <dcmtk/dcmimage/diregist.h>
  11. #include <dcmtk/dcmdata/dcrledrg.h>
  12. #include <dcmtk/dcmdata/dcuid.h>
  13. #include <sstream>
  14. #include <cmath>
  15. DicomIO::DicomIO()
  16. : Singleton< DicomIO >(),
  17. m_calibrated( false )
  18. {
  19. DcmRLEDecoderRegistration::registerCodecs();
  20. DJDecoderRegistration::registerCodecs();
  21. }
  22. DicomIO::~DicomIO()
  23. {
  24. DJDecoderRegistration::cleanup();
  25. DcmRLEDecoderRegistration::cleanup();
  26. }
  27. DicomIO::DicomIOType DicomIO::getType( std::string fileName )
  28. {
  29. DcmFileFormat fileFormat;
  30. OFCondition status = fileFormat.loadFile( fileName.c_str() );
  31. if ( status.bad() )
  32. {
  33. return DicomIO::DicomIOUnknown;
  34. }
  35. DcmDataset* dataset = fileFormat.getDataset();
  36. OFString SOPClassUID;
  37. if ( dataset->findAndGetOFString( DCM_SOPClassUID, SOPClassUID ).bad() )
  38. {
  39. return DicomIO::DicomIOUnknown;
  40. }
  41. if ( !SOPClassUID.compare( UID_UltrasoundImageStorage ) ||
  42. !SOPClassUID.compare( UID_MRImageStorage ) ||
  43. !SOPClassUID.compare( UID_SecondaryCaptureImageStorage ) )
  44. {
  45. return DicomIO::DicomIOImage;
  46. }
  47. if ( !SOPClassUID.compare( UID_UltrasoundMultiframeImageStorage ) )
  48. {
  49. return DicomIO::DicomIOMultiFrame;
  50. }
  51. return DicomIO::DicomIOUnmanaged;
  52. }
  53. bool DicomIO::readResolutions( DcmDataset* dataset,
  54. double& sizeX,
  55. double& sizeY )
  56. {
  57. if ( !dataset )
  58. {
  59. return false;
  60. }
  61. int nScales = 0;
  62. Float64 tmpFD = 0.0;
  63. if ( dataset->findAndGetFloat64( DCM_PixelSpacing, tmpFD, 0 ).good() )
  64. {
  65. sizeX = (double)tmpFD;
  66. nScales++;
  67. }
  68. if ( dataset->findAndGetFloat64( DCM_PixelSpacing, tmpFD, 1 ).good() )
  69. {
  70. sizeY = (double)tmpFD;
  71. nScales++;
  72. }
  73. if ( nScales != 2 )
  74. {
  75. nScales = 0;
  76. OFString SOPClassUID;
  77. if ( dataset->findAndGetOFString( DCM_SOPClassUID, SOPClassUID ).bad() )
  78. {
  79. return false;
  80. }
  81. if ( !SOPClassUID.compare( UID_UltrasoundImageStorage ) ||
  82. !SOPClassUID.compare( UID_UltrasoundMultiframeImageStorage ) )
  83. {
  84. if ( !m_manufacturer.compare( "Ultrasonix Medical Corp." ) )
  85. {
  86. if ( dataset->findAndGetFloat64( DCM_PhysicalDeltaX, tmpFD ).good() )
  87. {
  88. sizeX = 10.0 * fabs( tmpFD );
  89. nScales++;
  90. }
  91. if ( dataset->findAndGetFloat64( DCM_PhysicalDeltaY, tmpFD ).good() )
  92. {
  93. sizeY = 10.0 * fabs( tmpFD );
  94. nScales++;
  95. }
  96. }
  97. else
  98. {
  99. DcmSequenceOfItems* seq = NULL;
  100. if ( dataset->findAndGetSequence( DCM_SequenceOfUltrasoundRegions, seq ).good() )
  101. {
  102. Uint16 type;
  103. bool found = false;
  104. unsigned long i, nItems = seq->card();
  105. for ( i = 0; !found && ( i < nItems ); i++ )
  106. {
  107. DcmItem* item = seq->getItem( i );
  108. if ( item->findAndGetUint16( DCM_RegionSpatialFormat, type ).good() )
  109. {
  110. if ( type == 1 )
  111. {
  112. found = true;
  113. if ( item->findAndGetFloat64( DCM_PhysicalDeltaX, tmpFD ).good() )
  114. {
  115. sizeX = 10.0 * fabs( tmpFD );
  116. nScales++;
  117. }
  118. if ( item->findAndGetFloat64( DCM_PhysicalDeltaY, tmpFD ).good() )
  119. {
  120. sizeY = 10.0 * fabs( tmpFD );
  121. nScales++;
  122. }
  123. }
  124. }
  125. }
  126. }
  127. }
  128. }
  129. }
  130. return ( nScales == 2 ) ? true : false;
  131. }
  132. bool DicomIO::read( std::string fileName, ExtendedImage& image )
  133. {
  134. m_calibrated = false;
  135. DcmFileFormat fileFormat;
  136. OFCondition status = fileFormat.loadFile( fileName.c_str() );
  137. if ( status.bad() )
  138. {
  139. return false;
  140. }
  141. DcmDataset* dataset = fileFormat.getDataset();
  142. E_TransferSyntax xfer = dataset->getOriginalXfer();
  143. /*** hack for Medison jpeg images ***/
  144. OFString manufacturer;
  145. if ( dataset->findAndGetOFString( DCM_Manufacturer, manufacturer ).good() )
  146. {
  147. m_manufacturer = manufacturer.c_str();
  148. if ( !manufacturer.compare( "MEDISON" ) &&
  149. ( xfer >= EXS_JPEGProcess1TransferSyntax ) &&
  150. ( xfer <= EXS_JPEGProcess14SV1TransferSyntax ) )
  151. {
  152. dataset->putAndInsertString( DCM_PhotometricInterpretation, "YBR_FULL" );
  153. }
  154. }
  155. /*** end of hack ***/
  156. double sizeX = 1.0, sizeY = 1.0;
  157. m_calibrated = readResolutions( dataset, sizeX, sizeY );
  158. DicomImage dcmImage( dataset, xfer );
  159. if ( dcmImage.getStatus() != EIS_Normal )
  160. {
  161. return false;
  162. }
  163. dcmImage.setMinMaxWindow();
  164. if ( !image.IsNull() )
  165. {
  166. image.Destroy();
  167. }
  168. int height = dcmImage.getHeight();
  169. int width = dcmImage.getWidth();
  170. int imgWidth = width;
  171. int imgHeight = height;
  172. #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL )
  173. if ( ( (float)imgHeight / (float)imgWidth ) > 0.75f )
  174. {
  175. while ( ( (float)imgHeight / (float)imgWidth ) > 0.75f )
  176. {
  177. imgWidth++;
  178. }
  179. }
  180. else
  181. {
  182. while ( ( (float)imgHeight / (float)imgWidth ) < 0.75f )
  183. {
  184. imgHeight++;
  185. }
  186. }
  187. #endif
  188. if ( !image.Create( imgWidth, imgHeight, 24 ) )
  189. {
  190. return false;
  191. }
  192. unsigned char* d = (unsigned char*)dcmImage.getOutputData( 8 );
  193. #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL )
  194. unsigned char* imgPtr = (unsigned char*)image.GetBits();
  195. int pitch = image.GetPitch();
  196. int ww = 3 * width;
  197. int h = height;
  198. if ( dcmImage.isMonochrome() )
  199. {
  200. while ( h-- )
  201. {
  202. int w = width;
  203. unsigned char* ip = imgPtr;
  204. while ( w-- )
  205. {
  206. *ip++ = *d;
  207. *ip++ = *d;
  208. *ip++ = *d++;
  209. }
  210. imgPtr += pitch;
  211. }
  212. }
  213. else
  214. {
  215. while ( h-- )
  216. {
  217. int w = width;
  218. unsigned char* ip = imgPtr;
  219. while ( w-- )
  220. {
  221. *ip++ = *( d + 2 );
  222. *ip++ = *( d + 1 );
  223. *ip++ = *d;
  224. d += 3;
  225. }
  226. imgPtr += pitch;
  227. }
  228. }
  229. #else
  230. unsigned char* l = (unsigned char*)image.GetBits();
  231. int n = width * height;
  232. if ( dcmImage.isMonochrome() )
  233. {
  234. while ( n-- )
  235. {
  236. *l++ = *d;
  237. *l++ = *d;
  238. *l++ = *d++;
  239. }
  240. }
  241. else
  242. {
  243. while ( n-- )
  244. {
  245. *l++ = *( d + 2 );
  246. *l++ = *( d + 1 );
  247. *l++ = *d;
  248. d += 3;
  249. }
  250. }
  251. #endif
  252. image.SetResolution( (double)sizeX, (double)sizeY );
  253. return true;
  254. }
  255. bool DicomIO::read( std::string fileName, Video& video )
  256. {
  257. m_calibrated = false;
  258. DcmFileFormat fileFormat;
  259. OFCondition status = fileFormat.loadFile( fileName.c_str() );
  260. if ( status.bad() )
  261. {
  262. return false;
  263. }
  264. DcmDataset* dataset = fileFormat.getDataset();
  265. E_TransferSyntax xfer = dataset->getOriginalXfer();
  266. /*** hack for Medison jpeg images ***/
  267. OFString manufacturer;
  268. if ( dataset->findAndGetOFString( DCM_Manufacturer, manufacturer ).good() )
  269. {
  270. m_manufacturer = manufacturer.c_str();
  271. if ( !manufacturer.compare( "MEDISON" ) &&
  272. ( xfer >= EXS_JPEGProcess1TransferSyntax ) &&
  273. ( xfer <= EXS_JPEGProcess14SV1TransferSyntax ) )
  274. {
  275. dataset->putAndInsertString( DCM_PhotometricInterpretation, "YBR_FULL" );
  276. }
  277. }
  278. /*** end of hack ***/
  279. double sizeX = 1.0, sizeY = 1.0;
  280. m_calibrated = readResolutions( dataset, sizeX, sizeY );
  281. DicomImage dcmImage( dataset, xfer );
  282. if ( dcmImage.getStatus() != EIS_Normal )
  283. {
  284. return false;
  285. }
  286. dcmImage.setMinMaxWindow();
  287. if ( !video.IsNull() )
  288. {
  289. video.Clear();
  290. }
  291. bool isMonochrome = dcmImage.isMonochrome() ? true : false;
  292. unsigned long f, nf = dcmImage.getFrameCount();
  293. video.SetSize( dcmImage.getWidth(), dcmImage.getHeight() );
  294. for ( f = 0; f < nf; f++ )
  295. {
  296. Uint8* data = (Uint8*)dcmImage.getOutputData( 8, f );
  297. video.AddFrame( data, isMonochrome );
  298. }
  299. video.SetResolution( (double)sizeX, (double)sizeY );
  300. return true;
  301. }
  302. bool DicomIO::write( std::string fileName, ExtendedImage &image )
  303. {
  304. char uid[ 100 ];
  305. DcmFileFormat fileFormat;
  306. DcmDataset* dataset = fileFormat.getDataset();
  307. // SOP common
  308. dataset->putAndInsertString( DCM_SOPClassUID,
  309. UID_SecondaryCaptureImageStorage );
  310. dataset->putAndInsertString( DCM_SOPInstanceUID,
  311. dcmGenerateUniqueIdentifier( uid,
  312. SITE_INSTANCE_UID_ROOT ) );
  313. // Patient
  314. dataset->insertEmptyElement( DCM_PatientsName );
  315. dataset->insertEmptyElement( DCM_PatientID );
  316. dataset->insertEmptyElement( DCM_PatientsBirthDate );
  317. dataset->insertEmptyElement( DCM_PatientsSex );
  318. // Study
  319. dataset->putAndInsertString( DCM_StudyInstanceUID,
  320. dcmGenerateUniqueIdentifier( uid,
  321. SITE_STUDY_UID_ROOT ));
  322. dataset->insertEmptyElement( DCM_StudyDate );
  323. dataset->insertEmptyElement( DCM_StudyTime );
  324. dataset->insertEmptyElement( DCM_ReferringPhysiciansName );
  325. // Series
  326. dataset->putAndInsertString( DCM_Modality, "OT" );
  327. dataset->putAndInsertString( DCM_SeriesInstanceUID,
  328. dcmGenerateUniqueIdentifier( uid,
  329. SITE_SERIES_UID_ROOT ));
  330. dataset->insertEmptyElement( DCM_SeriesNumber );
  331. // Equipment
  332. dataset->putAndInsertString( DCM_ConversionType, "WSD" );
  333. // Image
  334. Uint16 spp = 3;
  335. Uint16 bitsAlloc = 8;
  336. Uint16 bitsStored = 8;
  337. Uint16 highBits = 7;
  338. std::string photometric( "RGB" );
  339. switch ( image.GetBPP() )
  340. {
  341. case 8:
  342. spp = 1;
  343. bitsAlloc = 8;
  344. bitsStored = 8;
  345. highBits = 7;
  346. photometric = "MONOCHROME2";
  347. break;
  348. case 16:
  349. spp = 1;
  350. bitsAlloc = 16;
  351. bitsStored = 16;
  352. highBits = 15;
  353. photometric = "MONOCHROME2";
  354. break;
  355. case 24:
  356. spp = 3;
  357. bitsAlloc = 8;
  358. bitsStored = 8;
  359. highBits = 7;
  360. photometric = "RGB";
  361. break;
  362. default:
  363. return false;
  364. break;
  365. }
  366. Uint16 dx = image.GetWidth();
  367. Uint16 dy = image.GetHeight();
  368. dataset->putAndInsertString( DCM_InstanceNumber, "1" );
  369. dataset->putAndInsertUint16( DCM_SamplesPerPixel, spp );
  370. dataset->putAndInsertString( DCM_PhotometricInterpretation,
  371. photometric.c_str() );
  372. dataset->putAndInsertUint16( DCM_Rows, dy );
  373. dataset->putAndInsertUint16( DCM_Columns, dx );
  374. dataset->putAndInsertUint16( DCM_BitsAllocated, bitsAlloc );
  375. dataset->putAndInsertUint16( DCM_BitsStored, bitsStored );
  376. dataset->putAndInsertUint16( DCM_HighBit, highBits );
  377. dataset->putAndInsertUint16( DCM_PixelRepresentation, 0 );
  378. dataset->putAndInsertUint16( DCM_PlanarConfiguration, 0 );
  379. if ( image.HasCalibration() )
  380. {
  381. std::ostringstream pixelSpacingX, pixelSpacingY;
  382. pixelSpacingX << image.GetResolutionX();
  383. std::string str = pixelSpacingX.str();
  384. if ( str.length() > 16 )
  385. {
  386. str.resize( 16 );
  387. }
  388. str += "\\";
  389. pixelSpacingY << image.GetResolutionY();
  390. std::string str2 = pixelSpacingY.str();
  391. if ( str2.length() > 16 )
  392. {
  393. str2.resize( 16 );
  394. }
  395. str += str2;
  396. dataset->putAndInsertString( DCM_PixelSpacing, str.c_str() );
  397. }
  398. unsigned long n = dx * dy * image.GetBPP() / 8;
  399. Uint8* data = NULL;
  400. #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL )
  401. int x, y;
  402. data = new Uint8[ n ];
  403. Uint8* dptr = data;
  404. for ( y = 0; y < dy; y++ )
  405. {
  406. for ( x = 0; x < dx; x++ )
  407. {
  408. COLORREF c = image.GetPixel( x, y );
  409. *dptr++ = GetRValue( c );
  410. *dptr++ = GetGValue( c );
  411. *dptr++ = GetBValue( c );
  412. }
  413. }
  414. #else
  415. data = (Uint8*)image.GetBits();
  416. #endif
  417. dataset->putAndInsertUint8Array( DCM_PixelData, data, n );
  418. OFCondition status = fileFormat.saveFile( fileName.c_str(),
  419. EXS_LittleEndianExplicit );
  420. #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL )
  421. delete[] data;
  422. #endif
  423. if ( status.bad() )
  424. {
  425. return false;
  426. }
  427. return true;
  428. }
  429. bool DicomIO::HasCalibration()
  430. {
  431. return m_calibrated;
  432. }