00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "gdcmSerieHelper.h"
00020 #include "gdcmDirList.h"
00021 #include "gdcmFile.h"
00022
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>
00031
00032 namespace GDCM_NAME_SPACE
00033 {
00034
00035
00036
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
00064 FileList *l = GetFirstSingleSerieUIDFileSet();
00065 while (l)
00066 {
00067
00068 for (GDCM_NAME_SPACE::FileList::iterator it = l->begin();
00069 it != l->end();
00070 ++it)
00071 {
00072 (*it)->Delete();
00073 }
00074 l->clear();
00075 delete l;
00076 l = GetNextSingleSerieUIDFileSet();
00077 }
00078
00079 SingleSerieUIDFileSetHT.clear();
00080 }
00081
00082
00083
00084
00085
00086
00091 void SerieHelper::AddFileName(std::string const &filename)
00092 {
00093
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
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
00137
00138
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
00150 allrules = 0;
00151 break;
00152 }
00153 }
00154
00155 if ( allrules )
00156 {
00157
00158
00159
00160
00161 std::string id = CreateUniqueSeriesIdentifier( header );
00162
00163
00164
00165 if ( SingleSerieUIDFileSetHT.count(id) == 0 )
00166 {
00167 gdcmDebugMacro(" New/gdcmSerieHelper.cxx Serie UID :[" << id << "]");
00168
00169 SingleSerieUIDFileSetHT[id] = new FileList;
00170 }
00171
00172 SingleSerieUIDFileSetHT[id]->push_back( header );
00173 }
00174 else
00175 {
00176
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
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
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);
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
00296
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
00347 }
00348 return true;
00349 }
00350
00351
00357
00358
00359
00360
00361
00362
00363
00364
00365
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00390
00391
00392
00393
00394
00395
00396
00397
00398
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
00459 for ( ;
00460 it != fileSet->end();
00461 ++it)
00462 {
00463
00464
00465
00466
00467
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
00482 CoherentFileSet[strOrient] = new FileList;
00483 }
00484
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;
00505 std::ostringstream ossPosition;
00506 std::string strPosition;
00507 FileList::const_iterator it = fileSet->begin();
00508
00509 for ( ;
00510 it != fileSet->end();
00511 ++it)
00512 {
00513
00514
00515
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);
00522 if ( strImPos == GDCM_UNFOUND )
00523 {
00524 gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00525
00526
00527
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
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
00555 CoherentFileSet[strPosition] = new FileList;
00556 }
00557
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;
00582
00583 FileList::const_iterator it = fileSet->begin();
00584
00585 for ( ;
00586 it != fileSet->end();
00587 ++it)
00588 {
00589
00590
00591
00592
00593 strTagValue = (*it)->GetEntryString(group,element);
00594
00595 if ( CoherentFileSet.count(strTagValue) == 0 )
00596 {
00597 gdcmDebugMacro(" New Tag Value :[" << strTagValue << "]");
00598
00599 CoherentFileSet[strTagValue] = new FileList;
00600 }
00601
00602 CoherentFileSet[strTagValue]->push_back( (*it) );
00603 }
00604 return CoherentFileSet;
00605 }
00606
00607
00608
00609
00610
00611
00625 bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList )
00626
00627 {
00628
00629
00630
00631
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;
00639
00640 std::multimap<double,File *> distmultimap;
00641
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
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
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
00672
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
00692
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
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
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
00745
00746
00747
00748
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();
00759
00760
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);
00771 if (it3 == distmultimap.end() )
00772 break;
00773 }
00774 }
00775 }
00776 else
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)
00785 {
00786 it4 = distmultimap.upper_bound((*it4).first);
00787 if (it4 == distmultimap.begin() )
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
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
00890 void SerieHelper::Print(std::ostream &os, std::string const &indent)
00891 {
00892
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
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
00917
00918
00919
00920
00921
00922
00923 AddRestriction( TagKey(0x0020, 0x0011) );
00924
00925
00926
00927
00928 AddRestriction( TagKey(0x0018, 0x0024) );
00929
00930
00931
00932
00933
00934 AddRestriction( TagKey(0x0018, 0x0050));
00935
00936
00937
00938
00939 AddRestriction( TagKey(0x0028, 0x0010));
00940
00941
00942
00943
00944 AddRestriction( TagKey(0x0028, 0x0011));
00945 }
00946
00960 std::string SerieHelper::CreateUniqueSeriesIdentifier( File *inFile )
00961 {
00962 if( inFile->IsReadable() )
00963 {
00964
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 += ".";
00982 }
00983 id += s;
00984 }
00985 }
00986
00987
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
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
01020
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
01035
01036 if (it2->convert)
01037 {
01038 if ( s != GDCM_UNFOUND)
01039 {
01040 converted = atof(s.c_str());
01041
01042
01044 sprintf(charConverted, "%016.6f",converted);
01045 s = charConverted;
01046 }
01047 }
01048
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 += "%%%";
01063 }
01064 id += inFile->GetFileName();
01065 id += "%%%";
01066 return id;
01067 }
01068
01069
01070
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
01081
01082
01083
01084
01085
01086
01087
01088
01089 }