1 /*=========================================================================
2
3 Program: GDCM (Grassroots DICOM). A DICOM library
4
5 Copyright (c) 2006-2011 Mathieu Malaterre
6 All rights reserved.
7 See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
8
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notice for more information.
12
13 =========================================================================*/
14 #include "gdcmScanner.h"
15 #include "gdcmTesting.h"
16 #include "gdcmIPPSorter.h"
17 #include "gdcmDirectionCosines.h"
18 #include <cmath>
19
20 /*
21 * The following example is a basic sorted which should work in generic cases.
22 * It sort files based on:
23 * Study Instance UID
24 * Series Instance UID
25 * Frame of Reference UID
26 * Image Orientation (Patient)
27 * Image Position (Patient) (Sorting based on IPP + IOP)
28 */
29
30 namespace gdcm {
31 const Tag t1(0x0020,0x000d); // Study Instance UID
32 const Tag t2(0x0020,0x000e); // Series Instance UID
33 const Tag t3(0x0020,0x0052); // Frame of Reference UID
34 const Tag t4(0x0020,0x0037); // Image Orientation (Patient)
35
36 class DiscriminateVolume
37 {
38 private:
39 std::vector< Directory::FilenamesType > SortedFiles;
40 std::vector< Directory::FilenamesType > UnsortedFiles;
41
GetAllFilenamesFromTagToValue(Scanner const & s,Directory::FilenamesType const & filesubset,Tag const & t,const char * valueref)42 Directory::FilenamesType GetAllFilenamesFromTagToValue(
43 Scanner const & s, Directory::FilenamesType const &filesubset, Tag const &t, const char *valueref)
44 {
45 Directory::FilenamesType theReturn;
46 if( valueref )
47 {
48 size_t len = strlen( valueref );
49 Directory::FilenamesType::const_iterator file = filesubset.begin();
50 for(; file != filesubset.end(); ++file)
51 {
52 const char *filename = file->c_str();
53 const char * value = s.GetValue(filename, t);
54 if( value && strncmp(value, valueref, len ) == 0 )
55 {
56 theReturn.push_back( filename );
57 }
58 }
59 }
60 return theReturn;
61 }
62
ProcessAIOP(Scanner const &,Directory::FilenamesType const & subset,const char * iopval)63 void ProcessAIOP(Scanner const & , Directory::FilenamesType const & subset, const char *iopval)
64 {
65 std::cout << "IOP: " << iopval << std::endl;
66 IPPSorter ipp;
67 ipp.SetComputeZSpacing( true );
68 ipp.SetZSpacingTolerance( 1e-3 ); // ??
69 bool b = ipp.Sort( subset );
70 if( !b )
71 {
72 // If you reach here this means you need one more parameter to discriminiat this
73 // series. Eg. T1 / T2 intertwinted. Multiple Echo (0018,0081)
74 std::cerr << "Failed to sort: " << subset.begin()->c_str() << std::endl;
75 for(
76 Directory::FilenamesType::const_iterator file = subset.begin();
77 file != subset.end(); ++file)
78 {
79 std::cerr << *file << std::endl;
80 }
81 UnsortedFiles.push_back( subset );
82 return ;
83 }
84 ipp.Print( std::cout );
85 SortedFiles.push_back( ipp.GetFilenames() );
86 }
87
ProcessAFrameOfRef(Scanner const & s,Directory::FilenamesType const & subset,const char * frameuid)88 void ProcessAFrameOfRef(Scanner const & s, Directory::FilenamesType const & subset, const char * frameuid)
89 {
90 // In this subset of files (belonging to same series), let's find those
91 // belonging to the same Frame ref UID:
92 Directory::FilenamesType files = GetAllFilenamesFromTagToValue(
93 s, subset, t3, frameuid);
94
95 std::set< std::string > iopset;
96
97 for(
98 Directory::FilenamesType::const_iterator file = files.begin();
99 file != files.end(); ++file)
100 {
101 //std::cout << *file << std::endl;
102 const char * value = s.GetValue(file->c_str(), gdcm::t4 );
103 assert( value );
104 iopset.insert( value );
105 }
106 size_t n = iopset.size();
107 if ( n == 0 )
108 {
109 assert( files.empty() );
110 return;
111 }
112
113 std::cout << "Frame of Ref: " << frameuid << std::endl;
114 if ( n == 1 )
115 {
116 ProcessAIOP(s, files, iopset.begin()->c_str() );
117 }
118 else
119 {
120 const char *f = files.begin()->c_str();
121 std::cerr << "More than one IOP: " << f << std::endl;
122 // Make sure that there is actually 'n' different IOP
123 gdcm::DirectionCosines ref;
124 gdcm::DirectionCosines dc;
125 for(
126 std::set< std::string >::const_iterator it = iopset.begin();
127 it != iopset.end(); ++it )
128 {
129 ref.SetFromString( it->c_str() );
130 for(
131 Directory::FilenamesType::const_iterator file = files.begin();
132 file != files.end(); ++file)
133 {
134 std::string value = s.GetValue(file->c_str(), gdcm::t4 );
135 if( value != it->c_str() )
136 {
137 dc.SetFromString( value.c_str() );
138 const double crossdot = ref.CrossDot(dc);
139 const double eps = std::fabs( 1. - crossdot );
140 if( eps < 1e-6 )
141 {
142 std::cerr << "Problem with IOP discrimination: " << file->c_str()
143 << " " << it->c_str() << std::endl;
144 return;
145 }
146 }
147 }
148 }
149 // If we reach here this means there is actually 'n' different IOP
150 for(
151 std::set< std::string >::const_iterator it = iopset.begin();
152 it != iopset.end(); ++it )
153 {
154 const char *iopvalue = it->c_str();
155 Directory::FilenamesType iopfiles = GetAllFilenamesFromTagToValue(
156 s, files, t4, iopvalue );
157 ProcessAIOP(s, iopfiles, iopvalue );
158 }
159 }
160 }
161
ProcessASeries(Scanner const & s,const char * seriesuid)162 void ProcessASeries(Scanner const & s, const char * seriesuid)
163 {
164 std::cout << "Series: " << seriesuid << std::endl;
165 // let's find all files belonging to this series:
166 Directory::FilenamesType seriesfiles = GetAllFilenamesFromTagToValue(
167 s, s.GetFilenames(), t2, seriesuid);
168
169 gdcm::Scanner::ValuesType vt3 = s.GetValues(t3);
170 for(
171 gdcm::Scanner::ValuesType::const_iterator it = vt3.begin()
172 ; it != vt3.end(); ++it )
173 {
174 ProcessAFrameOfRef(s, seriesfiles, it->c_str());
175 }
176 }
177
ProcessAStudy(Scanner const & s,const char * studyuid)178 void ProcessAStudy(Scanner const & s, const char * studyuid)
179 {
180 std::cout << "Study: " << studyuid << std::endl;
181 gdcm::Scanner::ValuesType vt2 = s.GetValues(t2);
182 for(
183 gdcm::Scanner::ValuesType::const_iterator it = vt2.begin()
184 ; it != vt2.end(); ++it )
185 {
186 ProcessASeries(s, it->c_str());
187 }
188 }
189 public:
190
Print(std::ostream & os)191 void Print( std::ostream & os )
192 {
193 os << "Sorted Files: " << std::endl;
194 for(
195 std::vector< Directory::FilenamesType >::const_iterator it = SortedFiles.begin();
196 it != SortedFiles.end(); ++it )
197 {
198 os << "Group: " << std::endl;
199 for(
200 Directory::FilenamesType::const_iterator file = it->begin();
201 file != it->end(); ++file)
202 {
203 os << *file << std::endl;
204 }
205 }
206 os << "Unsorted Files: " << std::endl;
207 for(
208 std::vector< Directory::FilenamesType >::const_iterator it = UnsortedFiles.begin();
209 it != UnsortedFiles.end(); ++it )
210 {
211 os << "Group: " << std::endl;
212 for(
213 Directory::FilenamesType::const_iterator file = it->begin();
214 file != it->end(); ++file)
215 {
216 os << *file << std::endl;
217 }
218 }
219
220 }
221
GetSortedFiles() const222 std::vector< Directory::FilenamesType > const & GetSortedFiles() const { return SortedFiles; }
GetUnsortedFiles() const223 std::vector< Directory::FilenamesType > const & GetUnsortedFiles() const { return UnsortedFiles; }
224
ProcessIntoVolume(Scanner const & s)225 void ProcessIntoVolume( Scanner const & s )
226 {
227 gdcm::Scanner::ValuesType vt1 = s.GetValues( gdcm::t1 );
228 for(
229 gdcm::Scanner::ValuesType::const_iterator it = vt1.begin()
230 ; it != vt1.end(); ++it )
231 {
232 ProcessAStudy( s, it->c_str() );
233 }
234
235 }
236
237 };
238
239 } // namespace gdcm
240
main(int argc,char * argv[])241 int main(int argc, char *argv[])
242 {
243 std::string dir1;
244 if( argc < 2 )
245 {
246 const char *extradataroot = nullptr;
247 #ifdef GDCM_BUILD_TESTING
248 extradataroot = gdcm::Testing::GetDataExtraRoot();
249 #endif
250 if( !extradataroot )
251 {
252 return 1;
253 }
254 dir1 = extradataroot;
255 dir1 += "/gdcmSampleData/ForSeriesTesting/VariousIncidences/ST1";
256 }
257 else
258 {
259 dir1 = argv[1];
260 }
261
262 gdcm::Directory d;
263 d.Load( dir1.c_str(), true ); // recursive !
264
265 gdcm::Scanner s;
266 s.AddTag( gdcm::t1 );
267 s.AddTag( gdcm::t2 );
268 s.AddTag( gdcm::t3 );
269 s.AddTag( gdcm::t4 );
270 bool b = s.Scan( d.GetFilenames() );
271 if( !b )
272 {
273 std::cerr << "Scanner failed" << std::endl;
274 return 1;
275 }
276
277 gdcm::DiscriminateVolume dv;
278 dv.ProcessIntoVolume( s );
279 dv.Print( std::cout );
280
281 return 0;
282 }
283