From 59d3befd7f593a3a6f10162d91bf757c1a4956ac Mon Sep 17 00:00:00 2001 From: malaterre Date: Mon, 8 Sep 2003 16:37:47 +0000 Subject: [PATCH] * src/gdcmHeaderHelper.[h cxx]: added new class that provide an interpretation to data given by gdcmHeader. For instance there are heuristics to get informations (look at different places). * it also include a specific class: gdcmSerieHeaderHelper devoted to sorting DICOM images based on different strategies. * modified Makefiles accordingly. --- ChangeLog | 7 + src/Makefile.am | 2 + src/gdcmHeaderHelper.cxx | 710 +++++++++++++++++++++++++++++++++++++++ src/gdcmHeaderHelper.h | 99 ++++++ src/win32/gdcmdll.dsp | 4 + vtk/win32/vtkgdcm.dsp | 4 + 6 files changed, 826 insertions(+) create mode 100644 src/gdcmHeaderHelper.cxx create mode 100644 src/gdcmHeaderHelper.h diff --git a/ChangeLog b/ChangeLog index 7a8b734d..70066411 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2003-09-08 Mathieu Malaterre + * src/gdcmHeaderHelper.[h cxx]: added new class that provide an + interpretation to data given by gdcmHeader. For instance there are + heuristics to get informations (look at different places). + * it also include a specific class: gdcmSerieHeaderHelper devoted to + sorting DICOM images based on different strategies. + * modified Makefiles accordingly. 2003-09-05 Mathieu Malaterre * src/*.cxx : added pragma disable 4786/4251 to get rid of ~4300 warning when building in debug mode diff --git a/src/Makefile.am b/src/Makefile.am index c60798f5..6d005201 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ libgdcm_la_SOURCES= \ gdcmException.cxx \ gdcmUtil.cxx \ gdcmHeader.cxx \ + gdcmHeaderHelper.cxx \ gdcmElValue.cxx \ gdcmDictEntry.cxx \ gdcmDict.cxx \ @@ -35,6 +36,7 @@ libgdcmincludedir = $(includedir) libgdcminclude_HEADERS = \ gdcmException.h \ gdcmHeader.h \ + gdcmHeaderHelper.h \ gdcmCommon.h \ gdcm.h \ gdcmDictSet.h \ diff --git a/src/gdcmHeaderHelper.cxx b/src/gdcmHeaderHelper.cxx new file mode 100644 index 00000000..41d85d0e --- /dev/null +++ b/src/gdcmHeaderHelper.cxx @@ -0,0 +1,710 @@ +// $Header: /cvs/public/gdcm/src/Attic/gdcmHeaderHelper.cxx,v 1.1 2003/09/08 16:37:47 malaterre Exp $ + +//This is needed when compiling in debug mode +#ifdef _MSC_VER +#pragma warning ( disable : 4800 ) +// 'identifier' : class 'type' needs to have dll-interface to be used by +// clients of class 'type2' +#pragma warning ( disable : 4251 ) +// 'identifier' : identifier was truncated to 'number' characters in the +// debug information +#pragma warning ( disable : 4786 ) +#endif //_MSC_VER + +#include "gdcmHeaderHelper.h" +#include "gdcmUtil.h" //for debug +#include +#include +#include //for bzero +using namespace std; + +//directory manipulation (os indep). +//cygwin ???? -> _WIN32 ?? +#ifdef _MSC_VER +#include +int GetDir(string dPath, list &filenames) +{ + WIN32_FIND_DATA FileData; + HANDLE hFile; + hFile = FindFirstFile(dPath.c_str(), &FileData); + if ( hFile == INVALID_HANDLE_VALUE ) + { + //No files ! + return false; + } + + filenames.push_back( FileData.cFileName ); + while( FindNextFile(hFile, &FileData ) != 0) + { + filenames.push_back( FileData.cFileName ); + } + return true; +} + +#else +#include + +int GetDir(string dPath, list &filenames) +{ + DIR *dir = opendir( dPath.c_str() ); + struct dirent *entry; + while((entry = readdir(dir)) != NULL) + { +// if( strncmp(entry->d_name, ".", 1) != 0 && strncmp(entry->d_name, "..", 2) != 0) + if( strncmp(entry->d_name, ".", 1) != 0 ) + { + filenames.push_back( dPath + "/" + entry->d_name ); + } + } + closedir(dir); + return true; +} + +#endif + +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief cstor + */ +gdcmHeaderHelper::gdcmHeaderHelper() : gdcmHeader( ) +{ +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief cstor + */ +gdcmHeaderHelper::gdcmHeaderHelper(const char *InFilename, + bool exception_on_error) : gdcmHeader( InFilename , exception_on_error) +{ +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief Return the size (in bytes) of a single pixel of data. + * @return The size in bytes of a single pixel of data. + * + */ +int gdcmHeaderHelper::GetPixelSize() { + string PixelType = GetPixelType(); + if (PixelType == "8U" || PixelType == "8S") + return 1; + if (PixelType == "16U" || PixelType == "16S") + return 2; + if (PixelType == "32U" || PixelType == "32S") + return 4; + 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, + * \warning 12 bit images appear as 16 bit. + * @return + */ +string gdcmHeaderHelper::GetPixelType() { + string BitsAlloc; + BitsAlloc = GetElValByName("Bits Allocated"); + if (BitsAlloc == "gdcm::Unfound") { + dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated"); + BitsAlloc = string("16"); + } + if (BitsAlloc == "12") + BitsAlloc = string("16"); + + string Signed; + Signed = GetElValByName("Pixel Representation"); + if (Signed == "gdcm::Unfound") { + dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation"); + BitsAlloc = string("0"); + } + if (Signed == "0") + Signed = string("U"); + else + Signed = string("S"); + + return( BitsAlloc + Signed); +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief gets the info from 0028,0030 : Pixel Spacing + * \ else 1. + * @return X dimension of a pixel + */ +float gdcmHeaderHelper::GetXSpacing() { + float xspacing, yspacing; + string StrSpacing = GetPubElValByNumber(0x0028,0x0030); + + if (StrSpacing == "gdcm::Unfound") { + dbg.Verbose(0, "gdcmHeader::GetXSpacing: unfound Pixel Spacing (0028,0030)"); + return 1.; + } + if( sscanf( StrSpacing.c_str(), "%f\\%f", &xspacing, &yspacing) != 2) + return 0.; + //else + return xspacing; +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief gets the info from 0028,0030 : Pixel Spacing + * \ else 1. + * @return Y dimension of a pixel + */ +float gdcmHeaderHelper::GetYSpacing() { + float xspacing, yspacing; + string StrSpacing = GetPubElValByNumber(0x0028,0x0030); + + if (StrSpacing == "gdcm::Unfound") { + dbg.Verbose(0, "gdcmHeader::GetYSpacing: unfound Pixel Spacing (0028,0030)"); + return 1.; + } + if( sscanf( StrSpacing.c_str(), "%f\\%f", &xspacing, &yspacing) != 2) + return 0.; + if (yspacing == 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", &xspacing, &yspacing); + } + return yspacing; +} + +//---------------------------------------------------------------------------- +/** + *\ingroup gdcmHeaderHelper + *\brief gets the info from 0018,0088 : Space Between Slices + *\ else from 0018,0050 : Slice Thickness + *\ else 1. + * @return Z dimension of a voxel-to be + */ +float gdcmHeaderHelper::GetZSpacing() { + // TODO : translate into English + // 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 + + string StrSpacingBSlices = GetPubElValByNumber(0x0018,0x0088); + + if (StrSpacingBSlices == "gdcm::Unfound") { + dbg.Verbose(0, "gdcmHeader::GetZSpacing: unfound StrSpacingBSlices"); + string StrSliceThickness = GetPubElValByNumber(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()); + } +} + +//---------------------------------------------------------------------------- +// +// 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? + +/** + * \ingroup gdcmHeaderHelper + * \brief gets the info from 0020,0032 : Image Position Patient + *\ else from 0020,0030 : Image Position (RET) + *\ else 0. + * @return up-left image corner position + */ +float gdcmHeaderHelper::GetXOrigin() { + float xImPos, yImPos, zImPos; + string StrImPos = GetPubElValByNumber(0x0020,0x0032); + + if (StrImPos == "gdcm::Unfound") { + dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position Patient (0020,0032)"); + StrImPos = GetPubElValByNumber(0x0020,0x0030); // For ACR-NEMA images + if (StrImPos == "gdcm::Unfound") { + dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position (RET) (0020,0030)"); + // 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; +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief gets the info from 0020,0032 : Image Position Patient + * \ else from 0020,0030 : Image Position (RET) + * \ else 0. + * @return up-left image corner position + */ +float gdcmHeaderHelper::GetYOrigin() { + float xImPos, yImPos, zImPos; + string StrImPos = GetPubElValByNumber(0x0020,0x0032); + + if (StrImPos == "gdcm::Unfound") { + dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position Patient (0020,0032)"); + StrImPos = GetPubElValByNumber(0x0020,0x0030); // For ACR-NEMA images + if (StrImPos == "gdcm::Unfound") { + dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position (RET) (0020,0030)"); + // 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; +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \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 position + */ +float gdcmHeaderHelper::GetZOrigin() { + float xImPos, yImPos, zImPos; + string StrImPos = GetPubElValByNumber(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 = GetPubElValByNumber(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; + } + } + string StrSliceLocation = GetPubElValByNumber(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)"); + string StrLocation = GetPubElValByNumber(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 +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \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. + string StrImNumber = GetPubElValByNumber(0x0020,0x0013); //0020 0013 IS REL Image Number + if (StrImNumber != "gdcm::Unfound") { + return atoi( StrImNumber.c_str() ); + } + return 0; //Hopeless +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief gets the info from 0008,0060 : Modality + * @return ModalityType + */ +ModalityType gdcmHeaderHelper::GetModality(void) { + string StrModality = GetPubElValByNumber(0x0008,0x0060); //0008 0060 CS ID Modality + if (StrModality != "gdcm::Unfound") { + if ( StrModality.find("CR") < StrModality.length()) + { + return CR; + } + else if ( StrModality.find("CT") < StrModality.length() ) + { + return CT; + } + 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("US") < StrModality.length()) + { + return US; + } + else if ( StrModality.find("XA") < StrModality.length()) + { + return XA; + } + else + { + //throw error return value ??? + // specified <> unknow in our database + return Unknow; + } + } + return Unknow; +} + +//---------------------------------------------------------------------------- +string gdcmHeaderHelper::GetStudyUID() +{ + return GetPubElValByNumber(0x0020,0x000d); //!0020 000d UI REL Study Instance UID +} +//---------------------------------------------------------------------------- +string gdcmHeaderHelper::GetSeriesUID() +{ + return GetPubElValByNumber(0x0020,0x000e); //!0020 000e UI REL Series Instance UID +} +//---------------------------------------------------------------------------- +string gdcmHeaderHelper::GetClassUID() +{ + return GetPubElValByNumber(0x0008,0x0016); //!0008 0016 UI ID SOP Class UID +} +//---------------------------------------------------------------------------- +string gdcmHeaderHelper::GetInstanceUID() +{ + return GetPubElValByNumber(0x0008,0x0018); //!0008 0018 UI ID SOP Instance UID +} + + + + + + + + + +gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper() +{ + //! \todo + for (list::iterator it = CoherentGdcmFileList.begin(); + it != CoherentGdcmFileList.end(); it++) + { + delete *it; + } + CoherentGdcmFileList.clear(); +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief gets the info from 0020,0037 : Image Orientation Patient + * @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; + + string StrImOriPat = GetPubElValByNumber(0x0020,0x0037); // 0020 0037 DS REL Image Orientation (Patient) + 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 + StrImOriPat = GetPubElValByNumber(0x0020,0x0035); //0020 0035 DS REL Image Orientation (RET) + 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 ; + } +} + +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief add a gdcmFile to the list based on file name + */ +void gdcmSerieHeaderHelper::AddFileName(string filename) +{ + gdcmHeaderHelper *GdcmFile = new gdcmHeaderHelper( filename.c_str() ); + this->CoherentGdcmFileList.push_back( GdcmFile ); +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief add a gdcmFile to the list + */ +void gdcmSerieHeaderHelper::AddGdcmFile(gdcmHeaderHelper *file) +{ + this->CoherentGdcmFileList.push_back( file ); +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief \todo + */ +void gdcmSerieHeaderHelper::SetDirectory(string dir) +{ + list filenames_list; + GetDir(dir, filenames_list); //OS specific + + for(list::iterator it = filenames_list.begin(); it != + filenames_list.end(); it++) + { + gdcmHeaderHelper *file = new gdcmHeaderHelper( it->c_str() ); + this->CoherentGdcmFileList.push_back( file ); + } +} +//---------------------------------------------------------------------------- +//This could be implemented in a 'Strategy Pattern' approach +//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 approcah :) +void gdcmSerieHeaderHelper::OrderGdcmFileList() +{ + if( ImagePositionPatientOrdering() ) + { + return ; + } + else if( ImageNumberOrdering() ) + { + return ; + } + else + { + FileNameOrdering(); + } +} +//---------------------------------------------------------------------------- +/** + * \ingroup gdcmHeaderHelper + * \brief + We may order, considering : + -# Image Number + -# Image Position Patient + -# More to come :) +*/ +//based on Jolinda's algorithm +bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() +{ + //iop is calculated based on the file file + float *cosines = new float[6]; + float normal[3]; + float ipp[3]; + float dist; + float min, max; + bool first = true; + int n=0; + vector distlist; + + //!\todo rewrite this for loop. + for (list::iterator it = CoherentGdcmFileList.begin(); + it != CoherentGdcmFileList.end(); it++) + { + if(first) { + (*it)->GetImageOrientationPatient(cosines); + + //You only have to do this once for all slices in the volume. Next, for + //each slice, calculate the distance along the slice normal using the IPP + //tag ("dist" is initialized to zero before reading the first slice) : + normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4]; + normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5]; + normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3]; + + ipp[0] = (*it)->GetXOrigin(); + ipp[1] = (*it)->GetYOrigin(); + ipp[2] = (*it)->GetZOrigin(); + + dist = 0; + for (int i = 0; i < 3; ++i) + dist += normal[i]*ipp[i]; + + if( dist == 0 ) + { + delete cosines; + return false; + } + + distlist.push_back( dist ); + + max = min = dist; + first = false; + } + else { + ipp[0] = (*it)->GetXOrigin(); + ipp[1] = (*it)->GetYOrigin(); + ipp[2] = (*it)->GetZOrigin(); + + dist = 0; + for (int i = 0; i < 3; ++i) + dist += normal[i]*ipp[i]; + + if( dist == 0 ) + { + delete cosines; + return false; + } + + + distlist.push_back( dist ); + + min = (min < dist) ? min : dist; + max = (max > dist) ? max : dist; + } + n++; + } + + //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. + vector CoherentGdcmFileVector(n); + //CoherentGdcmFileVector.reserve( n ); + CoherentGdcmFileVector.resize( n ); + //assert( CoherentGdcmFileVector.capacity() >= n ); + + float step = (max - min)/(n - 1); + int pos; + n = 0; + + //VC++ don't understand what scope is !! it -> it2 + for (list::iterator it2 = CoherentGdcmFileList.begin(); + it2 != CoherentGdcmFileList.end(); it2++, n++) + { + //2*n sort algo !! + //Assumption: all files are present (no one missing) + pos = (int)( fabs( (distlist[n]-min)/step) + .5 ); + + CoherentGdcmFileVector[pos] = *it2; + } + + CoherentGdcmFileList.clear(); //this doesn't delete list's element, node only + + //VC++ don't understand what scope is !! it -> it3 + for (vector::iterator it3 = CoherentGdcmFileVector.begin(); + it3 != CoherentGdcmFileVector.end(); it3++) + { + CoherentGdcmFileList.push_back( *it3 ); + } + + distlist.clear(); + CoherentGdcmFileVector.clear(); + delete[] cosines; + + return true; +} +//---------------------------------------------------------------------------- +//Based on Image Number +bool gdcmSerieHeaderHelper::ImageNumberOrdering() +{ + int min, max, pos; + int n = 0;//CoherentGdcmFileList.size(); //O(N) operation !! + unsigned char *partition; + + list::iterator it = CoherentGdcmFileList.begin(); + min = max = (*it)->GetImageNumber(); + + for (; it != CoherentGdcmFileList.end(); it++, n++) + { + pos = (*it)->GetImageNumber(); + + //else + min = (min < pos) ? min : pos; + } + + //bzeros(partition, n); //Cette fonction est déconseillée, utilisez plutôt memset. + partition = new unsigned char[n]; + memset(partition, 0, n); + + vector CoherentGdcmFileVector(n); + + //VC++ don't understand what scope is !! it -> it2 + for (list::iterator it2 = CoherentGdcmFileList.begin(); + it2 != CoherentGdcmFileList.end(); it2++) + { + pos = (*it2)->GetImageNumber(); + CoherentGdcmFileVector[pos - min] = *it2; + partition[pos - min]++; + } + + unsigned char mult; + for(int i=0; i it3 + CoherentGdcmFileList.clear(); //this doesn't delete list's element, node only + for (vector::iterator it3 = CoherentGdcmFileVector.begin(); + it3 != CoherentGdcmFileVector.end(); it3++) + { + CoherentGdcmFileList.push_back( *it3 ); + std::cout << (*it3)->GetImageNumber() << std::endl; + } + CoherentGdcmFileVector.clear(); + + delete partition; + return mult; +} +//---------------------------------------------------------------------------- +bool gdcmSerieHeaderHelper::FileNameOrdering() +{ + //using the sort + //sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end()); + return true; +} +//---------------------------------------------------------------------------- +list &gdcmSerieHeaderHelper::GetGdcmFileList() +{ + return CoherentGdcmFileList; +} +//---------------------------------------------------------------------------- diff --git a/src/gdcmHeaderHelper.h b/src/gdcmHeaderHelper.h new file mode 100644 index 00000000..6fb9e2d4 --- /dev/null +++ b/src/gdcmHeaderHelper.h @@ -0,0 +1,99 @@ +// $Header: /cvs/public/gdcm/src/Attic/gdcmHeaderHelper.h,v 1.1 2003/09/08 16:37:47 malaterre Exp $ + +#ifndef GDCMHEADERHELPER_H +#define GDCMHEADERHELPER_H + +#include "gdcmHeader.h" +#include +#include +#include + + enum ModalityType { + Unknow, + CR, + CT, + MR, + NM, + OT, + US, + XA }; + +/** + This class is meant to *interprate* 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(); + gdcmHeaderHelper::gdcmHeaderHelper(const char *filename, bool exception_on_error = false); + + //Ces fonction releve de l'interpretation des données de gdcmHeader + int GetPixelSize(); + std::string GetPixelType(); + + float GetXSpacing(); + float GetYSpacing(); + float GetZSpacing(); + + std::string GetStudyUID(); + std::string GetSeriesUID(); + std::string GetClassUID(); + std::string GetInstanceUID(); + + /** + change GetXImagePosition -> GetXOrigin in order not to confused 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 ); + +}; + +/** +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 { + +public: + gdcmSerieHeaderHelper::gdcmSerieHeaderHelper() {}; + gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper(); + + void AddFileName(std::string filename); //should return bool or throw error ? + void AddGdcmFile(gdcmHeaderHelper *file); + void SetDirectory(std::string dir); + void OrderGdcmFileList(); + + gdcmHeaderHelper *GetGdcmHeader() + { + //Assume all element in the list have the same global infos + return CoherentGdcmFileList.front(); + } + + std::list& GetGdcmFileList(); + +private: + bool ImagePositionPatientOrdering(); + bool ImageNumberOrdering(); + bool FileNameOrdering(); + + std::list CoherentGdcmFileList; + +}; + +#endif diff --git a/src/win32/gdcmdll.dsp b/src/win32/gdcmdll.dsp index 34fb5ceb..237f81c5 100644 --- a/src/win32/gdcmdll.dsp +++ b/src/win32/gdcmdll.dsp @@ -136,6 +136,10 @@ SOURCE=..\gdcmHeader.cxx # End Source File # Begin Source File +SOURCE=..\gdcmHeaderHelper.cxx +# End Source File +# Begin Source File + SOURCE=..\gdcmHeaderIdo.cxx # End Source File # Begin Source File diff --git a/vtk/win32/vtkgdcm.dsp b/vtk/win32/vtkgdcm.dsp index 292d4b65..0f7b7b96 100644 --- a/vtk/win32/vtkgdcm.dsp +++ b/vtk/win32/vtkgdcm.dsp @@ -132,6 +132,10 @@ SOURCE=..\..\src\gdcmHeader.cxx # End Source File # Begin Source File +SOURCE=..\..\src\gdcmHeaderHelper.cxx +# End Source File +# Begin Source File + SOURCE=..\..\src\gdcmHeaderIdo.cxx # End Source File # Begin Source File -- 2.45.1