#include "DicomIO.h" #include #include #include #include #include #include #include #include #include #include #include #include #include DicomIO::DicomIO() : Singleton< DicomIO >(), m_calibrated( false ) { DcmRLEDecoderRegistration::registerCodecs(); DJDecoderRegistration::registerCodecs(); } DicomIO::~DicomIO() { DJDecoderRegistration::cleanup(); DcmRLEDecoderRegistration::cleanup(); } DicomIO::DicomIOType DicomIO::getType( std::string fileName ) { DcmFileFormat fileFormat; OFCondition status = fileFormat.loadFile( fileName.c_str() ); if ( status.bad() ) { return DicomIO::DicomIOUnknown; } DcmDataset* dataset = fileFormat.getDataset(); OFString SOPClassUID; if ( dataset->findAndGetOFString( DCM_SOPClassUID, SOPClassUID ).bad() ) { return DicomIO::DicomIOUnknown; } if ( !SOPClassUID.compare( UID_UltrasoundImageStorage ) || !SOPClassUID.compare( UID_MRImageStorage ) || !SOPClassUID.compare( UID_SecondaryCaptureImageStorage ) ) { return DicomIO::DicomIOImage; } if ( !SOPClassUID.compare( UID_UltrasoundMultiframeImageStorage ) ) { return DicomIO::DicomIOMultiFrame; } return DicomIO::DicomIOUnmanaged; } bool DicomIO::readResolutions( DcmDataset* dataset, double& sizeX, double& sizeY ) { if ( !dataset ) { return false; } int nScales = 0; Float64 tmpFD = 0.0; if ( dataset->findAndGetFloat64( DCM_PixelSpacing, tmpFD, 0 ).good() ) { sizeX = (double)tmpFD; nScales++; } if ( dataset->findAndGetFloat64( DCM_PixelSpacing, tmpFD, 1 ).good() ) { sizeY = (double)tmpFD; nScales++; } if ( nScales != 2 ) { nScales = 0; OFString SOPClassUID; if ( dataset->findAndGetOFString( DCM_SOPClassUID, SOPClassUID ).bad() ) { return false; } if ( !SOPClassUID.compare( UID_UltrasoundImageStorage ) || !SOPClassUID.compare( UID_UltrasoundMultiframeImageStorage ) ) { if ( !m_manufacturer.compare( "Ultrasonix Medical Corp." ) ) { if ( dataset->findAndGetFloat64( DCM_PhysicalDeltaX, tmpFD ).good() ) { sizeX = 10.0 * fabs( tmpFD ); nScales++; } if ( dataset->findAndGetFloat64( DCM_PhysicalDeltaY, tmpFD ).good() ) { sizeY = 10.0 * fabs( tmpFD ); nScales++; } } else { DcmSequenceOfItems* seq = NULL; if ( dataset->findAndGetSequence( DCM_SequenceOfUltrasoundRegions, seq ).good() ) { Uint16 type; bool found = false; unsigned long i, nItems = seq->card(); for ( i = 0; !found && ( i < nItems ); i++ ) { DcmItem* item = seq->getItem( i ); if ( item->findAndGetUint16( DCM_RegionSpatialFormat, type ).good() ) { if ( type == 1 ) { found = true; if ( item->findAndGetFloat64( DCM_PhysicalDeltaX, tmpFD ).good() ) { sizeX = 10.0 * fabs( tmpFD ); nScales++; } if ( item->findAndGetFloat64( DCM_PhysicalDeltaY, tmpFD ).good() ) { sizeY = 10.0 * fabs( tmpFD ); nScales++; } } } } } } } } return ( nScales == 2 ) ? true : false; } bool DicomIO::read( std::string fileName, ExtendedImage& image ) { m_calibrated = false; DcmFileFormat fileFormat; OFCondition status = fileFormat.loadFile( fileName.c_str() ); if ( status.bad() ) { return false; } DcmDataset* dataset = fileFormat.getDataset(); E_TransferSyntax xfer = dataset->getOriginalXfer(); /*** hack for Medison jpeg images ***/ OFString manufacturer; if ( dataset->findAndGetOFString( DCM_Manufacturer, manufacturer ).good() ) { m_manufacturer = manufacturer.c_str(); if ( !manufacturer.compare( "MEDISON" ) && ( xfer >= EXS_JPEGProcess1TransferSyntax ) && ( xfer <= EXS_JPEGProcess14SV1TransferSyntax ) ) { dataset->putAndInsertString( DCM_PhotometricInterpretation, "YBR_FULL" ); } } /*** end of hack ***/ double sizeX = 1.0, sizeY = 1.0; m_calibrated = readResolutions( dataset, sizeX, sizeY ); DicomImage dcmImage( dataset, xfer ); if ( dcmImage.getStatus() != EIS_Normal ) { return false; } dcmImage.setMinMaxWindow(); if ( !image.IsNull() ) { image.Destroy(); } int height = dcmImage.getHeight(); int width = dcmImage.getWidth(); int imgWidth = width; int imgHeight = height; #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL ) if ( ( (float)imgHeight / (float)imgWidth ) > 0.75f ) { while ( ( (float)imgHeight / (float)imgWidth ) > 0.75f ) { imgWidth++; } } else { while ( ( (float)imgHeight / (float)imgWidth ) < 0.75f ) { imgHeight++; } } #endif if ( !image.Create( imgWidth, imgHeight, 24 ) ) { return false; } unsigned char* d = (unsigned char*)dcmImage.getOutputData( 8 ); #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL ) unsigned char* imgPtr = (unsigned char*)image.GetBits(); int pitch = image.GetPitch(); int ww = 3 * width; int h = height; if ( dcmImage.isMonochrome() ) { while ( h-- ) { int w = width; unsigned char* ip = imgPtr; while ( w-- ) { *ip++ = *d; *ip++ = *d; *ip++ = *d++; } imgPtr += pitch; } } else { while ( h-- ) { int w = width; unsigned char* ip = imgPtr; while ( w-- ) { *ip++ = *( d + 2 ); *ip++ = *( d + 1 ); *ip++ = *d; d += 3; } imgPtr += pitch; } } #else unsigned char* l = (unsigned char*)image.GetBits(); int n = width * height; if ( dcmImage.isMonochrome() ) { while ( n-- ) { *l++ = *d; *l++ = *d; *l++ = *d++; } } else { while ( n-- ) { *l++ = *( d + 2 ); *l++ = *( d + 1 ); *l++ = *d; d += 3; } } #endif image.SetResolution( (double)sizeX, (double)sizeY ); return true; } bool DicomIO::read( std::string fileName, Video& video ) { m_calibrated = false; DcmFileFormat fileFormat; OFCondition status = fileFormat.loadFile( fileName.c_str() ); if ( status.bad() ) { return false; } DcmDataset* dataset = fileFormat.getDataset(); E_TransferSyntax xfer = dataset->getOriginalXfer(); /*** hack for Medison jpeg images ***/ OFString manufacturer; if ( dataset->findAndGetOFString( DCM_Manufacturer, manufacturer ).good() ) { m_manufacturer = manufacturer.c_str(); if ( !manufacturer.compare( "MEDISON" ) && ( xfer >= EXS_JPEGProcess1TransferSyntax ) && ( xfer <= EXS_JPEGProcess14SV1TransferSyntax ) ) { dataset->putAndInsertString( DCM_PhotometricInterpretation, "YBR_FULL" ); } } /*** end of hack ***/ double sizeX = 1.0, sizeY = 1.0; m_calibrated = readResolutions( dataset, sizeX, sizeY ); DicomImage dcmImage( dataset, xfer ); if ( dcmImage.getStatus() != EIS_Normal ) { return false; } dcmImage.setMinMaxWindow(); if ( !video.IsNull() ) { video.Clear(); } bool isMonochrome = dcmImage.isMonochrome() ? true : false; unsigned long f, nf = dcmImage.getFrameCount(); video.SetSize( dcmImage.getWidth(), dcmImage.getHeight() ); for ( f = 0; f < nf; f++ ) { Uint8* data = (Uint8*)dcmImage.getOutputData( 8, f ); video.AddFrame( data, isMonochrome ); } video.SetResolution( (double)sizeX, (double)sizeY ); return true; } bool DicomIO::write( std::string fileName, ExtendedImage &image ) { char uid[ 100 ]; DcmFileFormat fileFormat; DcmDataset* dataset = fileFormat.getDataset(); // SOP common dataset->putAndInsertString( DCM_SOPClassUID, UID_SecondaryCaptureImageStorage ); dataset->putAndInsertString( DCM_SOPInstanceUID, dcmGenerateUniqueIdentifier( uid, SITE_INSTANCE_UID_ROOT ) ); // Patient dataset->insertEmptyElement( DCM_PatientsName ); dataset->insertEmptyElement( DCM_PatientID ); dataset->insertEmptyElement( DCM_PatientsBirthDate ); dataset->insertEmptyElement( DCM_PatientsSex ); // Study dataset->putAndInsertString( DCM_StudyInstanceUID, dcmGenerateUniqueIdentifier( uid, SITE_STUDY_UID_ROOT )); dataset->insertEmptyElement( DCM_StudyDate ); dataset->insertEmptyElement( DCM_StudyTime ); dataset->insertEmptyElement( DCM_ReferringPhysiciansName ); // Series dataset->putAndInsertString( DCM_Modality, "OT" ); dataset->putAndInsertString( DCM_SeriesInstanceUID, dcmGenerateUniqueIdentifier( uid, SITE_SERIES_UID_ROOT )); dataset->insertEmptyElement( DCM_SeriesNumber ); // Equipment dataset->putAndInsertString( DCM_ConversionType, "WSD" ); // Image Uint16 spp = 3; Uint16 bitsAlloc = 8; Uint16 bitsStored = 8; Uint16 highBits = 7; std::string photometric( "RGB" ); switch ( image.GetBPP() ) { case 8: spp = 1; bitsAlloc = 8; bitsStored = 8; highBits = 7; photometric = "MONOCHROME2"; break; case 16: spp = 1; bitsAlloc = 16; bitsStored = 16; highBits = 15; photometric = "MONOCHROME2"; break; case 24: spp = 3; bitsAlloc = 8; bitsStored = 8; highBits = 7; photometric = "RGB"; break; default: return false; break; } Uint16 dx = image.GetWidth(); Uint16 dy = image.GetHeight(); dataset->putAndInsertString( DCM_InstanceNumber, "1" ); dataset->putAndInsertUint16( DCM_SamplesPerPixel, spp ); dataset->putAndInsertString( DCM_PhotometricInterpretation, photometric.c_str() ); dataset->putAndInsertUint16( DCM_Rows, dy ); dataset->putAndInsertUint16( DCM_Columns, dx ); dataset->putAndInsertUint16( DCM_BitsAllocated, bitsAlloc ); dataset->putAndInsertUint16( DCM_BitsStored, bitsStored ); dataset->putAndInsertUint16( DCM_HighBit, highBits ); dataset->putAndInsertUint16( DCM_PixelRepresentation, 0 ); dataset->putAndInsertUint16( DCM_PlanarConfiguration, 0 ); if ( image.HasCalibration() ) { std::ostringstream pixelSpacingX, pixelSpacingY; pixelSpacingX << image.GetResolutionX(); std::string str = pixelSpacingX.str(); if ( str.length() > 16 ) { str.resize( 16 ); } str += "\\"; pixelSpacingY << image.GetResolutionY(); std::string str2 = pixelSpacingY.str(); if ( str2.length() > 16 ) { str2.resize( 16 ); } str += str2; dataset->putAndInsertString( DCM_PixelSpacing, str.c_str() ); } unsigned long n = dx * dy * image.GetBPP() / 8; Uint8* data = NULL; #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL ) int x, y; data = new Uint8[ n ]; Uint8* dptr = data; for ( y = 0; y < dy; y++ ) { for ( x = 0; x < dx; x++ ) { COLORREF c = image.GetPixel( x, y ); *dptr++ = GetRValue( c ); *dptr++ = GetGValue( c ); *dptr++ = GetBValue( c ); } } #else data = (Uint8*)image.GetBits(); #endif dataset->putAndInsertUint8Array( DCM_PixelData, data, n ); OFCondition status = fileFormat.saveFile( fileName.c_str(), EXS_LittleEndianExplicit ); #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL ) delete[] data; #endif if ( status.bad() ) { return false; } return true; } bool DicomIO::HasCalibration() { return m_calibrated; }