#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_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 ) ) { 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 ) || ( type == 2 ) ) { 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 ) { DcmFileFormat fileFormat; OFCondition status = fileFormat.loadFile( fileName.c_str() ); m_calibrated = false; if ( status.bad() ) { return false; } DcmDataset* dataset = fileFormat.getDataset(); double sizeX = -1.0, sizeY = -1.0; m_calibrated = readResolutions( dataset, sizeX, sizeY ); E_TransferSyntax xfer = dataset->getOriginalXfer(); // hack for Medison jpeg encoded images OFString manufacturer; if ( dataset->findAndGetOFString( DCM_Manufacturer, manufacturer ).good() ) { if ( !manufacturer.compare( "MEDISON" ) && ( xfer >= EXS_JPEGProcess1TransferSyntax ) && ( xfer <= EXS_JPEGProcess14SV1TransferSyntax ) ) { dataset->putAndInsertString( DCM_PhotometricInterpretation, "YBR_FULL" ); } } // end of hack DicomImage dcmImage( dataset, xfer ); if ( dcmImage.getStatus() != EIS_Normal ) { return false; } dcmImage.setMinMaxWindow(); if ( !image.IsNull() ) { image.Destroy(); } int w = dcmImage.getWidth(); int h = dcmImage.getHeight(); if ( !image.Create( w, h, 24 ) ) { return false; } unsigned char* p = (unsigned char*)dcmImage.getOutputData( 8 ); unsigned char* l = (unsigned char*)image.GetBuffer(); int n = w * h; if ( dcmImage.isMonochrome() ) { while ( n-- ) { *l++ = *p; *l++ = *p; *l++ = *p++; } } else { while ( n-- ) { *l++ = *( p + 2 ); *l++ = *( p + 1 ); *l++ = *p; p += 3; } } image.SetResolution( (double)sizeX, (double)sizeY ); return true; } bool DicomIO::read( std::string fileName, Video& video ) { DcmFileFormat fileFormat; OFCondition status = fileFormat.loadFile( fileName.c_str() ); m_calibrated = false; if ( status.bad() ) { return false; } DcmDataset* dataset = fileFormat.getDataset(); double sizeX = -1.0, sizeY = -1.0; m_calibrated = readResolutions( dataset, sizeX, sizeY ); E_TransferSyntax xfer = dataset->getOriginalXfer(); // hack for Medison jpeg encoded images OFString manufacturer; if ( dataset->findAndGetOFString( DCM_Manufacturer, manufacturer ).good() ) { if ( !manufacturer.compare( "MEDISON" ) && ( xfer >= EXS_JPEGProcess1TransferSyntax ) && ( xfer <= EXS_JPEGProcess14SV1TransferSyntax ) ) { dataset->putAndInsertString( DCM_PhotometricInterpretation, "YBR_FULL" ); } } // end of hack DicomImage dcmImage( dataset, xfer ); if ( dcmImage.getStatus() != EIS_Normal ) { return false; } dcmImage.setMinMaxWindow(); if ( !video.IsNull() ) { video.Clear(); } unsigned long f, nf = dcmImage.getFrameCount(); bool isMonochrome = dcmImage.isMonochrome() ? true : false; video.SetSize( dcmImage.getWidth(), dcmImage.getHeight() ); for ( f = 0; f < nf; f++ ) { unsigned char* p = (unsigned char*)dcmImage.getOutputData( 8 ); video.AddFrame( p, 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, "US" ); 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(); dataset->putAndInsertUint8Array( DCM_PixelData, (Uint8*)image.GetBuffer(), n ); OFCondition status = fileFormat.saveFile( fileName.c_str(), EXS_LittleEndianExplicit ); if ( status.bad() ) { return false; } return true; } bool DicomIO::HasCalibration() { return m_calibrated; } */