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
PeakExtraction.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 <itkImageFileWriter.h>
18 #include <itkResampleImageFilter.h>
20 
21 #include <mitkImage.h>
22 #include <mitkQBallImage.h>
23 #include <mitkImageCast.h>
24 #include <mitkImageToItk.h>
25 #include <mitkTensorImage.h>
26 
27 #include <mitkCoreObjectFactory.h>
28 #include "mitkCommandLineParser.h"
30 #include <itkFlipImageFilter.h>
31 #include <boost/lexical_cast.hpp>
32 #include <boost/algorithm/string.hpp>
33 
34 #include <mitkIOUtil.h>
35 
36 using namespace std;
37 
38 template<int shOrder>
39 int StartPeakExtraction(int argc, char* argv[])
40 {
41  mitkCommandLineParser parser;
42  parser.setArgumentPrefix("--", "-");
43  parser.addArgument("image", "i", mitkCommandLineParser::InputFile, "Input image", "sh coefficient image", us::Any(), false);
44  parser.addArgument("outroot", "o", mitkCommandLineParser::OutputDirectory, "Output directory", "output root", us::Any(), false);
45  parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask", "mask image");
46  parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization", "0=no norm, 1=max norm, 2=single vec norm", 1, true);
47  parser.addArgument("numpeaks", "p", mitkCommandLineParser::Int, "Max. number of peaks", "maximum number of extracted peaks", 2, true);
48  parser.addArgument("peakthres", "r", mitkCommandLineParser::Float, "Peak threshold", "peak threshold relative to largest peak", 0.4, true);
49  parser.addArgument("abspeakthres", "a", mitkCommandLineParser::Float, "Absolute peak threshold", "absolute peak threshold weighted with local GFA value", 0.06, true);
50  parser.addArgument("shConvention", "s", mitkCommandLineParser::String, "Use specified SH-basis", "use specified SH-basis (MITK, FSL, MRtrix)", string("MITK"), true);
51  parser.addArgument("noFlip", "f", mitkCommandLineParser::Bool, "No flip", "do not flip input image to match MITK coordinate convention");
52  parser.addArgument("clusterThres", "c", mitkCommandLineParser::Float, "Clustering threshold", "directions closer together than the specified angular threshold will be clustered (in rad)", 0.9);
53  parser.addArgument("flipX", "fx", mitkCommandLineParser::Bool, "Flip X", "Flip peaks in x direction");
54  parser.addArgument("flipY", "fy", mitkCommandLineParser::Bool, "Flip Y", "Flip peaks in y direction");
55  parser.addArgument("flipZ", "fz", mitkCommandLineParser::Bool, "Flip Z", "Flip peaks in z direction");
56 
57 
58  parser.setCategory("Preprocessing Tools");
59  parser.setTitle("Peak Extraction");
60  parser.setDescription("");
61  parser.setContributor("MBI");
62 
63  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
64  if (parsedArgs.size()==0)
65  return EXIT_FAILURE;
66 
67  // mandatory arguments
68  string imageName = us::any_cast<string>(parsedArgs["image"]);
69  string outRoot = us::any_cast<string>(parsedArgs["outroot"]);
70 
71  // optional arguments
72  string maskImageName("");
73  if (parsedArgs.count("mask"))
74  maskImageName = us::any_cast<string>(parsedArgs["mask"]);
75 
76  int normalization = 1;
77  if (parsedArgs.count("normalization"))
78  normalization = us::any_cast<int>(parsedArgs["normalization"]);
79 
80  int numPeaks = 2;
81  if (parsedArgs.count("numpeaks"))
82  numPeaks = us::any_cast<int>(parsedArgs["numpeaks"]);
83 
84  float peakThres = 0.4;
85  if (parsedArgs.count("peakthres"))
86  peakThres = us::any_cast<float>(parsedArgs["peakthres"]);
87 
88  float absPeakThres = 0.06;
89  if (parsedArgs.count("abspeakthres"))
90  absPeakThres = us::any_cast<float>(parsedArgs["abspeakthres"]);
91 
92  float clusterThres = 0.9;
93  if (parsedArgs.count("clusterThres"))
94  clusterThres = us::any_cast<float>(parsedArgs["clusterThres"]);
95 
96  bool noFlip = false;
97  if (parsedArgs.count("noFlip"))
98  noFlip = us::any_cast<bool>(parsedArgs["noFlip"]);
99 
100  bool flipX = false;
101  if (parsedArgs.count("flipX"))
102  flipX = us::any_cast<bool>(parsedArgs["flipX"]);
103 
104  bool flipY = false;
105  if (parsedArgs.count("flipY"))
106  flipY = us::any_cast<bool>(parsedArgs["flipY"]);
107 
108  bool flipZ = false;
109  if (parsedArgs.count("flipZ"))
110  flipZ = us::any_cast<bool>(parsedArgs["flipZ"]);
111 
112  std::cout << "image: " << imageName;
113  std::cout << "outroot: " << outRoot;
114  if (!maskImageName.empty())
115  std::cout << "mask: " << maskImageName;
116  else
117  std::cout << "no mask image selected";
118  std::cout << "numpeaks: " << numPeaks;
119  std::cout << "peakthres: " << peakThres;
120  std::cout << "abspeakthres: " << absPeakThres;
121  std::cout << "shOrder: " << shOrder;
122 
123  try
124  {
126  mitk::Image::Pointer mask = mitk::IOUtil::LoadImage(maskImageName);
127 
128  typedef itk::Image<unsigned char, 3> ItkUcharImgType;
131 
132  int toolkitConvention = 0;
133 
134  if (parsedArgs.count("shConvention"))
135  {
136  string convention = us::any_cast<string>(parsedArgs["shConvention"]).c_str();
137  if ( boost::algorithm::equals(convention, "FSL") )
138  {
139  toolkitConvention = 1;
140  std::cout << "Using FSL SH-basis";
141  }
142  else if ( boost::algorithm::equals(convention, "MRtrix") )
143  {
144  toolkitConvention = 2;
145  std::cout << "Using MRtrix SH-basis";
146  }
147  else
148  std::cout << "Using MITK SH-basis";
149  }
150  else
151  std::cout << "Using MITK SH-basis";
152 
153  ItkUcharImgType::Pointer itkMaskImage = NULL;
154  if (mask.IsNotNull())
155  {
156  try{
157  itkMaskImage = ItkUcharImgType::New();
158  mitk::CastToItkImage(mask, itkMaskImage);
159  filter->SetMaskImage(itkMaskImage);
160  }
161  catch(...)
162  {
163 
164  }
165  }
166 
167  if (toolkitConvention>0)
168  {
169  std::cout << "Converting coefficient image to MITK format";
171  typedef mitk::ImageToItk< itk::Image< float, 4 > > CasterType;
173  caster->SetInput(image);
174  caster->Update();
175  itk::Image< float, 4 >::Pointer itkImage = caster->GetOutput();
176 
177  typename ConverterType::Pointer converter = ConverterType::New();
178 
179  if (noFlip)
180  {
181  converter->SetInputImage(itkImage);
182  }
183  else
184  {
185  std::cout << "Flipping image";
186  itk::FixedArray<bool, 4> flipAxes;
187  flipAxes[0] = true;
188  flipAxes[1] = true;
189  flipAxes[2] = false;
190  flipAxes[3] = false;
191  itk::FlipImageFilter< itk::Image< float, 4 > >::Pointer flipper = itk::FlipImageFilter< itk::Image< float, 4 > >::New();
192  flipper->SetInput(itkImage);
193  flipper->SetFlipAxes(flipAxes);
194  flipper->Update();
195  itk::Image< float, 4 >::Pointer flipped = flipper->GetOutput();
196  itk::Matrix< double,4,4 > m = itkImage->GetDirection(); m[0][0] *= -1; m[1][1] *= -1;
197  flipped->SetDirection(m);
198 
199  itk::Point< float, 4 > o = itkImage->GetOrigin();
200  o[0] -= (flipped->GetLargestPossibleRegion().GetSize(0)-1);
201  o[1] -= (flipped->GetLargestPossibleRegion().GetSize(1)-1);
202  flipped->SetOrigin(o);
203  converter->SetInputImage(flipped);
204  }
205 
206  std::cout << "Starting conversion";
207  switch (toolkitConvention)
208  {
209  case 1:
210  converter->SetToolkit(ConverterType::FSL);
211  filter->SetToolkit(MaximaExtractionFilterType::FSL);
212  break;
213  case 2:
214  converter->SetToolkit(ConverterType::MRTRIX);
215  filter->SetToolkit(MaximaExtractionFilterType::MRTRIX);
216  break;
217  default:
218  converter->SetToolkit(ConverterType::FSL);
219  filter->SetToolkit(MaximaExtractionFilterType::FSL);
220  break;
221  }
222  converter->GenerateData();
223  filter->SetInput(converter->GetCoefficientImage());
224  }
225  else
226  {
227  try{
229  typename CasterType::Pointer caster = CasterType::New();
230  caster->SetInput(image);
231  caster->Update();
232  filter->SetInput(caster->GetOutput());
233  }
234  catch(...)
235  {
236  std::cout << "wrong image type";
237  return EXIT_FAILURE;
238  }
239  }
240 
241  filter->SetMaxNumPeaks(numPeaks);
242  filter->SetPeakThreshold(peakThres);
243  filter->SetAbsolutePeakThreshold(absPeakThres);
244  filter->SetAngularThreshold(1);
245  filter->SetClusteringThreshold(clusterThres);
246  filter->SetFlipX(flipX);
247  filter->SetFlipY(flipY);
248  filter->SetFlipZ(flipZ);
249 
250  switch (normalization)
251  {
252  case 0:
253  filter->SetNormalizationMethod(MaximaExtractionFilterType::NO_NORM);
254  break;
255  case 1:
256  filter->SetNormalizationMethod(MaximaExtractionFilterType::MAX_VEC_NORM);
257  break;
258  case 2:
259  filter->SetNormalizationMethod(MaximaExtractionFilterType::SINGLE_VEC_NORM);
260  break;
261  }
262 
263  std::cout << "Starting extraction";
264  filter->Update();
265 
266  // write direction images
267  {
268  typedef typename MaximaExtractionFilterType::ItkDirectionImageContainer ItkDirectionImageContainer;
269  typename ItkDirectionImageContainer::Pointer container = filter->GetDirectionImageContainer();
270  for (unsigned int i=0; i<container->Size(); i++)
271  {
272  typename MaximaExtractionFilterType::ItkDirectionImage::Pointer itkImg = container->GetElement(i);
273 
274  if (itkMaskImage.IsNotNull())
275  {
276  itkImg->SetDirection(itkMaskImage->GetDirection());
277  itkImg->SetOrigin(itkMaskImage->GetOrigin());
278  }
279 
280  string outfilename = outRoot;
281  outfilename.append("_DIRECTION_");
282  outfilename.append(boost::lexical_cast<string>(i));
283  outfilename.append(".nrrd");
284 
285  typedef itk::ImageFileWriter< typename MaximaExtractionFilterType::ItkDirectionImage > WriterType;
286  typename WriterType::Pointer writer = WriterType::New();
287  writer->SetFileName(outfilename);
288  writer->SetInput(itkImg);
289  writer->Update();
290  }
291  }
292 
293  // write num directions image
294  {
295  ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage();
296 
297  if (itkMaskImage.IsNotNull())
298  {
299  numDirImage->SetDirection(itkMaskImage->GetDirection());
300  numDirImage->SetOrigin(itkMaskImage->GetOrigin());
301  }
302 
303  string outfilename = outRoot.c_str();
304  outfilename.append("_NUM_DIRECTIONS.nrrd");
305  typedef itk::ImageFileWriter< ItkUcharImgType > WriterType;
307  writer->SetFileName(outfilename);
308  writer->SetInput(numDirImage);
309  writer->Update();
310  }
311 
312  // write vector field
313  {
314  mitk::FiberBundle::Pointer directions = filter->GetOutputFiberBundle();
315 
316  string outfilename = outRoot.c_str();
317  outfilename.append("_VECTOR_FIELD.fib");
318  mitk::IOUtil::Save(directions.GetPointer(),outfilename.c_str());
319  }
320  }
321  catch (itk::ExceptionObject e)
322  {
323  std::cout << e;
324  return EXIT_FAILURE;
325  }
326  catch (std::exception e)
327  {
328  std::cout << e.what();
329  return EXIT_FAILURE;
330  }
331  catch (...)
332  {
333  std::cout << "ERROR!?!";
334  return EXIT_FAILURE;
335  }
336  return EXIT_SUCCESS;
337 }
338 
342 int main(int argc, char* argv[])
343 {
344  mitkCommandLineParser parser;
345  parser.setArgumentPrefix("--", "-");
346  parser.addArgument("image", "i", mitkCommandLineParser::InputFile, "Input image", "sh coefficient image", us::Any(), false);
347  parser.addArgument("shOrder", "sh", mitkCommandLineParser::Int, "Spherical harmonics order", "spherical harmonics order");
348  parser.addArgument("outroot", "o", mitkCommandLineParser::OutputDirectory, "Output directory", "output root", us::Any(), false);
349  parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask", "mask image");
350  parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization", "0=no norm, 1=max norm, 2=single vec norm", 1, true);
351  parser.addArgument("numpeaks", "p", mitkCommandLineParser::Int, "Max. number of peaks", "maximum number of extracted peaks", 2, true);
352  parser.addArgument("peakthres", "r", mitkCommandLineParser::Float, "Peak threshold", "peak threshold relative to largest peak", 0.4, true);
353  parser.addArgument("abspeakthres", "a", mitkCommandLineParser::Float, "Absolute peak threshold", "absolute peak threshold weighted with local GFA value", 0.06, true);
354  parser.addArgument("shConvention", "s", mitkCommandLineParser::String, "Use specified SH-basis", "use specified SH-basis (MITK, FSL, MRtrix)", string("MITK"), true);
355  parser.addArgument("noFlip", "f", mitkCommandLineParser::Bool, "No flip", "do not flip input image to match MITK coordinate convention");
356 
357  parser.setCategory("Preprocessing Tools");
358  parser.setTitle("Peak Extraction");
359  parser.setDescription("Extract maxima in the input spherical harmonics image.");
360  parser.setContributor("MBI");
361 
362  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
363  if (parsedArgs.size()==0)
364  return EXIT_FAILURE;
365 
366 
367  int shOrder = -1;
368  if (parsedArgs.count("shOrder"))
369  shOrder = us::any_cast<int>(parsedArgs["shOrder"]);
370 
371  switch (shOrder)
372  {
373  case 4:
374  return StartPeakExtraction<4>(argc, argv);
375  case 6:
376  return StartPeakExtraction<6>(argc, argv);
377  case 8:
378  return StartPeakExtraction<8>(argc, argv);
379  case 10:
380  return StartPeakExtraction<10>(argc, argv);
381  case 12:
382  return StartPeakExtraction<12>(argc, argv);
383  }
384  return EXIT_FAILURE;
385 }
static void Save(const mitk::BaseData *data, const std::string &path)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:824
itk::SmartPointer< Self > Pointer
Extract ODF peaks by searching all local maxima on a densely sampled ODF und clustering these maxima ...
void setContributor(std::string contributor)
STL namespace.
ValueType * any_cast(Any *operand)
Definition: usAny.h:377
std::map< std::string, us::Any > parseArguments(const StringContainerType &arguments, bool *ok=nullptr)
int StartPeakExtraction(int argc, char *argv[])
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)
Definition: usAny.h:163
void setCategory(std::string category)
void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix)
bool equals(const mitk::ScalarType &val1, const mitk::ScalarType &val2, mitk::ScalarType epsilon=mitk::eps)
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
void setTitle(std::string title)
int main(int argc, char *argv[])
Extract maxima in the input spherical harmonics image.
void setDescription(std::string description)
static mitk::Image::Pointer LoadImage(const std::string &path)
LoadImage Convenience method to load an arbitrary mitkImage.
Definition: mitkIOUtil.cpp:597
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.