1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 
19 //  Software Guide : BeginLatex
20 //
21 //  This example illustrates how to read a DICOM series into a volume and then
22 //  print most of the DICOM header information. The binary fields are skipped.
23 //
24 //  \index{DICOM!Header}
25 //  \index{DICOM!Tags}
26 //  \index{DICOM!Printing Tags}
27 //
28 //  Software Guide : EndLatex
29 
30 // Software Guide : BeginLatex
31 //
32 // The header files for the series reader and the GDCM classes for image IO and
33 // name generation should be included first.
34 //
35 // Software Guide : EndLatex
36 
37 // Software Guide : BeginCodeSnippet
38 #include "itkImageSeriesReader.h"
39 #include "itkGDCMImageIO.h"
40 #include "itkGDCMSeriesFileNames.h"
41 // Software Guide : EndCodeSnippet
42 
main(int argc,char * argv[])43 int main( int argc, char* argv[] )
44 {
45   if( argc < 2 )
46     {
47     std::cerr << "Usage: " << argv[0] << " DicomDirectory " << std::endl;
48     return EXIT_FAILURE;
49     }
50 
51   // Software Guide : BeginLatex
52   //
53   //  Next, we instantiate the type to be used for storing the image once it is
54   //  read into memory.
55   //
56   // Software Guide : EndLatex
57 
58   // Software Guide : BeginCodeSnippet
59   using PixelType = signed short;
60   constexpr unsigned int Dimension = 3;
61 
62   using ImageType = itk::Image< PixelType, Dimension >;
63   // Software Guide : EndCodeSnippet
64 
65   // Software Guide : BeginLatex
66   //
67   // We use the image type for instantiating the series reader type and then we
68   // construct one object of this class.
69   //
70   // Software Guide : EndLatex
71 
72   // Software Guide : BeginCodeSnippet
73   using ReaderType = itk::ImageSeriesReader< ImageType >;
74 
75   ReaderType::Pointer reader = ReaderType::New();
76   // Software Guide : EndCodeSnippet
77 
78   // Software Guide : BeginLatex
79   //
80   // A GDCMImageIO object is created and assigned to the reader.
81   //
82   // Software Guide : EndLatex
83 
84   // Software Guide : BeginCodeSnippet
85   using ImageIOType = itk::GDCMImageIO;
86 
87   ImageIOType::Pointer dicomIO = ImageIOType::New();
88 
89   reader->SetImageIO( dicomIO );
90   // Software Guide : EndCodeSnippet
91 
92   // Software Guide : BeginLatex
93   //
94   // A GDCMSeriesFileNames is declared in order to generate the names of DICOM
95   // slices. We specify the directory with the \code{SetInputDirectory()} method
96   // and, in this case, take the directory name from the command line arguments.
97   // You could have obtained the directory name from a file dialog in a GUI.
98   //
99   // Software Guide : EndLatex
100 
101   // Software Guide : BeginCodeSnippet
102   using NamesGeneratorType = itk::GDCMSeriesFileNames;
103 
104   NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
105 
106   nameGenerator->SetInputDirectory( argv[1] );
107   // Software Guide : EndCodeSnippet
108 
109   // Software Guide : BeginLatex
110   //
111   // The list of files to read is obtained from the name generator by invoking
112   // the \code{GetInputFileNames()} method and receiving the results in a
113   // container of strings. The list of filenames is passed to the reader using
114   // the \code{SetFileNames()} method.
115   //
116   // Software Guide : EndLatex
117 
118   // Software Guide : BeginCodeSnippet
119   using FileNamesContainer = std::vector<std::string>;
120   FileNamesContainer fileNames = nameGenerator->GetInputFileNames();
121 
122   reader->SetFileNames( fileNames );
123   // Software Guide : EndCodeSnippet
124 
125   // Software Guide : BeginLatex
126   //
127   // We trigger the reader by invoking the \code{Update()} method. This
128   // invocation should normally be done inside a \code{try/catch} block given
129   // that it may eventually throw exceptions.
130   //
131   // Software Guide : EndLatex
132 
133   try
134     {
135     // Software Guide : BeginCodeSnippet
136     reader->Update();
137     // Software Guide : EndCodeSnippet
138     }
139   catch (itk::ExceptionObject &ex)
140     {
141     std::cout << ex << std::endl;
142     return EXIT_FAILURE;
143     }
144 
145   // Software Guide : BeginLatex
146   //
147   // ITK internally queries GDCM and obtains all the DICOM tags from the file
148   // headers. The tag values are stored in the \doxygen{MetaDataDictionary}
149   // which is a general-purpose container for \{key,value\} pairs. The Metadata
150   // dictionary can be recovered from any ImageIO class by invoking the
151   // \code{GetMetaDataDictionary()} method.
152   //
153   // \index{MetaDataDictionary}
154   // \index{ImageIO!GetMetaDataDictionary()}
155   //
156   // Software Guide : EndLatex
157 
158   // Software Guide : BeginCodeSnippet
159   using DictionaryType = itk::MetaDataDictionary;
160 
161   const  DictionaryType & dictionary = dicomIO->GetMetaDataDictionary();
162   // Software Guide : EndCodeSnippet
163 
164   // Software Guide : BeginLatex
165   //
166   // In this example, we are only interested in the DICOM tags that can be
167   // represented as strings. Therefore, we declare a \doxygen{MetaDataObject} of
168   // string type in order to receive those particular values.
169   //
170   // \index{MetaDataDictionary!MetaDataObject}
171   // \index{MetaDataDictionary!String entries}
172   // \index{MetaDataObject!Strings}
173   //
174   // Software Guide : EndLatex
175 
176   // Software Guide : BeginCodeSnippet
177   using MetaDataStringType = itk::MetaDataObject< std::string >;
178   // Software Guide : EndCodeSnippet
179 
180   // Software Guide : BeginLatex
181   //
182   // The metadata dictionary is organized as a container with its corresponding
183   // iterators. We can therefore visit all its entries by first getting access to
184   // its \code{Begin()} and \code{End()} methods.
185   //
186   // \index{MetaDataDictionary!Begin()}
187   // \index{MetaDataDictionary!End()}
188   // \index{MetaDataDictionary!Iterator}
189   // \index{MetaDataDictionary!ConstIterator}
190   //
191   // Software Guide : EndLatex
192 
193   // Software Guide : BeginCodeSnippet
194   auto itr = dictionary.Begin();
195   auto end = dictionary.End();
196   // Software Guide : EndCodeSnippet
197 
198   // Software Guide : BeginLatex
199   //
200   // We are now ready for walking through the list of DICOM tags. For this
201   // purpose we use the iterators that we just declared. At every entry we
202   // attempt to convert it into a string entry by using the \code{dynamic\_cast}
203   // based on RTTI information\footnote{Run Time Type Information}. The
204   // dictionary is organized like a \code{std::map} structure, so we should use
205   // the \code{first} and \code{second} members of every entry in order
206   // to get access to the \{key,value\} pairs.
207   //
208   // Software Guide : EndLatex
209 
210   // Software Guide : BeginCodeSnippet
211   while( itr != end )
212     {
213     itk::MetaDataObjectBase::Pointer  entry = itr->second;
214 
215     MetaDataStringType::Pointer entryvalue =
216       dynamic_cast<MetaDataStringType *>( entry.GetPointer() );
217 
218     if( entryvalue )
219       {
220       std::string tagkey   = itr->first;
221       std::string tagvalue = entryvalue->GetMetaDataObjectValue();
222       std::cout << tagkey <<  " = " << tagvalue << std::endl;
223       }
224 
225     ++itr;
226     }
227   // Software Guide : EndCodeSnippet
228 
229   //  Software Guide : BeginLatex
230   //
231   //  It is also possible to query for specific entries instead of reading all of
232   //  them as we did above. In this case, the user must provide the tag
233   //  identifier using the standard DICOM encoding. The identifier is stored in a
234   //  string and used as key in the dictionary.
235   //
236   //  Software Guide : EndLatex
237 
238   // Software Guide : BeginCodeSnippet
239   std::string entryId = "0010|0010";
240 
241   auto tagItr = dictionary.Find( entryId );
242 
243   if( tagItr == end )
244     {
245     std::cerr << "Tag " << entryId;
246     std::cerr << " not found in the DICOM header" << std::endl;
247     return EXIT_FAILURE;
248     }
249   // Software Guide : EndCodeSnippet
250 
251   // Software Guide : BeginLatex
252   //
253   // Since the entry may or may not be of string type we must again use a
254   // \code{dynamic\_cast} in order to attempt to convert it to a string dictionary
255   // entry. If the conversion is successful, we can then print out its content.
256   //
257   // Software Guide : EndLatex
258 
259   // Software Guide : BeginCodeSnippet
260   MetaDataStringType::ConstPointer entryvalue =
261     dynamic_cast<const MetaDataStringType *>( tagItr->second.GetPointer() );
262 
263   if( entryvalue )
264     {
265     std::string tagvalue = entryvalue->GetMetaDataObjectValue();
266     std::cout << "Patient's Name (" << entryId <<  ") ";
267     std::cout << " is: " << tagvalue << std::endl;
268     }
269   else
270     {
271     std::cerr << "Entry was not of string type" << std::endl;
272     return EXIT_FAILURE;
273     }
274   // Software Guide : EndCodeSnippet
275 
276   // Software Guide : BeginLatex
277   //
278   // This type of functionality will probably be more useful when provided
279   // through a graphical user interface. For a full description of the DICOM
280   // dictionary please look at the following file.
281   //
282   // \code{Insight/Utilities/gdcm/Dicts/dicomV3.dic}
283   //
284   // Software Guide : EndLatex
285 
286   return EXIT_SUCCESS;
287 
288 }
289