Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

gdcmSerieHelper.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002                                                                                 
00003   Program:   gdcm
00004   Module:    $RCSfile: gdcmSerieHelper.cxx,v $
00005   Language:  C++
00006   Date:      $Date: 2006/01/18 15:25:07 $
00007   Version:   $Revision: 1.42 $
00008                                                                                 
00009   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
00010   l'Image). All rights reserved. See Doc/License.txt or
00011   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
00012                                                                                 
00013      This software is distributed WITHOUT ANY WARRANTY; without even
00014      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00015      PURPOSE.  See the above copyright notices for more information.
00016                                                                                 
00017 =========================================================================*/
00018 
00019 #include "gdcmSerieHelper.h"
00020 #include "gdcmDirList.h"
00021 #include "gdcmFile.h"
00022 #include "gdcmDictEntry.h" // for TranslateToKey
00023 #include "gdcmDebug.h"
00024 #include "gdcmUtil.h"
00025 
00026 #include <math.h>
00027 #include <vector>
00028 #include <map>
00029 #include <algorithm>
00030 #include <stdio.h>  //for sscanf
00031 
00032 namespace gdcm 
00033 {
00034 //-----------------------------------------------------------------------------
00035 
00036 //-----------------------------------------------------------------------------
00037 // Constructor / Destructor
00041 SerieHelper::SerieHelper()
00042 {
00043    m_UseSeriesDetails = false;
00044    ClearAll();
00045    UserLessThanFunction = 0;
00046    DirectOrder = true;
00047 }
00048 
00052 SerieHelper::~SerieHelper()
00053 {
00054    ClearAll();
00055 }
00056 
00061 void SerieHelper::ClearAll()
00062 {
00063    // For all the 'Single SerieUID' Filesets that may already exist 
00064    FileList *l = GetFirstSingleSerieUIDFileSet();
00065    while (l)
00066    { 
00067       // For all the gdcm::File of a File set
00068       for (gdcm::FileList::iterator it  = l->begin();
00069                                     it != l->end(); 
00070                                   ++it)
00071       {
00072          (*it)->Delete(); // remove each entry
00073       }
00074       l->clear();
00075       delete l;     // remove the container
00076       l = GetNextSingleSerieUIDFileSet();
00077    }
00078 }
00079 
00080 //-----------------------------------------------------------------------------
00081 
00082 //-----------------------------------------------------------------------------
00083 
00084 // Public
00089 void SerieHelper::AddFileName(std::string const &filename)
00090 {
00091    // Create a DICOM file
00092    File *header = File::New();
00093    header->SetLoadMode(LoadMode);
00094    header->SetFileName( filename ); 
00095    header->Load();
00096 
00097    if ( header->IsReadable() )
00098    {
00099       int allrules = 1;
00100       // First step : the user defined a set of rules for the DICOM file
00101       // he is looking for.
00102       // Make sure the file corresponds to his set of rules:
00103 
00104       std::string s;
00105       for(SerieExRestrictions::iterator it2 = ExRestrictions.begin();
00106           it2 != ExRestrictions.end();
00107           ++it2)
00108       {
00109          const ExRule &r = *it2;
00110          s = header->GetEntryString( r.group, r.elem );
00111          if ( !Util::CompareDicomString(s, r.value.c_str(), r.op) )
00112          {
00113            // Argh ! This rule is unmatched; let's just quit
00114 
00115            allrules = 0;
00116            break;
00117          }
00118       }
00119 
00120       if ( allrules ) // all rules are respected:
00121       {
00122          // Allright! we have a found a DICOM that matches the user expectation. 
00123          // Let's add it!
00124 
00125          // 0020 000e UI REL Series Instance UID
00126          const std::string &uid = header->GetEntryString(0x0020, 0x000e);
00127          // if uid == GDCM_UNFOUND then consistently we should find GDCM_UNFOUND
00128          // no need here to do anything special
00129 
00130 
00131          if ( SingleSerieUIDFileSetHT.count(uid) == 0 )
00132          {
00133             gdcmDebugMacro(" New Serie UID :[" << uid << "]");
00134             // create a std::list in 'uid' position
00135             SingleSerieUIDFileSetHT[uid] = new FileList;
00136          }
00137          // Current Serie UID and DICOM header seems to match; add the file:
00138          SingleSerieUIDFileSetHT[uid]->push_back( header );
00139       }
00140       else
00141       {
00142          // at least one rule was unmatched we need to deallocate the file:
00143          header->Delete();
00144       }
00145    }
00146    else
00147    {
00148       gdcmWarningMacro("Could not read file: " << filename );
00149       header->Delete();
00150    }
00151 }
00152 
00171 void SerieHelper::AddGdcmFile(File *header)
00172 {
00173       int allrules = 1;
00174       // First step the user has defined a set of rules for the DICOM 
00175       // he is looking for.
00176       // make sure the file correspond to his set of rules:
00177       for(SerieRestrictions::iterator it =  Restrictions.begin();
00178                                       it != Restrictions.end();
00179                                     ++it)
00180       {
00181          const Rule &r = *it;
00182          const std::string s;// = header->GetEntryString( r.first );
00183          if ( !Util::DicomStringEqual(s, r.second.c_str()) )
00184          {
00185            // Argh ! This rule is unmatch let's just quit
00186            allrules = 0;
00187            break;
00188          }
00189       }
00190       if ( allrules ) // all rules are respected:
00191       {
00192          // Allright ! we have a found a DICOM that match the user expectation. 
00193          // Let's add it !
00194 
00195          const std::string &uid = "0";
00196          // Serie UID of the gdcm::File* may be different.
00197          // User is supposed to know what he wants
00198 
00199          if ( SingleSerieUIDFileSetHT.count(uid) == 0 )
00200          {
00201             gdcmDebugMacro(" New Serie UID :[" << uid << "]");
00202             // create a std::list in 'uid' position
00203             SingleSerieUIDFileSetHT[uid] = new FileList;
00204          }
00205          // Current Serie UID and DICOM header seems to match; add the file:
00206          SingleSerieUIDFileSetHT[uid]->push_back( header );
00207       }
00208          // Even if a rule was unmatch we don't deallocate the gdcm::File:
00209 }
00210 
00223 void SerieHelper::AddRestriction(TagKey const &key, 
00224                                  std::string const &value, int op)
00225 {
00226    ExRule r;
00227    r.group = key[0];
00228    r.elem  = key[1];
00229    r.value = value;
00230    r.op    = op;
00231    ExRestrictions.push_back( r ); 
00232 }
00233 
00247 void SerieHelper::AddRestriction(uint16_t group, uint16_t elem, 
00248                                  std::string const &value, int op)
00249 {
00250    ExRule r;
00251    r.group = group;
00252    r.elem  = elem;
00253    r.value = value;
00254    r.op    = op;
00255    ExRestrictions.push_back( r ); 
00256 }
00257 
00266 void SerieHelper::AddSeriesDetail(uint16_t group, uint16_t elem, bool convert)
00267 {
00268    
00269    ExDetail d;
00270    d.group   = group;
00271    d.elem    = elem;
00272    d.convert = convert;
00273    ExDetails.push_back( d ); 
00274 }
00280 void SerieHelper::SetDirectory(std::string const &dir, bool recursive)
00281 {
00282    DirList dirList(dir, recursive); // OS specific
00283   
00284    DirListType filenames_list = dirList.GetFilenames();
00285    for( DirListType::const_iterator it = filenames_list.begin(); 
00286         it != filenames_list.end(); ++it)
00287    {
00288       AddFileName( *it );
00289    }
00290 }
00291 
00299 void SerieHelper::OrderFileList(FileList *fileSet)
00300 {
00301 
00302    if ( SerieHelper::UserLessThanFunction )
00303    {
00304       UserOrdering( fileSet );
00305       return; 
00306    }
00307    else if ( ImagePositionPatientOrdering( fileSet ) )
00308    {
00309       return ;
00310    }
00311    else if ( ImageNumberOrdering(fileSet ) )
00312    {
00313       return ;
00314    }
00315    else  
00316    {
00317       FileNameOrdering(fileSet );
00318    }
00319 }
00320 
00325 bool SerieHelper::IsCoherent(FileList *fileSet)
00326 {
00327    if(fileSet->size() == 1)
00328    return true;
00329 
00330    FileList::const_iterator it = fileSet->begin();
00331 
00332    int nX =               (*it)->GetXSize();
00333    int nY =               (*it)->GetYSize();
00334    int pixelSize =        (*it)->GetPixelSize();
00335    bool signedPixelData = (*it)->IsSignedPixelData();
00336    it ++;
00337    for ( ;
00338          it != fileSet->end();
00339        ++it)
00340    {
00341       if ( (*it)->GetXSize() != nX )
00342          return false;
00343       if ( (*it)->GetYSize() != nY )
00344          return false;
00345       if ( (*it)->GetPixelSize() != pixelSize )
00346          return false;
00347       if ( (*it)->IsSignedPixelData() != signedPixelData )
00348          return false;
00349       // probabely more is to be checked (?)      
00350    }
00351    return true;
00352 }
00353 
00354 #ifndef GDCM_LEGACY_REMOVE
00355 
00356 FileList *SerieHelper::GetFirstCoherentFileList()
00357 {
00358    ItFileSetHt = SingleSerieUIDFileSetHT.begin();
00359    if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
00360       return ItFileSetHt->second;
00361    return NULL;
00362 }
00363 
00364 
00365 FileList *SerieHelper::GetNextCoherentFileList()
00366 {
00367    gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end());
00368   
00369    ++ItFileSetHt;
00370    if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
00371       return ItFileSetHt->second;
00372    return NULL;
00373 }
00374 
00375 
00376 FileList *SerieHelper::GetCoherentFileList(std::string SerieUID)
00377 {
00378    if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 )
00379       return 0;     
00380    return SingleSerieUIDFileSetHT[SerieUID];
00381 }
00382 #endif
00383 
00384 
00389 FileList *SerieHelper::GetFirstSingleSerieUIDFileSet()
00390 {
00391    ItFileSetHt = SingleSerieUIDFileSetHT.begin();
00392    if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
00393       return ItFileSetHt->second;
00394    return NULL;
00395 }
00396 
00402 FileList *SerieHelper::GetNextSingleSerieUIDFileSet()
00403 {
00404    gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end());
00405   
00406    ++ItFileSetHt;
00407    if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
00408       return ItFileSetHt->second;
00409    return NULL;
00410 }
00411 
00417 FileList *SerieHelper::GetSingleSerieUIDFileSet(std::string SerieUID)
00418 {
00419    if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 )
00420       return 0;     
00421    return SingleSerieUIDFileSetHT[SerieUID];
00422 }
00423 
00430 XCoherentFileSetmap SerieHelper::SplitOnOrientation(FileList *fileSet)
00431 {
00432    XCoherentFileSetmap CoherentFileSet;
00433 
00434    int nb = fileSet->size();
00435    if (nb == 0 )
00436       return CoherentFileSet;
00437    float iop[6];
00438 
00439    std::string strOrient;
00440    std::ostringstream ossOrient;   
00441    FileList::const_iterator it = fileSet->begin();
00442    it ++;
00443    for ( ;
00444          it != fileSet->end();
00445        ++it)
00446    {     
00447       // Information is in :      
00448       // 0020 0037 : Image Orientation (Patient) or
00449       // 0020 0035 : Image Orientation (RET)
00450 
00451       // Let's build again the 'cosines' string, to be sure of it's format      
00452       (*it)->GetImageOrientationPatient(iop);
00453 
00454       ossOrient << iop[0];      
00455       for (int i = 1; i < 6; i++)
00456       {
00457         ossOrient << "\\";
00458         ossOrient << iop[i]; 
00459       }      
00460       strOrient = ossOrient.str();
00461       ossOrient.str("");
00462       // FIXME : is it a 'cleaner' way to initialize an ostringstream? 
00463 
00464       if ( CoherentFileSet.count(strOrient) == 0 )
00465       {
00466          gdcmDebugMacro(" New Orientation :[" << strOrient << "]");
00467          // create a File set in 'orientation' position
00468          CoherentFileSet[strOrient] = new FileList;
00469       }
00470       // Current Orientation and DICOM header match; add the file:
00471       CoherentFileSet[strOrient]->push_back( (*it) );
00472    } 
00473    return CoherentFileSet;
00474 }
00475 
00482 XCoherentFileSetmap SerieHelper::SplitOnPosition(FileList *fileSet)
00483 {
00484    XCoherentFileSetmap CoherentFileSet;
00485 
00486    int nb = fileSet->size();
00487    if (nb == 0 )
00488       return CoherentFileSet;
00489    float pos[3];
00490    std::string strImPos;  // read on disc
00491    std::ostringstream ossPosition;
00492    std::string strPosition; // re computed
00493    FileList::const_iterator it = fileSet->begin();
00494    it ++;
00495    for ( ;
00496          it != fileSet->end();
00497        ++it)
00498    {     
00499       // Information is in :      
00500       // 0020,0032 : Image Position Patient
00501       // 0020,0030 : Image Position (RET)
00502 
00503       strImPos = (*it)->GetEntryString(0x0020,0x0032);
00504       if ( strImPos == GDCM_UNFOUND)
00505       {
00506          gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
00507          strImPos = (*it)->GetEntryString(0x0020,0x0030); // For ACR-NEMA images
00508          if ( strImPos == GDCM_UNFOUND )
00509          {
00510             gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00511             // User wants to split on the 'Position'
00512             // No 'Position' info found.
00513             // We return an empty Htable !
00514             return CoherentFileSet;
00515          }  
00516       }
00517 
00518       if ( sscanf( strImPos.c_str(), "%f \\%f \\%f ", 
00519                                               &pos[0], &pos[1], &pos[2]) != 3 )
00520       {
00521             gdcmWarningMacro( "Wrong number for Position : ["
00522                        << strImPos << "]" );
00523              return CoherentFileSet;
00524       }
00525 
00526       // Let's build again the 'position' string, to be sure of it's format      
00527 
00528       ossPosition << pos[0];      
00529       for (int i = 1; i < 3; i++)
00530       {
00531         ossPosition << "\\";
00532         ossPosition << pos[i]; 
00533       }      
00534       strPosition = ossPosition.str();
00535       ossPosition.str("");
00536             
00537       if ( CoherentFileSet.count(strPosition) == 0 )
00538       {
00539          gdcmDebugMacro(" New Position :[" << strPosition << "]");
00540          // create a File set in 'position' position
00541          CoherentFileSet[strPosition] = new FileList;
00542       }
00543       // Current Position and DICOM header match; add the file:
00544       CoherentFileSet[strPosition]->push_back( (*it) );
00545    }   
00546    return CoherentFileSet;
00547 }
00548 
00558 XCoherentFileSetmap SerieHelper::SplitOnTagValue(FileList *fileSet, 
00559                                                uint16_t group, uint16_t elem)
00560 {
00561    XCoherentFileSetmap CoherentFileSet;
00562 
00563    int nb = fileSet->size();
00564    if (nb == 0 )
00565       return CoherentFileSet;
00566 
00567    std::string strTagValue;  // read on disc
00568 
00569    FileList::const_iterator it = fileSet->begin();
00570    it ++;
00571    for ( ;
00572          it != fileSet->end();
00573        ++it)
00574    {     
00575       // Information is in :      
00576       // 0020,0032 : Image Position Patient
00577       // 0020,0030 : Image Position (RET)
00578 
00579       strTagValue = (*it)->GetEntryString(group,elem);
00580       
00581       if ( CoherentFileSet.count(strTagValue) == 0 )
00582       {
00583          gdcmDebugMacro(" New Tag Value :[" << strTagValue << "]");
00584          // create a File set in 'position' position
00585          CoherentFileSet[strTagValue] = new FileList;
00586       }
00587       // Current Tag value and DICOM header match; add the file:
00588       CoherentFileSet[strTagValue]->push_back( (*it) );
00589    }
00590    return CoherentFileSet;
00591 }
00592 
00593 //-----------------------------------------------------------------------------
00594 // Protected
00595 
00596 //-----------------------------------------------------------------------------
00597 // Private
00610 bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList )
00611 //based on Jolinda Smith's algorithm
00612 {
00613    //iop is calculated based on the file file
00614    float cosines[6];
00615    double normal[3];
00616    double ipp[3];
00617    double dist;
00618    double min = 0, max = 0;
00619    bool first = true;
00620 
00621    std::multimap<double,File *> distmultimap;
00622    // Use a multimap to sort the distances from 0,0,0
00623    for ( FileList::const_iterator 
00624          it = fileList->begin();
00625          it != fileList->end(); ++it )
00626    {
00627       if ( first ) 
00628       {
00629          (*it)->GetImageOrientationPatient( cosines );
00630       
00631          // You only have to do this once for all slices in the volume. Next, 
00632          // for each slice, calculate the distance along the slice normal 
00633          // using the IPP ("Image Position Patient") tag.
00634          // ("dist" is initialized to zero before reading the first slice) :
00635          normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4];
00636          normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5];
00637          normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3];
00638   
00639          ipp[0] = (*it)->GetXOrigin();
00640          ipp[1] = (*it)->GetYOrigin();
00641          ipp[2] = (*it)->GetZOrigin();
00642 
00643          dist = 0;
00644          for ( int i = 0; i < 3; ++i )
00645          {
00646             dist += normal[i]*ipp[i];
00647          }
00648     
00649          distmultimap.insert(std::pair<const double,File *>(dist, *it));
00650 
00651          max = min = dist;
00652          first = false;
00653       }
00654       else 
00655       {
00656          ipp[0] = (*it)->GetXOrigin();
00657          ipp[1] = (*it)->GetYOrigin();
00658          ipp[2] = (*it)->GetZOrigin();
00659   
00660          dist = 0;
00661          for ( int i = 0; i < 3; ++i )
00662          {
00663             dist += normal[i]*ipp[i];
00664          }
00665 
00666          distmultimap.insert(std::pair<const double,File *>(dist, *it));
00667 
00668          min = (min < dist) ? min : dist;
00669          max = (max > dist) ? max : dist;
00670       }
00671 
00672    }
00673 
00674    // Find out if min/max are coherent
00675    if ( min == max )
00676    {
00677      gdcmWarningMacro("Looks like all images have the exact same image position"
00678                       << ". No PositionPatientOrdering sort performed" );
00679      return false;
00680    }
00681 
00682    // Check to see if image shares a common position
00683     bool ok = true;
00684     for (std::multimap<double, File *>::iterator it2 = distmultimap.begin();
00685                                                  it2 != distmultimap.end();
00686                                                  ++it2)
00687     {
00688        if (distmultimap.count((*it2).first) != 1)
00689        {
00690           gdcmErrorMacro("File: "
00691                << ((*it2).second->GetFileName())
00692                << " Distance: "
00693                << (*it2).first
00694                << " position is not unique");
00695           ok = false;
00696        } 
00697     }
00698     if (!ok)
00699     {
00700        return false;
00701     }
00702   
00703    fileList->clear();  // doesn't delete list elements, only nodes
00704 
00705    if (DirectOrder)
00706    {  
00707       for (std::multimap<double, File *>::iterator it3 = distmultimap.begin();
00708                                                    it3 != distmultimap.end();
00709                                                  ++it3)
00710       {
00711          fileList->push_back( (*it3).second );
00712       }
00713    }
00714    else // user asked for reverse order
00715    {
00716       std::multimap<double, File *>::const_iterator it4;
00717       it4 = distmultimap.end();
00718       do
00719       {
00720          it4--;
00721          fileList->push_back( (*it4).second );
00722       } while (it4 != distmultimap.begin() );
00723    } 
00724 
00725    distmultimap.clear();
00726 
00727    return true;
00728 }
00729 
00730 bool SerieHelper::ImageNumberLessThan(File *file1, File *file2)
00731 {
00732   return file1->GetImageNumber() < file2->GetImageNumber();
00733 }
00734 
00735 bool SerieHelper::ImageNumberGreaterThan(File *file1, File *file2)
00736 {
00737   return file1->GetImageNumber() > file2->GetImageNumber();
00738 }
00739 
00748 bool SerieHelper::ImageNumberOrdering(FileList *fileList) 
00749 {
00750    int min, max, pos;
00751    int n = fileList->size();
00752 
00753    FileList::const_iterator it = fileList->begin();
00754    min = max = (*it)->GetImageNumber();
00755 
00756    for (; it != fileList->end(); ++it, ++n)
00757    {
00758       pos = (*it)->GetImageNumber();
00759       min = (min < pos) ? min : pos;
00760       max = (max > pos) ? max : pos;
00761    }
00762 
00763    // Find out if image numbers are coherent (consecutive)
00764    if ( min == max || max == 0 || max >= (n+min) )
00765    {
00766       gdcmWarningMacro( " 'Image numbers' not coherent. "
00767                         << " No ImageNumberOrdering sort performed.");
00768       return false;
00769    }
00770    if (DirectOrder) 
00771         Sort(fileList,SerieHelper::ImageNumberLessThan);
00772 //      std::sort(fileList->begin(), fileList->end(), 
00773 //                                          SerieHelper::ImageNumberLessThan );
00774    else
00775         Sort(fileList,SerieHelper::ImageNumberGreaterThan);
00776 //      std::sort(fileList->begin(), fileList->end(),
00777 //                                          SerieHelper::ImageNumberGreaterThan );
00778 
00779    return true;
00780 }
00781 
00782 bool SerieHelper::FileNameLessThan(File *file1, File *file2)
00783 {
00784    return file1->GetFileName() < file2->GetFileName();
00785 }
00786 
00787 bool SerieHelper::FileNameGreaterThan(File *file1, File *file2)
00788 {
00789    return file1->GetFileName() > file2->GetFileName();
00790 }
00796 bool SerieHelper::FileNameOrdering(FileList *fileList)
00797 {
00798    if (DirectOrder) 
00799         Sort(fileList,SerieHelper::FileNameLessThan);
00800 //      std::sort(fileList->begin(), fileList->end(), 
00801 //                                       SerieHelper::FileNameLessThan);
00802    else
00803         Sort(fileList,SerieHelper::FileNameGreaterThan);   
00804 //      std::sort(fileList->begin(), fileList->end(), 
00805 //                                       SerieHelper::FileNameGreaterThan);
00806 
00807    return true;
00808 }
00809 
00815 bool SerieHelper::UserOrdering(FileList *fileList)
00816 {
00817         Sort(fileList,SerieHelper::UserLessThanFunction);   
00818 //   std::sort(fileList->begin(), fileList->end(), 
00819 //                                             SerieHelper::UserLessThanFunction);
00820    if (!DirectOrder) 
00821    {
00822       std::reverse(fileList->begin(), fileList->end());
00823    }
00824    return true;
00825 }
00826 
00840 std::string SerieHelper::CreateUniqueSeriesIdentifier( File *inFile )
00841 {
00842    if( inFile->IsReadable() )
00843    {
00844      // 0020 000e UI REL Series Instance UID
00845     std::string uid =  inFile->GetEntryString (0x0020, 0x000e);
00846     std::string id = uid.c_str();
00847     if(m_UseSeriesDetails)
00848     {
00849     // If the user requests, additional information can be appended
00850     // to the SeriesUID to further differentiate volumes in the DICOM
00851     // objects being processed.
00852  
00853    // 0020 0011 Series Number
00854    // A scout scan prior to a CT volume scan can share the same
00855    // SeriesUID, but they will sometimes have a different Series Number
00856        std::string sNum = inFile->GetEntryString(0x0020, 0x0011);
00857        if( sNum == gdcm::GDCM_UNFOUND )
00858        {
00859            sNum = "";
00860        }
00861  // 0018 0024 Sequence Name
00862  // For T1-map and phase-contrast MRA, the different flip angles and
00863  // directions are only distinguished by the Sequence Name
00864          std::string sName = inFile->GetEntryString(0x0018, 0x0024);
00865          if( sName == gdcm::GDCM_UNFOUND )
00866          {
00867            sName = "";
00868          }
00869  
00870   // You can think on checking Image Orientation (0020,0037), as well.
00871   
00872 
00873   // 0018 0050 Slice Thickness
00874   // On some CT systems, scout scans and subsequence volume scans will
00875   // have the same SeriesUID and Series Number - YET the slice
00876   // thickness will differ from the scout slice and the volume slices.
00877          std::string sThick = inFile->GetEntryString (0x0018, 0x0050);
00878          if( sThick == gdcm::GDCM_UNFOUND )
00879          {
00880            sThick = "";
00881          }
00882   // 0028 0010 Rows
00883   // If the 2D images in a sequence don't have the same number of rows,
00884   // then it is difficult to reconstruct them into a 3D volume.
00885          std::string sRows = inFile->GetEntryString (0x0028, 0x0010);
00886          if( sRows == gdcm::GDCM_UNFOUND )
00887          {
00888            sRows = "";
00889          }
00890   // 0028 0011 Columns
00891   // If the 2D images in a sequence don't have the same number of columns,
00892   // then it is difficult to reconstruct them into a 3D volume.
00893          std::string sColumns = inFile->GetEntryString (0x0028, 0x0011);
00894          if( sColumns == gdcm::GDCM_UNFOUND )
00895          {
00896            sColumns = "";
00897          }
00898 
00899   // Concat the new info
00900          std::string num = sNum.c_str();
00901          num += sName.c_str();
00902          num += sThick.c_str();
00903          num += sRows.c_str();
00904          num += sColumns.c_str();
00905  
00906   // Add a loop, here, to deal with any extra user supplied tag.
00907   //      We allow user to add his own critierions 
00908   //      (he knows more than we do about his images!)
00909   //      ex : in tagging series, the only pertinent tag is
00910   //          0018|1312 [In-plane Phase Encoding Direction] values : ROW/COLUMN
00911   
00912       std::string s; 
00913       for(SeriesExDetails::iterator it2 = ExDetails.begin();
00914           it2 != ExDetails.end();
00915           ++it2)
00916       {
00917          const ExDetail &r = *it2;
00918          s = inFile->GetEntryString( r.group, r.elem );      
00919          num += s.c_str();
00920       }
00921    
00922   // Append the new info to the SeriesUID
00923          id += ".";
00924          id += num.c_str();
00925        }
00926    
00927   // Eliminate non-alphanum characters, including whitespace...
00928   // that may have been introduced by concats.
00929        for(unsigned int i=0; i<id.size(); i++)
00930        {
00931          while(i<id.size()
00932                && !( id[i] == '.' || id[i] == '-' || id[i] == '_'
00933                     || (id[i] >= 'a' && id[i] <= 'z')
00934                     || (id[i] >= '0' && id[i] <= '9')
00935                     || (id[i] >= 'A' && id[i] <= 'Z')))
00936          {
00937            id.erase(i, 1);
00938          }
00939        }
00940        return id;
00941      }
00942      else // Could not open inFile
00943      {
00944        gdcmWarningMacro("Could not parse series info.");
00945        std::string id = gdcm::GDCM_UNFOUND;
00946        return id;
00947      }
00948 }
00949 
00958 std::string SerieHelper::CreateUserDefinedFileIdentifier( File * inFile )
00959 {
00960   //     Deal with all user supplied tags.
00961   //      (user knows more than we do about his images!)
00962   
00963    float converted;
00964    std::string id;
00965    std::string s; 
00966    char charConverted[17]; 
00967    
00968    for(SeriesExDetails::iterator it2 = ExDetails.begin();
00969       it2 != ExDetails.end();
00970       ++it2)
00971    {
00972       const ExDetail &r = *it2;
00973       s = inFile->GetEntryString( r.group, r.elem );
00974       
00975       // User is allowed to ask 'convertion', to allow further ordering
00976       // e.g : 100 would be *before* 20; 000020.00 vs 00100.00 : OK
00977       if (it2->convert)
00978       {
00979          converted = atof(s.c_str());
00980          // probabely something much more complicated is possible, 
00981          // using C++ features
00983          sprintf(charConverted, "%016.6f",converted);
00984          s = charConverted;
00985       }
00986       // Eliminate non-alphanum characters, including whitespace.
00987       for(unsigned int i=0; i<s.size(); i++)
00988       {
00989          while(i<s.size()
00990             && !( s[i] == '.' || s[i] == '-'
00991                     || (s[i] >= 'a' && s[i] <= 'z')
00992                     || (s[i] >= '0' && s[i] <= '9')
00993                     || (s[i] >= 'A' && s[i] <= 'Z')))
00994          {
00995             s.erase(i, 1);
00996          }
00997       }
00998       
00999       id += s.c_str();
01000       id += "_"; // make the FileIdentifier Tokenizable
01001    }
01002    
01003    return id;             
01004 }
01005 //-----------------------------------------------------------------------------
01006 // Print
01010 void SerieHelper::Print(std::ostream &os, std::string const &indent)
01011 {
01012    // For all the Coherent File lists of the gdcm::Serie
01013    SingleSerieUIDFileSetmap::iterator itl = SingleSerieUIDFileSetHT.begin();
01014    if ( itl == SingleSerieUIDFileSetHT.end() )
01015    {
01016       gdcmWarningMacro( "No SingleSerieUID File set found" );
01017       return;
01018    }
01019    while (itl != SingleSerieUIDFileSetHT.end())
01020    { 
01021       os << "Serie UID :[" << itl->first << "]" << std::endl;
01022 
01023       // For all the files of a SingleSerieUID File set
01024       for (FileList::iterator it =  (itl->second)->begin();
01025                                   it != (itl->second)->end(); 
01026                                 ++it)
01027       {
01028          os << indent << " --- " << (*it)->GetFileName() << std::endl;
01029       }
01030       ++itl;
01031    }
01032 }
01033 
01034 //-----------------------------------------------------------------------------
01035 // Sort
01039 void SerieHelper::Sort(FileList *fileList, bool (*pt2Func)( File *file1, File *file2) )
01040 {
01041  std::sort(fileList->begin(), fileList->end(), pt2Func );
01042 }
01043 
01044 //-----------------------------------------------------------------------------
01045 } // end namespace gdcm

Generated on Fri Jan 20 10:14:26 2006 for gdcm by  doxygen 1.4.4