]> Creatis software - clitk.git/blobdiff - tools/clitkDicom2Image.cxx
Add instanceNumber sorting for clitkDicom2Image
[clitk.git] / tools / clitkDicom2Image.cxx
index a6323da9de5ba6ad89c75ab8372049ef569b3200..e705f85ca7e68fb6dd2a733cb67a3ea252f73d23 100644 (file)
 ===========================================================================**/
 
 // clitk includes
+#include "clitkIO.h"
 #include "clitkDicom2Image_ggo.h"
 #include "clitkCommon.h"
 #include "clitkImageCommon.h"
 #include "vvImageReader.h"
 #include "vvImageWriter.h"
+#include <itkGDCMImageIO.h>
+#include <itkGDCMSeriesFileNames.h>
 #include <gdcmFile.h>
 #include <vtkVersion.h>
 #include <vtkImageChangeInformation.h>
-#if GDCM_MAJOR_VERSION == 2
+#if GDCM_MAJOR_VERSION >= 2
   #include <gdcmImageHelper.h>
   #include <gdcmAttribute.h>
   #include <gdcmReader.h>
@@ -38,6 +41,8 @@ int main(int argc, char * argv[])
 {
   // init command line
   GGO(clitkDicom2Image, args_info);
+  CLITK_INIT;
+
   std::vector<std::string> input_files;
   ///if std_input is given, read the input files from stdin
   if (args_info.std_input_given) {
@@ -52,35 +57,69 @@ int main(int argc, char * argv[])
   } else for (unsigned int i=0; i<args_info.inputs_num; i++)
       input_files.push_back(args_info.inputs[i]);
 
+  //Get GDCMSeriesFileNames order to sort filenames
+  typedef itk::GDCMSeriesFileNames NamesGeneratorType;
+  NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
+  nameGenerator->SetUseSeriesDetails(false);
+  std::string folderName=".";
+  const size_t last_slash_idx = input_files[0].rfind('/');
+  if (std::string::npos != last_slash_idx)
+    folderName = input_files[0].substr(0, last_slash_idx);
+  nameGenerator->SetInputDirectory(folderName);
 
   //===========================================
   /// Get slices locations ...
-  int series_number = -1;
-  std::set<int> series_numbers;
-  std::map< int, std::vector<double> > theorigin;
-  std::map< int, std::vector<double> > sliceLocations;
-  std::map< int, std::vector<std::string> > seriesFiles;
+  std::string series_UID = "";
+  std::set<std::string> series_UIDs;
+  std::map< std::string, std::vector<double> > theorigin;
+  std::map< std::string, std::vector<double> > theorientation;
+  std::map< std::string, std::vector<double> > sliceLocations;
+  std::map< std::string, std::vector<double> > instanceNumber;
+  std::map< std::string, std::vector<std::string> > seriesFiles;
+#if GDCM_MAJOR_VERSION >= 2
+  if (args_info.verbose_flag)
+    std::cout << "Using GDCM-2.x" << std::endl;
+#else
+  if (args_info.verbose_flag) {
+    std::cout << "Not using GDCM-2.x" << std::endl;
+    std::cout<< "The image orientation is not supported with this version of GDCM" <<std::endl;
+  }
+#endif
   for(unsigned int i=0; i<args_info.inputs_num; i++) {
-    //std::cout << "Reading <" << input_files[i] << std::endl;
-#if GDCM_MAJOR_VERSION == 2
     if (args_info.verbose_flag)
-      std::cout << "Using GDCM-2.x" << std::endl;
+        std::cout << "Reading <" << input_files[i] << std::endl;
+#if GDCM_MAJOR_VERSION >= 2
     gdcm::Reader hreader;
     hreader.SetFileName(input_files[i].c_str());
     hreader.Read();
     gdcm::DataSet& ds = hreader.GetFile().GetDataSet();
 
-    if (args_info.extract_series_flag) {
-      gdcm::Attribute<0x20,0x11> series_number_att;
-      series_number_att.SetFromDataSet(hreader.GetFile().GetDataSet());
-      series_number = series_number_att.GetValue();
-    }
-    
-    series_numbers.insert(series_number);
-    theorigin[series_number] = gdcm::ImageHelper::GetOriginValue(hreader.GetFile());
-    sliceLocations[series_number].push_back(theorigin[series_number][2]);
-    seriesFiles[series_number].push_back(input_files[i]);
-    
+    gdcm::Attribute<0x20,0x000e> series_UID_att;
+    series_UID_att.SetFromDataSet(ds);
+    series_UID = series_UID_att.GetValue().c_str();
+
+    series_UIDs.insert(series_UID);
+    theorigin[series_UID] = gdcm::ImageHelper::GetOriginValue(hreader.GetFile());
+    theorientation[series_UID] = gdcm::ImageHelper::GetDirectionCosinesValue(hreader.GetFile());
+    if (args_info.patientSystem_flag) {
+      double n1 = theorientation[series_UID][1]*theorientation[series_UID][5]-
+                  theorientation[series_UID][2]*theorientation[series_UID][4];
+      double n2 = theorientation[series_UID][3]*theorientation[series_UID][2]-
+                  theorientation[series_UID][5]*theorientation[series_UID][0];
+      double n3 = theorientation[series_UID][0]*theorientation[series_UID][4]-
+                  theorientation[series_UID][1]*theorientation[series_UID][3];
+      double sloc = theorigin[series_UID][0]*n1+
+                    theorigin[series_UID][1]*n2+
+                    theorigin[series_UID][2]*n3;
+      sliceLocations[series_UID].push_back(sloc);
+    } else
+      sliceLocations[series_UID].push_back(theorigin[series_UID][2]);
+    seriesFiles[series_UID].push_back(input_files[i]);
+
+    gdcm::Attribute<0x20,0x0013> instanceNumber_att;
+    instanceNumber_att.SetFromDataSet(ds);
+    instanceNumber[series_UID].push_back(instanceNumber_att.GetValue());
+
     gdcm::Attribute<0x28, 0x100> pixel_size;
     pixel_size.SetFromDataSet(ds);
     /* if (pixel_size.GetValue() != 16)
@@ -91,24 +130,20 @@ int main(int argc, char * argv[])
        }
     */
 #else
-    if (args_info.verbose_flag)
-      std::cout << "Not using GDCM-2.x" << std::endl;
   gdcm::File *header = new gdcm::File();
   header->SetFileName(input_files[i]);
   header->SetMaxSizeLoadEntry(16384); // required ?
   header->Load();
 
-  if (args_info.extract_series_flag) {
-    series_number = atoi(header->GetEntryValue(0x20,0x11).c_str());
-  }
-  
-  series_numbers.insert(series_number);
-  theorigin[series_number].resize(3);
-  theorigin[series_number][0] = header->GetXOrigin();
-  theorigin[series_number][1] = header->GetYOrigin();
-  theorigin[series_number][2] = header->GetZOrigin();
-  sliceLocations[series_number].push_back(theorigin[series_number][2]);
-  seriesFiles[series_number].push_back(input_files[i]);
+  series_UID = header->GetEntryValue(0x20,0x000e).c_str();
+
+  series_UIDs.insert(series_UID);
+  theorigin[series_UID].resize(3);
+  theorigin[series_UID][0] = header->GetXOrigin();
+  theorigin[series_UID][1] = header->GetYOrigin();
+  theorigin[series_UID][2] = header->GetZOrigin();
+  sliceLocations[series_UID].push_back(theorigin[series_UID][2]);
+  seriesFiles[series_UID].push_back(input_files[i]);
   /*if (header->GetPixelSize() != 2) {
     std::cerr << "Pixel type 2 bytes ! " << std::endl;
     std::cerr << "In file " << input_files[i] << std::endl;
@@ -120,14 +155,37 @@ int main(int argc, char * argv[])
 
   //===========================================
   // Sort slices locations ...
-  std::set<int>::iterator sn = series_numbers.begin();
-  while ( sn != series_numbers.end() ) {
+  std::set<std::string>::iterator sn = series_UIDs.begin();
+  while ( sn != series_UIDs.end() ) {
     std::vector<double> locs = sliceLocations[*sn];
     std::vector<double> origin = theorigin[*sn];
+    std::vector<double> instanceNumberSerie = instanceNumber[*sn];
     std::vector<std::string> files = seriesFiles[*sn];
-    std::vector<int> sliceIndex;
-    clitk::GetSortedIndex(locs, sliceIndex);
-    if (args_info.verboseSliceLocation_flag) {
+    std::vector<int> sliceIndex(files.size());
+    //clitk::GetSortedIndex(locs, sliceIndex);
+    //Look for files into GDCMSeriesFileNames, because it sorts files correctly and take the order
+    const std::vector<std::string> & temp = nameGenerator->GetFileNames(*sn);
+    for(unsigned int i=0; i<files.size(); i++) {
+      int j(0);
+      bool found(false);
+      while (!found && j<temp.size()) {
+        const size_t last_slash_idx2 = temp[j].rfind('/');
+        std::string tempFilename(temp[j]);
+        if (temp[j][0] == '.' && temp[j][1] == '/')
+          tempFilename = temp[j].substr(2, temp[j].size()-1);
+        if (tempFilename == files[i]) {
+          sliceIndex[j] = i;
+          found = true;
+        }
+        ++j;
+      }
+    }
+    if (sliceIndex.size() == 0) { //ie. sn is not a serie present in files
+      sn++;
+      continue;
+    }
+
+    if (args_info.verbose_flag) {
       std::cout << locs[sliceIndex[0]] << " -> "
                 << sliceIndex[0] << " / " << 0 << " => "
                 << "0 mm "
@@ -171,19 +229,34 @@ int main(int argc, char * argv[])
     // Create ordered vector of filenames
     std::vector<std::string> sorted_files;
     sorted_files.resize(sliceIndex.size());
-    for(unsigned int i=0; i<sliceIndex.size(); i++)
-      sorted_files[i] = files[ sliceIndex[i] ];
+    if (!args_info.instanceNumber_flag) {
+      for(unsigned int i=0; i<sliceIndex.size(); i++)
+        sorted_files[i] = files[ sliceIndex[i] ];
+    } else {
+      std::vector<double>::iterator maxInstanceNumber = std::max_element(instanceNumberSerie.begin(), instanceNumberSerie.end());
+      std::vector<std::string> instanceNumberTemp(*maxInstanceNumber, "");
+      for(unsigned int i=0; i<instanceNumberSerie.size(); i++)
+        instanceNumberTemp[instanceNumberSerie[i]-1] = files[i];
+      unsigned int fillFiles(0);
+      for(unsigned int i=0; i<instanceNumberTemp.size(); i++) {
+          if (instanceNumberTemp[i] != "") {
+            sorted_files[fillFiles] = instanceNumberTemp[i];
+            ++fillFiles;
+          }
+       }
+    }
 
     //===========================================
     // Read write serie
     vvImageReader::Pointer reader = vvImageReader::New();
     reader->SetInputFilenames(sorted_files);
+    reader->SetPatientCoordinateSystem(args_info.patientSystem_flag);
     reader->Update(vvImageReader::DICOM);
     if (reader->GetLastError().size() != 0) {
       std::cerr << reader->GetLastError() << std::endl;
       return 1;
     }
-    
+
     vvImage::Pointer image = reader->GetOutput();
     vtkImageData* vtk_image = image->GetFirstVTKImageData();
     vtkImageChangeInformation* modifier = vtkImageChangeInformation::New();
@@ -205,22 +278,28 @@ int main(int argc, char * argv[])
     }
 
     std::string outfile;
-    if (series_numbers.size() == 1)
+    if (series_UIDs.size() == 1)
       outfile = args_info.output_arg;
     else {
       std::ostringstream name;
-      name << *sn << "_" << args_info.output_arg;
+      std::vector<std::string> directory = clitk::SplitFilename(args_info.output_arg);
+      if (directory.size() == 2)
+        name << directory[0] << "/" << *sn << "_" << directory[1];
+      else
+        name << *sn << "_" << args_info.output_arg;
       outfile = name.str();
     }
     vvImageWriter::Pointer writer = vvImageWriter::New();
     writer->SetInput(image);
+    if (args_info.patientSystem_flag && !image->GetTransform().empty())
+      writer->SetSaveTransform(true);
     writer->SetOutputFileName(outfile);
     writer->Update();
 
     modifier->Delete();
-    
+
     sn++;
   }
-  
+
   return 0;
 }