X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;ds=sidebyside;f=src%2FgdcmSerieHelper.cxx;h=5d7b6c48dbc236fd25c9f4cbaeeab22fbc9ff5c6;hb=96775cd7d34ec152fbf1430634bb338f524ee212;hp=72fc5f625c0d30ad853ef73d58edb721c1bcb31b;hpb=f80897f63dcbc709e372abe4a248ddbff9f2b33c;p=gdcm.git diff --git a/src/gdcmSerieHelper.cxx b/src/gdcmSerieHelper.cxx index 72fc5f62..5d7b6c48 100644 --- a/src/gdcmSerieHelper.cxx +++ b/src/gdcmSerieHelper.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSerieHelper.cxx,v $ Language: C++ - Date: $Date: 2005/11/28 11:54:51 $ - Version: $Revision: 1.37 $ + Date: $Date: 2006/02/05 23:13:36 $ + Version: $Revision: 1.46 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -209,11 +209,13 @@ void SerieHelper::AddGdcmFile(File *header) } /** - * \brief add a rules for restricting a DICOM file to be in the serie we are - * trying to find. For example you can select only the DICOM file from a + * \brief add a rule for restricting a DICOM file to be in the serie we are + * trying to find. For example you can select only the DICOM files from a * directory which would have a particular EchoTime==4.0. * This method is a user level, value is not required to be formatted as a DICOM * string + * \todo find a trick to allow user to say if he wants the Rectrictions + * to be *ored* (and not only *anded*) * @param key Target tag we want restrict on a given value * @param value value to be checked to exclude File * @param op operator we want to use to check @@ -229,6 +231,47 @@ void SerieHelper::AddRestriction(TagKey const &key, ExRestrictions.push_back( r ); } +/** + * \brief add a rule for restricting a DICOM file to be in the serie we are + * trying to find. For example you can select only the DICOM file from a + * directory which would have a particular EchoTime==4.0. + * This method is a user level, value is not required to be formatted as a DICOM + * string + * \todo find a trick to allow user if he wants the Rectrictions to be *ored* + * (and not only *anded*) + * @param group tag group number we want restrict on a given value + * @param elem tag element number we want restrict on a given value + * @param value value to be checked to exclude File + * @param op operator we want to use to check + */ +void SerieHelper::AddRestriction(uint16_t group, uint16_t elem, + std::string const &value, int op) +{ + ExRule r; + r.group = group; + r.elem = elem; + r.value = value; + r.op = op; + ExRestrictions.push_back( r ); +} + +/** + * \brief add an extra 'SerieDetail' for building a 'Serie Identifier' + * that ensures (hope so) File constistency (Series Instance UID doesn't. + * @param group tag group number we want restrict on a given value + * @param elem tag element number we want restrict on a given value + * @param convert wether we want 'convertion', to allow further ordering + * e.g : 100 would be *before* 20; 000020.00 vs 00100.00 : OK + */ +void SerieHelper::AddSeriesDetail(uint16_t group, uint16_t elem, bool convert) +{ + + ExDetail d; + d.group = group; + d.elem = elem; + d.convert = convert; + ExDetails.push_back( d ); +} /** * \brief Sets the root Directory * @param dir Name of the directory to deal with @@ -569,13 +612,13 @@ bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList ) { //iop is calculated based on the file file float cosines[6]; - float normal[3]; - float ipp[3]; - float dist; - float min = 0, max = 0; + double normal[3]; + double ipp[3]; + double dist; + double min = 0, max = 0; bool first = true; - std::multimap distmultimap; + std::multimap distmultimap; // Use a multimap to sort the distances from 0,0,0 for ( FileList::const_iterator it = fileList->begin(); @@ -603,7 +646,7 @@ bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList ) dist += normal[i]*ipp[i]; } - distmultimap.insert(std::pair(dist, *it)); + distmultimap.insert(std::pair(dist, *it)); max = min = dist; first = false; @@ -620,7 +663,7 @@ bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList ) dist += normal[i]*ipp[i]; } - distmultimap.insert(std::pair(dist, *it)); + distmultimap.insert(std::pair(dist, *it)); min = (min < dist) ? min : dist; max = (max > dist) ? max : dist; @@ -638,7 +681,7 @@ bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList ) // Check to see if image shares a common position bool ok = true; - for (std::multimap::iterator it2 = distmultimap.begin(); + for (std::multimap::iterator it2 = distmultimap.begin(); it2 != distmultimap.end(); ++it2) { @@ -661,7 +704,7 @@ bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList ) if (DirectOrder) { - for (std::multimap::iterator it3 = distmultimap.begin(); + for (std::multimap::iterator it3 = distmultimap.begin(); it3 != distmultimap.end(); ++it3) { @@ -670,7 +713,7 @@ bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList ) } else // user asked for reverse order { - std::multimap::const_iterator it4; + std::multimap::const_iterator it4; it4 = distmultimap.end(); do { @@ -725,11 +768,13 @@ bool SerieHelper::ImageNumberOrdering(FileList *fileList) return false; } if (DirectOrder) - std::sort(fileList->begin(), fileList->end(), - SerieHelper::ImageNumberLessThan ); + Sort(fileList,SerieHelper::ImageNumberLessThan); +// std::sort(fileList->begin(), fileList->end(), +// SerieHelper::ImageNumberLessThan ); else - std::sort(fileList->begin(), fileList->end(), - SerieHelper::ImageNumberGreaterThan ); + Sort(fileList,SerieHelper::ImageNumberGreaterThan); +// std::sort(fileList->begin(), fileList->end(), +// SerieHelper::ImageNumberGreaterThan ); return true; } @@ -751,11 +796,13 @@ bool SerieHelper::FileNameGreaterThan(File *file1, File *file2) bool SerieHelper::FileNameOrdering(FileList *fileList) { if (DirectOrder) - std::sort(fileList->begin(), fileList->end(), - SerieHelper::FileNameLessThan); + Sort(fileList,SerieHelper::FileNameLessThan); +// std::sort(fileList->begin(), fileList->end(), +// SerieHelper::FileNameLessThan); else - std::sort(fileList->begin(), fileList->end(), - SerieHelper::FileNameGreaterThan); + Sort(fileList,SerieHelper::FileNameGreaterThan); +// std::sort(fileList->begin(), fileList->end(), +// SerieHelper::FileNameGreaterThan); return true; } @@ -767,8 +814,9 @@ bool SerieHelper::FileNameOrdering(FileList *fileList) */ bool SerieHelper::UserOrdering(FileList *fileList) { - std::sort(fileList->begin(), fileList->end(), - SerieHelper::UserLessThanFunction); + Sort(fileList,SerieHelper::UserLessThanFunction); +// std::sort(fileList->begin(), fileList->end(), +// SerieHelper::UserLessThanFunction); if (!DirectOrder) { std::reverse(fileList->begin(), fileList->end()); @@ -776,7 +824,20 @@ bool SerieHelper::UserOrdering(FileList *fileList) return true; } -std::string SerieHelper::CreateUniqueSeriesIdentifier( File * inFile ) +/** + * \brief Heuristics to *try* to build a Serie Identifier that would ensure + * all the images are coherent. + * + * By default, uses the SeriesUID. If UseSeriesDetails(true) has been called, + * then additional identifying information is used. + * We allow user to add his own critierions, using AddSeriesDetail + * (he knows more than we do about his images!) + * ex : in tagging series, the only pertnent tag is + * 0018|1312 [In-plane Phase Encoding Direction] value : ROW/COLUMN + * @param inFile gdcm::File we want to build a Serie Identifier for. + * @return the SeriesIdentifier + */ +std::string SerieHelper::CreateUniqueSeriesIdentifier( File *inFile ) { if( inFile->IsReadable() ) { @@ -805,6 +866,10 @@ std::string SerieHelper::CreateUniqueSeriesIdentifier( File * inFile ) { sName = ""; } + + // You can think on checking Image Orientation (0020,0037), as well. + + // 0018 0050 Slice Thickness // On some CT systems, scout scans and subsequence volume scans will // have the same SeriesUID and Series Number - YET the slice @@ -830,25 +895,41 @@ std::string SerieHelper::CreateUniqueSeriesIdentifier( File * inFile ) { sColumns = ""; } - + // Concat the new info std::string num = sNum.c_str(); num += sName.c_str(); num += sThick.c_str(); num += sRows.c_str(); num += sColumns.c_str(); + + // Add a loop, here, to deal with any extra user supplied tag. + // We allow user to add his own critierions + // (he knows more than we do about his images!) + // ex : in tagging series, the only pertinent tag is + // 0018|1312 [In-plane Phase Encoding Direction] values : ROW/COLUMN + + std::string s; + for(SeriesExDetails::iterator it2 = ExDetails.begin(); + it2 != ExDetails.end(); + ++it2) + { + const ExDetail &r = *it2; + s = inFile->GetEntryString( r.group, r.elem ); + num += s.c_str(); + } // Append the new info to the SeriesUID id += "."; id += num.c_str(); } - // Eliminate non-alnum characters, including whitespace... + // Eliminate non-alphanum characters, including whitespace... // that may have been introduced by concats. for(unsigned int i=0; i= 'a' && id[i] <= 'z') || (id[i] >= '0' && id[i] <= '9') || (id[i] >= 'A' && id[i] <= 'Z'))) @@ -866,7 +947,64 @@ std::string SerieHelper::CreateUniqueSeriesIdentifier( File * inFile ) } } +/** + * \brief Allow user to build is own File Identifier (to be able to sort + * temporal series just as he wants) + * Criterions will be set with AddSeriesDetail. + * (Maybe the method should be moved elsewhere + * -File class? FileHelper class?- + * @return FileIdentifier (Tokenizable on '%%%'. Hope it's enough !) + */ +std::string SerieHelper::CreateUserDefinedFileIdentifier( File * inFile ) +{ + // Deal with all user supplied tags. + // (user knows more than we do about his images!) + + double converted; + std::string id; + std::string s; + char charConverted[17]; + + for(SeriesExDetails::iterator it2 = ExDetails.begin(); + it2 != ExDetails.end(); + ++it2) + { + const ExDetail &r = *it2; + s = inFile->GetEntryString( r.group, r.elem ); + // User is allowed to ask 'convertion', to allow further ordering + // e.g : 100 would be *before* 20; 000020.00 vs 00100.00 : OK + if (it2->convert) + { + if ( s != GDCM_UNFOUND) // Don't convert unfound fields ! + { + converted = atof(s.c_str()); + // probabely something much more complicated is possible, + // using C++ features + /// \todo check the behaviour when there are >0 and <0 numbers + sprintf(charConverted, "%016.6f",converted); + s = charConverted; + } + } + // Eliminate non-alphanum characters, including whitespace. + for(unsigned int i=0; i= 'a' && s[i] <= 'z') + || (s[i] >= '0' && s[i] <= '9') + || (s[i] >= 'A' && s[i] <= 'Z'))) + { + s.erase(i, 1); + } + } + + id += s.c_str(); + id += "%%%"; // make the FileIdentifier Tokenizable + } + + return id; +} //----------------------------------------------------------------------------- // Print /** @@ -896,5 +1034,15 @@ void SerieHelper::Print(std::ostream &os, std::string const &indent) } } +//----------------------------------------------------------------------------- +// Sort +/** + * \brief Sort FileList. + */ +void SerieHelper::Sort(FileList *fileList, bool (*pt2Func)( File *file1, File *file2) ) +{ + std::sort(fileList->begin(), fileList->end(), pt2Func ); +} + //----------------------------------------------------------------------------- } // end namespace gdcm