Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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.