Medical Imaging Interaction Toolkit  2018.4.99-08619e4f
Medical Imaging Interaction Toolkit
GenericFittingMiniApp.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 (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 // std includes
14 #include <string>
15 
16 // itk includes
17 #include "itksys/SystemTools.hxx"
18 
19 // CTK includes
20 #include "mitkCommandLineParser.h"
21 
22 // MITK includes
23 #include <mitkIOUtil.h>
28 #include <mitkModelFitInfo.h>
32 #include <mitkExtractTimeGrid.h>
35 
36 std::string inFilename;
37 std::string outFileName;
38 std::string maskFileName;
39 bool verbose(false);
40 bool roibased(false);
41 std::string functionName;
42 std::string formular;
45 
46 
47 void onFitEvent(::itk::Object* caller, const itk::EventObject & event, void* /*data*/)
48 {
49  itk::ProgressEvent progressEvent;
50 
51  if (progressEvent.CheckEvent(&event))
52  {
53  mitk::ParameterFitImageGeneratorBase* castedReporter = dynamic_cast<mitk::ParameterFitImageGeneratorBase*>(caller);
54  std::cout <<castedReporter->GetProgress()*100 << "% ";
55  }
56 }
57 
58 
60 {
61  // set general information about your MiniApp
62  parser.setCategory("Dynamic Data Analysis Tools");
63  parser.setTitle("Generic Fitting");
64  parser.setDescription("MiniApp that allows to make a pixel based fitting on the intensity signal over time for a given model function.");
65  parser.setContributor("DKFZ MIC");
67 
69  // how should arguments be prefixed
70  parser.setArgumentPrefix("--", "-");
71  // add each argument, unless specified otherwise each argument is optional
72  // see mitkCommandLineParser::addArgument for more information
73  parser.beginGroup("Model parameters");
74  parser.addArgument(
75  "function", "f", mitkCommandLineParser::String, "Model function", "Function that should be used to fit the intensity signals. Options are: \"Linear\" or \"<Parameter Number>\" (for generic formulas).", us::Any(std::string("Linear")));
76  parser.addArgument(
77  "formular", "y", mitkCommandLineParser::String, "Generic model function formular", "Formular of a generic model (if selected) that will be parsed and fitted.", us::Any());
78  parser.endGroup();
79  parser.beginGroup("Required I/O parameters");
80  parser.addArgument(
81  "input", "i", mitkCommandLineParser::File, "Input file", "input 3D+t image file", us::Any(), false, false, false, mitkCommandLineParser::Input);
82  parser.addArgument("output",
83  "o",
85  "Output file template",
86  "where to save the output parameter images. The specified path will be used as template to determine the format (via extension) and the name \"root\". For each parameter a suffix will be added to the name.",
87  us::Any(),
88  false, false, false, mitkCommandLineParser::Output);
89  parser.endGroup();
90 
91  parser.beginGroup("Optional parameters");
92  parser.addArgument(
93  "mask", "m", mitkCommandLineParser::File, "Mask file", "Mask that defines the spatial image region that should be fitted. Must have the same geometry as the input image!", us::Any(), true, false, false, mitkCommandLineParser::Input);
94  parser.addArgument(
95  "verbose", "v", mitkCommandLineParser::Bool, "Verbose Output", "Whether to produce verbose output");
96  parser.addArgument(
97  "roibased", "r", mitkCommandLineParser::Bool, "Roi based fitting", "Will compute a mean intesity signal over the ROI before fitting it. If this mode is used a mask must be specified.");
98  parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Help:", "Show this help text");
99  parser.endGroup();
101 }
102 
103 bool configureApplicationSettings(std::map<std::string, us::Any> parsedArgs)
104 {
105  if (parsedArgs.size() == 0)
106  return false;
107 
108  // parse, cast and set required arguments
109  functionName = "Linear";
110  if (parsedArgs.count("function"))
111  {
112  functionName = us::any_cast<std::string>(parsedArgs["function"]);
113  }
114  if (parsedArgs.count("formular"))
115  {
116  formular = us::any_cast<std::string>(parsedArgs["formular"]);
117  }
118  inFilename = us::any_cast<std::string>(parsedArgs["input"]);
119  outFileName = us::any_cast<std::string>(parsedArgs["output"]);
120 
121 
122  verbose = false;
123  if (parsedArgs.count("verbose"))
124  {
125  verbose = us::any_cast<bool>(parsedArgs["verbose"]);
126  }
127 
128  roibased = false;
129  if (parsedArgs.count("roibased"))
130  {
131  roibased = us::any_cast<bool>(parsedArgs["roibased"]);
132  }
133 
134  if (parsedArgs.count("mask"))
135  {
136  maskFileName = us::any_cast<std::string>(parsedArgs["mask"]);
137  }
138 
139  return true;
140 }
141 
143  parameterizer)
144 {
145  mitk::GenericParamModelParameterizer* genericParameterizer =
146  dynamic_cast<mitk::GenericParamModelParameterizer*>(parameterizer);
147 
148  if (genericParameterizer)
149  {
150  genericParameterizer->SetFunctionString(formular);
151  }
152 }
153 
155  const mitk::ModelParameterizerBase* parameterizer)
156 {
159 
162  fitFunctor->RegisterEvaluationParameter("Chi^2", chi2);
163 
164  mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel();
165 
166  ::itk::LevenbergMarquardtOptimizer::ScalesType scales;
167  scales.SetSize(refModel->GetNumberOfParameters());
168  scales.Fill(1.0);
169  fitFunctor->SetScales(scales);
170 
171  fitFunctor->SetDebugParameterMaps(true);
172 
173  return fitFunctor.GetPointer();
174 }
175 
176 template <typename TParameterizer>
177 void generateModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer&
178  /*modelFitInfo*/, mitk::ParameterFitImageGeneratorBase::Pointer& generator)
179 {
180  mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator =
182 
183  typename TParameterizer::Pointer modelParameterizer =
184  TParameterizer::New();
185 
186  configureInitialParametersOfParameterizer(modelParameterizer);
187 
188  //Specify fitting strategy and criterion parameters
189  mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer);
190 
191  //Parametrize fit generator
192  fitGenerator->SetModelParameterizer(modelParameterizer);
193 
194  fitGenerator->SetMask(mask);
195 
196  fitGenerator->SetDynamicImage(image);
197  fitGenerator->SetFitFunctor(fitFunctor);
198 
199  generator = fitGenerator.GetPointer();
200 }
201 
202 template <typename TParameterizer>
204  mitk::modelFit::ModelFitInfo::Pointer& /*modelFitInfo*/,
205  mitk::ParameterFitImageGeneratorBase::Pointer& generator)
206 {
207  mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator =
209 
210  typename TParameterizer::Pointer modelParameterizer =
211  TParameterizer::New();
212 
213  configureInitialParametersOfParameterizer(modelParameterizer);
214 
215  //Compute ROI signal
216  mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator =
218  signalGenerator->SetMask(mask);
219  signalGenerator->SetDynamicImage(image);
220  signalGenerator->Generate();
221 
222  mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean();
223 
224  //Specify fitting strategy and criterion parameters
225  mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer);
226 
227  //Parametrize fit generator
228  fitGenerator->SetModelParameterizer(modelParameterizer);
229  fitGenerator->SetMask(mask);
230  fitGenerator->SetFitFunctor(fitFunctor);
231  fitGenerator->SetSignal(roiSignal);
232  fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(image));
233 
234  generator = fitGenerator.GetPointer();
235 }
236 
237 void doFitting()
238 {
239  mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr;
240  mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr;
241 
242  ::itk::CStyleCommand::Pointer command = ::itk::CStyleCommand::New();
243  command->SetCallback(onFitEvent);
244 
245  bool isLinearFactory = functionName == "Linear";
246 
247  if (isLinearFactory)
248  {
249  std::cout << "Model: linear" << std::endl;
250  if (!roibased)
251  {
252  generateModelFit_PixelBased<mitk::LinearModelParameterizer>(fitSession, generator);
253  }
254  else
255  {
256  generateModelFit_ROIBased<mitk::LinearModelParameterizer>(fitSession, generator);
257  }
258  }
259  else
260  {
261  std::cout << "Model: generic (2 parameter)" << std::endl;
262  if (!roibased)
263  {
264  generateModelFit_PixelBased<mitk::GenericParamModelParameterizer>(fitSession, generator);
265  }
266  else
267  {
268  generateModelFit_ROIBased<mitk::GenericParamModelParameterizer>(fitSession, generator);
269  }
270  }
271 
272  if (generator.IsNotNull() )
273  {
274  std::cout << "Started fitting process..." << std::endl;
275  generator->AddObserver(::itk::AnyEvent(), command);
276  generator->Generate();
277  std::cout << std::endl << "Finished fitting process" << std::endl;
278 
279  mitk::storeModelFitGeneratorResults(outFileName, generator, fitSession);
280  }
281  else
282  {
283  mitkThrow() << "Fitting error! Could not initalize fitting job.";
284  }
285 }
286 
287 int main(int argc, char* argv[])
288 {
289  mitkCommandLineParser parser;
290  setupParser(parser);
291 
292  mitk::PreferenceListReaderOptionsFunctor readerFilterFunctor = mitk::PreferenceListReaderOptionsFunctor({ "MITK DICOM Reader v2 (classic config)" }, { "MITK DICOM Reader" });
293 
294  const std::map<std::string, us::Any>& parsedArgs = parser.parseArguments(argc, argv);
295  if (!configureApplicationSettings(parsedArgs))
296  {
297  return EXIT_FAILURE;
298  };
299 
300  // Show a help message
301  if (parsedArgs.count("help") || parsedArgs.count("h"))
302  {
303  std::cout << parser.helpText();
304  return EXIT_SUCCESS;
305  }
306 
308  try
309  {
310  image = mitk::IOUtil::Load<mitk::Image>(inFilename, &readerFilterFunctor);
311  std::cout << "Input: " << inFilename << std::endl;
312 
313  if (!maskFileName.empty())
314  {
315  mask = mitk::IOUtil::Load<mitk::Image>(maskFileName, &readerFilterFunctor);
316  std::cout << "Mask: " << maskFileName << std::endl;
317  }
318  else
319  {
320  std::cout << "Mask: none" << std::endl;
321  }
322 
323  if (roibased && mask.IsNull())
324  {
325  mitkThrow() << "Error. Cannot fit. Please specify mask if you select roi based fitting.";
326  }
327 
328  std::cout << "Style: ";
329  if (roibased)
330  {
331  std::cout << "ROI based";
332  }
333  else
334  {
335  std::cout << "pixel based";
336  }
337  std::cout << std::endl;
338 
339  doFitting();
340 
341  std::cout << "Processing finished." << std::endl;
342 
343  return EXIT_SUCCESS;
344  }
345  catch (const itk::ExceptionObject& e)
346  {
347  MITK_ERROR << e.what();
348  return EXIT_FAILURE;
349  }
350  catch (const std::exception& e)
351  {
352  MITK_ERROR << e.what();
353  return EXIT_FAILURE;
354  }
355  catch (...)
356  {
357  MITK_ERROR << "Unexpected error encountered.";
358  return EXIT_FAILURE;
359  }
360 }
Option callback functor with a preference list/ black list option selection strategy.
std::string formular
void generateModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer &, mitk::ParameterFitImageGeneratorBase::Pointer &generator)
virtual void SetFunctionString(mitk::ModelBase::FunctionStringType _arg)
#define MITK_ERROR
Definition: mitkLogMacros.h:20
std::string maskFileName
void setContributor(std::string contributor)
std::string inFilename
ValueType * any_cast(Any *operand)
Definition: usAny.h:377
std::string outFileName
bool roibased(false)
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, mitkCommandLineParser::Channel channel=mitkCommandLineParser::Channel::None)
std::map< std::string, us::Any > parseArguments(const StringContainerType &arguments, bool *ok=nullptr)
bool configureApplicationSettings(std::map< std::string, us::Any > parsedArgs)
virtual ModelBasePointer GenerateParameterizedModel(const IndexType &currentPosition) const =0
int main(int argc, char *argv[])
virtual double GetProgress() const =0
MITKMODELFIT_EXPORT ModelBase::TimeGridType ExtractTimeGrid(const Image *image)
#define mitkThrow()
bool verbose(false)
Definition: usAny.h:163
std::string helpText() const
void onFitEvent(::itk::Object *caller, const itk::EventObject &event, void *)
void doFitting()
void setCategory(std::string category)
mitk::Image::Pointer image
void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix)
void generateModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer &, mitk::ParameterFitImageGeneratorBase::Pointer &generator)
mitk::ModelFitFunctorBase::Pointer createDefaultFitFunctor(const mitk::ModelParameterizerBase *parameterizer)
void setupParser(mitkCommandLineParser &parser)
std::string functionName
void configureInitialParametersOfParameterizer(mitk::ModelParameterizerBase *parameterizer)
MITKMODELFIT_EXPORT void storeModelFitGeneratorResults(const std::string &outputPathTemplate, mitk::ParameterFitImageGeneratorBase *generator, const mitk::modelFit::ModelFitInfo *fitSession)
mitk::Image::Pointer mask
void setTitle(std::string title)
void setDescription(std::string description)
void beginGroup(const std::string &description)