Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
DiffusionDICOMLoader.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include "mitkImage.h"
18 #include "mitkBaseData.h"
20 #include <mitkImageCast.h>
21 #include <mitkITKImageImport.h>
22 
23 #include <itkImageFileWriter.h>
24 #include <itkNrrdImageIO.h>
25 #include "mitkCommandLineParser.h"
26 #include <itksys/SystemTools.hxx>
27 #include <itksys/Directory.hxx>
28 
32 #include "mitkDICOMSortByTag.h"
33 
35 #include <mitkIOUtil.h>
36 
37 using namespace std;
38 
40 {
41  static mitk::StringList inputs;
42  return inputs;
43 }
44 
45 // FIXME slash at the end
46 void SetInputFileNames( std::string input_directory )
47 {
48  // I. Get all files in directory
49  itksys::Directory input;
50  input.Load( input_directory.c_str() );
51 
52  // II. Push back files
53  mitk::StringList inputlist;//, mergedlist;
54  for( unsigned long idx=0; idx<input.GetNumberOfFiles(); idx++)
55  {
56  if( ! itksys::SystemTools::FileIsDirectory( input.GetFile(idx)) )
57  {
58  std::string fullpath = input_directory + "/" + std::string( input.GetFile(idx) );
59  //inputlist.push_back( itksys::SystemTools::ConvertToOutputPath( fullpath.c_str() ) );
60  inputlist.push_back( fullpath.c_str() );
61 
62  MITK_INFO("dicom.loader.inputdir.addfile") << input.GetFile(idx);
63  }
64  }
65 
66  /*mergedlist.reserve( GetInputFilenames().size() + inputlist.size() );
67 
68  mergedlist.insert( mergedlist.end(), GetInputFilenames().begin(), GetInputFilenames().end() );
69  mergedlist.insert( mergedlist.end(), inputlist.begin(), inputlist.end() );*/
70 
71  GetInputFilenames() = inputlist;//mergedlist;
72 
73  MITK_INFO("dicom.loader.setinputfiles.end") << "[]";
74 }
75 
76 
77 mitk::Image::Pointer ReadInDICOMFiles( mitk::StringList& input_files, std::string output_file )
78 {
80  //mitk::ClassicDICOMSeriesReader::Pointer gdcmReader = mitk::ClassicDICOMSeriesReader::New();
81  /* mitk::DICOMTagBasedSorter::Pointer tagSorter = mitk::DICOMTagBasedSorter::New();
82 
83  // Use tags as in Qmitk
84  // all the things that split by tag in DicomSeriesReader
85  tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0010) ); // Number of Rows
86  tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0011) ); // Number of Columns
87  tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0030) ); // Pixel Spacing
88  tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0018, 0x1164) ); // Imager Pixel Spacing
89  tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0020, 0x0037) ); // Image Orientation (Patient) // TODO add tolerance parameter (l. 1572 of original code)
90  // TODO handle as real vectors! cluster with configurable errors!
91  tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0020, 0x000e) ); // Series Instance UID
92  tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0018, 0x0050) ); // Slice Thickness
93  tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0008) ); // Number of Frames
94  //tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0020, 0x0052) ); // Frame of Reference UID
95 
96  // gdcmReader->AddSortingElement( tagSorter );
97  //mitk::DICOMFileReaderTestHelper::TestOutputsContainInputs( gdcmReader );
98 
99  mitk::DICOMSortCriterion::ConstPointer sorting =
100  mitk::SortByImagePositionPatient::New( // Image Position (Patient)
101  //mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0020, 0x0013), // instance number
102  mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0020, 0x0012), // aqcuisition number
103  mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0008, 0x0032), // aqcuisition time
104  mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0018, 0x1060), // trigger time
105  mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0008, 0x0018) // SOP instance UID (last resort, not really meaningful but decides clearly)
106  ).GetPointer()
107  ).GetPointer()
108  ).GetPointer()
109  ).GetPointer()
110  // ).GetPointer()
111  ).GetPointer();
112  tagSorter->SetSortCriterion( sorting );
113 
114  // mosaic
115  //gdcmReader->SetResolveMosaic( this->m_Controls->m_SplitMosaicCheckBox->isChecked() );
116  gdcmReader->AddSortingElement( tagSorter );*/
117  gdcmReader->SetInputFiles( input_files );
118 
119  try
120  {
121  gdcmReader->AnalyzeInputFiles();
122  }
123  catch( const itk::ExceptionObject &e)
124  {
125  MITK_ERROR << "Failed to analyze data. " << e.what();
126  }
127  catch( const std::exception &se)
128  {
129  MITK_ERROR << "Std Exception " << se.what();
130  }
131 
132 
133  gdcmReader->LoadImages();
134 
135  mitk::Image::Pointer loaded_image = gdcmReader->GetOutput(0).GetMitkImage();
136 
137  return loaded_image;
138 }
139 
140 typedef short DiffusionPixelType;
141 typedef itk::VectorImage<DiffusionPixelType,3> DwiImageType;
143 typedef DwiImageType::RegionType DwiRegionType;
144 typedef std::vector< DwiImageType::Pointer > DwiImageContainerType;
145 
148 typedef std::vector< GradientContainerType::Pointer > GradientListContainerType;
149 
150 void SearchForInputInSubdirs( std::string root_directory, std::string subdir_prefix , std::vector<DiffusionImageType::Pointer>& output_container)
151 {
152  // I. Get all dirs in directory
153  itksys::Directory rootdir;
154  rootdir.Load( root_directory.c_str() );
155 
156  MITK_INFO("dicom.loader.setinputdirs.start") << "Prefix = " << subdir_prefix;
157 
158  for( unsigned int idx=0; idx<rootdir.GetNumberOfFiles(); idx++)
159  {
160  std::string current_path = rootdir.GetFile(idx);
161 
162  std::string directory_path = std::string(rootdir.GetPath()) + current_path;
163 
164  MITK_INFO("dicom.loader.inputrootdir.test") << "ProbePath: " << current_path << "\n"
165  << "escaped to " << itksys::SystemTools::ConvertToOutputPath( directory_path.c_str() );
166 
167  MITK_INFO("dicom.loader.inputrootdir.test") << " IsDirectory: " << itksys::SystemTools::FileIsDirectory( directory_path.c_str() )
168  << " StartsWith: " << itksys::SystemTools::StringStartsWith( current_path.c_str(), subdir_prefix.c_str() );
169 
170  // test for prefix
171  if( itksys::SystemTools::FileIsDirectory( directory_path.c_str() )
172  && itksys::SystemTools::StringStartsWith( current_path.c_str(), subdir_prefix.c_str() )
173  )
174  {
175 
176  MITK_INFO("dicom.loader.inputrootdir.searchin") << directory_path;
177  SetInputFileNames( directory_path.c_str() );
178 
179  MITK_INFO("dicom.loader.inputrootdir.preload") << "[]" ;
181 
182  output_container.push_back( dwi );
183 
184 
185  }
186  }
187 
188  MITK_INFO("dicom.loader.setinputdirs.end") << "[]";
189 }
190 
191 
192 
193 using namespace mitk;
198 int main(int argc, char* argv[])
199 {
200  mitkCommandLineParser parser;
201  parser.setArgumentPrefix("--", "-");
202 
203  parser.setTitle("Diffusion Dicom Loader");
204  parser.setCategory("Preprocessing Tools");
205  parser.setDescription("Loads Diffusion Dicom files.");
206  parser.setContributor("MBI");
207 
208  parser.addArgument("inputdir", "i", mitkCommandLineParser::InputDirectory, "Input Directory" ,"input directory containing dicom files", us::Any(), false);
209  parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output File Name", "output file", us::Any(), false);
210  parser.addArgument("dwprefix", "p", mitkCommandLineParser::String, "Recursive Scan Prefix", "prefix for subfolders search rootdir is specified by the 'inputdir' argument value", us::Any(), true);
211  parser.addArgument("dryrun", "-s", mitkCommandLineParser::Bool, "Dry run","do not read, only look for input files ", us::Any(), true );
212 
213  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
214  if (parsedArgs.size()==0)
215  {
216  return EXIT_FAILURE;
217  }
218 
219  std::string inputDirectory = us::any_cast<std::string>( parsedArgs["inputdir"] );
220  MITK_INFO << "Loading data from directory: " << inputDirectory;
221 
222  // retrieve the prefix flag (if set)
223  bool search_for_subdirs = false;
224  std::string subdir_prefix;
225  if( parsedArgs.count("dwprefix"))
226  {
227  subdir_prefix = us::any_cast<std::string>( parsedArgs["dwprefix"] );
228  if (subdir_prefix != "")
229  {
230  MITK_INFO << "Prefix specified, will search for subdirs in the input directory!";
231  search_for_subdirs = true;
232  }
233  }
234 
235  // retrieve the output
236  std::string outputFile = us::any_cast< std::string >( parsedArgs["output"] );
237 
238  // if the executable is called with a single directory, just parse the given folder for files and read them into a diffusion image
239  if( !search_for_subdirs )
240  {
241  SetInputFileNames( inputDirectory );
242 
243  MITK_INFO << "Got " << GetInputFilenames().size() << " input files.";
245 
246  try
247  {
248  mitk::IOUtil::Save(d_img, outputFile.c_str());
249  }
250  catch( const itk::ExceptionObject& e)
251  {
252  MITK_ERROR << "Failed to write out the output file. \n\t Reason : ITK Exception " << e.what();
253  }
254 
255  }
256  // if the --dwprefix flag is set, then we have to look for the directories, load each of them separately and afterwards merge the images
257  else
258  {
259  std::vector<mitk::Image::Pointer> output_container;
260 
261  SearchForInputInSubdirs( inputDirectory, subdir_prefix, output_container );
262 
263  // final output image
265  if( output_container.size() > 1 )
266  {
267  DwiImageContainerType imageContainer;
268  GradientListContainerType gradientListContainer;
269  std::vector< double > bValueContainer;
270 
271  for ( std::vector< mitk::Image::Pointer >::iterator dwi = output_container.begin();
272  dwi != output_container.end(); ++dwi )
273  {
275  mitk::CastToItkImage(*dwi, itkVectorImagePointer);
276 
277  imageContainer.push_back(itkVectorImagePointer);
278  gradientListContainer.push_back( mitk::DiffusionPropertyHelper::GetGradientContainer(*dwi));
279  bValueContainer.push_back( mitk::DiffusionPropertyHelper::GetReferenceBValue(*dwi));
280  }
281 
282  typedef itk::MergeDiffusionImagesFilter<short> FilterType;
284  filter->SetImageVolumes(imageContainer);
285  filter->SetGradientLists(gradientListContainer);
286  filter->SetBValues(bValueContainer);
287  filter->Update();
288 
289  vnl_matrix_fixed< double, 3, 3 > mf; mf.set_identity();
290 
291  image = mitk::GrabItkImageMemory( filter->GetOutput() );
292  image->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetOutputGradients() ) );
293  image->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( filter->GetB_Value() ) );
295  mitk::DiffusionPropertyHelper propertyHelper( image );
296  propertyHelper.InitializeImage();
297  }
298  // just output the image if there was only one folder found
299  else
300  {
301  image = output_container.at(0);
302  }
303 
304  MITK_INFO("dicom.import.writeout") << " [OutputFile] " << outputFile.c_str();
305 
306  try
307  {
308  mitk::IOUtil::Save(image, outputFile.c_str());
309  }
310  catch( const itk::ExceptionObject& e)
311  {
312  MITK_ERROR << "Failed to write out the output file. \n\t Reason : ITK Exception " << e.what();
313  }
314 
315  }
316 
317  return 1;
318 }
static void Save(const mitk::BaseData *data, const std::string &path)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:824
static const std::string REFERENCEBVALUEPROPERTYNAME
itk::SmartPointer< Self > Pointer
#define MITK_INFO
Definition: mitkLogMacros.h:22
std::vector< DwiImageType::Pointer > DwiImageContainerType
#define MITK_ERROR
Definition: mitkLogMacros.h:24
void setContributor(std::string contributor)
STL namespace.
Helper class for mitk::Images containing diffusion weighted data.
DataCollection - Class to facilitate loading/accessing structured data.
ValueType * any_cast(Any *operand)
Definition: usAny.h:377
std::map< std::string, us::Any > parseArguments(const StringContainerType &arguments, bool *ok=nullptr)
Image::Pointer GrabItkImageMemory(itk::SmartPointer< ItkOutputImageType > &itkimage, mitk::Image *mitkImage=nullptr, const BaseGeometry *geometry=nullptr, bool update=true)
Grabs the memory of an itk::Image (with a specific type) and puts it into an mitk::Image.The memory is managed by the mitk::Image after calling this function. The itk::Image remains valid until the mitk::Image decides to free the memory.
static const std::string MEASUREMENTFRAMEPROPERTYNAME
mitk::Image DiffusionImageType
static mitk::StringList & GetInputFilenames()
GradientDirectionsProperty::GradientDirectionsContainerType GradientDirectionsContainerType
void InitializeImage()
Make certain the owned image is up to date with all necessary properties.
void addArgument(const std::string &longarg, const std::string &shortarg, Type type, const std::string &argLabel, const std::string &argHelp=std::string(), const us::Any &defaultValue=us::Any(), bool optional=true, bool ignoreRest=false, bool deprecated=false)
mitk::Image::Pointer ReadInDICOMFiles(mitk::StringList &input_files, std::string output_file)
Image class for storing images.
Definition: mitkImage.h:76
Definition: usAny.h:163
DwiImageType::PixelType DwiPixelType
itk::VectorImage< DiffusionPixelType, 3 > DwiImageType
mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientContainerType
void setCategory(std::string category)
static Pointer New()
std::vector< std::string > StringList
void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix)
static Pointer New()
void SetInputFileNames(std::string input_directory)
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
std::vector< GradientContainerType::Pointer > GradientListContainerType
void SearchForInputInSubdirs(std::string root_directory, std::string subdir_prefix, std::vector< DiffusionImageType::Pointer > &output_container)
GradientDirectionsContainerType::Pointer GetGradientContainer() const
Merges diffusion weighted images, e.g. to generate one multishell volume from several single shell vo...
unsigned short PixelType
static const std::string GRADIENTCONTAINERPROPERTYNAME
void setTitle(std::string title)
DwiImageType::RegionType DwiRegionType
void setDescription(std::string description)
int main(int argc, char *argv[])
short DiffusionPixelType
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.