/*========================================================================= Program: GDCM (Grassroots DICOM). A DICOM library Copyright (c) 2006-2011 Mathieu Malaterre All rights reserved. See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /* * the goal of this example is to mimic the behavior of disp_img_header * see http://www.gmecorp-usa.com/IM/NM/GC/ADAC/SV/adactechtips/Released_01Q3.pdf */ #include "gdcmReader.h" #include "gdcmPrivateTag.h" #include "gdcmAttribute.h" #include "gdcmImageWriter.h" #include #include #include #include #include #include struct dict { uint16_t key; const char *name; }; dict Array[] = { { 0x01, "Patient name" }, { 0x02, "Patient ID" }, { 0x03, "Patient sex" }, { 0x04, "Patient age" }, { 0x05, "Patient height" }, { 0x06, "Patient weight" }, { 0x07, "Exam date" }, { 0x08, "Dose admin. time" }, { 0x09, "Unique exam key" }, { 0x0a, "Exam procedure" }, { 0x0b, "Referring physician" }, { 0x0c, "Attending physician" }, { 0x0d, "Imaging modality" }, { 0x0e, "Hospital ID" }, { 0x0f, "Histogram crv file" }, { 0x10, "Acq. start time" }, { 0x11, "Object data type" }, { 0x12, "Image viewid" }, { 0x13, "Imaging device name" }, { 0x14, "Device serial number" }, { 0x15, "Collimator" }, { 0x16, "Software version" }, { 0x17, "Radiopharmaceutical #1" }, { 0x18, "Energy window #1 center" }, { 0x19, "Radiopharmaceutical #2" }, { 0x1a, "Energy window #1 width" }, { 0x1b, "Isotope imaging mode" }, { 0x1c, "Energy window #2 center" }, { 0x1d, "Energy window #2 width" }, { 0x1e, "Energy window #3 center" }, { 0x1f, "Energy window #3 width" }, { 0x20, "Energy window #4 center" }, { 0x21, "Energy window #4 width" }, { 0x22, "??Energy window #5 center" }, { 0x23, "??Energy window #5 width" }, { 0x24, "Patient orientation" }, { 0x25, "Spatial resolution" }, { 0x26, "Slice thickness" }, { 0x27, "Image X dimension" }, { 0x28, "Image Y dimension" }, { 0x29, "Image Z dimension" }, { 0x2a, "Image pixel width" }, { 0x2b, "Uniformity corr. file" }, { 0x2c, "Acquisition zoom factor" }, { 0x2d, "Total counts in set" }, { 0x2e, "Time / frame" }, { 0x2f, "Total acq. time" }, { 0x30, "Maximum pixel value" }, { 0x31, "Minimum pixel value" }, { 0x32, "R-R interval time" }, { 0x33, "Percent of cycle imaged" }, { 0x34, "# of cycles accepted" }, { 0x35, "# of cycles rejected" }, { 0x36, "Approximate ED frame" }, { 0x37, "Approximate ES frame" }, { 0x38, "Approximate EF" }, { 0x39, "Starting angle" }, { 0x3a, "Degrees of rotation" }, { 0x3b, "Direction of rotation" }, { 0x3c, "Cont. or step/shoot" }, { 0x3d, "Lim recon start frame" }, { 0x3e, "Upper window grey shade" }, { 0x3f, "Lower lvl grey shade" }, { 0x40, "Associated color map" }, { 0x41, "Custom color map file" }, { 0x42, "Manipulated image" }, { 0x43, "Axis of rotation corr." }, { 0x44, "Reorientation azimuth" }, { 0x45, "Reorientation elevation" }, { 0x46, "Filter type" }, { 0x47, "Filter order" }, { 0x48, "Filter cutoff frequency" }, { 0x49, "Reconstruction type" }, { 0x4a, "Attenuation coefficient" }, { 0x4b, "Associated parent file" }, { 0x4c, "Unique patient key" }, { 0x52, "Normalization crv file" }, { 0x53, "Unique object key" }, { 0x54, "This phase of VFR is" }, { 0x55, "True color value" }, { 0x56, "# of sets of x,y,z grps" }, { 0x57, "Scale factor of set" }, { 0x6d, "Date of birth" }, { 0x6e, "Directional orientation" }, { 0x6f, "Number of VFR studies" }, { 0x70, "R-R low tolerance" }, { 0x71, "R-R high tolerance" }, { 0x72, "Prog specific results:" }, { 0x99, nullptr } }; void printname( int , int , uint16_t v ) { if( v == 0x1 ) { std::cout << "DATABASE PARAMETERS" << std::endl; std::cout << "___________________" << std::endl; } else if( v == 0x27 ) { std::cout << "IMAGE PARAMETERS" << std::endl; std::cout << "________________" << std::endl; } else if( v == 0x13 ) { std::cout << "EXTRA PARAMETERS" << std::endl; std::cout << "________________" << std::endl; } else if( v == 0x2e ) { std::cout << "*** NOT CURRENTLY USED :" << std::endl; } static const unsigned int n = sizeof( Array ) / sizeof( *Array ) - 1; for( unsigned int i = 0; i < n; ++i ) { if( v == Array[i].key ) { std::cout << /*"" << std::dec << len << "," << mult << " " << */ Array[i].name; std::cout << " : "; return; } } std::cout << /*"\t# " << std::dec << len << "," << mult << */ std::hex << v << "\t: "; } uint16_t readint16(std::istream &is ) { uint16_t val; is.read( (char*)&val, sizeof( val )); return (uint16_t)((val>>8) | (val<<8)); } uint32_t readint32(std::istream &is ) { uint32_t val; is.read( (char*)&val, sizeof( val )); val= ((val<<8)&0xFF00FF00) | ((val>>8)&0x00FF00FF); return (val>>16) | (val<<16); } float readfloat32(std::istream &is ) { union { uint32_t val; float f;} dual; dual.val = readint32(is); return dual.f; } struct el { uint16_t v1; uint16_t v2; uint16_t v3; void read( std::istream & is ) { v1 = readint16(is); v2 = readint16(is); v3 = readint16(is); } void print( std::ostream & os ) { os << std::hex << v1 << "\t" << v2 << "\t" << v3 << std::endl; } }; std::vector Vel; void readelement( std::istream & is ) { el e; e.read( is ); Vel.push_back( e ); } void printascii( uint16_t tag, const char *buffer, size_t len ) { std::ostream & os = std::cout; if( tag == 0x72 ) { os << "\n "; for(size_t i = 0; i < len; ++i) { const char &c = buffer[i]; if( c == 0x0 ) os << "!"; else if( c == 0x0f ) os << " "; else if( c == 0x17 ) os << ":"; else if( c == 0x14 ) os << ":"; else if( c == 0x10 ) os << ":"; else if( c == 0x16 ) os << ":"; else if( c == 0x08 ) os << ":"; else if( c == 0x0b ) os << ":"; else if( c == 0x0e ) os << ":"; else if( c == 0x07 ) os << ":"; else os << c; } os << ""; } else { (void)len; os << "" << buffer << ""; } } bool DumpADAC( std::istream & is ) { std::ostream &os = std::cout; char magic[6 + 1]; magic[6] = 0; is.read( magic, 6); // std::cout << magic << " "; assert( strcmp( magic, "adac01" ) == 0 ); int c = is.get(); assert( c == 0 ); (void)c; c = is.get(); assert( c == 'X' ); uint16_t v; v = readint16(is); // std::cout << v << std::endl; assert( v == 512 ); (void)v; // ?? int nel = 87; for (int i = 0; i <= nel; ++i ) { readelement( is ); } char buffer[512]; for( int i = 0; i <= nel; ++i ) { const el &e = Vel[i]; int diff; if( i == nel ) { diff = 2048 - e.v3; if( diff > 512 ) diff = 512; } else { const el &enext = Vel[i+1]; diff = enext.v3 - e.v3; } is.seekg( e.v3, std::ios::beg ); //std::cout << "(" << std::hex << std::setw( 2 ) << std::setfill( '0' ) << e.v1 << ") " << std::hex << std::setw( 3 ) << std::setfill( '0' ) << e.v2 << " "; printname( diff, 0, e.v1 ); int mult = 1; if( e.v2 == 0 ) { is.read( buffer, diff); buffer[ diff ] = 0; printascii( e.v1, buffer, diff); } else if( e.v2 == 0x100 ) { mult = diff / 2; assert( diff == 2 * mult ); for ( int ii = 0; ii < mult; ++ii ) { if ( ii ) os << "\\"; uint16_t val = readint16(is); os << "" << std::dec << val << ""; } } else if( e.v2 == 0x200 ) { assert( diff == 4 ); uint32_t val = readint32(is); os << "" << std::dec << val << ""; } else if( e.v2 == 0x300 ) { assert( diff == 4 ); float val = readfloat32(is); os << "" << std::dec << val << ""; } else { assert( 0 ); } os << std::endl; } return true; } int main(int argc, char *argv[]) { if( argc < 2 ) return 1; const char *filename = argv[1]; gdcm::Reader reader; reader.SetFileName( filename ); if( !reader.Read() ) { std::cerr << "Failed to read: " << filename << std::endl; return 1; } const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); // (0019,1061) UN (OB) 61\64\61\63\30 # 2048,1 Ver200 ADAC Pegasys Headers const gdcm::PrivateTag tver200adacpegasysheaders(0x0019,0x61,"ADAC_IMG"); if( !ds.FindDataElement( tver200adacpegasysheaders ) ) return 1; const gdcm::DataElement& ver200adacpegasysheaders = ds.GetDataElement( tver200adacpegasysheaders ); if ( ver200adacpegasysheaders.IsEmpty() ) return 1; const gdcm::ByteValue * bv = ver200adacpegasysheaders.GetByteValue(); // (0019,1021) US 1 # 2,1 Ver200 Number of ADAC Headers // TODO // (0019,1041) IS [2048\221184 ] # 12,1-n Ver200 ADAC Header/Image Size if( bv->GetLength() != 2048 ) return 1; gdcm::Element el; const gdcm::PrivateTag tver200adacheaderimagesize(0x0019,0x41,"ADAC_IMG"); if( !ds.FindDataElement( tver200adacheaderimagesize ) ) return 1; const gdcm::DataElement& ver200adacheaderimagesize = ds.GetDataElement( tver200adacheaderimagesize ); el.SetFromDataElement( ver200adacheaderimagesize ); if( el.GetValue(0) != 2048 ) return 1; std::istringstream is; std::string dup( bv->GetPointer(), bv->GetLength() ); is.str( dup ); bool b = DumpADAC( is ); if( !b ) return 1; return 0; }