Program: gdcm
Module: $RCSfile: gdcmSerieHeader.cxx,v $
Language: C++
- Date: $Date: 2005/01/07 22:19:48 $
- Version: $Revision: 1.4 $
+ Date: $Date: 2005/02/01 19:05:53 $
+ Version: $Revision: 1.21 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
#include "gdcmSerieHeader.h"
#include "gdcmDirList.h"
-#include "gdcmHeader.h"
+#include "gdcmFile.h"
+#include "gdcmDebug.h"
#include <math.h>
#include <algorithm>
namespace gdcm
{
+typedef std::list<File* > GdcmFileList;
+typedef std::vector<File* > GdcmFileVector;
-typedef std::vector<Header* > GdcmHeaderVector;
//-----------------------------------------------------------------------------
// Constructor / Destructor
+/**
+ * \brief Constructor from a given SerieHeader
+ */
SerieHeader::SerieHeader()
{
- CoherentGdcmFileList.clear();
+ // For all the File lists of the gdcm::Serie
+ GdcmFileList *l = GetFirstCoherentFileList();
+ while (l)
+ {
+ // For all the files of a File list
+ for (GdcmFileList::iterator it = l->begin();
+ it != l->end();
+ ++it)
+ {
+ delete *it;
+ }
+ l->clear();
+ delete l;;
+ l = GetNextCoherentFileList();
+ }
}
+/**
+ * \brief Canonical destructor.
+ */
SerieHeader::~SerieHeader()
{
- /// \todo
- for ( GdcmHeaderList::const_iterator it = CoherentGdcmFileList.begin();
- it != CoherentGdcmFileList.end(); ++it)
- {
- delete *it;
+ // For all the Coherent File lists of the gdcm::Serie
+ GdcmFileList *l = GetFirstCoherentFileList();
+ while (l)
+ {
+ // For all the files of a Coherent File list
+ for (GdcmFileList::iterator it = l->begin();
+ it != l->end();
+ ++it)
+ {
+ delete *it;
+ }
+ l->clear();
+ delete l;
+ l = GetNextCoherentFileList();
}
- CoherentGdcmFileList.clear();
}
//-----------------------------------------------------------------------------
-// Print
//-----------------------------------------------------------------------------
+
// Public
/**
- * \brief add a File to the list based on file name
+ * \brief add a gdcm::File to the list corresponding to its Serie UID
* @param filename Name of the file to deal with
*/
void SerieHeader::AddFileName(std::string const &filename)
{
- Header *header = new Header( filename );
- CoherentGdcmFileList.push_back( header );
-}
+ //directly use string and not const char*:
+ File *header = new File( filename );
+ if( header->IsReadable() )
+ {
+ // 0020 000e UI REL Series Instance UID
+ std::string uid = header->GetEntryValue (0x0020, 0x000e);
+ // if uid == GDCM_UNFOUND then consistently we should find GDCM_UNFOUND
+ // no need here to do anything special
-/**
- * \brief add a File to the list
- * @param file Header to add
- */
-void SerieHeader::AddGdcmFile(Header *file)
-{
- CoherentGdcmFileList.push_back( file );
+ if ( CoherentGdcmFileListHT.count(uid) == 0 )
+ {
+ gdcmVerboseMacro(" New Serie UID :[" << uid << "]");
+ // create a std::list in 'uid' position
+ CoherentGdcmFileListHT[uid] = new GdcmFileList;
+ }
+ // Current Serie UID and DICOM header seems to match add the file:
+ CoherentGdcmFileListHT[uid]->push_back( header );
+ }
+ else
+ {
+ gdcmVerboseMacro("Could not read file: " << filename );
+ delete header;
+ }
}
/**
- * \brief Sets the Directory
+ * \brief Sets the root Directory
* @param dir Name of the directory to deal with
+ * @param recursive whether we want explore recursively the Directory
*/
-void SerieHeader::SetDirectory(std::string const &dir)
+void SerieHeader::SetDirectory(std::string const &dir, bool recursive)
{
- DirList filenames_list(dir); //OS specific
+ DirList dirList(dir, recursive); // OS specific
- for( DirList::const_iterator it = filenames_list.begin();
+ DirListType filenames_list = dirList.GetFilenames();
+ for( DirListType::const_iterator it = filenames_list.begin();
it != filenames_list.end(); ++it)
{
- //directly use string and not const char*:
- Header *header = new Header( *it );
- if( header->IsReadable() )
- {
- CoherentGdcmFileList.push_back( header );
- }
- else
- {
- delete header;
- }
+ AddFileName( *it );
}
}
/**
- * \brief Sorts the File List
+ * \brief Sorts the given 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 SerieHeader::OrderGdcmFileList()
+void SerieHeader::OrderGdcmFileList(GdcmFileList *CoherentGdcmFileList)
{
- if( ImagePositionPatientOrdering() )
+ if( ImagePositionPatientOrdering( CoherentGdcmFileList ) )
{
return ;
}
- else if( ImageNumberOrdering() )
+ else if( ImageNumberOrdering(CoherentGdcmFileList ) )
{
return ;
}
else
{
- FileNameOrdering();
+ FileNameOrdering(CoherentGdcmFileList );
}
}
+/**
+ * \brief Get the first List while visiting the CoherentFileListHT
+ * @return The first GdcmFileList if found, otherwhise NULL
+ */
+ std::list<File* > *SerieHeader::GetFirstCoherentFileList()
+// Why doesn't it compile ?!?
+//GdcmFileList *SerieHeader::GetFirstCoherentFileList()
+{
+ ItListHt = CoherentGdcmFileListHT.begin();
+ if( ItListHt != CoherentGdcmFileListHT.end() )
+ return ItListHt->second;
+ return NULL;
+}
+
+/**
+ * \brief Get the next List while visiting the CoherentFileListHT
+ * \note : meaningfull only if GetFirstCoherentFileList already called
+ * @return The next GdcmFileList if found, otherwhise NULL
+ */
+std::list<File* > *SerieHeader::GetNextCoherentFileList()
+{
+ gdcmAssertMacro (ItListHt != CoherentGdcmFileListHT.end());
+
+ ++ItListHt;
+ if ( ItListHt != CoherentGdcmFileListHT.end() )
+ return ItListHt->second;
+ return NULL;
+}
+
+/**
+ * \brief Get the Coherent Files list according to its Serie UID
+ * @param SerieUID SerieUID
+ * \return pointer to the Coherent Filseslist if found, otherwhise NULL
+ */
+GdcmFileList *SerieHeader::GetCoherentFileList(std::string SerieUID)
+{
+ if ( CoherentGdcmFileListHT.count(SerieUID) == 0 )
+ return 0;
+ return CoherentGdcmFileListHT[SerieUID];
+}
+
//-----------------------------------------------------------------------------
// Protected
//-----------------------------------------------------------------------------
// Private
/**
- * \ingroup Header
* \brief sorts the images, according to their Patient Position
* We may order, considering :
- * -# Image Number
* -# Image Position Patient
- * -# More to come :)
+ * -# Image Number
+ * -# More to come :-)
+ * @param CoherentGdcmFileList Coherent File list (same Serie UID) to sort
* @return false only if the header is bugged !
*/
-bool SerieHeader::ImagePositionPatientOrdering()
+bool SerieHeader::ImagePositionPatientOrdering(
+ GdcmFileList *CoherentGdcmFileList )
//based on Jolinda's algorithm
{
//iop is calculated based on the file file
- float *cosines = new float[6];
+ float cosines[6];
float normal[3];
float ipp[3];
float dist;
std::vector<float> distlist;
//!\todo rewrite this for loop.
- for ( GdcmHeaderList::const_iterator
- it = CoherentGdcmFileList.begin();
- it != CoherentGdcmFileList.end(); ++it )
+ for ( GdcmFileList::const_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,
+ // 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) :
if( dist == 0 )
{
- delete[] cosines;
return false;
}
if( dist == 0 )
{
- delete[] cosines;
return false;
}
// 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.
- GdcmHeaderVector CoherentGdcmFileVector(n);
+ GdcmFileVector CoherentGdcmFileVector(n);
// CoherentGdcmFileVector.reserve( n );
CoherentGdcmFileVector.resize( n );
// gdcmAssertMacro( CoherentGdcmFileVector.capacity() >= n );
n = 0;
//VC++ don't understand what scope is !! it -> it2
- for (GdcmHeaderList::const_iterator it2 = CoherentGdcmFileList.begin();
- it2 != CoherentGdcmFileList.end(); ++it2, ++n)
+ for (GdcmFileList::const_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;
+
+ // a Dicom 'Serie' may contain scout views
+ // and images may have differents directions
+ // -> More than one may have the same 'pos'
+ // Sorting has then NO meaning !
+ if (CoherentGdcmFileVector[pos]==NULL)
+ CoherentGdcmFileVector[pos] = *it2;
+ else
+ {
+ gdcmVerboseMacro( "2 files same position");
+ return false;
+ }
}
- CoherentGdcmFileList.clear(); //this doesn't delete list's element, node only
+ CoherentGdcmFileList->clear(); // doesn't delete list elements, only node
//VC++ don't understand what scope is !! it -> it3
- for (GdcmHeaderVector::const_iterator it3 = CoherentGdcmFileVector.begin();
+ for (GdcmFileVector::const_iterator it3 = CoherentGdcmFileVector.begin();
it3 != CoherentGdcmFileVector.end(); ++it3)
{
- CoherentGdcmFileList.push_back( *it3 );
+ CoherentGdcmFileList->push_back( *it3 );
}
distlist.clear();
CoherentGdcmFileVector.clear();
- delete[] cosines;
return true;
}
/**
- * \ingroup Header
* \brief sorts the images, according to their Image Number
- * @return false only if the header is bugged !
+ * \note Works only on bona fide files (i.e image number is a character string
+ * corresponding to an integer)
+ * within a bona fide serie (i.e image numbers are consecutive)
+ * @param CoherentGdcmFileList Coherent File list (same Serie UID) to sort
+ * @return false if non nona fide stuff encountered
*/
-
-bool SerieHeader::ImageNumberOrdering()
+bool SerieHeader::ImageNumberOrdering(GdcmFileList *CoherentGdcmFileList)
{
int min, max, pos;
int n = 0;//CoherentGdcmFileList.size() is a O(N) operation
- unsigned char *partition;
-
- GdcmHeaderList::const_iterator it = CoherentGdcmFileList.begin();
+
+ GdcmFileList::const_iterator it = CoherentGdcmFileList->begin();
min = max = (*it)->GetImageNumber();
- for (; it != CoherentGdcmFileList.end(); ++it, ++n)
+ for (; it != CoherentGdcmFileList->end(); ++it, ++n)
{
pos = (*it)->GetImageNumber();
-
- //else
min = (min < pos) ? min : pos;
max = (max > pos) ? max : pos;
}
- // Find out if sorting worked:
- if( min == max || max == 0 || max > (n+min)) return false;
+ // Find out if image numbers are coherent (consecutive)
+ if( min == max || max == 0 || max >= (n+min))
+ return false;
- //bzeros(partition, n); //This function is deprecated, better use memset.
- partition = new unsigned char[n];
- memset(partition, 0, n);
+ unsigned char *partition = new unsigned char[n];
+ memset(partition, 0, n);
- GdcmHeaderVector CoherentGdcmFileVector(n);
+ GdcmFileVector CoherentGdcmFileVector(n);
- //VC++ don't understand what scope is !! it -> it2
- for (GdcmHeaderList::const_iterator it2 = CoherentGdcmFileList.begin();
- it2 != CoherentGdcmFileList.end(); ++it2)
+ for (it = CoherentGdcmFileList->begin();
+ it != CoherentGdcmFileList->end(); ++it)
{
- pos = (*it2)->GetImageNumber();
- CoherentGdcmFileVector[pos - min] = *it2;
+ pos = (*it)->GetImageNumber();
+ CoherentGdcmFileVector[pos - min] = *it;
partition[pos - min]++;
}
- unsigned char mult = 1;
- for( int i=0; i<n ; i++ )
- {
- mult *= partition[i];
- }
-
- //VC++ don't understand what scope is !! it -> it3
- CoherentGdcmFileList.clear(); //this doesn't delete list's element, node only
- for ( GdcmHeaderVector::const_iterator it3 = CoherentGdcmFileVector.begin();
+ //VC++ doesn't understand what scope is, it -> it3
+ CoherentGdcmFileList->clear(); // doesn't delete list elements, only nodes
+ for ( GdcmFileVector::const_iterator it3 = CoherentGdcmFileVector.begin();
it3 != CoherentGdcmFileVector.end(); ++it3 )
{
- CoherentGdcmFileList.push_back( *it3 );
+ CoherentGdcmFileList->push_back( *it3 );
}
CoherentGdcmFileVector.clear();
-
delete[] partition;
- return (mult != 0);
+ return true;
}
-
/**
- * \ingroup Header
* \brief sorts the images, according to their File Name
+ * @param CoherentGdcmFileList Coherent File list (same Serie UID) to sort
* @return false only if the header is bugged !
*/
-bool SerieHeader::FileNameOrdering()
+bool SerieHeader::FileNameOrdering(GdcmFileList *)
{
- //using the sort
+ //TODO using the sort
//sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end());
return true;
}
-} // end namespace gdcm
//-----------------------------------------------------------------------------
+// Print
+/**
+ * \brief Canonical printer.
+ */
+void SerieHeader::Print()
+{
+ // For all the Coherent File lists of the gdcm::Serie
+ CoherentFileListmap::iterator itl = CoherentGdcmFileListHT.begin();
+ if ( itl == CoherentGdcmFileListHT.end() )
+ {
+ gdcmVerboseMacro( "No Coherent File list found" );
+ return;
+ }
+ while (itl != CoherentGdcmFileListHT.end())
+ {
+ std::cout << "Serie UID :[" << itl->first << "]" << std::endl;
+
+ // For all the files of a Coherent File list
+ for (GdcmFileList::iterator it = (itl->second)->begin();
+ it != (itl->second)->end();
+ ++it)
+ {
+ std::cout << " --- " << (*it)->GetFileName() << std::endl;
+ }
+ ++itl;
+ }
+}
+
+//-----------------------------------------------------------------------------
+} // end namespace gdcm