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 #include "gdcmDictEntry.h"
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>
00031
00032 namespace gdcm
00033 {
00034
00035
00036
00037
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
00064 FileList *l = GetFirstSingleSerieUIDFileSet();
00065 while (l)
00066 {
00067
00068 for (gdcm::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
00080
00081
00082
00083
00084
00089 void SerieHelper::AddFileName(std::string const &filename)
00090 {
00091
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
00101
00102
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
00114
00115 allrules = 0;
00116 break;
00117 }
00118 }
00119
00120 if ( allrules )
00121 {
00122
00123
00124
00125
00126 const std::string &uid = header->GetEntryString(0x0020, 0x000e);
00127
00128
00129
00130
00131 if ( SingleSerieUIDFileSetHT.count(uid) == 0 )
00132 {
00133 gdcmDebugMacro(" New Serie UID :[" << uid << "]");
00134
00135 SingleSerieUIDFileSetHT[uid] = new FileList;
00136 }
00137
00138 SingleSerieUIDFileSetHT[uid]->push_back( header );
00139 }
00140 else
00141 {
00142
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
00175
00176
00177 for(SerieRestrictions::iterator it = Restrictions.begin();
00178 it != Restrictions.end();
00179 ++it)
00180 {
00181 const Rule &r = *it;
00182 const std::string s;
00183 if ( !Util::DicomStringEqual(s, r.second.c_str()) )
00184 {
00185
00186 allrules = 0;
00187 break;
00188 }
00189 }
00190 if ( allrules )
00191 {
00192
00193
00194
00195 const std::string &uid = "0";
00196
00197
00198
00199 if ( SingleSerieUIDFileSetHT.count(uid) == 0 )
00200 {
00201 gdcmDebugMacro(" New Serie UID :[" << uid << "]");
00202
00203 SingleSerieUIDFileSetHT[uid] = new FileList;
00204 }
00205
00206 SingleSerieUIDFileSetHT[uid]->push_back( header );
00207 }
00208
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);
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
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
00448
00449
00450
00451
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
00463
00464 if ( CoherentFileSet.count(strOrient) == 0 )
00465 {
00466 gdcmDebugMacro(" New Orientation :[" << strOrient << "]");
00467
00468 CoherentFileSet[strOrient] = new FileList;
00469 }
00470
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;
00491 std::ostringstream ossPosition;
00492 std::string strPosition;
00493 FileList::const_iterator it = fileSet->begin();
00494 it ++;
00495 for ( ;
00496 it != fileSet->end();
00497 ++it)
00498 {
00499
00500
00501
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);
00508 if ( strImPos == GDCM_UNFOUND )
00509 {
00510 gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00511
00512
00513
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
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
00541 CoherentFileSet[strPosition] = new FileList;
00542 }
00543
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;
00568
00569 FileList::const_iterator it = fileSet->begin();
00570 it ++;
00571 for ( ;
00572 it != fileSet->end();
00573 ++it)
00574 {
00575
00576
00577
00578
00579 strTagValue = (*it)->GetEntryString(group,elem);
00580
00581 if ( CoherentFileSet.count(strTagValue) == 0 )
00582 {
00583 gdcmDebugMacro(" New Tag Value :[" << strTagValue << "]");
00584
00585 CoherentFileSet[strTagValue] = new FileList;
00586 }
00587
00588 CoherentFileSet[strTagValue]->push_back( (*it) );
00589 }
00590 return CoherentFileSet;
00591 }
00592
00593
00594
00595
00596
00597
00610 bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList )
00611
00612 {
00613
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
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
00632
00633
00634
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
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
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();
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
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
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
00773
00774 else
00775 Sort(fileList,SerieHelper::ImageNumberGreaterThan);
00776
00777
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
00801
00802 else
00803 Sort(fileList,SerieHelper::FileNameGreaterThan);
00804
00805
00806
00807 return true;
00808 }
00809
00815 bool SerieHelper::UserOrdering(FileList *fileList)
00816 {
00817 Sort(fileList,SerieHelper::UserLessThanFunction);
00818
00819
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
00845 std::string uid = inFile->GetEntryString (0x0020, 0x000e);
00846 std::string id = uid.c_str();
00847 if(m_UseSeriesDetails)
00848 {
00849
00850
00851
00852
00853
00854
00855
00856 std::string sNum = inFile->GetEntryString(0x0020, 0x0011);
00857 if( sNum == gdcm::GDCM_UNFOUND )
00858 {
00859 sNum = "";
00860 }
00861
00862
00863
00864 std::string sName = inFile->GetEntryString(0x0018, 0x0024);
00865 if( sName == gdcm::GDCM_UNFOUND )
00866 {
00867 sName = "";
00868 }
00869
00870
00871
00872
00873
00874
00875
00876
00877 std::string sThick = inFile->GetEntryString (0x0018, 0x0050);
00878 if( sThick == gdcm::GDCM_UNFOUND )
00879 {
00880 sThick = "";
00881 }
00882
00883
00884
00885 std::string sRows = inFile->GetEntryString (0x0028, 0x0010);
00886 if( sRows == gdcm::GDCM_UNFOUND )
00887 {
00888 sRows = "";
00889 }
00890
00891
00892
00893 std::string sColumns = inFile->GetEntryString (0x0028, 0x0011);
00894 if( sColumns == gdcm::GDCM_UNFOUND )
00895 {
00896 sColumns = "";
00897 }
00898
00899
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
00907
00908
00909
00910
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
00923 id += ".";
00924 id += num.c_str();
00925 }
00926
00927
00928
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
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
00961
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
00976
00977 if (it2->convert)
00978 {
00979 converted = atof(s.c_str());
00980
00981
00983 sprintf(charConverted, "%016.6f",converted);
00984 s = charConverted;
00985 }
00986
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 += "_";
01001 }
01002
01003 return id;
01004 }
01005
01006
01010 void SerieHelper::Print(std::ostream &os, std::string const &indent)
01011 {
01012
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
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
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 }