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