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"
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>
37 //====================================================================
38 int main(int argc, char * argv[])
41 GGO(clitkDicom2Image, args_info);
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) {
51 input_files.push_back(tmp);
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]);
59 //===========================================
60 /// Get slices locations ...
61 int series_number = -1;
62 std::set<int> series_numbers;
63 std::map< int, std::vector<double> > theorigin;
64 std::map< int, std::vector<double> > theorientation;
65 std::map< int, std::vector<double> > sliceLocations;
66 std::map< int, 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;
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;
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
81 hreader.SetFileName(input_files[i].c_str());
83 gdcm::DataSet& ds = hreader.GetFile().GetDataSet();
85 if (args_info.extract_series_flag) {
86 gdcm::Attribute<0x20,0x11> series_number_att;
87 series_number_att.SetFromDataSet(ds);
88 series_number = series_number_att.GetValue();
91 series_numbers.insert(series_number);
92 theorigin[series_number] = gdcm::ImageHelper::GetOriginValue(hreader.GetFile());
93 theorientation[series_number] = gdcm::ImageHelper::GetDirectionCosinesValue(hreader.GetFile());
94 double n1 = theorientation[series_number][1]*theorientation[series_number][5]-
95 theorientation[series_number][2]*theorientation[series_number][4];
96 double n2 = theorientation[series_number][3]*theorientation[series_number][2]-
97 theorientation[series_number][5]*theorientation[series_number][0];
98 double n3 = theorientation[series_number][0]*theorientation[series_number][4]-
99 theorientation[series_number][1]*theorientation[series_number][3];
100 double sloc = theorigin[series_number][0]*n1+
101 theorigin[series_number][1]*n2+
102 theorigin[series_number][2]*n3;
103 sliceLocations[series_number].push_back(sloc);
104 seriesFiles[series_number].push_back(input_files[i]);
106 gdcm::Attribute<0x28, 0x100> pixel_size;
107 pixel_size.SetFromDataSet(ds);
108 /* if (pixel_size.GetValue() != 16)
110 std::cerr << "Pixel type not 2 bytes ! " << std::endl;
111 std::cerr << "In file " << input_files[i] << std::endl;
116 gdcm::File *header = new gdcm::File();
117 header->SetFileName(input_files[i]);
118 header->SetMaxSizeLoadEntry(16384); // required ?
121 if (args_info.extract_series_flag) {
122 series_number = atoi(header->GetEntryValue(0x20,0x11).c_str());
125 series_numbers.insert(series_number);
126 theorigin[series_number].resize(3);
127 theorigin[series_number][0] = header->GetXOrigin();
128 theorigin[series_number][1] = header->GetYOrigin();
129 theorigin[series_number][2] = header->GetZOrigin();
130 sliceLocations[series_number].push_back(theorigin[series_number][2]);
131 seriesFiles[series_number].push_back(input_files[i]);
132 /*if (header->GetPixelSize() != 2) {
133 std::cerr << "Pixel type 2 bytes ! " << std::endl;
134 std::cerr << "In file " << input_files[i] << std::endl;
141 //===========================================
142 // Sort slices locations ...
143 std::set<int>::iterator sn = series_numbers.begin();
144 while ( sn != series_numbers.end() ) {
145 std::vector<double> locs = sliceLocations[*sn];
146 std::vector<double> origin = theorigin[*sn];
147 std::vector<std::string> files = seriesFiles[*sn];
148 std::vector<int> sliceIndex;
149 clitk::GetSortedIndex(locs, sliceIndex);
150 if (args_info.verbose_flag) {
151 std::cout << locs[sliceIndex[0]] << " -> "
152 << sliceIndex[0] << " / " << 0 << " => "
154 << files[sliceIndex[0]]
156 for(unsigned int i=1; i<sliceIndex.size(); i++) {
157 std::cout << locs[sliceIndex[i]] << " -> "
158 << sliceIndex[i] << " / " << i << " => "
159 << locs[sliceIndex[i]] - locs[sliceIndex[i-1]]
161 << files[sliceIndex[i]]
166 //===========================================
167 // Analyze slices locations ...
170 double tolerance = args_info.tolerance_arg;
171 double previous = locs[sliceIndex[0]];
172 for(unsigned int i=1; i<sliceIndex.size(); i++) {
173 currentDist = locs[sliceIndex[i]]-previous;
175 if (fabs(dist-currentDist) > tolerance) {
176 std::cout << "ERROR : " << std::endl
177 << "Current slice pos is = " << locs[sliceIndex[i]] << std::endl
178 << "Previous slice pos is = " << previous << std::endl
179 << "Current file is = " << files[sliceIndex[i]] << std::endl
180 << "Current index is = " << i << std::endl
181 << "Current sortindex is = " << sliceIndex[i] << std::endl
182 << "Current slice diff = " << dist << std::endl
183 << "Current error = " << fabs(dist-currentDist) << std::endl;
186 } else dist = currentDist;
187 previous = locs[sliceIndex[i]];
190 //===========================================
191 // Create ordered vector of filenames
192 std::vector<std::string> sorted_files;
193 sorted_files.resize(sliceIndex.size());
194 for(unsigned int i=0; i<sliceIndex.size(); i++)
195 sorted_files[i] = files[ sliceIndex[i] ];
197 //===========================================
199 vvImageReader::Pointer reader = vvImageReader::New();
200 reader->SetInputFilenames(sorted_files);
201 reader->Update(vvImageReader::DICOM);
202 if (reader->GetLastError().size() != 0) {
203 std::cerr << reader->GetLastError() << std::endl;
207 vvImage::Pointer image = reader->GetOutput();
208 vtkImageData* vtk_image = image->GetFirstVTKImageData();
209 vtkImageChangeInformation* modifier = vtkImageChangeInformation::New();
210 if (args_info.focal_origin_given) {
211 std::vector<double> spacing = image->GetSpacing();
212 std::vector<int> size = image->GetSize();
213 origin[0] = -spacing[0]*size[0]/2.0;
214 origin[1] = -spacing[1]*size[1]/2.0;
215 #if VTK_MAJOR_VERSION <= 5
216 modifier->SetInput(vtk_image);
218 modifier->SetInputData(vtk_image);
220 modifier->SetOutputOrigin(origin[0], origin[1], locs[sliceIndex[0]]);
222 vvImage::Pointer focal_image = vvImage::New();
223 focal_image->AddVtkImage(modifier->GetOutput());
228 if (series_numbers.size() == 1)
229 outfile = args_info.output_arg;
231 std::ostringstream name;
232 std::vector<std::string> directory = clitk::SplitFilename(args_info.output_arg);
233 if (directory.size() == 2)
234 name << directory[0] << "/" << *sn << "_" << directory[1];
236 name << *sn << "_" << args_info.output_arg;
237 outfile = name.str();
241 if (!image->GetTransform().empty()) {
242 for(unsigned int i=0; i<4; i++) {
243 for(unsigned int j=0; j<4; j++) {
244 double elt = image->GetTransform()[0]->GetMatrix()->GetElement(i,j);
245 if(i==j && elt!=1.) {
248 if(i!=j && elt!=0.) {
254 vvImageWriter::Pointer writer = vvImageWriter::New();
255 writer->SetInput(image);
257 writer->SetSaveTransform(true);
259 writer->SetOutputFileName(outfile);