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
NativeHeadCTSegmentation.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 <mitkCoreObjectFactory.h>
18 #include "mitkImage.h"
19 #include <boost/lexical_cast.hpp>
20 #include "mitkCommandLineParser.h"
21 #include <mitkIOUtil.h>
22 #include <itksys/SystemTools.hxx>
23 #include <mitkITKImageImport.h>
24 #include <mitkImageCast.h>
25 #include <mitkProperties.h>
26 
27 // ITK
28 #include <itkImageRegionIterator.h>
29 
30 // MITK
31 #include <mitkIOUtil.h>
32 
33 // Classification
34 #include <mitkCLUtil.h>
36 #include <mitkAbstractFileReader.h>
37 
38 #include <QDir>
39 #include <QString>
40 #include <QStringList>
41 
42 #include <mitkImageAccessByItk.h>
43 
44 using namespace mitk;
45 
46 typedef unsigned int uint;
47 void ReadMitkProjectImageAndMask(std::string input_file, mitk::Image::Pointer & raw_image, mitk::Image::Pointer & class_mask, Image::Pointer &brain_mask);
48 std::map<unsigned int, double> VolumeUnderMaskByLabel(mitk::Image::Pointer mask);
49 
53 int main(int argc, char* argv[])
54 {
55  mitkCommandLineParser parser;
56  parser.setArgumentPrefix("--", "-");
57 
58  // required params
59  parser.addArgument("inputdir", "i", mitkCommandLineParser::InputDirectory, "Input Directory", "Contains input feature files.", us::Any(), false);
60  parser.addArgument("outputdir", "o", mitkCommandLineParser::OutputDirectory, "Output Directory", "Destination of output files.", us::Any(), false);
61 
62  // optional params
63  parser.addArgument("select", "s", mitkCommandLineParser::String, "Item selection", "Using Regular expression, seperated by space e.g.: '*.nrrd *.vtk *test*'",std::string("*.mitk"),true);
64  // parser.addArgument("treecount", "tc", mitkCommandLineParser::Int, "Treecount", "Number of trees.",50,true);
65  // parser.addArgument("treedepth", "td", mitkCommandLineParser::Int, "Treedepth", "Maximal tree depth.",50,true);
66  // parser.addArgument("minsplitnodesize", "min", mitkCommandLineParser::Int, "Minimum split node size.", "Minimum split node size.",2,true);
67  // parser.addArgument("precision", "p", mitkCommandLineParser::Float, "Split precision.", "Precision.", mitk::eps,true);
68  // parser.addArgument("fraction", "f", mitkCommandLineParser::Float, "Fraction of samples per tree.", "Fraction of samples per tree.", 0.6f,true);
69  // parser.addArgument("replacment", "r", mitkCommandLineParser::Bool, "Sample with replacement.", "Sample with replacement.", true,true);
70 
71  // Miniapp Infos
72  parser.setCategory("Classification Tools");
73  parser.setTitle("Native Head CT Segmentation");
74  parser.setDescription("Using vigra random forest");
75  parser.setContributor("Jonas Cordes");
76 
77  // Params parsing
78  std::map<std::string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
79  if (parsedArgs.size()==0)
80  return EXIT_FAILURE;
81 
82  std::string inputdir = us::any_cast<std::string>(parsedArgs["inputdir"]);
83  std::string outputdir = us::any_cast<std::string>(parsedArgs["outputdir"]);
84 
85  // int treecount = parsedArgs.count("treecount") ? us::any_cast<int>(parsedArgs["treecount"]) : 50;
86  // int treedepth = parsedArgs.count("treedepth") ? us::any_cast<int>(parsedArgs["treedepth"]) : 50;
87  // int minsplitnodesize = parsedArgs.count("minsplitnodesize") ? us::any_cast<int>(parsedArgs["minsplitnodesize"]) : 2;
88  // float precision = parsedArgs.count("precision") ? us::any_cast<float>(parsedArgs["precision"]) : mitk::eps;
89  // float fraction = parsedArgs.count("fraction") ? us::any_cast<float>(parsedArgs["fraction"]) : 0.6;
90  // bool withreplacement = parsedArgs.count("replacment") ? us::any_cast<float>(parsedArgs["replacment"]) : true;
91  std::string filt_select = parsedArgs.count("select") ? us::any_cast<std::string>(parsedArgs["select"]) : "*.mitk";
92 
93  QString filter(filt_select.c_str());
94  QDir dir(inputdir.c_str());
95  auto strl = dir.entryList(filter.split(" "),QDir::Files);
96 
97  // create the one
99  uint n_samples = 45000;
100  uint n_samples_per_image = n_samples / strl.size();
101  uint n_features = 2;
102 
103  {// Training
104  Eigen::MatrixXd feature_matrix(n_samples, n_features);
105  Eigen::MatrixXi label_matrix(n_samples, 1);
106 
107  uint pos = 0;
108 
109  for(auto entry : strl)
110  {
111  mitk::Image::Pointer raw_image, class_mask, brain_mask;
112  ReadMitkProjectImageAndMask(inputdir + entry.toStdString(), raw_image, class_mask, brain_mask);
113 
114  mitk::Image::Pointer brain_mask_sampled;
115  AccessFixedDimensionByItk_2(brain_mask, mitk::CLUtil::itkSampleLabel, 3, brain_mask_sampled, n_samples_per_image);
116 
117  mitk::Image::Pointer csf_prob;
118  mitk::CLUtil::ProbabilityMap(raw_image,13.9, 8.3,csf_prob);
121  mitk::CLUtil::FillHoleGrayscale(csf_prob,csf_prob);
122 
123  feature_matrix.block(pos, 0, n_samples_per_image, 1) = mitk::CLUtil::Transform<double>(raw_image,brain_mask_sampled);
124  feature_matrix.block(pos, 1, n_samples_per_image, 1) = mitk::CLUtil::Transform<double>(csf_prob,brain_mask_sampled);
125 
126  label_matrix.block(pos, 0, n_samples_per_image, 1) = mitk::CLUtil::Transform<int>(class_mask, brain_mask_sampled);
127  pos += n_samples_per_image;
128  }
129  classifier->Train(feature_matrix, label_matrix);
130  classifier->PrintParameter();
131  }
132 
133  std::map<std::string, std::pair<double, double> > map_error;
134 
135  for(auto entry: strl)
136  {
137  mitk::Image::Pointer raw_image, class_mask, brain_mask;
138  ReadMitkProjectImageAndMask(inputdir + entry.toStdString(), raw_image, class_mask, brain_mask);
139 
140  auto map_true = VolumeUnderMaskByLabel(class_mask);
141 
142  mitk::Image::Pointer csf_prob;
143  mitk::CLUtil::ProbabilityMap(raw_image,13.9, 8.3,csf_prob);
146  mitk::CLUtil::FillHoleGrayscale(csf_prob,csf_prob);
147 
148  uint count = 0;
149  mitk::CLUtil::CountVoxel(brain_mask,count);
150 
151  Eigen::MatrixXd feature_matrix(count,n_features);
152  feature_matrix.block(0, 0, count, 1) = mitk::CLUtil::Transform<double>(raw_image,brain_mask);
153  feature_matrix.block(0, 1, count, 1) = mitk::CLUtil::Transform<double>(csf_prob,brain_mask);
154 
155  mitk::Image::Pointer result_mask = mitk::CLUtil::Transform<int>(classifier->Predict(feature_matrix),brain_mask);
156 
157  std::string name = itksys::SystemTools::GetFilenameWithoutExtension(entry.toStdString());
158  mitk::IOUtil::Save(result_mask,outputdir + name + ".nrrd");
159 
160  auto map_pred = VolumeUnderMaskByLabel(result_mask);
161 
162  map_error[entry.toStdString()] = std::make_pair(std::abs(map_true[1] - map_pred[1]) / map_true[1], map_true[2] != 0 ? std::abs(map_true[2] - map_pred[2]) / map_true[2]: 0);
163  }
164 
165  double mean_error_csf = 0;
166  double mean_error_les = 0;
167  double num_subjects = map_error.size();
168  for(auto entry: map_error)
169  {
170  MITK_INFO(entry.first.c_str()) << "CSF error: " << entry.second.first << "%\t LES error: " << entry.second.second << "%";
171  mean_error_csf += entry.second.first;
172  mean_error_les += entry.second.second;
173  }
174  MITK_INFO("Mean") << "CSF error: " << mean_error_csf/num_subjects << "%\t LES error: " << mean_error_les/num_subjects << "%";
175 
176  return EXIT_SUCCESS;
177 }
178 
179 void ReadMitkProjectImageAndMask(std::string input_file, mitk::Image::Pointer & raw_image, mitk::Image::Pointer & class_mask, mitk::Image::Pointer & brain_mask)
180 {
181  auto so = mitk::IOUtil::Load(input_file);
182 
183  std::map<uint, uint> map;
184 
185  mitk::CLUtil::CountVoxel(dynamic_cast<mitk::Image *>(so[1].GetPointer()), map);
186 
187  raw_image = map.size() <= 7 ? dynamic_cast<mitk::Image *>(so[0].GetPointer()) : dynamic_cast<mitk::Image *>(so[1].GetPointer());
188  class_mask = map.size() <= 7 ? dynamic_cast<mitk::Image *>(so[1].GetPointer()) : dynamic_cast<mitk::Image *>(so[0].GetPointer());
189 
190  std::map<uint, uint> merge_instructions;// = {{0,0},{1,1},{2,1},{3,1},{4,2},{5,3},{6,3}};
191  merge_instructions[0] = 0;
192  merge_instructions[1] = 1;
193  merge_instructions[2] = 1;
194  merge_instructions[3] = 1;
195  merge_instructions[4] = 2;
196  merge_instructions[5] = 3;
197  merge_instructions[6] = 3;
198  mitk::CLUtil::MergeLabels(class_mask, merge_instructions);
199 
200  brain_mask = class_mask->Clone();
201  //merge_instructions = {{0,0},{1,1},{2,1},{3,1},{4,1},{5,1},{6,1}};
202  merge_instructions[0] = 0;
203  merge_instructions[1] = 1;
204  merge_instructions[2] = 1;
205  merge_instructions[3] = 1;
206  merge_instructions[4] = 1;
207  merge_instructions[5] = 1;
208  merge_instructions[6] = 1;
209  mitk::CLUtil::MergeLabels(brain_mask, merge_instructions);
210 }
211 
212 std::map<unsigned int, double> VolumeUnderMaskByLabel(mitk::Image::Pointer mask)
213 {
215  mitk::CastToItkImage(mask,img);
216 
217  std::map<unsigned int, double> volume_map;
218  itk::ImageRegionConstIterator<itk::Image<unsigned int, 3>> it(img,img->GetLargestPossibleRegion());
219  while(!it.IsAtEnd())
220  {
221  itk::Image<unsigned int, 3>::PixelType value = it.Value();
222  if(volume_map.find(value)== volume_map.end())
223  volume_map[value] = 0;
224  volume_map[value]++;
225  ++it;
226  }
227 
228  auto spacing = img->GetSpacing();
229  double volumeUnit = spacing[0] * spacing[1] * spacing[2];
230  volumeUnit *= 0.001;
231 
232  for(auto entry: volume_map)
233  entry.second *= volumeUnit;
234 
235  return volume_map;
236 }
static void Save(const mitk::BaseData *data, const std::string &path)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:824
itk::SmartPointer< Self > Pointer
#define MITK_INFO
Definition: mitkLogMacros.h:22
static void itkSampleLabel(TImageType1 *image, TImageType2 *output, double acceptrate, unsigned int label)
Definition: mitkCLUtil.h:307
void setContributor(std::string contributor)
DataCollection - Class to facilitate loading/accessing structured data.
ValueType * any_cast(Any *operand)
Definition: usAny.h:377
void ReadMitkProjectImageAndMask(std::string input_file, mitk::Image::Pointer &raw_image, mitk::Image::Pointer &class_mask, Image::Pointer &brain_mask)
std::map< std::string, us::Any > parseArguments(const StringContainerType &arguments, bool *ok=nullptr)
int main(int argc, char *argv[])
static void DilateGrayscale(mitk::Image::Pointer &image, unsigned int radius, mitk::CLUtil::MorphologicalDimensions d, mitk::Image::Pointer &outimage)
DilateGrayscale.
Definition: mitkCLUtil.cpp:39
static void FillHoleGrayscale(mitk::Image::Pointer &image, mitk::Image::Pointer &outimage)
FillHoleGrayscale.
Definition: mitkCLUtil.cpp:44
static void ErodeGrayscale(mitk::Image::Pointer &image, unsigned int radius, mitk::CLUtil::MorphologicalDimensions d, mitk::Image::Pointer &outimage)
ErodeGrayscale.
Definition: mitkCLUtil.cpp:34
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)
#define AccessFixedDimensionByItk_2(mitkImage, itkImageTypeFunction, dimension, arg1, arg2)
Image class for storing images.
Definition: mitkImage.h:76
Definition: usAny.h:163
static void ProbabilityMap(const mitk::Image::Pointer &sourceImage, double mean, double std_dev, mitk::Image::Pointer &resultImage)
ProbabilityMap.
Definition: mitkCLUtil.cpp:29
void setCategory(std::string category)
unsigned int uint
void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix)
std::map< unsigned int, double > VolumeUnderMaskByLabel(mitk::Image::Pointer mask)
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
static void MergeLabels(mitk::Image::Pointer &img, const std::map< unsigned int, unsigned int > &map)
MergeLabels.
Definition: mitkCLUtil.cpp:64
MITKMATCHPOINTREGISTRATION_EXPORT ResultImageType::Pointer map(const InputImageType *input, const RegistrationType *registration, bool throwOnOutOfInputAreaError=false, const double &paddingValue=0, const ResultImageGeometryType *resultGeometry=NULL, bool throwOnMappingError=true, const double &errorValue=0, mitk::ImageMappingInterpolator::Type interpolatorType=mitk::ImageMappingInterpolator::Linear)
unsigned short PixelType
static DataStorage::SetOfObjects::Pointer Load(const std::string &path, DataStorage &storage)
Load a file into the given DataStorage.
Definition: mitkIOUtil.cpp:483
void setTitle(std::string title)
static void CountVoxel(mitk::Image::Pointer image, std::map< unsigned int, unsigned int > &map)
CountVoxel.
Definition: mitkCLUtil.cpp:69
void setDescription(std::string description)
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.