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
LocalDirectionalFiberPlausibility.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 <mitkBaseData.h>
18 #include <mitkImageCast.h>
19 #include <mitkImageToItk.h>
21 #include <metaCommand.h>
22 #include "mitkCommandLineParser.h"
24 #include <usAny.h>
25 #include <itkImageFileWriter.h>
26 #include <mitkIOUtil.h>
27 #include <boost/lexical_cast.hpp>
28 #include <iostream>
29 #include <fstream>
30 #include <itksys/SystemTools.hxx>
31 #include <mitkCoreObjectFactory.h>
32 
33 #define _USE_MATH_DEFINES
34 #include <math.h>
35 
36 using namespace std;
37 
41 int main(int argc, char* argv[])
42 {
43  mitkCommandLineParser parser;
44 
45  parser.setTitle("Local Directional Fiber Plausibility");
46  parser.setCategory("Fiber Tracking and Processing Methods");
47  parser.setDescription("Calculate angular error of a tractogram with respect to the input reference directions.");
48  parser.setContributor("MBI");
49 
50  parser.setArgumentPrefix("--", "-");
51  parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false);
52  parser.addArgument("reference", "r", mitkCommandLineParser::StringList, "Reference images:", "reference direction images", us::Any(), false);
53  parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false);
54  parser.addArgument("mask", "m", mitkCommandLineParser::StringList, "Masks:", "mask images");
55  parser.addArgument("athresh", "a", mitkCommandLineParser::Float, "Angular threshold:", "angular threshold in degrees. closer fiber directions are regarded as one direction and clustered together.", 25, true);
56  parser.addArgument("sthresh", "s", mitkCommandLineParser::Float, "Size threshold:", "Relative peak size threshold per voxel.", 0.0, true);
57  parser.addArgument("maxdirs", "md", mitkCommandLineParser::Int, "Max. Clusters:", "Maximum number of fiber clusters.", 0, true);
58  parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Verbose:", "output optional and intermediate calculation results");
59  parser.addArgument("ignore", "n", mitkCommandLineParser::Bool, "Ignore:", "don't increase error for missing or too many directions");
60  parser.addArgument("empty", "e", mitkCommandLineParser::Bool, "Empty Voxels:", "don't increase error for empty voxels");
61  parser.addArgument("fileID", "id", mitkCommandLineParser::String, "ID:", "optional ID field");
62 
63  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
64  if (parsedArgs.size()==0)
65  return EXIT_FAILURE;
66 
69  if (parsedArgs.count("mask"))
70  maskImages = us::any_cast<mitkCommandLineParser::StringContainerType>(parsedArgs["mask"]);
71 
72  string fibFile = us::any_cast<string>(parsedArgs["input"]);
73 
74  float angularThreshold = 25;
75  if (parsedArgs.count("athresh"))
76  angularThreshold = us::any_cast<float>(parsedArgs["athresh"]);
77 
78  float sizeThreshold = 0;
79  if (parsedArgs.count("sthresh"))
80  sizeThreshold = us::any_cast<float>(parsedArgs["sthresh"]);
81 
82  int maxDirs = 0;
83  if (parsedArgs.count("maxdirs"))
84  maxDirs = us::any_cast<int>(parsedArgs["maxdirs"]);
85 
86  string outRoot = us::any_cast<string>(parsedArgs["out"]);
87 
88  bool verbose = false;
89  if (parsedArgs.count("verbose"))
90  verbose = us::any_cast<bool>(parsedArgs["verbose"]);
91 
92  bool ignoreMissing = false;
93  if (parsedArgs.count("ignore"))
94  ignoreMissing = us::any_cast<bool>(parsedArgs["ignore"]);
95 
96  bool ignoreEmpty = false;
97  if (parsedArgs.count("empty"))
98  ignoreEmpty = us::any_cast<bool>(parsedArgs["empty"]);
99 
100  string fileID = "";
101  if (parsedArgs.count("fileID"))
102  fileID = us::any_cast<string>(parsedArgs["fileID"]);
103 
104 
105  try
106  {
107  typedef itk::Image<unsigned char, 3> ItkUcharImgType;
108  typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType;
109  typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType;
110  typedef itk::EvaluateDirectionImagesFilter< float > EvaluationFilterType;
111 
112  // load fiber bundle
113  mitk::FiberBundle::Pointer inputTractogram = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::LoadDataNode(fibFile)->GetData());
114 
115  // load reference directions
117  for (unsigned int i=0; i<referenceImages.size(); i++)
118  {
119  try
120  {
121  mitk::Image::Pointer img = dynamic_cast<mitk::Image*>(mitk::IOUtil::LoadDataNode(referenceImages.at(i))->GetData());
124  caster->SetInput(img);
125  caster->Update();
126  ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput();
127  referenceImageContainer->InsertElement(referenceImageContainer->Size(),itkImg);
128  }
129  catch(...){ std::cout << "could not load: " << referenceImages.at(i); }
130  }
131 
133  ItkDirectionImage3DType::Pointer dirImg = referenceImageContainer->GetElement(0);
134  itkMaskImage->SetSpacing( dirImg->GetSpacing() );
135  itkMaskImage->SetOrigin( dirImg->GetOrigin() );
136  itkMaskImage->SetDirection( dirImg->GetDirection() );
137  itkMaskImage->SetLargestPossibleRegion( dirImg->GetLargestPossibleRegion() );
138  itkMaskImage->SetBufferedRegion( dirImg->GetLargestPossibleRegion() );
139  itkMaskImage->SetRequestedRegion( dirImg->GetLargestPossibleRegion() );
140  itkMaskImage->Allocate();
141  itkMaskImage->FillBuffer(1);
142 
143  // extract directions from fiber bundle
145  fOdfFilter->SetFiberBundle(inputTractogram);
146  fOdfFilter->SetMaskImage(itkMaskImage);
147  fOdfFilter->SetAngularThreshold(cos(angularThreshold*M_PI/180));
148  fOdfFilter->SetNormalizeVectors(true);
149  fOdfFilter->SetUseWorkingCopy(false);
150  fOdfFilter->SetSizeThreshold(sizeThreshold);
151  fOdfFilter->SetMaxNumDirections(maxDirs);
152  fOdfFilter->Update();
153  ItkDirectionImageContainerType::Pointer directionImageContainer = fOdfFilter->GetDirectionImageContainer();
154 
155  if (verbose)
156  {
157  // write vector field
158  mitk::FiberBundle::Pointer directions = fOdfFilter->GetOutputFiberBundle();
159 
160  string outfilename = outRoot;
161  outfilename.append("_VECTOR_FIELD.fib");
162 
163  mitk::IOUtil::SaveBaseData(directions.GetPointer(), outfilename );
164 
165  // write direction images
166  for (unsigned int i=0; i<directionImageContainer->Size(); i++)
167  {
168  itk::TractsToVectorImageFilter<float>::ItkDirectionImageType::Pointer itkImg = directionImageContainer->GetElement(i);
169  typedef itk::ImageFileWriter< itk::TractsToVectorImageFilter<float>::ItkDirectionImageType > WriterType;
171 
172  string outfilename = outRoot;
173  outfilename.append("_DIRECTION_");
174  outfilename.append(boost::lexical_cast<string>(i));
175  outfilename.append(".nrrd");
176 
177  writer->SetFileName(outfilename.c_str());
178  writer->SetInput(itkImg);
179  writer->Update();
180  }
181 
182  // write num direction image
183  {
184  ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage();
185  typedef itk::ImageFileWriter< ItkUcharImgType > WriterType;
187 
188  string outfilename = outRoot;
189  outfilename.append("_NUM_DIRECTIONS.nrrd");
190 
191  writer->SetFileName(outfilename.c_str());
192  writer->SetInput(numDirImage);
193  writer->Update();
194  }
195  }
196 
197  string logFile = outRoot;
198  logFile.append("_ANGULAR_ERROR.csv");
199  ofstream file;
200  file.open (logFile.c_str());
201 
202  if (maskImages.size()>0)
203  {
204  for (unsigned int i=0; i<maskImages.size(); i++)
205  {
206  mitk::Image::Pointer mitkMaskImage = dynamic_cast<mitk::Image*>(mitk::IOUtil::LoadDataNode(maskImages.at(i))->GetData());
207  mitk::CastToItkImage(mitkMaskImage, itkMaskImage);
208 
209  // evaluate directions
211  evaluationFilter->SetImageSet(directionImageContainer);
212  evaluationFilter->SetReferenceImageSet(referenceImageContainer);
213  evaluationFilter->SetMaskImage(itkMaskImage);
214  evaluationFilter->SetIgnoreMissingDirections(ignoreMissing);
215  evaluationFilter->SetIgnoreEmptyVoxels(ignoreEmpty);
216  evaluationFilter->Update();
217 
218  if (verbose)
219  {
220  EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0);
221  typedef itk::ImageFileWriter< EvaluationFilterType::OutputImageType > WriterType;
223 
224  string outfilename = outRoot;
225  outfilename.append("_ERROR_IMAGE.nrrd");
226 
227  writer->SetFileName(outfilename.c_str());
228  writer->SetInput(angularErrorImage);
229  writer->Update();
230  }
231 
232  string maskFileName = itksys::SystemTools::GetFilenameWithoutExtension(maskImages.at(i));
233  unsigned found = maskFileName.find_last_of("_");
234 
235  string sens = itksys::SystemTools::GetFilenameWithoutLastExtension(fibFile);
236  if (!fileID.empty())
237  sens = fileID;
238  sens.append(",");
239 
240  sens.append(maskFileName.substr(found+1));
241  sens.append(",");
242 
243  sens.append(boost::lexical_cast<string>(evaluationFilter->GetMeanAngularError()));
244  sens.append(",");
245 
246  sens.append(boost::lexical_cast<string>(evaluationFilter->GetMedianAngularError()));
247  sens.append(",");
248 
249  sens.append(boost::lexical_cast<string>(evaluationFilter->GetMaxAngularError()));
250  sens.append(",");
251 
252  sens.append(boost::lexical_cast<string>(evaluationFilter->GetMinAngularError()));
253  sens.append(",");
254 
255  sens.append(boost::lexical_cast<string>(std::sqrt(evaluationFilter->GetVarAngularError())));
256  sens.append(";\n");
257  file << sens;
258  }
259  }
260  else
261  {
262  // evaluate directions
264  evaluationFilter->SetImageSet(directionImageContainer);
265  evaluationFilter->SetReferenceImageSet(referenceImageContainer);
266  evaluationFilter->SetMaskImage(itkMaskImage);
267  evaluationFilter->SetIgnoreMissingDirections(ignoreMissing);
268  evaluationFilter->SetIgnoreEmptyVoxels(ignoreEmpty);
269  evaluationFilter->Update();
270 
271  if (verbose)
272  {
273  EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0);
274  typedef itk::ImageFileWriter< EvaluationFilterType::OutputImageType > WriterType;
276 
277  string outfilename = outRoot;
278  outfilename.append("_ERROR_IMAGE.nrrd");
279 
280  writer->SetFileName(outfilename.c_str());
281  writer->SetInput(angularErrorImage);
282  writer->Update();
283  }
284 
285  string sens = itksys::SystemTools::GetFilenameWithoutLastExtension(fibFile);
286  if (!fileID.empty())
287  sens = fileID;
288  sens.append(",");
289 
290  sens.append(boost::lexical_cast<string>(evaluationFilter->GetMeanAngularError()));
291  sens.append(",");
292 
293  sens.append(boost::lexical_cast<string>(evaluationFilter->GetMedianAngularError()));
294  sens.append(",");
295 
296  sens.append(boost::lexical_cast<string>(evaluationFilter->GetMaxAngularError()));
297  sens.append(",");
298 
299  sens.append(boost::lexical_cast<string>(evaluationFilter->GetMinAngularError()));
300  sens.append(",");
301 
302  sens.append(boost::lexical_cast<string>(std::sqrt(evaluationFilter->GetVarAngularError())));
303  sens.append(";\n");
304  file << sens;
305  }
306  file.close();
307  }
308  catch (itk::ExceptionObject e)
309  {
310  std::cout << e;
311  return EXIT_FAILURE;
312  }
313  catch (std::exception e)
314  {
315  std::cout << e.what();
316  return EXIT_FAILURE;
317  }
318  catch (...)
319  {
320  std::cout << "ERROR!?!";
321  return EXIT_FAILURE;
322  }
323  return EXIT_SUCCESS;
324 }
int main(int argc, char *argv[])
Calculate angular error of a tractogram with respect to the input reference directions.
itk::SmartPointer< Self > Pointer
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)
T::Pointer GetData(const std::string &name)
static bool SaveBaseData(mitk::BaseData *data, const std::string &path)
SaveBaseData Convenience method to save arbitrary baseData.
Definition: mitkIOUtil.cpp:888
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)
Evaluates the voxel-wise angular error between two sets of directions.
Image class for storing images.
Definition: mitkImage.h:76
static std::ofstream * logFile
Definition: mitkLog.cpp:30
Definition: usAny.h:163
Base Class for Fiber Bundles;.
void setCategory(std::string category)
static mitk::DataNode::Pointer LoadDataNode(const std::string &path)
LoadDataNode Method to load an arbitrary DataNode.
Definition: mitkIOUtil.cpp:586
void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix)
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< std::string > StringContainerType
void setTitle(std::string title)
void setDescription(std::string description)
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.