Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.