1 /*=========================================================================
4 Module: $RCSfile: gdcmSerieHeader.cxx,v $
6 Date: $Date: 2005/02/01 19:05:53 $
7 Version: $Revision: 1.21 $
9 Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10 l'Image). All rights reserved. See Doc/License.txt or
11 http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
13 This software is distributed WITHOUT ANY WARRANTY; without even
14 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 PURPOSE. See the above copyright notices for more information.
17 =========================================================================*/
19 #include "gdcmSerieHeader.h"
20 #include "gdcmDirList.h"
22 #include "gdcmDebug.h"
30 typedef std::list<File* > GdcmFileList;
31 typedef std::vector<File* > GdcmFileVector;
33 //-----------------------------------------------------------------------------
34 // Constructor / Destructor
36 * \brief Constructor from a given SerieHeader
38 SerieHeader::SerieHeader()
40 // For all the File lists of the gdcm::Serie
41 GdcmFileList *l = GetFirstCoherentFileList();
44 // For all the files of a File list
45 for (GdcmFileList::iterator it = l->begin();
53 l = GetNextCoherentFileList();
58 * \brief Canonical destructor.
60 SerieHeader::~SerieHeader()
62 // For all the Coherent File lists of the gdcm::Serie
63 GdcmFileList *l = GetFirstCoherentFileList();
66 // For all the files of a Coherent File list
67 for (GdcmFileList::iterator it = l->begin();
75 l = GetNextCoherentFileList();
79 //-----------------------------------------------------------------------------
81 //-----------------------------------------------------------------------------
85 * \brief add a gdcm::File to the list corresponding to its Serie UID
86 * @param filename Name of the file to deal with
88 void SerieHeader::AddFileName(std::string const &filename)
90 //directly use string and not const char*:
91 File *header = new File( filename );
92 if( header->IsReadable() )
94 // 0020 000e UI REL Series Instance UID
95 std::string uid = header->GetEntryValue (0x0020, 0x000e);
96 // if uid == GDCM_UNFOUND then consistently we should find GDCM_UNFOUND
97 // no need here to do anything special
99 if ( CoherentGdcmFileListHT.count(uid) == 0 )
101 gdcmVerboseMacro(" New Serie UID :[" << uid << "]");
102 // create a std::list in 'uid' position
103 CoherentGdcmFileListHT[uid] = new GdcmFileList;
105 // Current Serie UID and DICOM header seems to match add the file:
106 CoherentGdcmFileListHT[uid]->push_back( header );
110 gdcmVerboseMacro("Could not read file: " << filename );
116 * \brief Sets the root Directory
117 * @param dir Name of the directory to deal with
118 * @param recursive whether we want explore recursively the Directory
120 void SerieHeader::SetDirectory(std::string const &dir, bool recursive)
122 DirList dirList(dir, recursive); // OS specific
124 DirListType filenames_list = dirList.GetFilenames();
125 for( DirListType::const_iterator it = filenames_list.begin();
126 it != filenames_list.end(); ++it)
133 * \brief Sorts the given File List
134 * \warning This could be implemented in a 'Strategy Pattern' approach
135 * But as I don't know how to do it, I leave it this way
136 * BTW, this is also a Strategy, I don't know this is the best approach :)
138 void SerieHeader::OrderGdcmFileList(GdcmFileList *CoherentGdcmFileList)
140 if( ImagePositionPatientOrdering( CoherentGdcmFileList ) )
144 else if( ImageNumberOrdering(CoherentGdcmFileList ) )
150 FileNameOrdering(CoherentGdcmFileList );
155 * \brief Get the first List while visiting the CoherentFileListHT
156 * @return The first GdcmFileList if found, otherwhise NULL
158 std::list<File* > *SerieHeader::GetFirstCoherentFileList()
159 // Why doesn't it compile ?!?
160 //GdcmFileList *SerieHeader::GetFirstCoherentFileList()
162 ItListHt = CoherentGdcmFileListHT.begin();
163 if( ItListHt != CoherentGdcmFileListHT.end() )
164 return ItListHt->second;
169 * \brief Get the next List while visiting the CoherentFileListHT
170 * \note : meaningfull only if GetFirstCoherentFileList already called
171 * @return The next GdcmFileList if found, otherwhise NULL
173 std::list<File* > *SerieHeader::GetNextCoherentFileList()
175 gdcmAssertMacro (ItListHt != CoherentGdcmFileListHT.end());
178 if ( ItListHt != CoherentGdcmFileListHT.end() )
179 return ItListHt->second;
184 * \brief Get the Coherent Files list according to its Serie UID
185 * @param SerieUID SerieUID
186 * \return pointer to the Coherent Filseslist if found, otherwhise NULL
188 GdcmFileList *SerieHeader::GetCoherentFileList(std::string SerieUID)
190 if ( CoherentGdcmFileListHT.count(SerieUID) == 0 )
192 return CoherentGdcmFileListHT[SerieUID];
195 //-----------------------------------------------------------------------------
198 //-----------------------------------------------------------------------------
201 * \brief sorts the images, according to their Patient Position
202 * We may order, considering :
203 * -# Image Position Patient
205 * -# More to come :-)
206 * @param CoherentGdcmFileList Coherent File list (same Serie UID) to sort
207 * @return false only if the header is bugged !
209 bool SerieHeader::ImagePositionPatientOrdering(
210 GdcmFileList *CoherentGdcmFileList )
211 //based on Jolinda's algorithm
213 //iop is calculated based on the file file
218 float min = 0, max = 0;
221 std::vector<float> distlist;
223 //!\todo rewrite this for loop.
224 for ( GdcmFileList::const_iterator
225 it = CoherentGdcmFileList->begin();
226 it != CoherentGdcmFileList->end(); ++it )
230 (*it)->GetImageOrientationPatient( cosines );
232 // You only have to do this once for all slices in the volume. Next,
233 // for each slice, calculate the distance along the slice normal
234 // using the IPP tag ("dist" is initialized to zero before reading
235 // the first slice) :
236 normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4];
237 normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5];
238 normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3];
240 ipp[0] = (*it)->GetXOrigin();
241 ipp[1] = (*it)->GetYOrigin();
242 ipp[2] = (*it)->GetZOrigin();
245 for ( int i = 0; i < 3; ++i )
247 dist += normal[i]*ipp[i];
255 distlist.push_back( dist );
262 ipp[0] = (*it)->GetXOrigin();
263 ipp[1] = (*it)->GetYOrigin();
264 ipp[2] = (*it)->GetZOrigin();
267 for ( int i = 0; i < 3; ++i )
269 dist += normal[i]*ipp[i];
277 distlist.push_back( dist );
279 min = (min < dist) ? min : dist;
280 max = (max > dist) ? max : dist;
285 // Then I order the slices according to the value "dist". Finally, once
286 // I've read in all the slices, I calculate the z-spacing as the difference
287 // between the "dist" values for the first two slices.
288 GdcmFileVector CoherentGdcmFileVector(n);
289 // CoherentGdcmFileVector.reserve( n );
290 CoherentGdcmFileVector.resize( n );
291 // gdcmAssertMacro( CoherentGdcmFileVector.capacity() >= n );
293 float step = (max - min)/(n - 1);
297 //VC++ don't understand what scope is !! it -> it2
298 for (GdcmFileList::const_iterator it2 = CoherentGdcmFileList->begin();
299 it2 != CoherentGdcmFileList->end(); ++it2, ++n)
302 //Assumption: all files are present (no one missing)
303 pos = (int)( fabs( (distlist[n]-min)/step) + .5 );
305 // a Dicom 'Serie' may contain scout views
306 // and images may have differents directions
307 // -> More than one may have the same 'pos'
308 // Sorting has then NO meaning !
309 if (CoherentGdcmFileVector[pos]==NULL)
310 CoherentGdcmFileVector[pos] = *it2;
313 gdcmVerboseMacro( "2 files same position");
318 CoherentGdcmFileList->clear(); // doesn't delete list elements, only node
320 //VC++ don't understand what scope is !! it -> it3
321 for (GdcmFileVector::const_iterator it3 = CoherentGdcmFileVector.begin();
322 it3 != CoherentGdcmFileVector.end(); ++it3)
324 CoherentGdcmFileList->push_back( *it3 );
328 CoherentGdcmFileVector.clear();
334 * \brief sorts the images, according to their Image Number
335 * \note Works only on bona fide files (i.e image number is a character string
336 * corresponding to an integer)
337 * within a bona fide serie (i.e image numbers are consecutive)
338 * @param CoherentGdcmFileList Coherent File list (same Serie UID) to sort
339 * @return false if non nona fide stuff encountered
341 bool SerieHeader::ImageNumberOrdering(GdcmFileList *CoherentGdcmFileList)
344 int n = 0;//CoherentGdcmFileList.size() is a O(N) operation
346 GdcmFileList::const_iterator it = CoherentGdcmFileList->begin();
347 min = max = (*it)->GetImageNumber();
349 for (; it != CoherentGdcmFileList->end(); ++it, ++n)
351 pos = (*it)->GetImageNumber();
352 min = (min < pos) ? min : pos;
353 max = (max > pos) ? max : pos;
356 // Find out if image numbers are coherent (consecutive)
357 if( min == max || max == 0 || max >= (n+min))
360 unsigned char *partition = new unsigned char[n];
361 memset(partition, 0, n);
363 GdcmFileVector CoherentGdcmFileVector(n);
365 for (it = CoherentGdcmFileList->begin();
366 it != CoherentGdcmFileList->end(); ++it)
368 pos = (*it)->GetImageNumber();
369 CoherentGdcmFileVector[pos - min] = *it;
370 partition[pos - min]++;
373 //VC++ doesn't understand what scope is, it -> it3
374 CoherentGdcmFileList->clear(); // doesn't delete list elements, only nodes
375 for ( GdcmFileVector::const_iterator it3 = CoherentGdcmFileVector.begin();
376 it3 != CoherentGdcmFileVector.end(); ++it3 )
378 CoherentGdcmFileList->push_back( *it3 );
380 CoherentGdcmFileVector.clear();
387 * \brief sorts the images, according to their File Name
388 * @param CoherentGdcmFileList Coherent File list (same Serie UID) to sort
389 * @return false only if the header is bugged !
391 bool SerieHeader::FileNameOrdering(GdcmFileList *)
393 //TODO using the sort
394 //sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end());
398 //-----------------------------------------------------------------------------
401 * \brief Canonical printer.
403 void SerieHeader::Print()
405 // For all the Coherent File lists of the gdcm::Serie
406 CoherentFileListmap::iterator itl = CoherentGdcmFileListHT.begin();
407 if ( itl == CoherentGdcmFileListHT.end() )
409 gdcmVerboseMacro( "No Coherent File list found" );
412 while (itl != CoherentGdcmFileListHT.end())
414 std::cout << "Serie UID :[" << itl->first << "]" << std::endl;
416 // For all the files of a Coherent File list
417 for (GdcmFileList::iterator it = (itl->second)->begin();
418 it != (itl->second)->end();
421 std::cout << " --- " << (*it)->GetFileName() << std::endl;
427 //-----------------------------------------------------------------------------
428 } // end namespace gdcm