Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkLibSVMClassifierTest.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 #include <mitkTestingMacros.h>
14 #include <mitkTestFixture.h>
15 #include "mitkIOUtil.h"
16 #include "itkArray2D.h"
17 
18 #include <mitkLibSVMClassifier.h>
19 #include <itkLabelSampler.h>
20 #include <mitkImageCast.h>
22 #include <itkCSVArray2DFileReader.h>
23 #include <itkCSVArray2DDataObject.h>
24 #include <itkCSVNumericObjectFileWriter.h>
25 
26 //#include <boost/algorithm/string.hpp>
27 
28 class mitkLibSVMClassifierTestSuite : public mitk::TestFixture
29 {
30  CPPUNIT_TEST_SUITE(mitkLibSVMClassifierTestSuite);
31  MITK_TEST(TrainSVMClassifier_MatlabDataSet_shouldReturnTrue);
32  MITK_TEST(TrainSVMClassifier_BreastCancerDataSet_shouldReturnTrue);
33  CPPUNIT_TEST_SUITE_END();
34 
35 private:
36 
37  typedef Eigen::Matrix<double ,Eigen::Dynamic,Eigen::Dynamic> MatrixDoubleType;
38  typedef Eigen::Matrix<int, Eigen::Dynamic,Eigen::Dynamic> MatrixIntType;
39 
40  Eigen::MatrixXd m_TrainingMatrixX;
41  Eigen::MatrixXi m_TrainingLabelMatrixY;
42  Eigen::MatrixXd m_TestXPredict;
43  Eigen::MatrixXi m_TestYPredict;
44 
46 
47 public:
48 
49  /*Reading an file, which includes the trainingdataset and the testdataset, and convert the
50  content of the file into an 2dim matrixpair.
51  There are an delimiter, which separates the matrix into an trainingmatrix and testmatrix */
52  template<typename T>
53  std::pair<Eigen::Matrix<T ,Eigen::Dynamic,Eigen::Dynamic>,Eigen::Matrix<T ,Eigen::Dynamic,Eigen::Dynamic> >convertCSVToMatrix(const std::string &path, char delimiter,double range, bool isXMatrix)
54  {
55  typename itk::CSVArray2DFileReader<T>::Pointer fr = itk::CSVArray2DFileReader<T>::New();
56  fr->SetFileName(path);
57  fr->SetFieldDelimiterCharacter(delimiter);
58  fr->HasColumnHeadersOff();
59  fr->HasRowHeadersOff();
60  fr->Parse();
61  try{
62  fr->Update();
63  }catch(itk::ExceptionObject& ex){
64  cout << "Exception caught!" << std::endl;
65  cout << ex << std::endl;
66  }
67 
68  typename itk::CSVArray2DDataObject<T>::Pointer p = fr->GetOutput();
69  unsigned int maxrowrange = p->GetMatrix().rows();
70  unsigned int c = p->GetMatrix().cols();
71  auto percentRange = (unsigned int)(maxrowrange*range);
72 
73  if(isXMatrix == true)
74  {
75  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> trainMatrixX(percentRange,c);
76  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> testMatrixXPredict(maxrowrange-percentRange,c);
77 
78  for(unsigned int row = 0; row < percentRange; row++){
79  for(unsigned int col = 0; col < c; col++){
80  trainMatrixX(row,col) = p->GetData(row,col);
81  }
82  }
83 
84  for(unsigned int row = percentRange; row < maxrowrange; row++){
85  for(unsigned int col = 0; col < c; col++){
86  testMatrixXPredict(row-percentRange,col) = p->GetData(row,col);
87  }
88  }
89 
90  return std::make_pair(trainMatrixX,testMatrixXPredict);
91  }
92  else
93  {
94  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> trainLabelMatrixY(percentRange,c);
95  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> testMatrixYPredict(maxrowrange-percentRange,c);
96 
97  for(unsigned int row = 0; row < percentRange; row++){
98  for(unsigned int col = 0; col < c; col++){
99  trainLabelMatrixY(row,col) = p->GetData(row,col);
100  }
101  }
102 
103  for(unsigned int row = percentRange; row < maxrowrange; row++){
104  for(unsigned int col = 0; col < c; col++){
105  testMatrixYPredict(row-percentRange,col) = p->GetData(row,col);
106  }
107  }
108 
109  return std::make_pair(trainLabelMatrixY,testMatrixYPredict);
110  }
111  }
112 
113  /*
114  Reading an csv-data and transfer the included datas into an matrix.
115  */
116  template<typename T>
117  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> readCsvData(const std::string &path, char delimiter)
118  {
119  typename itk::CSVArray2DFileReader<T>::Pointer fr = itk::CSVArray2DFileReader<T>::New();
120  fr->SetFileName(path);
121  fr->SetFieldDelimiterCharacter(delimiter);
122  fr->HasColumnHeadersOff();
123  fr->HasRowHeadersOff();
124  fr->Parse();
125  try{
126  fr->Update();
127  }catch(itk::ExceptionObject& ex){
128  cout << "Exception caught!" << std::endl;
129  cout << ex << std::endl;
130  }
131 
132  typename itk::CSVArray2DDataObject<T>::Pointer p = fr->GetOutput();
133  unsigned int maxrowrange = p->GetMatrix().rows();
134  unsigned int maxcols = p->GetMatrix().cols();
135  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> matrix(maxrowrange,maxcols);
136 
137  for(unsigned int rows = 0; rows < maxrowrange; rows++){
138  for(unsigned int cols = 0; cols < maxcols; cols++ ){
139  matrix(rows,cols) = p->GetData(rows,cols);
140  }
141  }
142 
143  return matrix;
144  }
145 
146  /*
147  Write the content of the array into an own csv-data in the following sequence:
148  root.csv: 1 2 3 0 0 4
149  writen.csv: 1 1:2 2:3 3:0 4:0 5:4
150  */
151  template<typename T>
152  void writeMatrixToCsv(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> paramMatrix,const std::string &path)
153  {
154  std::ofstream outputstream (path,std::ofstream::out); // 682
155 
156  if(outputstream.is_open()){
157  for(int i = 0; i < paramMatrix.rows(); i++){
158  outputstream << paramMatrix(i,0);
159  for(int j = 1; j < 11; j++){
160  outputstream << " " << j << ":" << paramMatrix(i,j);
161  }
162  outputstream << endl;
163  }
164  outputstream.close();
165  }
166  else{
167  cout << "Unable to write into CSV" << endl;
168  }
169  }
170 
171  /*
172  Train the classifier with an exampledataset of mattlab.
173  Note: The included data are gaußan normaldistributed.
174  */
175  void TrainSVMClassifier_MatlabDataSet_shouldReturnTrue()
176  {
177  /* Declarating an featurematrixdataset, the first matrix
178  of the matrixpair is the trainingmatrix and the second one is the testmatrix.*/
179  std::pair<MatrixDoubleType,MatrixDoubleType> matrixDouble;
180  matrixDouble = convertCSVToMatrix<double>(GetTestDataFilePath("Classification/FeaturematrixMatlab.csv"),';',0.5,true);
181  m_TrainingMatrixX = matrixDouble.first;
182  m_TestXPredict = matrixDouble.second;
183 
184  /* The declaration of the labelmatrixdataset is equivalent to the declaration
185  of the featurematrixdataset.*/
186  std::pair<MatrixIntType,MatrixIntType> matrixInt;
187  matrixInt = convertCSVToMatrix<int>(GetTestDataFilePath("Classification/LabelmatrixMatlab.csv"),';',0.5,false);
188  m_TrainingLabelMatrixY = matrixInt.first;
189  m_TestYPredict = matrixInt.second;
190  classifier = mitk::LibSVMClassifier::New();
191 
192  /* Setting of the SVM-Parameters*/
193  classifier->SetGamma(1/(double)(m_TrainingMatrixX.cols()));
194  classifier->SetSvmType(0);
195  classifier->SetKernelType(0);
196 
197  /* Train the classifier, by giving trainingdataset for the labels and features.
198  The result in an colunmvector of the labels.*/
199  classifier->Train(m_TrainingMatrixX,m_TrainingLabelMatrixY);
200  Eigen::MatrixXi classes = classifier->Predict(m_TestXPredict);
201 
202  /* Testing the matching between the calculated
203  colunmvector and the result of the SVM */
204  unsigned int maxrows = classes.rows();
205 
206  int count = 0;
207 
208  for (unsigned int i = 0; i < maxrows; i++)
209  {
210  if(classes(i, 0) == m_TestYPredict(i, 0))
211  ++count;
212  }
213 
214  MITK_INFO << 100*count/(double)(maxrows) << "%";
215  MITK_TEST_CONDITION(isEqual<int>(m_TestYPredict,classes),"Expected vector and occured vector match.");
216  }
217 
218  // Method of testing for assertions.
219  template<typename T>
220  bool isEqual(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> expected, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> actual)
221  {
222  bool isSimilar = true;
223  unsigned int mrow = expected.rows();
224  unsigned int mcol = expected.cols();
225  for(unsigned int i = 0; i < mrow; i++){
226  for(unsigned int j = 0; j < mcol; j++){
227  if(expected(i,j) != actual(i,j)){
228  isSimilar = false;
229  }
230  }
231  }
232  return isSimilar;
233  }
234 
235  // Method of intervalltesting
236  template<typename T>
237  bool isIntervall(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> expected, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> actual, double lowrange, double toprange)
238  {
239  bool isInIntervall = false;
240  int count = 0;
241  unsigned int rowRange = expected.rows();
242  unsigned int colRange = expected.cols();
243  for(unsigned int i = 0; i < rowRange; i++){
244  for(unsigned int j = 0; j < colRange; j++){
245  if(expected(i,j) == actual(i,j)){
246  count++;
247  }
248  }
249 
250  double valueOfMatch = 100*count/(double)(rowRange);
251  if((lowrange <= valueOfMatch) && (toprange >= valueOfMatch)){
252  isInIntervall = true;
253  }
254  }
255  return isInIntervall;
256  }
257 
258  /*
259  Train the classifier with the dataset of breastcancer patients from the
260  LibSVM Libary
261  */
262  void TrainSVMClassifier_BreastCancerDataSet_shouldReturnTrue()
263  {
264  /* Declarating an featurematrixdataset, the first matrix
265  of the matrixpair is the trainingmatrix and the second one is the testmatrix.*/
266  std::pair<MatrixDoubleType,MatrixDoubleType> matrixDouble;
267  matrixDouble = convertCSVToMatrix<double>(GetTestDataFilePath("Classification/FeaturematrixBreastcancer.csv"),';',0.5,true);
268  m_TrainingMatrixX = matrixDouble.first;
269  m_TestXPredict = matrixDouble.second;
270 
271  /* The declaration of the labelmatrixdataset is equivalent to the declaration
272  of the featurematrixdataset.*/
273  std::pair<MatrixIntType,MatrixIntType> matrixInt;
274  matrixInt = convertCSVToMatrix<int>(GetTestDataFilePath("Classification/LabelmatrixBreastcancer.csv"),';',0.5,false);
275  m_TrainingLabelMatrixY = matrixInt.first;
276  m_TestYPredict = matrixInt.second;
277 
278  /* Setting of the SVM-Parameters*/
279  classifier = mitk::LibSVMClassifier::New();
280  classifier->SetGamma(1/(double)(m_TrainingMatrixX.cols()));
281  classifier->SetSvmType(0);
282  classifier->SetKernelType(2);
283 
284  /* Train the classifier, by giving trainingdataset for the labels and features.
285  The result in an colunmvector of the labels.*/
286  classifier->Train(m_TrainingMatrixX,m_TrainingLabelMatrixY);
287  Eigen::MatrixXi classes = classifier->Predict(m_TestXPredict);
288 
289  /* Testing the matching between the calculated colunmvector and the result
290  of the SVM */
291  unsigned int maxrows = classes.rows();
292 
293  int count = 0;
294 
295  for (unsigned int i = 0; i < maxrows; i++)
296  {
297  if (classes(i, 0) == m_TestYPredict(i, 0))
298  ++count;
299  }
300 
301  MITK_INFO << 100*count/(double)(maxrows) << "%";
302  MITK_TEST_CONDITION(isIntervall<int>(m_TestYPredict,classes,75,100),"Testvalue is in range.");
303  }
304 
305  void TestThreadedDecisionForest()
306  {
307  }
308 };
309 
310 MITK_TEST_SUITE_REGISTRATION(mitkLibSVMClassifier)
MITK_TEST_SUITE_REGISTRATION(mitkImageToItk)
#define MITK_INFO
Definition: mitkLogMacros.h:18
#define MITK_TEST(TESTMETHOD)
Adds a test to the current test suite.
static std::string GetTestDataFilePath(const std::string &testData)
Get the absolute path for test data.
#define MITK_TEST_CONDITION(COND, MSG)
Test fixture for parameterized tests.
static Pointer New()