]> Creatis software - clitk.git/blob - tools/clitkDicom2Image.cxx
b3bcc902de0699f224e2047f9922f4f0f057bc29
[clitk.git] / tools / clitkDicom2Image.cxx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to:
5   - University of LYON              http://www.universite-lyon.fr/
6   - Léon Bérard cancer center       http://www.centreleonberard.fr
7   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
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 copyright notices for more information.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
18
19 // clitk includes
20 #include "clitkIO.h"
21 #include "clitkDicom2Image_ggo.h"
22 #include "clitkCommon.h"
23 #include "clitkImageCommon.h"
24 #include "vvImageReader.h"
25 #include "vvImageWriter.h"
26 #include <gdcmFile.h>
27 #include <vtkVersion.h>
28 #include <vtkImageChangeInformation.h>
29 #if GDCM_MAJOR_VERSION >= 2
30   #include <gdcmImageHelper.h>
31   #include <gdcmAttribute.h>
32   #include <gdcmReader.h>
33 #endif
34
35 #include <set>
36
37 //====================================================================
38 int main(int argc, char * argv[])
39 {
40   // init command line
41   GGO(clitkDicom2Image, args_info);
42   CLITK_INIT;
43
44   std::vector<std::string> input_files;
45   ///if std_input is given, read the input files from stdin
46   if (args_info.std_input_given) {
47     while (true) {
48       std::string tmp;
49       std::cin >> tmp;
50       if(std::cin.good())
51         input_files.push_back(tmp);
52       else break;
53     }
54     args_info.inputs_num=input_files.size();
55   } else for (unsigned int i=0; i<args_info.inputs_num; i++)
56       input_files.push_back(args_info.inputs[i]);
57
58
59   //===========================================
60   /// Get slices locations ...
61   std::string series_UID = "";
62   std::set<std::string> series_UIDs;
63   std::map< std::string, std::vector<double> > theorigin;
64   std::map< std::string, std::vector<double> > theorientation;
65   std::map< std::string, std::vector<double> > sliceLocations;
66   std::map< std::string, std::vector<std::string> > seriesFiles;
67 #if GDCM_MAJOR_VERSION >= 2
68   if (args_info.verbose_flag)
69     std::cout << "Using GDCM-2.x" << std::endl;
70 #else
71   if (args_info.verbose_flag) {
72     std::cout << "Not using GDCM-2.x" << std::endl;
73     std::cout<< "The image orientation is not supported with this version of GDCM" <<std::endl;
74   }
75 #endif
76   for(unsigned int i=0; i<args_info.inputs_num; i++) {
77     if (args_info.verbose_flag)
78         std::cout << "Reading <" << input_files[i] << std::endl;
79 #if GDCM_MAJOR_VERSION >= 2
80     gdcm::Reader hreader;
81     hreader.SetFileName(input_files[i].c_str());
82     hreader.Read();
83     gdcm::DataSet& ds = hreader.GetFile().GetDataSet();
84
85     if (args_info.extract_series_flag) {
86       gdcm::Attribute<0x20,0x000e> series_UID_att;
87       series_UID_att.SetFromDataSet(ds);
88       series_UID = series_UID_att.GetValue();
89     }
90
91     series_UIDs.insert(series_UID);
92     theorigin[series_UID] = gdcm::ImageHelper::GetOriginValue(hreader.GetFile());
93     theorientation[series_UID] = gdcm::ImageHelper::GetDirectionCosinesValue(hreader.GetFile());
94     if (args_info.patientSystem_flag) {
95       double n1 = theorientation[series_UID][1]*theorientation[series_UID][5]-
96                   theorientation[series_UID][2]*theorientation[series_UID][4];
97       double n2 = theorientation[series_UID][3]*theorientation[series_UID][2]-
98                   theorientation[series_UID][5]*theorientation[series_UID][0];
99       double n3 = theorientation[series_UID][0]*theorientation[series_UID][4]-
100                   theorientation[series_UID][1]*theorientation[series_UID][3];
101       double sloc = theorigin[series_UID][0]*n1+
102                     theorigin[series_UID][1]*n2+
103                     theorigin[series_UID][2]*n3;
104       sliceLocations[series_UID].push_back(sloc);
105     } else
106       sliceLocations[series_UID].push_back(theorigin[series_UID][2]);
107     seriesFiles[series_UID].push_back(input_files[i]);
108
109     gdcm::Attribute<0x28, 0x100> pixel_size;
110     pixel_size.SetFromDataSet(ds);
111     /* if (pixel_size.GetValue() != 16)
112        {
113        std::cerr << "Pixel type not 2 bytes ! " << std::endl;
114        std::cerr << "In file " << input_files[i] << std::endl;
115        exit(0);
116        }
117     */
118 #else
119   gdcm::File *header = new gdcm::File();
120   header->SetFileName(input_files[i]);
121   header->SetMaxSizeLoadEntry(16384); // required ?
122   header->Load();
123
124   if (args_info.extract_series_flag) {
125     series_UID = header->GetEntryValue(0x20,0x000e).c_str();
126   }
127
128   series_UIDs.insert(series_UID);
129   theorigin[series_UID].resize(3);
130   theorigin[series_UID][0] = header->GetXOrigin();
131   theorigin[series_UID][1] = header->GetYOrigin();
132   theorigin[series_UID][2] = header->GetZOrigin();
133   sliceLocations[series_UID].push_back(theorigin[series_UID][2]);
134   seriesFiles[series_UID].push_back(input_files[i]);
135   /*if (header->GetPixelSize() != 2) {
136     std::cerr << "Pixel type 2 bytes ! " << std::endl;
137     std::cerr << "In file " << input_files[i] << std::endl;
138     exit(0);
139   }
140   */
141 #endif
142   }
143
144   //===========================================
145   // Sort slices locations ...
146   std::set<std::string>::iterator sn = series_UIDs.begin();
147   while ( sn != series_UIDs.end() ) {
148     std::vector<double> locs = sliceLocations[*sn];
149     std::vector<double> origin = theorigin[*sn];
150     std::vector<std::string> files = seriesFiles[*sn];
151     std::vector<int> sliceIndex;
152     clitk::GetSortedIndex(locs, sliceIndex);
153     if (args_info.verbose_flag) {
154       std::cout << locs[sliceIndex[0]] << " -> "
155                 << sliceIndex[0] << " / " << 0 << " => "
156                 << "0 mm "
157                 << files[sliceIndex[0]]
158                 << std::endl;
159       for(unsigned int i=1; i<sliceIndex.size(); i++) {
160         std::cout << locs[sliceIndex[i]] << " -> "
161                   << sliceIndex[i] << " / " << i << " => "
162                   << locs[sliceIndex[i]] - locs[sliceIndex[i-1]]
163                   << "mm "
164                   << files[sliceIndex[i]]
165                   << std::endl;
166       }
167     }
168
169     //===========================================
170     // Analyze slices locations ...
171     double currentDist;
172     double dist=0;
173     double tolerance = args_info.tolerance_arg;
174     double previous = locs[sliceIndex[0]];
175     for(unsigned int i=1; i<sliceIndex.size(); i++) {
176       currentDist = locs[sliceIndex[i]]-previous;
177       if (i!=1) {
178         if (fabs(dist-currentDist) > tolerance) {
179           std::cout << "ERROR : " << std::endl
180                     << "Current slice pos is  = " << locs[sliceIndex[i]] << std::endl
181                     << "Previous slice pos is = " << previous << std::endl
182                     << "Current file is       = " << files[sliceIndex[i]] << std::endl
183                     << "Current index is      = " << i << std::endl
184                     << "Current sortindex is  = " << sliceIndex[i] << std::endl
185                     << "Current slice diff    = " << dist << std::endl
186                     << "Current error         = " << fabs(dist-currentDist) << std::endl;
187           exit(1);
188         }
189       } else dist = currentDist;
190       previous = locs[sliceIndex[i]];
191     }
192
193     //===========================================
194     // Create ordered vector of filenames
195     std::vector<std::string> sorted_files;
196     sorted_files.resize(sliceIndex.size());
197     for(unsigned int i=0; i<sliceIndex.size(); i++)
198       sorted_files[i] = files[ sliceIndex[i] ];
199
200     //===========================================
201     // Read write serie
202     vvImageReader::Pointer reader = vvImageReader::New();
203     reader->SetInputFilenames(sorted_files);
204     reader->SetPatientCoordinateSystem(args_info.patientSystem_flag);
205     reader->Update(vvImageReader::DICOM);
206     if (reader->GetLastError().size() != 0) {
207       std::cerr << reader->GetLastError() << std::endl;
208       return 1;
209     }
210
211     vvImage::Pointer image = reader->GetOutput();
212     vtkImageData* vtk_image = image->GetFirstVTKImageData();
213     vtkImageChangeInformation* modifier = vtkImageChangeInformation::New();
214     if  (args_info.focal_origin_given) {
215       std::vector<double> spacing = image->GetSpacing();
216       std::vector<int> size = image->GetSize();
217       origin[0] = -spacing[0]*size[0]/2.0;
218       origin[1] = -spacing[1]*size[1]/2.0;
219 #if VTK_MAJOR_VERSION <= 5
220       modifier->SetInput(vtk_image);
221 #else
222       modifier->SetInputData(vtk_image);
223 #endif
224       modifier->SetOutputOrigin(origin[0], origin[1], locs[sliceIndex[0]]);
225       modifier->Update();
226       vvImage::Pointer focal_image = vvImage::New();
227       focal_image->AddVtkImage(modifier->GetOutput());
228       image = focal_image;
229     }
230
231     std::string outfile;
232     if (series_UIDs.size() == 1)
233       outfile = args_info.output_arg;
234     else {
235       std::ostringstream name;
236       std::vector<std::string> directory = clitk::SplitFilename(args_info.output_arg);
237       if (directory.size() == 2)
238         name << directory[0] << "/" << *sn << "_" << directory[1];
239       else
240         name << *sn << "_" << args_info.output_arg;
241       outfile = name.str();
242     }
243     vvImageWriter::Pointer writer = vvImageWriter::New();
244     writer->SetInput(image);
245     if (args_info.patientSystem_flag && !image->GetTransform().empty())
246       writer->SetSaveTransform(true);
247     writer->SetOutputFileName(outfile);
248     writer->Update();
249
250     modifier->Delete();
251
252     sn++;
253   }
254
255   return 0;
256 }