From: malaterre Date: Mon, 21 Jun 2004 04:18:23 +0000 (+0000) Subject: ENH:First chunk of patch: X-Git-Tag: Version0.5.bp~129 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=b3f903e00dbe97bcd6697ba659d0f1aa586bbbb8;p=gdcm.git ENH:First chunk of patch: 1. Get rid of gdcmHeaderHelper, the class was only gdcmHeader with nice default values, no big deal 2. Left a legacy mode where you can still use the class gdcmHeaderHelper 3. Some minor clean up, but all the tests are passing --- diff --git a/gdcmPython/CMakeLists.txt b/gdcmPython/CMakeLists.txt index a5a26ed7..2b094c63 100644 --- a/gdcmPython/CMakeLists.txt +++ b/gdcmPython/CMakeLists.txt @@ -184,7 +184,8 @@ IF(GDCM_VTK) vtkCommonPython vtkIOPython) ENDIF (GDCM_WRAP_PYTHON) - +ENDIF(GDCM_VTK) + # generate a setup.py according to VTK installation # put it in subdir in order to not override old one @@ -193,7 +194,6 @@ IF(GDCM_VTK) ${GDCM_SOURCE_DIR}/gdcmPython/setup.py.in ${GDCM_BINARY_DIR}/setup.py ) -ENDIF(GDCM_VTK) #----------------------------------------------------------------------------- # Install stuff: diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 834a3d1e..a6bfec4f 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.cxx,v $ Language: C++ - Date: $Date: 2004/06/20 18:08:47 $ - Version: $Revision: 1.19 $ + Date: $Date: 2004/06/21 04:18:25 $ + Version: $Revision: 1.20 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -95,23 +95,23 @@ const unsigned int gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE = 64; * with a FALSE value for the 'enable_sequence' param. * ('public elements' may be embedded in 'shadow Sequences') */ -gdcmDocument::gdcmDocument(const char *inFilename, - bool exception_on_error, - bool enable_sequences, - bool ignore_shadow) +gdcmDocument::gdcmDocument(std::string const & inFilename, + bool exception_on_error, + bool enable_sequences, + bool ignore_shadow) : gdcmElementSet(-1) { enableSequences=enable_sequences; - ignoreShadow =ignore_shadow; + IgnoreShadow =ignore_shadow; SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); - filename = inFilename; + Filename = inFilename; Initialise(); if ( !OpenFile(exception_on_error)) return; dbg.Verbose(0, "gdcmDocument::gdcmDocument: starting parsing of file: ", - filename.c_str()); + Filename.c_str()); rewind(fp); fseek(fp,0L,SEEK_END); @@ -125,6 +125,7 @@ gdcmDocument::gdcmDocument(const char *inFilename, SQDepthLevel=0; long l=ParseDES( this, beg, lgt, false); // le Load sera fait a la volee + (void)l; //is l used anywhere ? CloseFile(); // -------------------------------------------------------------- @@ -139,7 +140,7 @@ gdcmDocument::gdcmDocument(const char *inFilename, RecCode == "CANRME_AILIBOD1_1." ) // for brain-damaged softwares // with "little-endian strings" { - filetype = gdcmACR_LIBIDO; + Filetype = gdcmACR_LIBIDO; std::string rows = GetEntryByNumber(0x0028, 0x0010); std::string columns = GetEntryByNumber(0x0028, 0x0011); SetEntryByNumber(columns, 0x0028, 0x0010); @@ -242,7 +243,7 @@ bool gdcmDocument::SetShaDict(DictKey dictName){ * false otherwise. */ bool gdcmDocument::IsReadable(void) { - if(filetype==gdcmUnknown) { + if(Filetype==gdcmUnknown) { dbg.Verbose(0, "gdcmDocument::IsReadable: wrong filetype"); return(false); } @@ -425,7 +426,7 @@ bool gdcmDocument::IsDicomV3(void) { * @return the FileType code */ FileType gdcmDocument::GetFileType(void) { - return(filetype); + return Filetype; } /** @@ -436,7 +437,7 @@ FileType gdcmDocument::GetFileType(void) { FILE *gdcmDocument::OpenFile(bool exception_on_error) throw(gdcmFileError) { - fp=fopen(filename.c_str(),"rb"); + fp=fopen(Filename.c_str(),"rb"); if(!fp) { @@ -444,11 +445,9 @@ FILE *gdcmDocument::OpenFile(bool exception_on_error) throw gdcmFileError("gdcmDocument::gdcmDocument(const char *, bool)"); else { - std::cout <<"gdcmDocument::OpenFile cannot open file: " - << filename.c_str() << std::endl; dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file: ", - filename.c_str()); - return (NULL); + Filename.c_str()); + return NULL; } } @@ -459,22 +458,22 @@ FILE *gdcmDocument::OpenFile(bool exception_on_error) //ACR -- or DICOM with no Preamble -- if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200) - return(fp); + return fp; //DICOM fseek(fp, 126L, SEEK_CUR); char dicm[4]; fread(dicm, (size_t)4, (size_t)1, fp); if( memcmp(dicm, "DICM", 4) == 0 ) - return(fp); + return fp; fclose(fp); - dbg.Verbose(0, "gdcmDocument::OpenFile not DICOM/ACR", filename.c_str()); + dbg.Verbose(0, "gdcmDocument::OpenFile not DICOM/ACR", Filename.c_str()); } else { - dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file", filename.c_str()); + dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file", Filename.c_str()); } - return(NULL); + return NULL; } /** @@ -558,7 +557,7 @@ bool gdcmDocument::Write(FILE *fp, FileType type) { */ WriteEntries(fp,type); - return(true); + return true; } /** @@ -574,7 +573,8 @@ bool gdcmDocument::Write(FILE *fp, FileType type) { gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber( std::string Value, guint16 Group, - guint16 Elem ){ + guint16 Elem ) +{ gdcmDocEntry* CurrentEntry; gdcmValEntry* ValEntry; @@ -587,7 +587,7 @@ gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber( { dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: call to" " NewDocEntryByNumber failed."); - return (gdcmValEntry *)0; + return NULL; } ValEntry = new gdcmValEntry(CurrentEntry); if ( !AddEntry(ValEntry)) @@ -607,13 +607,13 @@ gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber( { dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: removal" " of previous DocEntry failed."); - return (gdcmValEntry *)0; + return NULL; } if ( !AddEntry(ValEntry)) { dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: adding" " promoted ValEntry failed."); - return (gdcmValEntry *)0; + return NULL; } } } @@ -645,12 +645,14 @@ gdcmBinEntry * gdcmDocument::ReplaceOrCreateByNumber( a =NewBinEntryByNumber(Group, Elem); if (a == NULL) return NULL; + b = new gdcmBinEntry(a); AddEntry(b); } SetEntryByNumber(voidArea, lgth, Group, Elem); b->SetVoidArea(voidArea); - return (gdcmBinEntry*)b; + + return b; } @@ -681,7 +683,7 @@ bool gdcmDocument::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 El */ int gdcmDocument::CheckIfEntryExistByNumber(guint16 group, guint16 element ) { std::string key = gdcmDictEntry::TranslateToKey(group, element ); - return (tagHT.count(key)); + return tagHT.count(key); } /** @@ -698,7 +700,7 @@ std::string gdcmDocument::GetEntryByName(std::string tagName) { if( dictEntry == NULL) return GDCM_UNFOUND; - return(GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement())); + return GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()); } /** @@ -787,8 +789,8 @@ bool gdcmDocument::SetEntryByName(std::string content,std::string tagName) { if( dictEntry == NULL) return false; - return(SetEntryByNumber(content,dictEntry->GetGroup(), - dictEntry->GetElement())); + return SetEntryByNumber(content,dictEntry->GetGroup(), + dictEntry->GetElement()); } /** @@ -842,6 +844,7 @@ bool gdcmDocument::SetEntryByNumber(void *content, guint16 group, guint16 element) { + (void)lgth; //not used TagKey key = gdcmDictEntry::TranslateToKey(group, element); if ( ! tagHT.count(key)) return false; @@ -935,11 +938,12 @@ void *gdcmDocument::LoadEntryVoidArea(guint16 Group, guint16 Elem) return NULL; size_t o =(size_t)Element->GetOffset(); fseek(fp, o, SEEK_SET); - size_t l=Element->GetLength(); + size_t l = Element->GetLength(); char* a = new char[l]; - if(!a) + if(!a) { + dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea cannot allocate a"); return NULL; - + } SetEntryVoidAreaByNumber(a, Group, Elem); /// \todo check the result size_t l2 = fread(a, 1, l ,fp); @@ -977,7 +981,7 @@ bool gdcmDocument::SetEntryVoidAreaByNumber(void * area, * Only non even entries are analyzed */ void gdcmDocument::UpdateShaEntries(void) { - gdcmDictEntry *entry; + //gdcmDictEntry *entry; std::string vr; /// \todo TODO : still any use to explore recursively the whole structure? @@ -1254,6 +1258,7 @@ bool gdcmDocument::WriteEntry(gdcmDocEntry *tag, FILE *_fp,FileType type) if (gdcmBinEntry* BinEntry = dynamic_cast< gdcmBinEntry* >(tag) ) { + (void)BinEntry; //not used /// \todo FIXME : when voidArea belong to gdcmBinEntry only, fix /// voidArea length // @@ -1269,6 +1274,8 @@ bool gdcmDocument::WriteEntry(gdcmDocEntry *tag, FILE *_fp,FileType type) WriteEntryValue(tag, _fp, type); return true; } + + return false; //default behavior ? } /** @@ -1385,7 +1392,7 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set, long offset, long l_max, bool gdcmBinEntry *bn; gdcmSeqEntry *sq; VRKey vr; - long l; + unsigned long l; int depth; depth = set->GetDepthLevel(); @@ -1469,6 +1476,7 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set, long offset, long l_max, bool long lgt = ParseSQ( sq, NewDocEntry->GetOffset(), l, delim_mode); + (void)lgt; //not used... } // FIXME : on en fait quoi, de lgt ? set->AddEntry(sq); @@ -1494,8 +1502,10 @@ long gdcmDocument::ParseSQ(gdcmSeqEntry *set, gdcmDocEntry *NewDocEntry = (gdcmDocEntry *)0; gdcmSQItem *itemSQ; bool dlm_mod; - int lgr, l, lgth; + int lgr, lgth; + unsigned int l; int depth = set->GetDepthLevel(); + (void)depth; //not used while (true) { NewDocEntry = ReadNextDocEntry(); @@ -1656,7 +1666,7 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry *Entry) guint16 length16; - if ( (filetype == gdcmExplicitVR) && (! Entry->IsImplicitVR()) ) + if ( (Filetype == gdcmExplicitVR) && (! Entry->IsImplicitVR()) ) { if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) { @@ -1763,7 +1773,7 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry *Entry) */ void gdcmDocument::FindDocEntryVR( gdcmDocEntry *Entry) { - if (filetype != gdcmExplicitVR) + if (Filetype != gdcmExplicitVR) return; char VR[3]; @@ -2195,7 +2205,7 @@ bool gdcmDocument::IsDocEntryAnInteger(gdcmDocEntry *Entry) { * (swaps it depending on processor endianity) * @return read value */ -guint16 gdcmDocument::ReadInt16(void) { +guint16 gdcmDocument::ReadInt16() { guint16 g; size_t item_read; item_read = fread (&g, (size_t)2,(size_t)1, fp); @@ -2215,7 +2225,7 @@ guint16 gdcmDocument::ReadInt16(void) { * (swaps it depending on processor endianity) * @return read value */ -guint32 gdcmDocument::ReadInt32(void) { +guint32 gdcmDocument::ReadInt32() { guint32 g; size_t item_read; item_read = fread (&g, (size_t)4,(size_t)1, fp); @@ -2247,7 +2257,7 @@ void gdcmDocument::SkipBytes(guint32 NBytes) { void gdcmDocument::Initialise(void) { RefPubDict = gdcmGlobal::GetDicts()->GetDefaultPubDict(); - RefShaDict = (gdcmDict*)0; + RefShaDict = NULL; } /** @@ -2320,13 +2330,13 @@ bool gdcmDocument::CheckSwap() { // Use gdcmDocument::dicom_vr to test all the possibilities // instead of just checking for UL, OB and UI !? group 0000 { - filetype = gdcmExplicitVR; + Filetype = gdcmExplicitVR; dbg.Verbose(1, "gdcmDocument::CheckSwap:", "explicit Value Representation"); } else { - filetype = gdcmImplicitVR; + Filetype = gdcmImplicitVR; dbg.Verbose(1, "gdcmDocument::CheckSwap:", "not an explicit Value Representation"); } @@ -2371,19 +2381,19 @@ bool gdcmDocument::CheckSwap() { switch (s32) { case 0x00040000 : sw = 3412; - filetype = gdcmACR; + Filetype = gdcmACR; return true; case 0x04000000 : sw = 4321; - filetype = gdcmACR; + Filetype = gdcmACR; return true; case 0x00000400 : sw = 2143; - filetype = gdcmACR; + Filetype = gdcmACR; return true; case 0x00000004 : sw = 0; - filetype = gdcmACR; + Filetype = gdcmACR; return true; default : @@ -2409,18 +2419,18 @@ bool gdcmDocument::CheckSwap() { case 0x0004 : case 0x0008 : sw = 0; - filetype = gdcmACR; + Filetype = gdcmACR; return true; case 0x0200 : case 0x0400 : case 0x0800 : sw = 4321; - filetype = gdcmACR; + Filetype = gdcmACR; return true; default : dbg.Verbose(0, "gdcmDocument::CheckSwap:", "ACR/NEMA unfound swap info (Really hopeless !)"); - filetype = gdcmUnknown; + Filetype = gdcmUnknown; return false; } @@ -2827,7 +2837,7 @@ void gdcmDocument::Parse7FE0 (void) // BTW, what is the purpous of those length anyhow !? char * BasicOffsetTableItemValue = new char[ItemLength + 1]; fread(BasicOffsetTableItemValue, ItemLength, 1, fp); - for (int i=0; i < ItemLength; i += 4){ + for (unsigned int i=0; i < ItemLength; i += 4){ guint32 IndividualLength; IndividualLength = str2num(&BasicOffsetTableItemValue[i],guint32); std::ostringstream s; @@ -2842,7 +2852,7 @@ void gdcmDocument::Parse7FE0 (void) // JPEG Image //// We then skip (not reading them) all the fragments of images: - while ( ItemLength = ReadItemTagLength() ) + while ( (ItemLength = ReadItemTagLength()) ) { SkipBytes(ItemLength); } @@ -2855,7 +2865,7 @@ void gdcmDocument::Parse7FE0 (void) long RleSegmentLength[15], fragmentLength; // while 'Sequence Delimiter Item' (fffe,e0dd) not found - while ( fragmentLength = ReadSequenceDelimiterTagLength() ) + while ( (fragmentLength = ReadSequenceDelimiterTagLength()) ) { // Parse fragments of the current Fragment (Frame) //------------------ scanning (not reading) fragment pixels @@ -2894,7 +2904,6 @@ void gdcmDocument::Parse7FE0 (void) SkipBytes(RleSegmentLength[nbRleSegments]); } } - return; } /** @@ -2904,47 +2913,49 @@ void gdcmDocument::Parse7FE0 (void) * @param document * @return true if 'smaller' */ - bool gdcmDocument::operator<(gdcmDocument &document){ +bool gdcmDocument::operator<(gdcmDocument &document) +{ std::string s1,s2; // Patient Name s1=this->GetEntryByNumber(0x0010,0x0010); s2=document.GetEntryByNumber(0x0010,0x0010); if(s1 < s2) - return(true); + return true; else if(s1 > s2) - return(false); + return false; else { // Patient ID s1=this->GetEntryByNumber(0x0010,0x0020); s2=document.GetEntryByNumber(0x0010,0x0020); if (s1 < s2) - return(true); + return true; else if (s1 > s2) - return(1); + return true; else { // Study Instance UID s1=this->GetEntryByNumber(0x0020,0x000d); s2=document.GetEntryByNumber(0x0020,0x000d); if (s1 < s2) - return(true); + return true; else if(s1 > s2) - return(false); + return false; else { // Serie Instance UID s1=this->GetEntryByNumber(0x0020,0x000e); s2=document.GetEntryByNumber(0x0020,0x000e); if (s1 < s2) - return(true); + return true; else if(s1 > s2) - return(false); + return false; } } } - return(false); + + return false; } diff --git a/src/gdcmDocument.h b/src/gdcmDocument.h index bc12f0d5..95f7e610 100644 --- a/src/gdcmDocument.h +++ b/src/gdcmDocument.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.h,v $ Language: C++ - Date: $Date: 2004/06/18 12:26:54 $ - Version: $Revision: 1.11 $ + Date: $Date: 2004/06/21 04:18:25 $ + Version: $Revision: 1.12 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -58,7 +58,7 @@ private: /// \brief Equals =1 if user wants to skip shadow groups while parsing /// (to save space) - int ignoreShadow; + int IgnoreShadow; /// \brief Size threshold above which an element value will NOT be loaded /// in memory (to avoid loading the image/volume itself). By default, @@ -73,7 +73,7 @@ private: protected: /// Refering underlying filename. - std::string filename; + std::string Filename; /// \brief SWap code (e.g. Big Endian, Little Endian, Bad Big Endian, /// Bad Little Endian) according to the processor Endianity and @@ -84,7 +84,7 @@ protected: FILE *fp; /// ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown - FileType filetype; + FileType Filetype; /// After opening the file, we read HEADER_LENGTH_TO_READ bytes. static const unsigned int HEADER_LENGTH_TO_READ; @@ -158,7 +158,7 @@ public: virtual void *LoadEntryVoidArea (guint16 Group, guint16 Element); void LoadVLEntry (gdcmDocEntry *entry); -// System access + // System access guint16 SwapShort(guint16); // needed by gdcmFile guint32 SwapLong(guint32); // needed by gdcmFile guint16 UnswapShort(guint16); // needed by gdcmFile @@ -169,14 +169,14 @@ protected: // to instanciate from this class gdcmDocument (only gdcmHeader and // gdcmDicomDir are meaningfull). gdcmDocument(bool exception_on_error = false); - gdcmDocument(const char *inFilename, + gdcmDocument(std::string const & inFilename, bool exception_on_error = false, bool enable_sequences = false, bool ignore_shadow = false); virtual ~gdcmDocument(void); void gdcmDocument::Parse7FE0 (void); -// Entry + // Entry int CheckIfEntryExistByNumber(guint16 Group, guint16 Elem ); // int ! public: virtual std::string GetEntryByName (std::string tagName); @@ -197,9 +197,9 @@ protected: virtual void *GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem); virtual bool SetEntryVoidAreaByNumber(void *a, guint16 Group, guint16 Elem); - virtual void UpdateShaEntries(void); + virtual void UpdateShaEntries(); -// Header entry + // Header entry gdcmDocEntry *GetDocEntryByNumber (guint16 group, guint16 element); gdcmDocEntry *GetDocEntryByName (std::string Name); @@ -209,7 +209,7 @@ protected: void LoadDocEntrySafe(gdcmDocEntry *); private: -// Read + // Read long ParseDES(gdcmDocEntrySet *set, long offset, long l_max,bool delim_mode); long ParseSQ(gdcmSeqEntry *seq, long offset, long l_max, bool delim_mode); @@ -227,18 +227,18 @@ private: void FixDocEntryFoundLength(gdcmDocEntry *, guint32); bool IsDocEntryAnInteger (gdcmDocEntry *); - guint32 FindDocEntryLengthOB(void); + guint32 FindDocEntryLengthOB(); - guint16 ReadInt16(void); - guint32 ReadInt32(void); + guint16 ReadInt16(); + guint32 ReadInt32(); void SkipBytes(guint32); guint32 ReadTagLength(guint16, guint16); - guint32 ReadItemTagLength(void); - guint32 ReadSequenceDelimiterTagLength(void); + guint32 ReadItemTagLength(); + guint32 ReadSequenceDelimiterTagLength(); - void Initialise(void); - bool CheckSwap(void); - void SwitchSwapToBigEndian(void); + void Initialise(); + bool CheckSwap(); + void SwitchSwapToBigEndian(); void SetMaxSizeLoadEntry(long); void SetMaxSizePrintEntry(long); @@ -252,7 +252,7 @@ private: std::string fourth = "unkn", std::string name = "unkn"); // DocEntry related utilities - gdcmDocEntry *ReadNextDocEntry (void); + gdcmDocEntry *ReadNextDocEntry (); gdcmDocEntry *NewDocEntryByNumber(guint16 group, guint16 element); gdcmDocEntry *NewDocEntryByName (std::string Name); @@ -266,22 +266,22 @@ private: public: // Accessors: /// Accessor to \ref printLevel - void SetPrintLevel(int level) { printLevel = level; }; + inline void SetPrintLevel(int level) { printLevel = level; } /// Accessor to \ref filename - inline std::string GetFileName(void) {return filename;} + inline std::string &GetFileName() { return Filename; } /// Accessor to \ref filename - inline void SetFileName(char* fileName) {filename = fileName;} + inline void SetFileName(const char* fileName) { Filename = fileName; } /// Accessor to \ref gdcmElementSet::tagHT - inline TagDocEntryHT &GetEntry(void) { return tagHT; }; + inline TagDocEntryHT &GetEntry() { return tagHT; }; /// 'Swap code' accessor (see \ref sw ) - inline int GetSwapCode(void) { return sw; } + inline int GetSwapCode() { return sw; } /// File pointer - inline FILE * GetFP(void) { return fp; } + inline FILE * GetFP() { return fp; } bool operator<(gdcmDocument &document); diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index 19d00890..4318d69f 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmHeader.cxx,v $ Language: C++ - Date: $Date: 2004/06/20 18:08:47 $ - Version: $Revision: 1.165 $ + Date: $Date: 2004/06/21 04:18:25 $ + Version: $Revision: 1.166 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -36,11 +36,11 @@ * @param ignore_shadow = true if user wants to skip shadow groups * during parsing, to save memory space */ -gdcmHeader::gdcmHeader(const char *InFilename, +gdcmHeader::gdcmHeader(std::string const & filename, bool exception_on_error, bool enable_sequences, bool ignore_shadow): - gdcmDocument(InFilename,exception_on_error,enable_sequences,ignore_shadow) + gdcmDocument(filename,exception_on_error,enable_sequences,ignore_shadow) { /* typedef struct { @@ -69,12 +69,12 @@ gdcmHeader::gdcmHeader(const char *InFilename, if (GrPixel == 0xe07f) // sometimes Image Location value doesn't follow GrPixel = 0x7fe0; // the supposed processor endianity. // see gdcmData/cr172241.dcm - if (GrPixel != 0x7fe0) + if (GrPixel != 0x7fe0) { // This is a kludge for old dirty Philips imager. NumPixel = 0x1010; - else + } else { NumPixel = 0x0010; - + } } /** @@ -110,7 +110,7 @@ gdcmHeader::~gdcmHeader (void) { */ bool gdcmHeader::IsReadable(void) { if(!gdcmDocument::IsReadable()) { - return(false); + return false; } std::string res = GetEntryByNumber(0x0028, 0x0005); if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 ) @@ -181,6 +181,412 @@ int gdcmHeader::GetZSize(void) { return 1; } +/** + * \ingroup gdcmHeader + * \brief gets the info from 0028,0030 : Pixel Spacing + * else 1.0 + * @return X dimension of a pixel + */ +float gdcmHeader::GetXSpacing() { + float xspacing, yspacing; + std::string StrSpacing = GetEntryByNumber(0x0028,0x0030); + + if (StrSpacing == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetXSpacing: unfound Pixel Spacing (0028,0030)"); + return 1.; + } + int nbValues; + if( (nbValues = sscanf( StrSpacing.c_str(), "%f\\%f", &yspacing, &xspacing)) != 2) { + if (nbValues==1) // if single value is found, xspacing is defaulted to yspacing + return yspacing; + } + if (xspacing == 0.) { + dbg.Verbose(0, "gdcmHeader::GetYSpacing: gdcmData/CT-MONO2-8-abdo.dcm problem"); + // seems to be a bug in the header ... + sscanf( StrSpacing.c_str(), "%f\\0\\%f", &yspacing, &xspacing); + } + return xspacing; +} + +/** + * \ingroup gdcmHeader + * \brief gets the info from 0028,0030 : Pixel Spacing + * else 1.0 + * @return Y dimension of a pixel + */ +float gdcmHeader::GetYSpacing() { + float yspacing; + std::string StrSpacing = GetEntryByNumber(0x0028,0x0030); + + if (StrSpacing == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetYSpacing: unfound Pixel Spacing (0028,0030)"); + return 1.; + } + sscanf( StrSpacing.c_str(), "%f", &yspacing); + return yspacing; +} + +/** + *\ingroup gdcmHeader + *\brief gets the info from 0018,0088 : Space Between Slices + * else from 0018,0050 : Slice Thickness + * else 1.0 + * @return Z dimension of a voxel-to be + */ +float gdcmHeader::GetZSpacing() { + // Spacing Between Slices : distance entre le milieu de chaque coupe + // Les coupes peuvent etre : + // jointives (Spacing between Slices = Slice Thickness) + // chevauchantes (Spacing between Slices < Slice Thickness) + // disjointes (Spacing between Slices > Slice Thickness) + // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal + // ca interesse le physicien de l'IRM, pas le visualisateur de volumes ... + // Si le Spacing Between Slices est absent, + // on suppose que les coupes sont jointives + + std::string StrSpacingBSlices = GetEntryByNumber(0x0018,0x0088); + + if (StrSpacingBSlices == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetZSpacing: unfound StrSpacingBSlices"); + std::string StrSliceThickness = GetEntryByNumber(0x0018,0x0050); + if (StrSliceThickness == GDCM_UNFOUND) + return 1.; + else + // if no 'Spacing Between Slices' is found, + // we assume slices join together + // (no overlapping, no interslice gap) + // if they don't, we're fucked up + return atof(StrSliceThickness.c_str()); + } else { + return atof(StrSpacingBSlices.c_str()); + } +} + +/** + *\ingroup gdcmHeader + *\brief gets the info from 0028,1052 : Rescale Intercept + * @return Rescale Intercept + */ +float gdcmHeader::GetRescaleIntercept() { + float resInter = 0.; + std::string StrRescInter = GetEntryByNumber(0x0028,0x1052); //0028 1052 DS IMG Rescale Intercept + if (StrRescInter != GDCM_UNFOUND) { + if( sscanf( StrRescInter.c_str(), "%f", &resInter) != 1) { + dbg.Verbose(0, "gdcmHeader::GetRescaleIntercept: Rescale Slope is empty"); + // bug in the element 0x0028,0x1052 + } + } + return resInter; +} + +/** + *\ingroup gdcmHeader + *\brief gets the info from 0028,1053 : Rescale Slope + * @return Rescale Slope + */ + float gdcmHeader::GetRescaleSlope() { + float resSlope = 1.; + std::string StrRescSlope = GetEntryByNumber(0x0028,0x1053); //0028 1053 DS IMG Rescale Slope + if (StrRescSlope != GDCM_UNFOUND) { + if( sscanf( StrRescSlope.c_str(), "%f", &resSlope) != 1) { + dbg.Verbose(0, "gdcmHeader::GetRescaleSlope: Rescale Slope is empty"); + // bug in the element 0x0028,0x1053 + } + } + return resSlope; +} + +/** + * \ingroup gdcmHeader + * \brief This function is intended to user who doesn't want + * to have to manage a LUT and expects to get an RBG Pixel image + * (or a monochrome one ...) + * \warning to be used with GetImagePixels() + * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR) + */ +int gdcmHeader::GetNumberOfScalarComponents() { + if (GetSamplesPerPixel() ==3) + return 3; + + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old RGB images) + if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24") + return 3; + + std::string PhotometricInterpretation = + gdcmHeader::GetEntryByNumber(0x0028,0x0004); + + if ( ( PhotometricInterpretation == "PALETTE COLOR ") ) { + if (HasLUT()) // PALETTE COLOR is NOT enough + return 3; + else + return 1; + } + + //beware of trailing space at end of string + if (PhotometricInterpretation.find(GDCM_UNFOUND) < + PhotometricInterpretation.length() || + PhotometricInterpretation.find("MONOCHROME1") < + PhotometricInterpretation.length() || + PhotometricInterpretation.find("MONOCHROME2") < + PhotometricInterpretation.length() ) + return 1; + else + // we assume that *all* kinds of YBR are dealt with + return 3; +} + +/** + * \ingroup gdcmHeader + * \brief This function is intended to user that DOESN'T want + * to get RGB pixels image when it's stored as a PALETTE COLOR image + * - the (vtk) user is supposed to know how deal with LUTs - + * \warning to be used with GetImagePixelsRaw() + * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -) + */ +int gdcmHeader::GetNumberOfScalarComponentsRaw() { + + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old RGB images) + if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24") + return 3; + + // we assume that *all* kinds of YBR are dealt with + return GetSamplesPerPixel(); +} + +/** + *\ingroup gdcmHeader + *\brief gets the info from 0020,000d : Study Instance UID + *\todo ? : return the ACR-NEMA element value if DICOM one is not found + * @return Study Instance UID + */ +//std::string gdcmHeader::GetStudyUID(){ +// return GetEntryByNumber(0x0020,0x000d); //0020 000d UI REL Study Instance UID +//} + +/** + *\ingroup gdcmHeader + *\brief gets the info from 0020,000e : Series Instance UID + *\todo ? : return the ACR-NEMA element value if DICOM one is not found + * @return Series Instance UID + */ +//std::string gdcmHeader::GetSeriesUID(){ +// return GetEntryByNumber(0x0020,0x000e); //0020 000e UI REL Series Instance UID +//} + +/** + *\ingroup gdcmHeader + *\brief gets the info from 0008,0016 : SOP Class UID + *\todo ? : return the ACR-NEMA element value if DICOM one is not found + * @return SOP Class UID + */ +//std::string gdcmHeader::GetClassUID(){ +// return GetEntryByNumber(0x0008,0x0016); //0008 0016 UI ID SOP Class UID +//} + +/** + *\brief gets the info from 0008,0018 : SOP Instance UID + *\todo ? : return the ACR-NEMA element value if DICOM one is not found + * @return SOP Instance UID + */ +//std::string gdcmHeader::GetInstanceUID(){ +// return GetEntryByNumber(0x0008,0x0018); //0008 0018 UI ID SOP Instance UID +//} +// +// -------------- Remember ! ---------------------------------- +// +// Image Position Patient (0020,0032): +// If not found (ACR_NEMA) we try Image Position (0020,0030) +// If not found (ACR-NEMA), we consider Slice Location (0020,1041) +// or Location (0020,0050) +// as the Z coordinate, +// 0. for all the coordinates if nothing is found + +// \todo find a way to inform the caller nothing was found +// \todo How to tell the caller a wrong number of values was found? +// +// --------------------------------------------------------------- +// + +/** + * \brief gets the info from 0020,0032 : Image Position Patient + * else from 0020,0030 : Image Position (RET) + * else 0. + * @return up-left image corner X position + */ + +float gdcmHeader::GetXOrigin() { + float xImPos, yImPos, zImPos; + std::string StrImPos = GetEntryByNumber(0x0020,0x0032); + + if (StrImPos == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position Patient (0020,0032)"); + StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images + if (StrImPos == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position (RET) (0020,0030)"); + /// \todo How to tell the caller nothing was found ? + return 0.; + } + } + if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) + return 0.; + return xImPos; +} + +/** + * \brief gets the info from 0020,0032 : Image Position Patient + * else from 0020,0030 : Image Position (RET) + * else 0. + * @return up-left image corner Y position + */ +float gdcmHeader::GetYOrigin() { + float xImPos, yImPos, zImPos; + std::string StrImPos = GetEntryByNumber(0x0020,0x0032); + + if (StrImPos == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position Patient (0020,0032)"); + StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images + if (StrImPos == GDCM_UNFOUND) { + dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position (RET) (0020,0030)"); + /// \todo How to tell the caller nothing was found ? + return 0.; + } + } + if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) + return 0.; + return yImPos; +} + +/** + * \brief gets the info from 0020,0032 : Image Position Patient + * \ else from 0020,0030 : Image Position (RET) + * \ else from 0020,1041 : Slice Location + * \ else from 0020,0050 : Location + * \ else 0. + * @return up-left image corner Z position + */ +float gdcmHeader::GetZOrigin() { + float xImPos, yImPos, zImPos; + std::string StrImPos = GetEntryByNumber(0x0020,0x0032); + if (StrImPos != GDCM_UNFOUND) { + if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) { + dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position Patient (0020,0032)"); + return 0.; // bug in the element 0x0020,0x0032 + } else { + return zImPos; + } + } + StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images + if (StrImPos != GDCM_UNFOUND) { + if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) { + dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position (RET) (0020,0030)"); + return 0.; // bug in the element 0x0020,0x0032 + } else { + return zImPos; + } + } + std::string StrSliceLocation = GetEntryByNumber(0x0020,0x1041);// for *very* old ACR-NEMA images + if (StrSliceLocation != GDCM_UNFOUND) { + if( sscanf( StrSliceLocation.c_str(), "%f", &zImPos) !=1) { + dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Slice Location (0020,1041)"); + return 0.; // bug in the element 0x0020,0x1041 + } else { + return zImPos; + } + } + dbg.Verbose(0, "gdcmHeader::GetZImagePosition: unfound Slice Location (0020,1041)"); + std::string StrLocation = GetEntryByNumber(0x0020,0x0050); + if (StrLocation != GDCM_UNFOUND) { + if( sscanf( StrLocation.c_str(), "%f", &zImPos) !=1) { + dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Location (0020,0050)"); + return 0.; // bug in the element 0x0020,0x0050 + } else { + return zImPos; + } + } + dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Location (0020,0050)"); + return 0.; // Hopeless +} + +/** + * \brief gets the info from 0020,0013 : Image Number + * \ else 0. + * @return image number + */ +int gdcmHeader::GetImageNumber() { + // The function i atoi() takes the address of an area of memory as + // parameter and converts the string stored at that location to an integer + // using the external decimal to internal binary conversion rules. This may + // be preferable to sscanf() since atoi() is a much smaller, simpler and + // faster function. sscanf() can do all possible conversions whereas + // atoi() can only do single decimal integer conversions. + std::string StrImNumber = GetEntryByNumber(0x0020,0x0013); //0020 0013 IS REL Image Number + if (StrImNumber != GDCM_UNFOUND) { + return atoi( StrImNumber.c_str() ); + } + return 0; //Hopeless +} + +/** + * \brief gets the info from 0008,0060 : Modality + * @return Modality Type + */ +ModalityType gdcmHeader::GetModality(void) { + // 0008 0060 CS ID Modality + std::string StrModality = GetEntryByNumber(0x0008,0x0060); + if (StrModality != GDCM_UNFOUND) { + if ( StrModality.find("AU") < StrModality.length()) return AU; + else if ( StrModality.find("AS") < StrModality.length()) return AS; + else if ( StrModality.find("BI") < StrModality.length()) return BI; + else if ( StrModality.find("CF") < StrModality.length()) return CF; + else if ( StrModality.find("CP") < StrModality.length()) return CP; + else if ( StrModality.find("CR") < StrModality.length()) return CR; + else if ( StrModality.find("CT") < StrModality.length()) return CT; + else if ( StrModality.find("CS") < StrModality.length()) return CS; + else if ( StrModality.find("DD") < StrModality.length()) return DD; + else if ( StrModality.find("DF") < StrModality.length()) return DF; + else if ( StrModality.find("DG") < StrModality.length()) return DG; + else if ( StrModality.find("DM") < StrModality.length()) return DM; + else if ( StrModality.find("DS") < StrModality.length()) return DS; + else if ( StrModality.find("DX") < StrModality.length()) return DX; + else if ( StrModality.find("ECG") < StrModality.length()) return ECG; + else if ( StrModality.find("EPS") < StrModality.length()) return EPS; + else if ( StrModality.find("FA") < StrModality.length()) return FA; + else if ( StrModality.find("FS") < StrModality.length()) return FS; + else if ( StrModality.find("HC") < StrModality.length()) return HC; + else if ( StrModality.find("HD") < StrModality.length()) return HD; + else if ( StrModality.find("LP") < StrModality.length()) return LP; + else if ( StrModality.find("LS") < StrModality.length()) return LS; + else if ( StrModality.find("MA") < StrModality.length()) return MA; + else if ( StrModality.find("MR") < StrModality.length()) return MR; + else if ( StrModality.find("NM") < StrModality.length()) return NM; + else if ( StrModality.find("OT") < StrModality.length()) return OT; + else if ( StrModality.find("PT") < StrModality.length()) return PT; + else if ( StrModality.find("RF") < StrModality.length()) return RF; + else if ( StrModality.find("RG") < StrModality.length()) return RG; + else if ( StrModality.find("RTDOSE") < StrModality.length()) return RTDOSE; + else if ( StrModality.find("RTIMAGE") < StrModality.length()) return RTIMAGE; + else if ( StrModality.find("RTPLAN") < StrModality.length()) return RTPLAN; + else if ( StrModality.find("RTSTRUCT")< StrModality.length()) return RTSTRUCT; + else if ( StrModality.find("SM") < StrModality.length()) return SM; + else if ( StrModality.find("ST") < StrModality.length()) return ST; + else if ( StrModality.find("TG") < StrModality.length()) return TG; + else if ( StrModality.find("US") < StrModality.length()) return US; + else if ( StrModality.find("VF") < StrModality.length()) return VF; + else if ( StrModality.find("XA") < StrModality.length()) return XA; + else if ( StrModality.find("XC") < StrModality.length()) return XC; + + else + { + /// \todo throw error return value ??? + /// specified <> unknow in our database + return Unknow; + } + } + return Unknow; +} + /** * \ingroup gdcmHeader * \brief Retrieve the number of Bits Stored (actually used) @@ -188,7 +594,7 @@ int gdcmHeader::GetZSize(void) { * @return The encountered number of Bits Stored, 0 by default. * 0 means the file is NOT USABLE. The caller has to check it ! */ -int gdcmHeader::GetBitsStored(void) { +int gdcmHeader::GetBitsStored() { std::string StrSize = GetEntryByNumber(0x0028,0x0101); if (StrSize == GDCM_UNFOUND) return 0; // It's supposed to be mandatory @@ -245,7 +651,12 @@ int gdcmHeader::GetPlanarConfiguration(void) { * @return The size in bytes of a single pixel of data; 0 by default * 0 means the file is NOT USABLE; the caller will have to check */ -int gdcmHeader::GetPixelSize(void) { +int gdcmHeader::GetPixelSize() { + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old RGB images) +// if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24") +// return 3; + std::string PixelType = GetPixelType(); if (PixelType == "8U" || PixelType == "8S") return 1; @@ -274,7 +685,7 @@ int gdcmHeader::GetPixelSize(void) { * 24 bit images appear as 8 bit * @return 0S if nothing found. NOT USABLE file. The caller has to check */ -std::string gdcmHeader::GetPixelType(void) { +std::string gdcmHeader::GetPixelType() { std::string BitsAlloc = GetEntryByNumber(0x0028, 0x0100); // Bits Allocated if (BitsAlloc == GDCM_UNFOUND) { dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated"); @@ -356,7 +767,7 @@ size_t gdcmHeader::GetPixelAreaLength(void) { * Please warn me if you know sbdy that *does* know ... jprx * @return true if LUT Descriptors and LUT Tables were found */ -bool gdcmHeader::HasLUT(void) { +bool gdcmHeader::HasLUT() { // Check the presence of the LUT Descriptors, and LUT Tables // LutDescriptorRed @@ -589,7 +1000,7 @@ void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { * \brief anonymize a Header (removes Patient's personal info) * (read the code to see which ones ...) */ -bool gdcmHeader::anonymizeHeader() { +bool gdcmHeader::AnonymizeHeader() { gdcmDocEntry *patientNameHE = GetDocEntryByNumber (0x0010, 0x0010); @@ -598,9 +1009,9 @@ bool gdcmHeader::anonymizeHeader() { ReplaceIfExistByNumber (" ",0x0010, 0x0020); // Patient ID if (patientNameHE) { - std::string StudyInstanceUID = GetEntryByNumber (0x0020, 0x000d); - if (StudyInstanceUID !=GDCM_UNFOUND) - ReplaceOrCreateByNumber(StudyInstanceUID, 0x0010, 0x0010); + std::string studyInstanceUID = GetEntryByNumber (0x0020, 0x000d); + if (studyInstanceUID !=GDCM_UNFOUND) + ReplaceOrCreateByNumber(studyInstanceUID, 0x0010, 0x0010); else ReplaceOrCreateByNumber(std::string("anonymised"), 0x0010, 0x0010); } @@ -658,6 +1069,43 @@ bool gdcmHeader::anonymizeHeader() { //300e 0004 DA RT Review Date return true; } + +/** + * \brief gets the info from 0020,0037 : Image Orientation Patient + * @param iop adress of the (6)float aray to receive values + * @return cosines of image orientation patient + */ +void gdcmHeader::GetImageOrientationPatient( float* iop ) { + + //iop is supposed to be float[6] + iop[0] = iop[1] = iop[2] = iop[3] = iop[4] = iop[5] = 0; + + // 0020 0037 DS REL Image Orientation (Patient) + std::string StrImOriPat = GetEntryByNumber(0x0020,0x0037); + if (StrImOriPat != GDCM_UNFOUND) { + if( sscanf( StrImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", + &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6) { + dbg.Verbose(0, "gdcmHeader::GetImageOrientationPatient: wrong Image Orientation Patient (0020,0037)"); + return ; // bug in the element 0x0020,0x0037 + } + else + return ; + } + + //For ACR-NEMA + // 0020 0035 DS REL Image Orientation (RET) + StrImOriPat = GetEntryByNumber(0x0020,0x0035); + if (StrImOriPat != GDCM_UNFOUND) { + if( sscanf( StrImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", + &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6) { + dbg.Verbose(0, "gdcmHeader::GetImageOrientationPatient: wrong Image Orientation Patient (0020,0035)"); + return ; // bug in the element 0x0020,0x0035 + } + else + return ; + } +} + //----------------------------------------------------------------------------- // Private diff --git a/src/gdcmHeader.h b/src/gdcmHeader.h index 88c5dcdb..75d5eb1a 100644 --- a/src/gdcmHeader.h +++ b/src/gdcmHeader.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmHeader.h,v $ Language: C++ - Date: $Date: 2004/06/20 18:08:48 $ - Version: $Revision: 1.74 $ + Date: $Date: 2004/06/21 04:18:26 $ + Version: $Revision: 1.75 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -41,6 +41,55 @@ * protected due to Swig limitations for as Has_a dependency between * gdcmFile and gdcmHeader. */ + +//----------------------------------------------------------------------------- +// Dicom Part 3.3 Compliant +enum ModalityType { + Unknow, + AU, // Voice Audio + AS, // Angioscopy + BI, // Biomagnetic Imaging + CF, // Cinefluorography + CP, // Culposcopy + CR, // Computed Radiography + CS, // Cystoscopy + CT, // Computed Tomography + DD, // Duplex Dopler + DF, // Digital Fluoroscopy + DG, // Diaphanography + DM, // Digital Microscopy + DS, // Digital Substraction Angiography + DX, // Digital Radiography + ECG, // Echocardiography + EPS, // Basic Cardiac EP + ES, // Endoscopy + FA, // Fluorescein Angiography + FS, // Fundoscopy + HC, // Hard Copy + HD, // Hemodynamic + LP, // Laparoscopy + LS, // Laser Surface Scan + MA, // Magnetic Resonance Angiography + MR, // Magnetic Resonance + NM, // Nuclear Medicine + OT, // Other + PT, // Positron Emission Tomography + RF, // Radio Fluoroscopy + RG, // Radiographic Imaging + RTDOSE, // Radiotherapy Dose + RTIMAGE, // Radiotherapy Image + RTPLAN, // Radiotherapy Plan + RTSTRUCT, // Radiotherapy Structure Set + SM, // Microscopic Imaging + ST, // Single-photon Emission Computed Tomography + TG, // Thermography + US, // Ultrasound + VF, // Videofluorography + XA, // X-Ray Angiography + XC // Photographic Imaging +}; +//----------------------------------------------------------------------------- + class GDCM_EXPORT gdcmHeader : public gdcmDocument { protected: @@ -59,7 +108,7 @@ protected: public: gdcmHeader(bool exception_on_error = false); - gdcmHeader(const char *filename, + gdcmHeader(std::string const & filename, bool exception_on_error = false, bool enable_sequences = false, bool skip_shadow = false); @@ -67,42 +116,80 @@ public: virtual ~gdcmHeader(); // Standard values and informations contained in the header - virtual bool IsReadable(void); + virtual bool IsReadable(); // Some heuristic based accessors, end user intended - // (to be moved to gdcmHeaderHelper?) - int GetXSize(void); - int GetYSize(void); - int GetZSize(void); - int GetBitsStored(void); - int GetBitsAllocated(void); - int GetSamplesPerPixel(void); - int GetPlanarConfiguration(void); - - int GetPixelSize(void); - std::string GetPixelType(void); - size_t GetPixelOffset(void); - size_t GetPixelAreaLength(void); - - bool HasLUT(void); - int GetLUTNbits(void); - unsigned char * GetLUTRGBA(void); - - std::string GetTransfertSyntaxName(void); + int GetBitsStored(); + int GetBitsAllocated(); + int GetSamplesPerPixel(); + int GetPlanarConfiguration(); + int GetPixelSize(); + + int GetPixelSizeGetPixelType(); + std::string GetPixelType(); + size_t GetPixelOffset(); + size_t GetPixelAreaLength(); + + //Some image informations needed for third package imaging library + int GetXSize(); + int GetYSize(); + int GetZSize(); + + float GetXSpacing(); + float GetYSpacing(); + float GetZSpacing(); + //void GetSpacing(float &x, float &y, float &z); + + // Useful for rescaling graylevel: + float GetRescaleIntercept(); + float GetRescaleSlope(); + + int GetNumberOfScalarComponents(); + int GetNumberOfScalarComponentsRaw(); + + // This is usefull for strategy of ordering study / series + // Marking them as deprecated since I believe this is achieve in the + // gdcmDocument operator< + //std::string GetStudyUID(); + //std::string GetSeriesUID(); + //std::string GetClassUID(); + //std::string GetInstanceUID(); + + int GetImageNumber(); + ModalityType GetModality(); + + /** + * change GetXImagePosition -> GetXOrigin in order not to confuse reader + * -# GetXOrigin can return default value (=0) if it was not ImagePosition + * -# Image Position is different in dicomV3 <> ACR NEMA -> better use generic + * name + */ + float GetXOrigin(); + float GetYOrigin(); + float GetZOrigin(); + //void GetOrigin(float &x, float &y, float &z); + + bool HasLUT(); + int GetLUTNbits(); + unsigned char * GetLUTRGBA(); + + std::string GetTransfertSyntaxName(); /// Accessor to \ref gdcmHeader::GrPixel - guint16 GetGrPixel(void) {return GrPixel;} + guint16 GetGrPixel() {return GrPixel;} /// Accessor to \ref gdcmHeader::NumPixel - guint16 GetNumPixel(void) {return NumPixel;} + guint16 GetNumPixel() {return NumPixel;} /// Read (used in gdcmFile) - void SetImageDataSize(size_t ExpectedSize); + void SetImageDataSize(size_t expectedSize); protected: - bool anonymizeHeader(void); -private: + bool AnonymizeHeader(); + void GetImageOrientationPatient( float* iop ); +private: + friend class gdcmSerieHeader; }; //----------------------------------------------------------------------------- diff --git a/src/gdcmHeaderHelper.cxx b/src/gdcmHeaderHelper.cxx index 1b1af705..e2492dc8 100644 --- a/src/gdcmHeaderHelper.cxx +++ b/src/gdcmHeaderHelper.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmHeaderHelper.cxx,v $ Language: C++ - Date: $Date: 2004/06/20 18:08:48 $ - Version: $Revision: 1.37 $ + Date: $Date: 2004/06/21 04:18:26 $ + Version: $Revision: 1.38 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -24,569 +24,11 @@ #include #include -//----------------------------------------------------------------------------- -/** - * \brief constructor - */ -gdcmHeaderHelper::gdcmHeaderHelper() : gdcmHeader( ) { - -} - -/** - * \brief constructor - * @param InFilename Name of the file to deal with - * @param exception_on_error - * @param enable_sequences = true to allow the header - * to be parsed *inside* the SeQuences, - * when they have an actual length - * @param ignore_shadow = true if user wants to skip shadow groups - * during parsing, to save memory space - */ -gdcmHeaderHelper::gdcmHeaderHelper(const char *InFilename, - bool exception_on_error, - bool enable_sequences, - bool ignore_shadow) - : gdcmHeader( InFilename, - exception_on_error, - enable_sequences, - ignore_shadow) -{ -} - -//----------------------------------------------------------------------------- -// Print - -//----------------------------------------------------------------------------- -// Public -/** - * \brief Returns the size (in bytes) of a single pixel of data. - * @return The size in bytes of a single pixel of data. - * - */ -int gdcmHeaderHelper::GetPixelSize() { - - // 0028 0100 US IMG Bits Allocated - // (in order no to be messed up by old RGB images) - if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24") - return 3; - - std::string PixelType = GetPixelType(); - if (PixelType == "8U" || PixelType == "8S") - return 1; - if (PixelType == "16U" || PixelType == "16S") - return 2; - if (PixelType == "32U" || PixelType == "32S") - return 4; - if (PixelType == "FD") // to help unfortunate users to manage DOUBLE - return 8; - dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type"); - return 0; -} - -/** - * \ingroup gdcmHeaderHelper - * \brief Build the Pixel Type of the image. - * Possible values are: - * - 8U unsigned 8 bit, - * - 8S signed 8 bit, - * - 16U unsigned 16 bit, - * - 16S signed 16 bit, - * - 32U unsigned 32 bit, - * - 32S signed 32 bit, - * - FD Double, - * \warning 12 bit images appear as 16 bit. - * 24 bit images appear as 8 bit - * 64 bit means 'DOUBLE' images - * (no DOUBLE images in kosher DICOM, - * but so usefull for people that miss them ;-) - * @return - */ -std::string gdcmHeaderHelper::GetPixelType() { - std::string BitsAlloc; - BitsAlloc = GetEntryByNumber(0x0028, 0x0100); - if (BitsAlloc == GDCM_UNFOUND) { // Bits Allocated - dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated"); - BitsAlloc = std::string("16"); - } - if (BitsAlloc == "12") // It will be unpacked - BitsAlloc = std::string("16"); - else if (BitsAlloc == "24") // (in order no to be messed up - BitsAlloc = std::string("8"); // by old RGB images) - - std::string Signed; - Signed = GetEntryByNumber(0x0028, 0x0103); - if (Signed == GDCM_UNFOUND) { // "Pixel Representation" - dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation"); - BitsAlloc = std::string("0"); - } - if (BitsAlloc == "64") // to help users that want to deal with DOUBLE - return("FD"); - - if (Signed == "0") - Signed = std::string("U"); - else - Signed = std::string("S"); - - return( BitsAlloc + Signed); -} - -/** - * \ingroup gdcmHeaderHelper - * \brief gets the info from 0028,0030 : Pixel Spacing - * else 1.0 - * @return X dimension of a pixel - */ -float gdcmHeaderHelper::GetXSpacing() { - float xspacing, yspacing; - std::string StrSpacing = GetEntryByNumber(0x0028,0x0030); - - if (StrSpacing == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetXSpacing: unfound Pixel Spacing (0028,0030)"); - return 1.; - } - int nbValues; - if( (nbValues = sscanf( StrSpacing.c_str(), "%f\\%f", &yspacing, &xspacing)) != 2) { - if (nbValues==1) // if single value is found, xspacing is defaulted to yspacing - return yspacing; - } - if (xspacing == 0.) { - dbg.Verbose(0, "gdcmHeader::GetYSpacing: gdcmData/CT-MONO2-8-abdo.dcm problem"); - // seems to be a bug in the header ... - sscanf( StrSpacing.c_str(), "%f\\0\\%f", &yspacing, &xspacing); - } - return xspacing; -} - -/** - * \ingroup gdcmHeaderHelper - * \brief gets the info from 0028,0030 : Pixel Spacing - * else 1.0 - * @return Y dimension of a pixel - */ -float gdcmHeaderHelper::GetYSpacing() { - float yspacing; - std::string StrSpacing = GetEntryByNumber(0x0028,0x0030); - - if (StrSpacing == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetYSpacing: unfound Pixel Spacing (0028,0030)"); - return 1.; - } - sscanf( StrSpacing.c_str(), "%f", &yspacing); - return yspacing; -} - -/** - *\ingroup gdcmHeaderHelper - *\brief gets the info from 0018,0088 : Space Between Slices - * else from 0018,0050 : Slice Thickness - * else 1.0 - * @return Z dimension of a voxel-to be - */ -float gdcmHeaderHelper::GetZSpacing() { - // Spacing Between Slices : distance entre le milieu de chaque coupe - // Les coupes peuvent etre : - // jointives (Spacing between Slices = Slice Thickness) - // chevauchantes (Spacing between Slices < Slice Thickness) - // disjointes (Spacing between Slices > Slice Thickness) - // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal - // ca interesse le physicien de l'IRM, pas le visualisateur de volumes ... - // Si le Spacing Between Slices est absent, - // on suppose que les coupes sont jointives - - std::string StrSpacingBSlices = GetEntryByNumber(0x0018,0x0088); - - if (StrSpacingBSlices == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetZSpacing: unfound StrSpacingBSlices"); - std::string StrSliceThickness = GetEntryByNumber(0x0018,0x0050); - if (StrSliceThickness == GDCM_UNFOUND) - return 1.; - else - // if no 'Spacing Between Slices' is found, - // we assume slices join together - // (no overlapping, no interslice gap) - // if they don't, we're fucked up - return atof(StrSliceThickness.c_str()); - } else { - return atof(StrSpacingBSlices.c_str()); - } -} - -/** - *\ingroup gdcmHeaderHelper - *\brief gets the info from 0028,1052 : Rescale Intercept - * @return Rescale Intercept - */ -float gdcmHeaderHelper::GetRescaleIntercept() { - float resInter = 0.; - std::string StrRescInter = GetEntryByNumber(0x0028,0x1052); //0028 1052 DS IMG Rescale Intercept - if (StrRescInter != GDCM_UNFOUND) { - if( sscanf( StrRescInter.c_str(), "%f", &resInter) != 1) { - dbg.Verbose(0, "gdcmHeader::GetRescaleIntercept: Rescale Slope is empty"); - // bug in the element 0x0028,0x1052 - } - } - return resInter; -} - -/** - *\ingroup gdcmHeaderHelper - *\brief gets the info from 0028,1053 : Rescale Slope - * @return Rescale Slope - */ - float gdcmHeaderHelper::GetRescaleSlope() { - float resSlope = 1.; - std::string StrRescSlope = GetEntryByNumber(0x0028,0x1053); //0028 1053 DS IMG Rescale Slope - if (StrRescSlope != GDCM_UNFOUND) { - if( sscanf( StrRescSlope.c_str(), "%f", &resSlope) != 1) { - dbg.Verbose(0, "gdcmHeader::GetRescaleSlope: Rescale Slope is empty"); - // bug in the element 0x0028,0x1053 - } - } - return resSlope; -} - -/** - * \ingroup gdcmHeaderHelper - * \brief This function is intended to user who doesn't want - * to have to manage a LUT and expects to get an RBG Pixel image - * (or a monochrome one ...) - * \warning to be used with GetImagePixels() - * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR) - */ -int gdcmHeaderHelper::GetNumberOfScalarComponents() { - if (GetSamplesPerPixel() ==3) - return 3; - - // 0028 0100 US IMG Bits Allocated - // (in order no to be messed up by old RGB images) - if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24") - return 3; - - std::string PhotometricInterpretation = - gdcmHeader::GetEntryByNumber(0x0028,0x0004); - - if ( ( PhotometricInterpretation == "PALETTE COLOR ") ) { - if (HasLUT()) // PALETTE COLOR is NOT enough - return 3; - else - return 1; - } - - //beware of trailing space at end of string - if (PhotometricInterpretation.find(GDCM_UNFOUND) < - PhotometricInterpretation.length() || - PhotometricInterpretation.find("MONOCHROME1") < - PhotometricInterpretation.length() || - PhotometricInterpretation.find("MONOCHROME2") < - PhotometricInterpretation.length() ) - return 1; - else - // we assume that *all* kinds of YBR are dealt with - return 3; -} - -/** - * \ingroup gdcmHeaderHelper - * \brief This function is intended to user that DOESN'T want - * to get RGB pixels image when it's stored as a PALETTE COLOR image - * - the (vtk) user is supposed to know how deal with LUTs - - * \warning to be used with GetImagePixelsRaw() - * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -) - */ -int gdcmHeaderHelper::GetNumberOfScalarComponentsRaw() { - - // 0028 0100 US IMG Bits Allocated - // (in order no to be messed up by old RGB images) - if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24") - return 3; - - // we assume that *all* kinds of YBR are dealt with - return GetSamplesPerPixel(); -} - -/** - *\ingroup gdcmHeaderHelper - *\brief gets the info from 0020,000d : Study Instance UID - *\todo ? : return the ACR-NEMA element value if DICOM one is not found - * @return Study Instance UID - */ - std::string gdcmHeaderHelper::GetStudyUID(){ - return GetEntryByNumber(0x0020,0x000d); //0020 000d UI REL Study Instance UID -} - -/** - *\ingroup gdcmHeaderHelper - *\brief gets the info from 0020,000e : Series Instance UID - *\todo ? : return the ACR-NEMA element value if DICOM one is not found - * @return Series Instance UID - */ - std::string gdcmHeaderHelper::GetSeriesUID(){ - return GetEntryByNumber(0x0020,0x000e); //0020 000e UI REL Series Instance UID -} - -/** - *\ingroup gdcmHeaderHelper - *\brief gets the info from 0008,0016 : SOP Class UID - *\todo ? : return the ACR-NEMA element value if DICOM one is not found - * @return SOP Class UID - */ - std::string gdcmHeaderHelper::GetClassUID(){ - return GetEntryByNumber(0x0008,0x0016); //0008 0016 UI ID SOP Class UID -} - -/** - *\brief gets the info from 0008,0018 : SOP Instance UID - *\todo ? : return the ACR-NEMA element value if DICOM one is not found - * @return SOP Instance UID - */ - std::string gdcmHeaderHelper::GetInstanceUID(){ - return GetEntryByNumber(0x0008,0x0018); //0008 0018 UI ID SOP Instance UID -} -// -// -------------- Remember ! ---------------------------------- -// -// Image Position Patient (0020,0032): -// If not found (ACR_NEMA) we try Image Position (0020,0030) -// If not found (ACR-NEMA), we consider Slice Location (0020,1041) -// or Location (0020,0050) -// as the Z coordinate, -// 0. for all the coordinates if nothing is found - -// \todo find a way to inform the caller nothing was found -// \todo How to tell the caller a wrong number of values was found? -// -// --------------------------------------------------------------- -// - -/** - * \brief gets the info from 0020,0032 : Image Position Patient - * else from 0020,0030 : Image Position (RET) - * else 0. - * @return up-left image corner X position - */ - -float gdcmHeaderHelper::GetXOrigin() { - float xImPos, yImPos, zImPos; - std::string StrImPos = GetEntryByNumber(0x0020,0x0032); - - if (StrImPos == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position Patient (0020,0032)"); - StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images - if (StrImPos == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position (RET) (0020,0030)"); - /// \todo How to tell the caller nothing was found ? - return 0.; - } - } - if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) - return 0.; - return xImPos; -} - -/** - * \brief gets the info from 0020,0032 : Image Position Patient - * else from 0020,0030 : Image Position (RET) - * else 0. - * @return up-left image corner Y position - */ -float gdcmHeaderHelper::GetYOrigin() { - float xImPos, yImPos, zImPos; - std::string StrImPos = GetEntryByNumber(0x0020,0x0032); - - if (StrImPos == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position Patient (0020,0032)"); - StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images - if (StrImPos == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position (RET) (0020,0030)"); - /// \todo How to tell the caller nothing was found ? - return 0.; - } - } - if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) - return 0.; - return yImPos; -} - -/** - * \brief gets the info from 0020,0032 : Image Position Patient - * \ else from 0020,0030 : Image Position (RET) - * \ else from 0020,1041 : Slice Location - * \ else from 0020,0050 : Location - * \ else 0. - * @return up-left image corner Z position - */ -float gdcmHeaderHelper::GetZOrigin() { - float xImPos, yImPos, zImPos; - std::string StrImPos = GetEntryByNumber(0x0020,0x0032); - if (StrImPos != GDCM_UNFOUND) { - if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) { - dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position Patient (0020,0032)"); - return 0.; // bug in the element 0x0020,0x0032 - } else { - return zImPos; - } - } - StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images - if (StrImPos != GDCM_UNFOUND) { - if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) { - dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position (RET) (0020,0030)"); - return 0.; // bug in the element 0x0020,0x0032 - } else { - return zImPos; - } - } - std::string StrSliceLocation = GetEntryByNumber(0x0020,0x1041);// for *very* old ACR-NEMA images - if (StrSliceLocation != GDCM_UNFOUND) { - if( sscanf( StrSliceLocation.c_str(), "%f", &zImPos) !=1) { - dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Slice Location (0020,1041)"); - return 0.; // bug in the element 0x0020,0x1041 - } else { - return zImPos; - } - } - dbg.Verbose(0, "gdcmHeader::GetZImagePosition: unfound Slice Location (0020,1041)"); - std::string StrLocation = GetEntryByNumber(0x0020,0x0050); - if (StrLocation != GDCM_UNFOUND) { - if( sscanf( StrLocation.c_str(), "%f", &zImPos) !=1) { - dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Location (0020,0050)"); - return 0.; // bug in the element 0x0020,0x0050 - } else { - return zImPos; - } - } - dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Location (0020,0050)"); - return 0.; // Hopeless -} - -/** - * \brief gets the info from 0020,0013 : Image Number - * \ else 0. - * @return image number - */ -int gdcmHeaderHelper::GetImageNumber() { - // The function i atoi() takes the address of an area of memory as - // parameter and converts the string stored at that location to an integer - // using the external decimal to internal binary conversion rules. This may - // be preferable to sscanf() since atoi() is a much smaller, simpler and - // faster function. sscanf() can do all possible conversions whereas - // atoi() can only do single decimal integer conversions. - std::string StrImNumber = GetEntryByNumber(0x0020,0x0013); //0020 0013 IS REL Image Number - if (StrImNumber != GDCM_UNFOUND) { - return atoi( StrImNumber.c_str() ); - } - return 0; //Hopeless -} - -/** - * \brief gets the info from 0008,0060 : Modality - * @return Modality Type - */ -ModalityType gdcmHeaderHelper::GetModality(void) { - // 0008 0060 CS ID Modality - std::string StrModality = GetEntryByNumber(0x0008,0x0060); - if (StrModality != GDCM_UNFOUND) { - if ( StrModality.find("AU") < StrModality.length()) return AU; - else if ( StrModality.find("AS") < StrModality.length()) return AS; - else if ( StrModality.find("BI") < StrModality.length()) return BI; - else if ( StrModality.find("CF") < StrModality.length()) return CF; - else if ( StrModality.find("CP") < StrModality.length()) return CP; - else if ( StrModality.find("CR") < StrModality.length()) return CR; - else if ( StrModality.find("CT") < StrModality.length()) return CT; - else if ( StrModality.find("CS") < StrModality.length()) return CS; - else if ( StrModality.find("DD") < StrModality.length()) return DD; - else if ( StrModality.find("DF") < StrModality.length()) return DF; - else if ( StrModality.find("DG") < StrModality.length()) return DG; - else if ( StrModality.find("DM") < StrModality.length()) return DM; - else if ( StrModality.find("DS") < StrModality.length()) return DS; - else if ( StrModality.find("DX") < StrModality.length()) return DX; - else if ( StrModality.find("ECG") < StrModality.length()) return ECG; - else if ( StrModality.find("EPS") < StrModality.length()) return EPS; - else if ( StrModality.find("FA") < StrModality.length()) return FA; - else if ( StrModality.find("FS") < StrModality.length()) return FS; - else if ( StrModality.find("HC") < StrModality.length()) return HC; - else if ( StrModality.find("HD") < StrModality.length()) return HD; - else if ( StrModality.find("LP") < StrModality.length()) return LP; - else if ( StrModality.find("LS") < StrModality.length()) return LS; - else if ( StrModality.find("MA") < StrModality.length()) return MA; - else if ( StrModality.find("MR") < StrModality.length()) return MR; - else if ( StrModality.find("NM") < StrModality.length()) return NM; - else if ( StrModality.find("OT") < StrModality.length()) return OT; - else if ( StrModality.find("PT") < StrModality.length()) return PT; - else if ( StrModality.find("RF") < StrModality.length()) return RF; - else if ( StrModality.find("RG") < StrModality.length()) return RG; - else if ( StrModality.find("RTDOSE") < StrModality.length()) return RTDOSE; - else if ( StrModality.find("RTIMAGE") < StrModality.length()) return RTIMAGE; - else if ( StrModality.find("RTPLAN") < StrModality.length()) return RTPLAN; - else if ( StrModality.find("RTSTRUCT")< StrModality.length()) return RTSTRUCT; - else if ( StrModality.find("SM") < StrModality.length()) return SM; - else if ( StrModality.find("ST") < StrModality.length()) return ST; - else if ( StrModality.find("TG") < StrModality.length()) return TG; - else if ( StrModality.find("US") < StrModality.length()) return US; - else if ( StrModality.find("VF") < StrModality.length()) return VF; - else if ( StrModality.find("XA") < StrModality.length()) return XA; - else if ( StrModality.find("XC") < StrModality.length()) return XC; - - else - { - /// \todo throw error return value ??? - /// specified <> unknow in our database - return Unknow; - } - } - return Unknow; -} - -/** - * \brief gets the info from 0020,0037 : Image Orientation Patient - * @param iop adress of the (6)float aray to receive values - * @return cosines of image orientation patient - */ -void gdcmHeaderHelper::GetImageOrientationPatient( float* iop ) { - - //iop is supposed to be float[6] - iop[0] = iop[1] = iop[2] = iop[3] = iop[4] = iop[5] = 0; - - // 0020 0037 DS REL Image Orientation (Patient) - std::string StrImOriPat = GetEntryByNumber(0x0020,0x0037); - if (StrImOriPat != GDCM_UNFOUND) { - if( sscanf( StrImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", - &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6) { - dbg.Verbose(0, "gdcmHeader::GetImageOrientationPatient: wrong Image Orientation Patient (0020,0037)"); - return ; // bug in the element 0x0020,0x0037 - } - else - return ; - } - - //For ACR-NEMA - // 0020 0035 DS REL Image Orientation (RET) - StrImOriPat = GetEntryByNumber(0x0020,0x0035); - if (StrImOriPat != GDCM_UNFOUND) { - if( sscanf( StrImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", - &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6) { - dbg.Verbose(0, "gdcmHeader::GetImageOrientationPatient: wrong Image Orientation Patient (0020,0035)"); - return ; // bug in the element 0x0020,0x0035 - } - else - return ; - } -} - -//----------------------------------------------------------------------------- -// Protected - -//----------------------------------------------------------------------------- -// Private - -//----------------------------------------------------------------------------- - - - //----------------------------------------------------------------------------- // Constructor / Destructor -gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper(){ +gdcmSerieHeader::~gdcmSerieHeader(){ /// \todo - for (std::list::iterator it = CoherentGdcmFileList.begin(); + for (std::list::iterator it = CoherentGdcmFileList.begin(); it != CoherentGdcmFileList.end(); it++) { delete *it; @@ -603,16 +45,16 @@ gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper(){ * \brief add a gdcmFile to the list based on file name * @param filename Name of the file to deal with */ -void gdcmSerieHeaderHelper::AddFileName(std::string filename) { - gdcmHeaderHelper *GdcmFile = new gdcmHeaderHelper( filename.c_str() ); +void gdcmSerieHeader::AddFileName(std::string filename) { + gdcmHeader *GdcmFile = new gdcmHeader( filename ); this->CoherentGdcmFileList.push_back( GdcmFile ); } /** * \brief add a gdcmFile to the list - * @param file gdcmHeaderHelper to add + * @param file gdcmHeader to add */ -void gdcmSerieHeaderHelper::AddGdcmFile(gdcmHeaderHelper *file){ +void gdcmSerieHeader::AddGdcmFile(gdcmHeader *file){ this->CoherentGdcmFileList.push_back( file ); } @@ -620,13 +62,13 @@ void gdcmSerieHeaderHelper::AddGdcmFile(gdcmHeaderHelper *file){ * \brief Sets the Directory * @param dir Name of the directory to deal with */ -void gdcmSerieHeaderHelper::SetDirectory(std::string dir){ +void gdcmSerieHeader::SetDirectory(std::string dir){ gdcmDirList filenames_list(dir); //OS specific for(gdcmDirList::iterator it = filenames_list.begin(); it !=filenames_list.end(); it++) { - gdcmHeaderHelper *file = new gdcmHeaderHelper( it->c_str() ); + gdcmHeader *file = new gdcmHeader( it->c_str() ); this->CoherentGdcmFileList.push_back( file ); } } @@ -637,7 +79,7 @@ void gdcmSerieHeaderHelper::SetDirectory(std::string dir){ * But as I don't know how to do it, I leave it this way * BTW, this is also a Strategy, I don't know this is the best approach :) */ -void gdcmSerieHeaderHelper::OrderGdcmFileList(){ +void gdcmSerieHeader::OrderGdcmFileList(){ if( ImagePositionPatientOrdering() ) { return ; } @@ -652,7 +94,7 @@ void gdcmSerieHeaderHelper::OrderGdcmFileList(){ * \brief Gets the *coherent* File List * @return the *coherent* File List */ -std::list &gdcmSerieHeaderHelper::GetGdcmFileList() { +std::list &gdcmSerieHeader::GetGdcmFileList() { return CoherentGdcmFileList; } @@ -662,7 +104,7 @@ std::list &gdcmSerieHeaderHelper::GetGdcmFileList() { //----------------------------------------------------------------------------- // Private /** - * \ingroup gdcmHeaderHelper + * \ingroup gdcmHeader * \brief sorts the images, according to their Patient Position * We may order, considering : * -# Image Number @@ -670,7 +112,7 @@ std::list &gdcmSerieHeaderHelper::GetGdcmFileList() { * -# More to come :) * @return false only if the header is bugged ! */ -bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() +bool gdcmSerieHeader::ImagePositionPatientOrdering() //based on Jolinda's algorithm { //iop is calculated based on the file file @@ -684,7 +126,7 @@ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() std::vector distlist; //!\todo rewrite this for loop. - for (std::list::iterator it = CoherentGdcmFileList.begin(); + for (std::list::iterator it = CoherentGdcmFileList.begin(); it != CoherentGdcmFileList.end(); it++) { if(first) { @@ -742,7 +184,7 @@ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() //Then I order the slices according to the value "dist". Finally, once //I've read in all the slices, I calculate the z-spacing as the difference //between the "dist" values for the first two slices. - std::vector CoherentGdcmFileVector(n); + std::vector CoherentGdcmFileVector(n); //CoherentGdcmFileVector.reserve( n ); CoherentGdcmFileVector.resize( n ); //assert( CoherentGdcmFileVector.capacity() >= n ); @@ -752,7 +194,7 @@ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() n = 0; //VC++ don't understand what scope is !! it -> it2 - for (std::list::iterator it2 = CoherentGdcmFileList.begin(); + for (std::list::iterator it2 = CoherentGdcmFileList.begin(); it2 != CoherentGdcmFileList.end(); it2++, n++) { //2*n sort algo !! @@ -765,7 +207,7 @@ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() CoherentGdcmFileList.clear(); //this doesn't delete list's element, node only //VC++ don't understand what scope is !! it -> it3 - for (std::vector::iterator it3 = CoherentGdcmFileVector.begin(); + for (std::vector::iterator it3 = CoherentGdcmFileVector.begin(); it3 != CoherentGdcmFileVector.end(); it3++) { CoherentGdcmFileList.push_back( *it3 ); @@ -779,17 +221,17 @@ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() } /** - * \ingroup gdcmHeaderHelper + * \ingroup gdcmHeader * \brief sorts the images, according to their Image Number * @return false only if the header is bugged ! */ -bool gdcmSerieHeaderHelper::ImageNumberOrdering() { +bool gdcmSerieHeader::ImageNumberOrdering() { int min, max, pos; int n = 0;//CoherentGdcmFileList.size() is a O(N) operation !! unsigned char *partition; - std::list::iterator it = CoherentGdcmFileList.begin(); + std::list::iterator it = CoherentGdcmFileList.begin(); min = max = (*it)->GetImageNumber(); for (; it != CoherentGdcmFileList.end(); it++, n++) @@ -804,10 +246,10 @@ bool gdcmSerieHeaderHelper::ImageNumberOrdering() { partition = new unsigned char[n]; memset(partition, 0, n); - std::vector CoherentGdcmFileVector(n); + std::vector CoherentGdcmFileVector(n); //VC++ don't understand what scope is !! it -> it2 - for (std::list::iterator it2 = CoherentGdcmFileList.begin(); + for (std::list::iterator it2 = CoherentGdcmFileList.begin(); it2 != CoherentGdcmFileList.end(); it2++) { pos = (*it2)->GetImageNumber(); @@ -823,7 +265,7 @@ bool gdcmSerieHeaderHelper::ImageNumberOrdering() { //VC++ don't understand what scope is !! it -> it3 CoherentGdcmFileList.clear(); //this doesn't delete list's element, node only - for (std::vector::iterator it3 = CoherentGdcmFileVector.begin(); + for (std::vector::iterator it3 = CoherentGdcmFileVector.begin(); it3 != CoherentGdcmFileVector.end(); it3++) { CoherentGdcmFileList.push_back( *it3 ); @@ -836,11 +278,11 @@ bool gdcmSerieHeaderHelper::ImageNumberOrdering() { /** - * \ingroup gdcmHeaderHelper + * \ingroup gdcmHeader * \brief sorts the images, according to their File Name * @return false only if the header is bugged ! */ - bool gdcmSerieHeaderHelper::FileNameOrdering() { + bool gdcmSerieHeader::FileNameOrdering() { //using the sort //sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end()); return true; diff --git a/src/gdcmHeaderHelper.h b/src/gdcmHeaderHelper.h index 9381f7f9..9aa136cc 100644 --- a/src/gdcmHeaderHelper.h +++ b/src/gdcmHeaderHelper.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmHeaderHelper.h,v $ Language: C++ - Date: $Date: 2004/06/20 18:08:48 $ - Version: $Revision: 1.16 $ + Date: $Date: 2004/06/21 04:18:26 $ + Version: $Revision: 1.17 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -22,140 +22,42 @@ #include "gdcmHeader.h" //----------------------------------------------------------------------------- -// Dicom Part 3.3 Compliant -enum ModalityType { - Unknow, - AU, // Voice Audio - AS, // Angioscopy - BI, // Biomagnetic Imaging - CF, // Cinefluorography - CP, // Culposcopy - CR, // Computed Radiography - CS, // Cystoscopy - CT, // Computed Tomography - DD, // Duplex Dopler - DF, // Digital Fluoroscopy - DG, // Diaphanography - DM, // Digital Microscopy - DS, // Digital Substraction Angiography - DX, // Digital Radiography - ECG, // Echocardiography - EPS, // Basic Cardiac EP - ES, // Endoscopy - FA, // Fluorescein Angiography - FS, // Fundoscopy - HC, // Hard Copy - HD, // Hemodynamic - LP, // Laparoscopy - LS, // Laser Surface Scan - MA, // Magnetic Resonance Angiography - MR, // Magnetic Resonance - NM, // Nuclear Medicine - OT, // Other - PT, // Positron Emission Tomography - RF, // Radio Fluoroscopy - RG, // Radiographic Imaging - RTDOSE, // Radiotherapy Dose - RTIMAGE, // Radiotherapy Image - RTPLAN, // Radiotherapy Plan - RTSTRUCT, // Radiotherapy Structure Set - SM, // Microscopic Imaging - ST, // Single-photon Emission Computed Tomography - TG, // Thermography - US, // Ultrasound - VF, // Videofluorography - XA, // X-Ray Angiography - XC // Photographic Imaging -}; - -//----------------------------------------------------------------------------- -/* - * \defgroup gdcmHeaderHelper - * \brief - * - * - This class is meant to *interpret* data given from gdcmHeader - * - That is to say : - * - it will help other dev to link against there lib - * - return value instead of string - * - will be able to search for data at some other place - * - return *default value* which is not a gdcmHeader goal - * - ... - */ -class GDCM_EXPORT gdcmHeaderHelper : public gdcmHeader { -public: - gdcmHeaderHelper(); - gdcmHeaderHelper(const char *filename, - bool exception_on_error = false, - bool enable_sequences = false, - bool ignore_shadow = false); - - int GetPixelSize(); - std::string GetPixelType(); - - float GetXSpacing(); - float GetYSpacing(); - float GetZSpacing(); - - // Usefull for rescaling graylevel: - float GetRescaleIntercept(); - float GetRescaleSlope(); - int GetNumberOfScalarComponents(); - int GetNumberOfScalarComponentsRaw(); - - std::string GetStudyUID(); - std::string GetSeriesUID(); - std::string GetClassUID(); - std::string GetInstanceUID(); - - /** - * change GetXImagePosition -> GetXOrigin in order not to confuse reader - * -# GetXOrigin can return default value (=0) if it was not ImagePosition - * -# Image Position is different in dicomV3 <> ACR NEMA -> better use generic - * name - */ - float GetXOrigin(); - float GetYOrigin(); - float GetZOrigin(); - - int GetImageNumber(); - ModalityType GetModality(); - - void GetImageOrientationPatient( float* iop ); +class GDCM_EXPORT gdcmHeaderHelper : public gdcmHeader +{ }; -//----------------------------------------------------------------------------- /* - * \defgroup gdcmSerieHeaderHelper + * \defgroup gdcmSerieHeader * \brief * * - This class should be used for a stack of 2D dicom images. * - For a multiframe dicom image better use directly gdcmHeaderHelper */ -class GDCM_EXPORT gdcmSerieHeaderHelper { +class GDCM_EXPORT gdcmSerieHeader { public: - gdcmSerieHeaderHelper() {}; - ~gdcmSerieHeaderHelper(); + gdcmSerieHeader() {}; + ~gdcmSerieHeader(); void AddFileName(std::string filename); //should return bool or throw error ? - void AddGdcmFile(gdcmHeaderHelper *file); + void AddGdcmFile(gdcmHeader *file); void SetDirectory(std::string dir); void OrderGdcmFileList(); - inline gdcmHeaderHelper *GetGdcmHeader() + inline gdcmHeader *GetGdcmHeader() { //Assume all element in the list have the same global infos return CoherentGdcmFileList.front(); } - std::list& GetGdcmFileList(); + std::list& GetGdcmFileList(); private: bool ImagePositionPatientOrdering(); bool ImageNumberOrdering(); bool FileNameOrdering(); - std::list CoherentGdcmFileList; + std::list CoherentGdcmFileList; }; //----------------------------------------------------------------------------- diff --git a/vtk/vtkGdcmReader.cxx b/vtk/vtkGdcmReader.cxx index ea4545a0..7c514894 100644 --- a/vtk/vtkGdcmReader.cxx +++ b/vtk/vtkGdcmReader.cxx @@ -261,9 +261,9 @@ void vtkGdcmReader::ExecuteData(vtkDataObject *output) { // The memory size for a full stack of images of course depends // on the number of planes and the size of each image: - size_t StackNumPixels = this->NumColumns * this->NumLines - * this->TotalNumberOfPlanes * this->NumComponents; - size_t stack_size = StackNumPixels * this->PixelSize; + //size_t StackNumPixels = this->NumColumns * this->NumLines + // * this->TotalNumberOfPlanes * this->NumComponents; + //size_t stack_size = StackNumPixels * this->PixelSize; //not used // Allocate pixel data space itself. // Variables for the UpdateProgress. We shall use 50 steps to signify @@ -441,7 +441,7 @@ int vtkGdcmReader::CheckFileCoherence() fclose(fp); // Stage 1.2: check for Gdcm parsability - gdcmHeaderHelper GdcmHeader(FileName->c_str(), false, true); + gdcmHeader GdcmHeader(FileName->c_str(), false, true); // true : for enableSequences if (!GdcmHeader.IsReadable()) { diff --git a/vtk/vtkgdcmViewer.cxx b/vtk/vtkgdcmViewer.cxx index e6326efd..709d93da 100644 --- a/vtk/vtkgdcmViewer.cxx +++ b/vtk/vtkgdcmViewer.cxx @@ -27,7 +27,7 @@ class vtkgdcmObserver : public vtkCommand { this->ImageViewer = NULL; } - virtual void Execute(vtkObject *wdg, unsigned long event, void* calldata) + virtual void Execute(vtkObject *, unsigned long event, void* ) { if ( this->ImageViewer ) { @@ -85,7 +85,7 @@ int main(int argc, char *argv[]) } viewer->SetupInteractor (iren); - vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange(); + //vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange(); //viewer->SetColorWindow (range[1] - range[0]); //viewer->SetColorLevel (0.5 * (range[1] + range[0]));