1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
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
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.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
21 #include "clitkDicom2Image_ggo.h"
22 #include "clitkCommon.h"
23 #include "clitkImageCommon.h"
24 #include "vvImageReader.h"
25 #include "vvImageWriter.h"
26 #include <itkGDCMImageIO.h>
27 #include <itkGDCMSeriesFileNames.h>
29 #include <vtkVersion.h>
30 #include <vtkImageChangeInformation.h>
31 #if GDCM_MAJOR_VERSION >= 2
32 #include <gdcmImageHelper.h>
33 #include <gdcmAttribute.h>
34 #include <gdcmReader.h>
39 //====================================================================
40 int main(int argc, char * argv[])
43 GGO(clitkDicom2Image, args_info);
46 std::vector<std::string> input_files;
47 ///if std_input is given, read the input files from stdin
48 if (args_info.std_input_given) {
53 input_files.push_back(tmp);
56 args_info.inputs_num=input_files.size();
57 } else for (unsigned int i=0; i<args_info.inputs_num; i++)
58 input_files.push_back(args_info.inputs[i]);
60 //Get GDCMSeriesFileNames order to sort filenames
61 typedef itk::GDCMSeriesFileNames NamesGeneratorType;
62 NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
63 nameGenerator->SetUseSeriesDetails(false);
64 std::string folderName=".";
66 const size_t last_slash_idx = input_files[0].rfind('\\');
68 const size_t last_slash_idx = input_files[0].rfind('/');
70 if (std::string::npos != last_slash_idx)
71 folderName = input_files[0].substr(0, last_slash_idx);
72 nameGenerator->SetInputDirectory(folderName);
74 //===========================================
75 /// Get slices locations ...
76 std::string series_UID = "";
77 std::set<std::string> series_UIDs;
78 std::map< std::string, std::vector<double> > theorigin;
79 std::map< std::string, std::vector<double> > theorientation;
80 std::map< std::string, std::vector<double> > sliceLocations;
81 std::map< std::string, std::vector<double> > instanceNumber;
82 std::map< std::string, std::vector<std::string> > seriesFiles;
83 #if GDCM_MAJOR_VERSION >= 2
84 if (args_info.verbose_flag)
85 std::cout << "Using GDCM-2.x" << std::endl;
87 if (args_info.verbose_flag) {
88 std::cout << "Not using GDCM-2.x" << std::endl;
89 std::cout<< "The image orientation is not supported with this version of GDCM" <<std::endl;
92 for(unsigned int i=0; i<args_info.inputs_num; i++) {
93 if (args_info.verbose_flag)
94 std::cout << "Reading < " << input_files[i] << std::endl;
95 #if GDCM_MAJOR_VERSION >= 2
97 hreader.SetFileName(input_files[i].c_str());
99 gdcm::DataSet& ds = hreader.GetFile().GetDataSet();
101 gdcm::Attribute<0x20,0x000e> series_UID_att;
102 series_UID_att.SetFromDataSet(ds);
103 series_UID = series_UID_att.GetValue().c_str();
105 series_UIDs.insert(series_UID);
106 theorigin[series_UID] = gdcm::ImageHelper::GetOriginValue(hreader.GetFile());
107 theorientation[series_UID] = gdcm::ImageHelper::GetDirectionCosinesValue(hreader.GetFile());
108 if (args_info.patientSystem_flag) {
109 double n1 = theorientation[series_UID][1]*theorientation[series_UID][5]-
110 theorientation[series_UID][2]*theorientation[series_UID][4];
111 double n2 = theorientation[series_UID][3]*theorientation[series_UID][2]-
112 theorientation[series_UID][5]*theorientation[series_UID][0];
113 double n3 = theorientation[series_UID][0]*theorientation[series_UID][4]-
114 theorientation[series_UID][1]*theorientation[series_UID][3];
115 double sloc = theorigin[series_UID][0]*n1+
116 theorigin[series_UID][1]*n2+
117 theorigin[series_UID][2]*n3;
118 sliceLocations[series_UID].push_back(sloc);
120 sliceLocations[series_UID].push_back(theorigin[series_UID][2]);
121 seriesFiles[series_UID].push_back(input_files[i]);
123 gdcm::Attribute<0x20,0x0013> instanceNumber_att;
124 instanceNumber_att.SetFromDataSet(ds);
125 instanceNumber[series_UID].push_back(instanceNumber_att.GetValue());
127 gdcm::Attribute<0x28, 0x100> pixel_size;
128 pixel_size.SetFromDataSet(ds);
129 /* if (pixel_size.GetValue() != 16)
131 std::cerr << "Pixel type not 2 bytes ! " << std::endl;
132 std::cerr << "In file " << input_files[i] << std::endl;
137 gdcm::File *header = new gdcm::File();
138 header->SetFileName(input_files[i]);
139 header->SetMaxSizeLoadEntry(16384); // required ?
142 series_UID = header->GetEntryValue(0x20,0x000e).c_str();
144 series_UIDs.insert(series_UID);
145 theorigin[series_UID].resize(3);
146 theorigin[series_UID][0] = header->GetXOrigin();
147 theorigin[series_UID][1] = header->GetYOrigin();
148 theorigin[series_UID][2] = header->GetZOrigin();
149 sliceLocations[series_UID].push_back(theorigin[series_UID][2]);
150 seriesFiles[series_UID].push_back(input_files[i]);
151 /*if (header->GetPixelSize() != 2) {
152 std::cerr << "Pixel type 2 bytes ! " << std::endl;
153 std::cerr << "In file " << input_files[i] << std::endl;
160 //===========================================
161 // Sort slices locations ...
162 std::set<std::string>::iterator sn = series_UIDs.begin();
163 while ( sn != series_UIDs.end() ) {
164 std::vector<double> locs = sliceLocations[*sn];
165 std::vector<double> origin = theorigin[*sn];
166 std::vector<double> instanceNumberSerie = instanceNumber[*sn];
167 std::vector<std::string> files = seriesFiles[*sn];
168 //Let's process the filenames -- it is mandatory for the line "if (tempFilename == files[i])"
169 for(unsigned int i=0; i<files.size(); i++) {
171 const size_t first_slash_idx_fn = files[i].find('\\');
173 const size_t first_slash_idx_fn = files[i].find('/');
175 if (std::string::npos != first_slash_idx_fn && first_slash_idx_fn == 1 && files[i][0] == '.')
176 files[i] = files[i].substr(first_slash_idx_fn+1);
178 std::vector<int> sliceIndex(files.size());
179 //clitk::GetSortedIndex(locs, sliceIndex);
180 //Look for files into GDCMSeriesFileNames, because it sorts files correctly and take the order
181 const std::vector<std::string> & temp = nameGenerator->GetFileNames(*sn);
182 for(unsigned int i=0; i<files.size(); i++) {
185 while (!found && j<temp.size()) {
186 std::string tempFilename(temp[j]);
188 // There is a bug on Windows, the last \ is a /...
189 // Let's substitute it
190 const size_t last_slash_idx_win = tempFilename.rfind('/');
191 tempFilename[last_slash_idx_win] = '\\';
192 const size_t first_slash_idx = tempFilename.find('\\');
194 const size_t first_slash_idx = tempFilename.find('/');
196 if (std::string::npos != first_slash_idx && first_slash_idx == 1 && tempFilename[0] == '.')
197 tempFilename = tempFilename.substr(first_slash_idx+1);
198 if (tempFilename == files[i]) {
205 if (sliceIndex.size() == 0) { //ie. sn is not a serie present in files
210 if (args_info.verbose_flag) {
211 std::cout << locs[sliceIndex[0]] << " -> "
212 << sliceIndex[0] << " / " << 0 << " => "
214 << files[sliceIndex[0]]
216 for(unsigned int i=1; i<sliceIndex.size(); i++) {
217 std::cout << locs[sliceIndex[i]] << " -> "
218 << sliceIndex[i] << " / " << i << " => "
219 << locs[sliceIndex[i]] - locs[sliceIndex[i-1]]
221 << files[sliceIndex[i]]
226 //===========================================
227 // Analyze slices locations ...
230 double tolerance = args_info.tolerance_arg;
231 double previous = locs[sliceIndex[0]];
232 for(unsigned int i=1; i<sliceIndex.size(); i++) {
233 currentDist = locs[sliceIndex[i]]-previous;
235 if (fabs(dist-currentDist) > tolerance) {
236 std::cout << "ERROR : " << std::endl
237 << "Current slice pos is = " << locs[sliceIndex[i]] << std::endl
238 << "Previous slice pos is = " << previous << std::endl
239 << "Current file is = " << files[sliceIndex[i]] << std::endl
240 << "Current index is = " << i << std::endl
241 << "Current sortindex is = " << sliceIndex[i] << std::endl
242 << "Current slice diff = " << dist << std::endl
243 << "Current error = " << fabs(dist-currentDist) << std::endl;
246 } else dist = currentDist;
247 previous = locs[sliceIndex[i]];
250 //===========================================
251 // Create ordered vector of filenames
252 std::vector<std::string> sorted_files;
253 sorted_files.resize(sliceIndex.size());
254 if (!args_info.instanceNumber_flag) {
255 for(unsigned int i=0; i<sliceIndex.size(); i++)
256 sorted_files[i] = files[ sliceIndex[i] ];
258 std::vector<double>::iterator maxInstanceNumber = std::max_element(instanceNumberSerie.begin(), instanceNumberSerie.end());
259 std::vector<std::string> instanceNumberTemp(*maxInstanceNumber, "");
260 for(unsigned int i=0; i<instanceNumberSerie.size(); i++)
261 instanceNumberTemp[instanceNumberSerie[i]-1] = files[i];
262 unsigned int fillFiles(0);
263 for(unsigned int i=0; i<instanceNumberTemp.size(); i++) {
264 if (instanceNumberTemp[i] != "") {
265 sorted_files[fillFiles] = instanceNumberTemp[i];
271 //===========================================
272 // Reverse the slice order (for MR from HEH)
273 if (args_info.reverse_flag)
274 std::reverse(sorted_files.begin(), sorted_files.end());
276 //===========================================
278 vvImageReader::Pointer reader = vvImageReader::New();
279 reader->SetInputFilenames(sorted_files);
280 reader->SetPatientCoordinateSystem(args_info.patientSystem_flag);
281 reader->Update(vvImageReader::DICOM);
282 if (reader->GetLastError().size() != 0) {
283 std::cerr << reader->GetLastError() << std::endl;
287 vvImage::Pointer image = reader->GetOutput();
288 vtkImageData* vtk_image = image->GetFirstVTKImageData();
289 vtkImageChangeInformation* modifier = vtkImageChangeInformation::New();
290 if (args_info.focal_origin_given) {
291 std::vector<double> spacing = image->GetSpacing();
292 std::vector<int> size = image->GetSize();
293 origin[0] = -spacing[0]*size[0]/2.0;
294 origin[1] = -spacing[1]*size[1]/2.0;
295 #if VTK_MAJOR_VERSION <= 5
296 modifier->SetInput(vtk_image);
298 modifier->SetInputData(vtk_image);
300 modifier->SetOutputOrigin(origin[0], origin[1], locs[sliceIndex[0]]);
302 vvImage::Pointer focal_image = vvImage::New();
303 focal_image->AddVtkImage(modifier->GetOutput(), image->GetTransform()[0]);
308 if (series_UIDs.size() == 1)
309 outfile = args_info.output_arg;
311 std::ostringstream name;
312 std::vector<std::string> directory = clitk::SplitFilename(args_info.output_arg);
313 if (directory.size() == 2)
315 name << directory[0] << "\\" << *sn << "_" << directory[1];
317 name << directory[0] << "/" << *sn << "_" << directory[1];
320 name << *sn << "_" << args_info.output_arg;
321 outfile = name.str();
323 vvImageWriter::Pointer writer = vvImageWriter::New();
324 writer->SetInput(image);
325 if (args_info.patientSystem_flag && !image->GetTransform().empty())
326 writer->SetSaveTransform(true);
327 writer->SetOutputFileName(outfile);