DumpADAC.cxx
/*=========================================================================
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 <iostream>
#include <fstream>
#include <vector>
#include <string.h>
#include <assert.h>
#include <stdint.h>
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<el> 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<gdcm::VR::IS,gdcm::VM::VM2> 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;
}
gdcm::ByteValue
Class to represent binary value (array of bytes).
Definition gdcmByteValue.h:35
gdcm::ByteValue::GetPointer
const char * GetPointer() const
Definition gdcmByteValue.h:110
gdcm::ByteValue::GetLength
VL GetLength() const override
Definition gdcmByteValue.h:77
gdcm::DataElement
Class to represent a Data Element either Implicit or Explicit.
Definition gdcmDataElement.h:59
gdcm::DataElement::GetByteValue
const ByteValue * GetByteValue() const
Definition gdcmDataElement.h:133
gdcm::DataElement::IsEmpty
bool IsEmpty() const
Check if Data Element is empty.
Definition gdcmDataElement.h:106
gdcm::DataSet
Class to represent a Data Set (which contains Data Elements).
Definition gdcmDataSet.h:56
gdcm::DataSet::GetDataElement
const DataElement & GetDataElement(const Tag &t) const
Definition gdcmDataSet.h:188
gdcm::DataSet::FindDataElement
bool FindDataElement(const PrivateTag &t) const
Look up if private tag 't' is present in the dataset:
gdcm::Element
Element class.
Definition gdcmElement.h:70
gdcm::Element::GetValue
const VRToType< TVR >::Type & GetValue(unsigned int idx=0) const
Definition gdcmElement.h:94
gdcm::Element::SetFromDataElement
void SetFromDataElement(DataElement const &de)
Definition gdcmElement.h:110
gdcm::File::GetDataSet
const DataSet & GetDataSet() const
Get Data Set.
Definition gdcmFile.h:57
gdcm::PrivateTag
Class to represent a Private DICOM Data Element (Attribute) Tag (Group, Element, Owner).
Definition gdcmPrivateTag.h:39
gdcm::Reader
Reader ala DOM (Document Object Model).
Definition gdcmReader.h:54
gdcm::Reader::GetFile
const File & GetFile() const
Set/Get File.
Definition gdcmReader.h:72
gdcm::Reader::Read
virtual bool Read()
Main function to read a file.
gdcm::Reader::SetFileName
void SetFileName(const char *filename_native)
gdcmAttribute.h
gdcmImageWriter.h
gdcmPrivateTag.h
gdcmReader.h