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