// gdcmHeaderHelper.cxx
//-----------------------------------------------------------------------------
#include "gdcmHeaderHelper.h"
+#include "gdcmDirList.h"
-#include "gdcmUtil.h" //for debug
+#include "gdcmDebug.h"
#include <math.h>
#include <algorithm>
-
-#ifdef _MSC_VER
- #include <windows.h>
-
- int GetDir(std::string dPath, std::list<std::string> &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 <dirent.h>
-
- int GetDir(std::string dPath, std::list<std::string> &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 <vector>
//-----------------------------------------------------------------------------
-// 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)
{
}
// 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.
*
*/
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;
}
* - 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() {
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
/**
* \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() {
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 ...
/**
* \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() {
}
}
+/**
+ *\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
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) {
// 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;
/**
* \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' -)
*/
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(){
+/**
+ *\ingroup gdcmHeaderHelper
+ *\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)
// 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);
/**
* \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;
* \ 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;
/**
* \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
/**
* \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 ) {
/**
* \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) {
gdcmHeaderHelper *GdcmFile = new gdcmHeaderHelper( filename.c_str() );
/**
* \ingroup gdcmHeaderHelper
* \brief add a gdcmFile to the list
+ * @param file gdcmHeaderHelper to add
*/
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<std::string> filenames_list;
- GetDir(dir, filenames_list); //OS specific
+ gdcmDirList filenames_list(dir); //OS specific
- for(std::list<std::string>::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 :)
+/**
+ * \ingroup gdcmHeaderHelper
+ * \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() )
- {
+ if( ImagePositionPatientOrdering() ) {
return ;
}
- else if( ImageNumberOrdering() )
- {
+ else if( ImageNumberOrdering() ) {
return ;
- }
- else
- {
+ } else {
FileNameOrdering();
}
}
+/**
+ * \ingroup gdcmHeaderHelper
+ * \brief Gets the *coherent* File List
+ * @return the *coherent* File List
+*/
std::list<gdcmHeaderHelper*> &gdcmSerieHeaderHelper::GetGdcmFileList() {
return CoherentGdcmFileList;
}
// 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
delete[] cosines;
return false;
}
-
distlist.push_back( dist );
return true;
}
-//Based on Image Number
+/**
+ * \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<gdcmHeaderHelper*>::iterator it = CoherentGdcmFileList.begin();
return (mult!=0);
}
-bool gdcmSerieHeaderHelper::FileNameOrdering() {
+
+/**
+ * \ingroup gdcmHeaderHelper
+ * \brief sorts the images, according to their File Name
+ * @return false only if the header is bugged !
+ */
+ bool gdcmSerieHeaderHelper::FileNameOrdering() {
//using the sort
//sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end());
return true;