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: 2007/07/05 09:34:12 $
00007   Version:   $Revision: 1.59 $
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 : no more !
00023 #include "gdcmDebug.h"
00024 #include "gdcmUtil.h"
00025 
00026 #include <math.h>
00027 #include <vector>
00028 #include <algorithm>
00029 #include <map>
00030 #include <stdio.h>  //for sscanf
00031 
00032 namespace GDCM_NAME_SPACE
00033 {
00034 
00035 //-----------------------------------------------------------------------------
00036 // Constructor / Destructor
00040 SerieHelper::SerieHelper()
00041 {
00042    m_UseSeriesDetails = false;
00043    ClearAll();
00044    UserLessThanFunction = 0;
00045    DirectOrder = true;
00046    
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_NAME_SPACE::File of a File set
00068       for (GDCM_NAME_SPACE::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    // Need to clear that too:
00079    SingleSerieUIDFileSetHT.clear();
00080 }
00081 
00082 //-----------------------------------------------------------------------------
00083 
00084 //-----------------------------------------------------------------------------
00085 
00086 // Public
00091 void SerieHelper::AddFileName(std::string const &filename)
00092 {
00093    // Create a DICOM file
00094    File *header = File::New();
00095    header->SetLoadMode(LoadMode);
00096    header->SetFileName( filename ); 
00097    header->Load();
00098 
00099    if ( header->IsReadable() )
00100    {
00101       if ( !AddFile( header ) )
00102       {
00103          // at least one rule was unmatched we need to deallocate the file:
00104          header->Delete();
00105       }
00106    }
00107    else
00108    {
00109       gdcmWarningMacro("Could not read file: " << filename );
00110       header->Delete();
00111    }
00112 }
00113 
00133 bool SerieHelper::AddFile(File *header)
00134 {
00135    int allrules = 1;
00136    // First step the user has defined a set of rules for the DICOM 
00137    // he is looking for.
00138    // make sure the file correspond to his set of rules:
00139 
00140    std::string s;
00141    for(SerieExRestrictions::iterator it2 = ExRestrictions.begin();
00142      it2 != ExRestrictions.end();
00143      ++it2)
00144    {
00145       const ExRule &r = *it2;
00146       s = header->GetEntryString( r.group, r.elem );
00147       if ( !Util::CompareDicomString(s, r.value.c_str(), r.op) )
00148       {
00149          // Argh ! This rule is unmatched; let's just quit
00150          allrules = 0;
00151          break;
00152       }
00153    }
00154 
00155    if ( allrules ) // all rules are respected:
00156    {
00157       // Allright! we have a found a DICOM that matches the user expectation. 
00158       // Let's add it to the specific 'id' which by default is uid (Serie UID)
00159       // but can be `refined` by user with more paramater (see AddRestriction(g,e))
00160  
00161       std::string id = CreateUniqueSeriesIdentifier( header );
00162       // if id == GDCM_UNFOUND then consistently we should find GDCM_UNFOUND
00163       // no need here to do anything special
00164  
00165       if ( SingleSerieUIDFileSetHT.count(id) == 0 )
00166       {
00167          gdcmDebugMacro(" New/gdcmSerieHelper.cxx Serie UID :[" << id << "]");
00168          // create a std::list in 'id' position
00169          SingleSerieUIDFileSetHT[id] = new FileList;
00170       }
00171       // Current Serie UID and DICOM header seems to match add the file:
00172       SingleSerieUIDFileSetHT[id]->push_back( header );
00173    }
00174    else
00175    {
00176       // one rule not matched, tell user:
00177       return false;
00178    }
00179    return true;
00180 }
00181 
00194 void SerieHelper::AddRestriction(TagKey const &key, 
00195                                  std::string const &value, int op)
00196 {
00197    ExRule r;
00198    r.group = key[0];
00199    r.elem  = key[1];
00200    r.value = value;
00201    r.op    = op;
00202    ExRestrictions.push_back( r ); 
00203 }
00204 
00205 void SerieHelper::AddRestriction(TagKey const &key)
00206 {
00207   ExRule r;
00208   r.group = key[0];
00209   r.elem  = key[1];
00210   ExRefine.push_back( r );
00211 }
00212 
00213 //#ifndef GDCM_LEGACY_REMOVE
00228 void SerieHelper::AddRestriction(uint16_t group, uint16_t elem, 
00229                                  std::string const &value, int op)
00230 {
00231   TagKey t(group, elem);
00232   AddRestriction(t, value, op);
00233 }
00234 
00235 //#endif
00236 
00245 void SerieHelper::AddSeriesDetail(uint16_t group, uint16_t elem, bool convert)
00246 {   
00247    ExDetail d;
00248    d.group   = group;
00249    d.elem    = elem;
00250    d.convert = convert;
00251    ExDetails.push_back( d ); 
00252 }
00258 void SerieHelper::SetDirectory(std::string const &dir, bool recursive)
00259 {
00260    DirList dirList(dir, recursive); // OS specific
00261   
00262    DirListType filenames_list = dirList.GetFilenames();
00263    for( DirListType::const_iterator it = filenames_list.begin(); 
00264         it != filenames_list.end(); ++it)
00265    {
00266       AddFileName( *it );
00267    }
00268 }
00269 
00274 void SerieHelper::SetDicomDirSerie(DicomDirSerie *se)
00275 {
00276    DirList dirList(se);
00277   
00278    DirListType filenames_list = dirList.GetFilenames();
00279    for( DirListType::const_iterator it = filenames_list.begin(); 
00280         it != filenames_list.end(); ++it)
00281    {
00282       AddFileName( *it );
00283    }
00284 }
00285 
00293 void SerieHelper::OrderFileList(FileList *fileSet)
00294 {
00295    // Only computed during ImagePositionPatientOrdering
00296    // (need to sort the FileList using IPP and IOP !)
00297    ZSpacing = -1.0;
00298    
00299    if ( SerieHelper::UserLessThanFunction )
00300    {
00301       UserOrdering( fileSet );
00302       return; 
00303    }
00304    else if ( ImagePositionPatientOrdering( fileSet ) )
00305    {
00306       return ;
00307    }
00308    else if ( ImageNumberOrdering(fileSet ) )
00309    {
00310       return ;
00311    }
00312    else  
00313    {
00314       FileNameOrdering(fileSet );
00315    }
00316 }
00317 
00322 bool SerieHelper::IsCoherent(FileList *fileSet)
00323 {
00324    if(fileSet->size() == 1)
00325    return true;
00326 
00327    FileList::const_iterator it = fileSet->begin();
00328 
00329    int nX =               (*it)->GetXSize();
00330    int nY =               (*it)->GetYSize();
00331    int pixelSize =        (*it)->GetPixelSize();
00332    bool signedPixelData = (*it)->IsSignedPixelData();
00333    it ++;
00334    for ( ;
00335          it != fileSet->end();
00336        ++it)
00337    {
00338       if ( (*it)->GetXSize() != nX )
00339          return false;
00340       if ( (*it)->GetYSize() != nY )
00341          return false;
00342       if ( (*it)->GetPixelSize() != pixelSize )
00343          return false;
00344       if ( (*it)->IsSignedPixelData() != signedPixelData )
00345          return false;
00346       // probabely more is to be checked (?)
00347    }
00348    return true;
00349 }
00350 
00351 //#ifndef GDCM_LEGACY_REMOVE
00357  /*
00358 FileList *SerieHelper::GetFirstCoherentFileList()
00359 {
00360    ItFileSetHt = SingleSerieUIDFileSetHT.begin();
00361    if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
00362       return ItFileSetHt->second;
00363    return NULL;
00364 }
00365 */
00372  /*
00373 FileList *SerieHelper::GetNextCoherentFileList()
00374 {
00375    gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end());
00376   
00377    ++ItFileSetHt;
00378    if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
00379       return ItFileSetHt->second;
00380    return NULL;
00381 }
00382 */
00383 
00390  /*
00391 FileList *SerieHelper::GetCoherentFileList(std::string SerieUID)
00392 {
00393    if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 )
00394       return 0;     
00395    return SingleSerieUIDFileSetHT[SerieUID];
00396 }
00397 */
00398 //#endif
00399 
00400 
00405 FileList *SerieHelper::GetFirstSingleSerieUIDFileSet()
00406 {
00407    ItFileSetHt = SingleSerieUIDFileSetHT.begin();
00408    if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
00409       return ItFileSetHt->second;
00410    return NULL;
00411 }
00412 
00418 FileList *SerieHelper::GetNextSingleSerieUIDFileSet()
00419 {
00420    gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end());
00421   
00422    ++ItFileSetHt;
00423    if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
00424       return ItFileSetHt->second;
00425    return NULL;
00426 }
00427 
00433 FileList *SerieHelper::GetSingleSerieUIDFileSet(std::string SerieUID)
00434 {
00435    if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 )
00436       return 0;     
00437    return SingleSerieUIDFileSetHT[SerieUID];
00438 }
00439 
00446 XCoherentFileSetmap SerieHelper::SplitOnOrientation(FileList *fileSet)
00447 {
00448    XCoherentFileSetmap CoherentFileSet;
00449 
00450    int nb = fileSet->size();
00451    if (nb == 0 )
00452       return CoherentFileSet;
00453    float iop[6];
00454    std::string strOrient;
00455    std::ostringstream ossOrient;
00456 
00457    FileList::const_iterator it = fileSet->begin();
00458    //it ++;
00459    for ( ;
00460          it != fileSet->end();
00461        ++it)
00462    {     
00463       // Information is in :      
00464       // 0020 0037 : Image Orientation (Patient) or
00465       // 0020 0035 : Image Orientation (RET)
00466 
00467       // Let's build again the 'cosines' string, to be sure of it's format      
00468       (*it)->GetImageOrientationPatient(iop);
00469 
00470       ossOrient << iop[0];      
00471       for (int i = 1; i < 6; i++)
00472       {
00473         ossOrient << "\\";
00474         ossOrient << iop[i]; 
00475       }      
00476       strOrient = ossOrient.str();
00477       ossOrient.str("");
00478       if ( CoherentFileSet.count(strOrient) == 0 )
00479       {
00480          gdcmDebugMacro(" New Orientation :[" << strOrient << "]");
00481          // create a File set in 'orientation' position
00482          CoherentFileSet[strOrient] = new FileList;
00483       }
00484       // Current Orientation and DICOM header match; add the file:
00485       CoherentFileSet[strOrient]->push_back( (*it) );
00486    }
00487    return CoherentFileSet;
00488 }
00489 
00496 XCoherentFileSetmap SerieHelper::SplitOnPosition(FileList *fileSet)
00497 {
00498    XCoherentFileSetmap CoherentFileSet;
00499 
00500    int nb = fileSet->size();
00501    if (nb == 0 )
00502       return CoherentFileSet;
00503    float pos[3];
00504    std::string strImPos;  // read on disc
00505    std::ostringstream ossPosition;
00506    std::string strPosition; // re computed
00507    FileList::const_iterator it = fileSet->begin();
00508    //it ++;
00509    for ( ;
00510          it != fileSet->end();
00511        ++it)
00512    {     
00513       // Information is in :      
00514       // 0020,0032 : Image Position Patient
00515       // 0020,0030 : Image Position (RET)
00516 
00517       strImPos = (*it)->GetEntryString(0x0020,0x0032);
00518       if ( strImPos == GDCM_UNFOUND)
00519       {
00520          gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
00521          strImPos = (*it)->GetEntryString(0x0020,0x0030); // For ACR-NEMA images
00522          if ( strImPos == GDCM_UNFOUND )
00523          {
00524             gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00525             // User wants to split on the 'Position'
00526             // No 'Position' info found.
00527             // We return an empty Htable !
00528             return CoherentFileSet;
00529          }  
00530       }
00531 
00532       if ( sscanf( strImPos.c_str(), "%f \\%f \\%f ", 
00533                                               &pos[0], &pos[1], &pos[2]) != 3 )
00534       {
00535             gdcmWarningMacro( "Wrong number for Position : ["
00536                        << strImPos << "]" );
00537              return CoherentFileSet;
00538       }
00539 
00540       // Let's build again the 'position' string, to be sure of it's format      
00541 
00542       ossPosition << pos[0];      
00543       for (int i = 1; i < 3; i++)
00544       {
00545         ossPosition << "\\";
00546         ossPosition << pos[i]; 
00547       }      
00548       strPosition = ossPosition.str();
00549       ossPosition.str("");
00550 
00551       if ( CoherentFileSet.count(strPosition) == 0 )
00552       {
00553          gdcmDebugMacro(" New Position :[" << strPosition << "]");
00554          // create a File set in 'position' position
00555          CoherentFileSet[strPosition] = new FileList;
00556       }
00557       // Current Position and DICOM header match; add the file:
00558       CoherentFileSet[strPosition]->push_back( (*it) );
00559    }   
00560    return CoherentFileSet;
00561 }
00562 
00572 XCoherentFileSetmap SerieHelper::SplitOnTagValue(FileList *fileSet, 
00573                                                uint16_t group, uint16_t element)
00574 {
00575    XCoherentFileSetmap CoherentFileSet;
00576 
00577    int nb = fileSet->size();
00578    if (nb == 0 )
00579       return CoherentFileSet;
00580 
00581    std::string strTagValue;  // read on disc
00582 
00583    FileList::const_iterator it = fileSet->begin();
00584    //it ++;
00585    for ( ;
00586          it != fileSet->end();
00587        ++it)
00588    {     
00589       // Information is in :      
00590       // 0020,0032 : Image Position Patient
00591       // 0020,0030 : Image Position (RET)
00592 
00593       strTagValue = (*it)->GetEntryString(group,element);
00594       
00595       if ( CoherentFileSet.count(strTagValue) == 0 )
00596       {
00597          gdcmDebugMacro(" New Tag Value :[" << strTagValue << "]");
00598          // create a File set in 'position' position
00599          CoherentFileSet[strTagValue] = new FileList;
00600       }
00601       // Current Tag value and DICOM header match; add the file:
00602       CoherentFileSet[strTagValue]->push_back( (*it) );
00603    }
00604    return CoherentFileSet;
00605 }
00606 
00607 //-----------------------------------------------------------------------------
00608 // Protected
00609 
00610 //-----------------------------------------------------------------------------
00611 // Private
00625 bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList )
00626 //based on Jolinda Smith's algorithm
00627 {
00628 //Tags always use the same coordinate system, where "x" is left
00629 //to right, "y" is posterior to anterior, and "z" is foot to head (RAH).
00630 
00631    //iop is calculated based on the file file
00632    float cosines[6];
00633    double normal[3];
00634    double ipp[3];
00635    double dist;
00636    double min = 0, max = 0;
00637    bool first = true;
00638    ZSpacing = -1.0;  // will be updated if process doesn't fail
00639 
00640    std::multimap<double,File *> distmultimap;
00641    // Use a multimap to sort the distances from 0,0,0
00642    for ( FileList::const_iterator 
00643          it = fileList->begin();
00644          it != fileList->end(); ++it )
00645    {
00646       if ( first ) 
00647       {
00648          (*it)->GetImageOrientationPatient( cosines );
00649 
00650    // The "Image Orientation Patient" tag gives the direction cosines 
00651    // for the rows and columns for the three axes defined above. 
00652    // Typical axial slices will have a value 1/0/0/0/1/0: 
00653    // rows increase from left to right, 
00654    // columns increase from posterior to anterior. This is your everyday
00655    // "looking up from the bottom of the head with the eyeballs up" image. 
00656    
00657    // The "Image Position Patient" tag gives the coordinates of the first
00658    // voxel in the image in the "RAH" coordinate system, relative to some
00659    // origin.   
00660 
00661    // First, calculate the slice normal from IOP : 
00662           
00663          // You only have to do this once for all slices in the volume. Next, 
00664          // for each slice, calculate the distance along the slice normal 
00665          // using the IPP ("Image Position Patient") tag.
00666          // ("dist" is initialized to zero before reading the first slice) :
00667          normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4];
00668          normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5];
00669          normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3];
00670 
00671    // For each slice (here : the first), calculate the distance along 
00672    // the slice normal using the IPP tag 
00673     
00674          ipp[0] = (*it)->GetXOrigin();
00675          ipp[1] = (*it)->GetYOrigin();
00676          ipp[2] = (*it)->GetZOrigin();
00677 
00678          dist = 0;
00679          for ( int i = 0; i < 3; ++i )
00680          {
00681             dist += normal[i]*ipp[i];
00682          }
00683     
00684          distmultimap.insert(std::pair<const double,File *>(dist, *it));
00685 
00686          max = min = dist;
00687          first = false;
00688       }
00689       else 
00690       {
00691    // Next, for each slice, calculate the distance along the slice normal
00692    // using the IPP tag 
00693          ipp[0] = (*it)->GetXOrigin();
00694          ipp[1] = (*it)->GetYOrigin();
00695          ipp[2] = (*it)->GetZOrigin();
00696 
00697          dist = 0;
00698          for ( int i = 0; i < 3; ++i )
00699          {
00700             dist += normal[i]*ipp[i];
00701          }
00702 
00703          distmultimap.insert(std::pair<const double,File *>(dist, *it));
00704 
00705          min = (min < dist) ? min : dist;
00706          max = (max > dist) ? max : dist;
00707       }
00708    }
00709 
00710    // Find out if min/max are coherent
00711    if ( min == max )
00712    {
00713      gdcmWarningMacro("Looks like all images have the exact same image position. "
00714                       << "No PositionPatientOrdering sort performed. " 
00715                       << "No 'ZSpacing' calculated! ");
00716      return false;
00717    }
00718 
00719    // Check to see if image shares a common position
00720    bool ok = true;
00721    for (std::multimap<double, File *>::iterator it2 = distmultimap.begin();
00722         it2 != distmultimap.end();
00723         ++it2)
00724    {
00725       if (distmultimap.count((*it2).first) != 1)
00726       {
00727          gdcmErrorMacro("File: ["
00728               << ((*it2).second->GetFileName())
00729               << "] : more than ONE file at distance: '"
00730               << (*it2).first
00731               << " (position is not unique!) " 
00732               << "No PositionPatientOrdering sort performed. " 
00733               << "No 'ZSpacing' calculated! ");      
00734 
00735          ok = false;
00736       }
00737    }
00738    if (!ok)
00739    {
00740       if (! DropDuplicatePositions)
00741          return false;
00742    }
00743 
00744 // Now, we could calculate Z Spacing as the difference
00745 // between the "dist" values for the first two slices.
00746 
00747 // The following (un)-commented out code is let here
00748 // to be re-used by whomsoever is interested...
00749 
00750     std::multimap<double, File *>::iterator it5 = distmultimap.begin();
00751     double d1 = (*it5).first;
00752     it5++;
00753     double d2 = (*it5).first;
00754     ZSpacing = d1-d2;
00755     if (ZSpacing < 0.0)
00756        ZSpacing = - ZSpacing;
00757 
00758    fileList->clear();  // doesn't delete list elements, only nodes
00759 
00760 // Acording to user requierement, we sort direct order or reverse order.
00761    if (DirectOrder)
00762    {  
00763       for (std::multimap<double, File *>::iterator it3 = distmultimap.begin();
00764            it3 != distmultimap.end();
00765            ++it3)
00766       {
00767          fileList->push_back( (*it3).second );
00768          if (DropDuplicatePositions)
00769          {
00770             it3 =  distmultimap.upper_bound((*it3).first); // skip all duplicates
00771             if (it3 == distmultimap.end() )  // if last image, stop iterate
00772                break;
00773          }
00774       }
00775    }
00776    else // user asked for reverse order
00777    {
00778       std::multimap<double, File *>::const_iterator it4;
00779       it4 = distmultimap.end();
00780       do
00781       {
00782          it4--;
00783          fileList->push_back( (*it4).second );
00784          if (DropDuplicatePositions)  // skip all duplicates
00785          {
00786            it4 =  distmultimap.upper_bound((*it4).first);
00787            if (it4 == distmultimap.begin() ) // if first image, stop iterate
00788                break;
00789          } 
00790       } while (it4 != distmultimap.begin() );
00791    }
00792 
00793    distmultimap.clear();
00794 
00795    return true;
00796 }
00797 
00798 bool SerieHelper::ImageNumberLessThan(File *file1, File *file2)
00799 {
00800   return file1->GetImageNumber() < file2->GetImageNumber();
00801 }
00802 
00803 bool SerieHelper::ImageNumberGreaterThan(File *file1, File *file2)
00804 {
00805   return file1->GetImageNumber() > file2->GetImageNumber();
00806 }
00807 
00816 bool SerieHelper::ImageNumberOrdering(FileList *fileList) 
00817 {
00818    int min, max, pos;
00819    int n = fileList->size();
00820 
00821    FileList::const_iterator it = fileList->begin();
00822    min = max = (*it)->GetImageNumber();
00823 
00824    for (; it != fileList->end(); ++it, ++n)
00825    {
00826       pos = (*it)->GetImageNumber();
00827       min = (min < pos) ? min : pos;
00828       max = (max > pos) ? max : pos;
00829    }
00830 
00831    // Find out if image numbers are coherent (consecutive)
00832    if ( min == max || max == 0 || max >= (n+min) )
00833    {
00834       gdcmWarningMacro( " 'Image numbers' not coherent. "
00835                         << " No ImageNumberOrdering sort performed.");
00836       return false;
00837    }
00838    if (DirectOrder)
00839       Sort(fileList,SerieHelper::ImageNumberLessThan);
00840    else
00841       Sort(fileList,SerieHelper::ImageNumberGreaterThan);
00842 
00843    return true;
00844 }
00845 
00846 bool SerieHelper::FileNameLessThan(File *file1, File *file2)
00847 {
00848    return file1->GetFileName() < file2->GetFileName();
00849 }
00850 
00851 bool SerieHelper::FileNameGreaterThan(File *file1, File *file2)
00852 {
00853    return file1->GetFileName() > file2->GetFileName();
00854 }
00860 bool SerieHelper::FileNameOrdering(FileList *fileList)
00861 {
00862    if (DirectOrder) 
00863       Sort(fileList,SerieHelper::FileNameLessThan);
00864    else
00865       Sort(fileList,SerieHelper::FileNameGreaterThan);   
00866 
00867    return true;
00868 }
00869 
00875 bool SerieHelper::UserOrdering(FileList *fileList)
00876 {
00877    Sort(fileList,SerieHelper::UserLessThanFunction);   
00878    if (!DirectOrder) 
00879    {
00880       std::reverse(fileList->begin(), fileList->end());
00881    }
00882    return true;
00883 }
00884 
00885 //-----------------------------------------------------------------------------
00886 // Print
00890 void SerieHelper::Print(std::ostream &os, std::string const &indent)
00891 {
00892    // For all the Coherent File lists of the GDCM_NAME_SPACE::Serie
00893    SingleSerieUIDFileSetmap::iterator itl = SingleSerieUIDFileSetHT.begin();
00894    if ( itl == SingleSerieUIDFileSetHT.end() )
00895    {
00896       gdcmWarningMacro( "No SingleSerieUID File set found" );
00897       return;
00898    }
00899    while (itl != SingleSerieUIDFileSetHT.end())
00900    { 
00901       os << "Serie UID :[" << itl->first << "]" << std::endl;
00902 
00903       // For all the files of a SingleSerieUID File set
00904       for (FileList::iterator it =  (itl->second)->begin();
00905                                   it != (itl->second)->end(); 
00906                                 ++it)
00907       {
00908          os << indent << " --- " << (*it)->GetFileName() << std::endl;
00909       }
00910       ++itl;
00911    }
00912 }
00913 
00914 void SerieHelper::CreateDefaultUniqueSeriesIdentifier()
00915 {
00916    // If the user requests, additional information can be appended
00917    // to the SeriesUID to further differentiate volumes in the DICOM
00918    // objects being processed.
00919  
00920    // 0020 0011 Series Number
00921    // A scout scan prior to a CT volume scan can share the same
00922    //   SeriesUID, but they will sometimes have a different Series Number
00923    AddRestriction( TagKey(0x0020, 0x0011) );
00924    
00925    // 0018 0024 Sequence Name
00926    // For T1-map and phase-contrast MRA, the different flip angles and
00927    //   directions are only distinguished by the Sequence Name
00928    AddRestriction( TagKey(0x0018, 0x0024) );
00929    
00930    // 0018 0050 Slice Thickness
00931    // On some CT systems, scout scans and subsequence volume scans will
00932    //   have the same SeriesUID and Series Number - YET the slice 
00933    //   thickness will differ from the scout slice and the volume slices.
00934    AddRestriction( TagKey(0x0018, 0x0050));
00935    
00936    // 0028 0010 Rows
00937    // If the 2D images in a sequence don't have the same number of rows,
00938    // then it is difficult to reconstruct them into a 3D volume.
00939    AddRestriction( TagKey(0x0028, 0x0010));
00940    
00941    // 0028 0011 Columns
00942    // If the 2D images in a sequence don't have the same number of columns,
00943    // then it is difficult to reconstruct them into a 3D volume.
00944    AddRestriction( TagKey(0x0028, 0x0011));
00945 }
00946 
00960 std::string SerieHelper::CreateUniqueSeriesIdentifier( File *inFile )
00961 {
00962    if( inFile->IsReadable() )
00963    {
00964     // 0020 000e UI REL Series Instance UID
00965     std::string uid = inFile->GetEntryString (0x0020, 0x000e);
00966     std::string id = uid.c_str();
00967     if(m_UseSeriesDetails)
00968       {
00969       for(SerieExRestrictions::iterator it2 = ExRefine.begin();
00970         it2 != ExRefine.end();
00971         ++it2)
00972         {
00973         const ExRule &r = *it2;
00974         std::string s = inFile->GetEntryString( r.group, r.elem );
00975         if( s == GDCM_UNFOUND )
00976           {
00977           s = "";
00978           }
00979         if( id == uid && !s.empty() )
00980           {
00981           id += "."; // add separator
00982           }
00983         id += s;
00984         }
00985       }
00986     // Eliminate non-alnum characters, including whitespace...
00987     //   that may have been introduced by concats.
00988     for(unsigned int i=0; i<id.size(); i++)
00989       {
00990       while(i<id.size() 
00991         && !( id[i] == '.'
00992           || (id[i] >= 'a' && id[i] <= 'z')
00993           || (id[i] >= '0' && id[i] <= '9')
00994           || (id[i] >= 'A' && id[i] <= 'Z')))
00995         {
00996         id.erase(i, 1);
00997         }
00998       }
00999     return id;
01000     }
01001   else // Could not open inFile
01002     {
01003     gdcmWarningMacro("Could not parse series info.");
01004     std::string id = GDCM_UNFOUND;
01005     return id;
01006     }
01007 }
01008 
01017 std::string SerieHelper::CreateUserDefinedFileIdentifier( File * inFile )
01018 {
01019   //     Deal with all user supplied tags.
01020   //      (user knows more than we do about his images!)
01021   
01022    double converted;
01023    std::string id;
01024    std::string s; 
01025    char charConverted[17]; 
01026    
01027    for(SeriesExDetails::iterator it2 = ExDetails.begin();
01028       it2 != ExDetails.end();
01029       ++it2)
01030    {
01031       const ExDetail &r = *it2;
01032       s = inFile->GetEntryString( r.group, r.elem );
01033 
01034       // User is allowed to ask for 'convertion', to allow further ordering
01035       // e.g : 100 would be *before* 20; 000020.00 vs 00100.00 : OK
01036       if (it2->convert)
01037       {
01038          if ( s != GDCM_UNFOUND) // Don't convert unfound fields !
01039          {
01040             converted = atof(s.c_str());
01041             // probabely something much more complicated is possible, 
01042             // using C++ features
01044             sprintf(charConverted, "%016.6f",converted);
01045             s = charConverted;
01046          }
01047       }
01048       // Eliminate non-alphanum characters, including whitespace.
01049       for(unsigned int i=0; i<s.size(); i++)
01050       {
01051          while(i<s.size()
01052                && !( s[i] == '.' || s[i] == '%' || s[i] == '_'
01053                  || (s[i] >= 'a' && s[i] <= 'z')
01054                  || (s[i] >= '0' && s[i] <= '9')
01055                  || (s[i] >= 'A' && s[i] <= 'Z')))
01056          {
01057             s.erase(i, 1);
01058          }
01059       }
01060       
01061       id += s.c_str();
01062       id += "%%%"; // make the FileIdentifier Tokenizable
01063    }
01064    id += inFile->GetFileName();
01065    id += "%%%"; 
01066    return id;             
01067 }
01068 
01069 //-----------------------------------------------------------------------------
01070 // Sort
01074 void SerieHelper::Sort(FileList *fileList, bool (*pt2Func)( File *file1, File *file2) )
01075 {
01076  std::sort(fileList->begin(), fileList->end(), pt2Func );
01077 }
01078 
01079 /*
01080 #ifndef GDCM_LEGACY_REMOVE
01081 bool SerieHelper::AddGdcmFile(File* header)
01082 {
01083   return AddFile(header);
01084 }
01085 #endif
01086 */
01087 
01088 //-----------------------------------------------------------------------------
01089 } // end namespace gdcm

Generated on Fri Aug 24 12:59:32 2007 for gdcm by  doxygen 1.4.6