X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmHeaderHelper.cxx;h=54f9b4ec897fcf5ec4890e5e0fdab234e62d9526;hb=3f0c0dc58eba64083f79a898d6f60119cd448650;hp=aeb83222b903773c2b60aea05300859cbd3d4b05;hpb=bafdfafe6c1b30607035fc4018c0405169b348e8;p=gdcm.git diff --git a/src/gdcmHeaderHelper.cxx b/src/gdcmHeaderHelper.cxx index aeb83222..54f9b4ec 100644 --- a/src/gdcmHeaderHelper.cxx +++ b/src/gdcmHeaderHelper.cxx @@ -1,75 +1,39 @@ // gdcmHeaderHelper.cxx //----------------------------------------------------------------------------- #include "gdcmHeaderHelper.h" +#include "gdcmDirList.h" -#include "gdcmUtil.h" //for debug +#include "gdcmDebug.h" #include #include - -#ifdef _MSC_VER - #include - - int GetDir(std::string dPath, std::list &filenames) - { - //For now dPath should have an ending "\" - WIN32_FIND_DATA FileData; - HANDLE hFile; - hFile = FindFirstFile((dPath+"*").c_str(), &FileData); - if ( hFile == INVALID_HANDLE_VALUE ) - { - //No files ! - return false; - } - - if( strncmp(FileData.cFileName, ".", 1) != 0 ) - filenames.push_back( dPath+FileData.cFileName ); - while( FindNextFile(hFile, &FileData ) != 0) - { - if( strncmp(FileData.cFileName, ".", 1) != 0 ) - filenames.push_back( dPath+FileData.cFileName ); - } - return true; - } - -#else - #include - - int GetDir(std::string dPath, std::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 +#include //----------------------------------------------------------------------------- -// gdcmHeaderHelper -//----------------------------------------------------------------------------- -// Constructor / Destructor /** - * \ingroup gdcmHeaderHelper - * \brief cstor + * \brief constructor */ -gdcmHeaderHelper::gdcmHeaderHelper() : gdcmHeader( ) -{ +gdcmHeaderHelper::gdcmHeaderHelper() : gdcmHeader( ) { + } /** - * \ingroup gdcmHeaderHelper - * \brief cstor + * \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) : gdcmHeader( InFilename , exception_on_error) + bool exception_on_error, + bool enable_sequences, + bool ignore_shadow) + : gdcmHeader( InFilename, + exception_on_error, + enable_sequences, + ignore_shadow) { } @@ -79,8 +43,7 @@ gdcmHeaderHelper::gdcmHeaderHelper(const char *InFilename, //----------------------------------------------------------------------------- // Public /** - * \ingroup gdcmHeaderHelper - * \brief Return the size (in bytes) of a single pixel of data. + * \brief Returns the size (in bytes) of a single pixel of data. * @return The size in bytes of a single pixel of data. * */ @@ -98,6 +61,8 @@ int gdcmHeaderHelper::GetPixelSize() { 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; } @@ -112,8 +77,12 @@ int gdcmHeaderHelper::GetPixelSize() { * - 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 + * 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() { @@ -127,13 +96,16 @@ std::string gdcmHeaderHelper::GetPixelType() { 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 @@ -145,7 +117,7 @@ std::string gdcmHeaderHelper::GetPixelType() { /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0028,0030 : Pixel Spacing - * \ else 1. + * else 1.0 * @return X dimension of a pixel */ float gdcmHeaderHelper::GetXSpacing() { @@ -156,8 +128,11 @@ float gdcmHeaderHelper::GetXSpacing() { dbg.Verbose(0, "gdcmHeader::GetXSpacing: unfound Pixel Spacing (0028,0030)"); return 1.; } - if( sscanf( StrSpacing.c_str(), "%f\\%f", &yspacing, &xspacing) != 2) - return 0.; + 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 ... @@ -169,32 +144,26 @@ float gdcmHeaderHelper::GetXSpacing() { /** * \ingroup gdcmHeaderHelper * \brief gets the info from 0028,0030 : Pixel Spacing - * \ else 1. + * else 1.0 * @return Y dimension of a pixel */ float gdcmHeaderHelper::GetYSpacing() { - float xspacing, yspacing; + float yspacing; std::string StrSpacing = GetEntryByNumber(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", &yspacing, &xspacing) != 2) - return 0.; - 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); - } + 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. + * else from 0018,0050 : Slice Thickness + * else 1.0 * @return Z dimension of a voxel-to be */ float gdcmHeaderHelper::GetZSpacing() { @@ -226,8 +195,12 @@ float gdcmHeaderHelper::GetZSpacing() { } } -float gdcmHeaderHelper::GetRescaleIntercept() -{ +/** + *\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) { @@ -239,8 +212,12 @@ float gdcmHeaderHelper::GetRescaleIntercept() return resInter; } -float gdcmHeaderHelper::GetRescaleSlope() -{ +/** + *\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) { @@ -249,19 +226,18 @@ float gdcmHeaderHelper::GetRescaleSlope() // bug in the element 0x0028,0x1053 } } - return resSlope; + return resSlope; } /** * \ingroup gdcmHeaderHelper - * \brief This function is intended to user who doesn't whan - * \ to have to manage a LUT and expects to get an RBG Pixel image - * \ (or a monochrome one ...) + * \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; @@ -296,8 +272,8 @@ int gdcmHeaderHelper::GetNumberOfScalarComponents() { /** * \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 - + * 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' -) */ @@ -312,26 +288,47 @@ int gdcmHeaderHelper::GetNumberOfScalarComponentsRaw() { return GetSamplesPerPixel(); } -std::string gdcmHeaderHelper::GetStudyUID() -{ +/** + *\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 } -std::string gdcmHeaderHelper::GetSeriesUID() -{ +/** + *\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 } -std::string gdcmHeaderHelper::GetClassUID() -{ +/** + *\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 } -std::string gdcmHeaderHelper::GetInstanceUID() -{ +/** + *\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) @@ -339,15 +336,19 @@ std::string gdcmHeaderHelper::GetInstanceUID() // 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? +// \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 + * 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); @@ -357,7 +358,7 @@ float gdcmHeaderHelper::GetXOrigin() { StrImPos = GetEntryByNumber(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 ? + /// \todo How to tell the caller nothing was found ? return 0.; } } @@ -367,11 +368,10 @@ float gdcmHeaderHelper::GetXOrigin() { } /** - * \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 + * else from 0020,0030 : Image Position (RET) + * else 0. + * @return up-left image corner Y position */ float gdcmHeaderHelper::GetYOrigin() { float xImPos, yImPos, zImPos; @@ -382,7 +382,7 @@ float gdcmHeaderHelper::GetYOrigin() { StrImPos = GetEntryByNumber(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 ? + /// \todo How to tell the caller nothing was found ? return 0.; } } @@ -392,13 +392,12 @@ float gdcmHeaderHelper::GetYOrigin() { } /** - * \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 + * @return up-left image corner Z position */ float gdcmHeaderHelper::GetZOrigin() { float xImPos, yImPos, zImPos; @@ -444,17 +443,17 @@ float gdcmHeaderHelper::GetZOrigin() { } /** - * \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. + // 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() ); @@ -463,12 +462,12 @@ int gdcmHeaderHelper::GetImageNumber() { } /** - * \ingroup gdcmHeaderHelper * \brief gets the info from 0008,0060 : Modality - * @return ModalityType + * @return Modality Type */ ModalityType gdcmHeaderHelper::GetModality(void) { - std::string StrModality = GetEntryByNumber(0x0008,0x0060); //0008 0060 CS ID Modality + // 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; @@ -513,8 +512,8 @@ ModalityType gdcmHeaderHelper::GetModality(void) { else { - //throw error return value ??? - // specified <> unknow in our database + /// \todo throw error return value ??? + /// specified <> unknow in our database return Unknow; } } @@ -522,8 +521,8 @@ ModalityType gdcmHeaderHelper::GetModality(void) { } /** - * \ingroup gdcmHeaderHelper * \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 ) { @@ -531,7 +530,8 @@ 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; - std::string StrImOriPat = GetEntryByNumber(0x0020,0x0037); // 0020 0037 DS REL Image Orientation (Patient) + // 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) { @@ -543,7 +543,8 @@ void gdcmHeaderHelper::GetImageOrientationPatient( float* iop ) { } //For ACR-NEMA - StrImOriPat = GetEntryByNumber(0x0020,0x0035); //0020 0035 DS REL Image Orientation (RET) + // 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) { @@ -565,13 +566,10 @@ void gdcmHeaderHelper::GetImageOrientationPatient( float* iop ) { -//----------------------------------------------------------------------------- -// gdcmSerieHeaderHelper //----------------------------------------------------------------------------- // Constructor / Destructor -gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper() -{ - //! \todo +gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper(){ + /// \todo for (std::list::iterator it = CoherentGdcmFileList.begin(); it != CoherentGdcmFileList.end(); it++) { @@ -586,62 +584,59 @@ gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper() //----------------------------------------------------------------------------- // Public /** - * \ingroup gdcmHeaderHelper * \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) -{ +void gdcmSerieHeaderHelper::AddFileName(std::string filename) { gdcmHeaderHelper *GdcmFile = new gdcmHeaderHelper( filename.c_str() ); this->CoherentGdcmFileList.push_back( GdcmFile ); } /** - * \ingroup gdcmHeaderHelper * \brief add a gdcmFile to the list + * @param file gdcmHeaderHelper to add */ -void gdcmSerieHeaderHelper::AddGdcmFile(gdcmHeaderHelper *file) -{ +void gdcmSerieHeaderHelper::AddGdcmFile(gdcmHeaderHelper *file){ this->CoherentGdcmFileList.push_back( file ); } /** - * \ingroup gdcmHeaderHelper - * \brief \todo + * \brief Sets the Directory + * @param dir Name of the directory to deal with */ -void gdcmSerieHeaderHelper::SetDirectory(std::string dir) -{ - std::list filenames_list; - GetDir(dir, filenames_list); //OS specific +void gdcmSerieHeaderHelper::SetDirectory(std::string dir){ + gdcmDirList filenames_list(dir); //OS specific - for(std::list::iterator it = filenames_list.begin(); it != - filenames_list.end(); it++) + for(gdcmDirList::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 approach :) -void gdcmSerieHeaderHelper::OrderGdcmFileList() -{ - if( ImagePositionPatientOrdering() ) - { +/** + * \brief Sorts the File List + * \warning 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 approach :) +*/ +void gdcmSerieHeaderHelper::OrderGdcmFileList(){ + if( ImagePositionPatientOrdering() ) { return ; } - else if( ImageNumberOrdering() ) - { + else if( ImageNumberOrdering() ) { return ; - } - else - { + } else { FileNameOrdering(); } } -std::list &gdcmSerieHeaderHelper::GetGdcmFileList() -{ +/** + * \brief Gets the *coherent* File List + * @return the *coherent* File List +*/ +std::list &gdcmSerieHeaderHelper::GetGdcmFileList() { return CoherentGdcmFileList; } @@ -652,11 +647,12 @@ std::list &gdcmSerieHeaderHelper::GetGdcmFileList() // Private /** * \ingroup gdcmHeaderHelper - * \brief + * \brief sorts the images, according to their Patient Position * We may order, considering : * -# Image Number * -# Image Position Patient * -# More to come :) + * @return false only if the header is bugged ! */ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() //based on Jolinda's algorithm @@ -718,7 +714,6 @@ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() delete[] cosines; return false; } - distlist.push_back( dist ); @@ -767,11 +762,15 @@ bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering() return true; } -//Based on Image Number -bool gdcmSerieHeaderHelper::ImageNumberOrdering() -{ +/** + * \ingroup gdcmHeaderHelper + * \brief sorts the images, according to their Image Number + * @return false only if the header is bugged ! + */ + +bool gdcmSerieHeaderHelper::ImageNumberOrdering() { int min, max, pos; - int n = 0;//CoherentGdcmFileList.size(); //O(N) operation !! + int n = 0;//CoherentGdcmFileList.size() is a O(N) operation !! unsigned char *partition; std::list::iterator it = CoherentGdcmFileList.begin(); @@ -800,7 +799,7 @@ bool gdcmSerieHeaderHelper::ImageNumberOrdering() partition[pos - min]++; } - unsigned char mult; + unsigned char mult = 1; for(int i=0; i