Medical Imaging Interaction Toolkit  2018.4.99-12ad79a3
Medical Imaging Interaction Toolkit
CLUtilities/test/mitkGlobalFeaturesTest.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 
17 #include <mitkImageCast.h>
21 #include <cmath>
22 
23 #include <mitkImageGenerator.h>
24 
25 template <typename TPixelType>
26 static mitk::Image::Pointer GenerateMaskImage(unsigned int dimX,
27  unsigned int dimY,
28  unsigned int dimZ,
29  float spacingX = 1,
30  float spacingY = 1,
31  float spacingZ = 1)
32 {
33  typedef itk::Image< TPixelType, 3 > ImageType;
34  typename ImageType::RegionType imageRegion;
35  imageRegion.SetSize(0, dimX);
36  imageRegion.SetSize(1, dimY);
37  imageRegion.SetSize(2, dimZ);
38  typename ImageType::SpacingType spacing;
39  spacing[0] = spacingX;
40  spacing[1] = spacingY;
41  spacing[2] = spacingZ;
42 
43  mitk::Point3D origin; origin.Fill(0.0);
44  itk::Matrix<double, 3, 3> directionMatrix; directionMatrix.SetIdentity();
45 
46  typename ImageType::Pointer image = ImageType::New();
47  image->SetSpacing( spacing );
48  image->SetOrigin( origin );
49  image->SetDirection( directionMatrix );
50  image->SetLargestPossibleRegion( imageRegion );
51  image->SetBufferedRegion( imageRegion );
52  image->SetRequestedRegion( imageRegion );
53  image->Allocate();
54  image->FillBuffer(1);
55 
57  mitkImage->InitializeByItk( image.GetPointer() );
58  mitkImage->SetVolume( image->GetBufferPointer() );
59  return mitkImage;
60 }
61 
62 template <typename TPixelType>
64  unsigned int dimY,
65  unsigned int dimZ,
66  float spacingX = 1,
67  float spacingY = 1,
68  float spacingZ = 1)
69 {
70  typedef itk::Image< TPixelType, 3 > ImageType;
71  typename ImageType::RegionType imageRegion;
72  imageRegion.SetSize(0, dimX);
73  imageRegion.SetSize(1, dimY);
74  imageRegion.SetSize(2, dimZ);
75  typename ImageType::SpacingType spacing;
76  spacing[0] = spacingX;
77  spacing[1] = spacingY;
78  spacing[2] = spacingZ;
79 
80  mitk::Point3D origin; origin.Fill(0.0);
81  itk::Matrix<double, 3, 3> directionMatrix; directionMatrix.SetIdentity();
82 
83  typename ImageType::Pointer image = ImageType::New();
84  image->SetSpacing( spacing );
85  image->SetOrigin( origin );
86  image->SetDirection( directionMatrix );
87  image->SetLargestPossibleRegion( imageRegion );
88  image->SetBufferedRegion( imageRegion );
89  image->SetRequestedRegion( imageRegion );
90  image->Allocate();
91  image->FillBuffer(0.0);
92 
93  typedef itk::ImageRegionIterator<ImageType> IteratorOutputType;
94  IteratorOutputType it(image, imageRegion);
95  it.GoToBegin();
96 
97  TPixelType val = 0;
98  while(!it.IsAtEnd())
99  {
100  it.Set(val % dimX);
101  val++;
102  ++it;
103  }
104 
106  mitkImage->InitializeByItk( image.GetPointer() );
107  mitkImage->SetVolume( image->GetBufferPointer() );
108  return mitkImage;
109 }
110 
111 
112 class mitkGlobalFeaturesTestSuite : public mitk::TestFixture
113 {
114  CPPUNIT_TEST_SUITE(mitkGlobalFeaturesTestSuite );
115 
116  MITK_TEST(FirstOrder_SinglePoint);
117  MITK_TEST(FirstOrder_QubicArea);
118  //MITK_TEST(RunLenght_QubicArea);
119  MITK_TEST(Coocurrence_QubicArea);
120  //MITK_TEST(TestFirstOrderStatistic);
121  // MITK_TEST(TestThreadedDecisionForest);
122 
123  CPPUNIT_TEST_SUITE_END();
124 
125 private:
126 
127  typedef itk::Image<double,3> ImageType;
128  typedef itk::Image<unsigned char,3> MaskType;
129 
130  mitk::Image::Pointer m_Image,m_Mask,m_Mask1;
131  ImageType::Pointer m_ItkImage;
132  MaskType::Pointer m_ItkMask,m_ItkMask1;
133 
134  mitk::Image::Pointer m_GradientImage, m_GradientMask;
135 
136 public:
137 
138  void setUp(void) override
139  {
140  // Load Image Data
141  m_Image = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Pic3D.nrrd"));
142  mitk::CastToItkImage(m_Image,m_ItkImage);
143 
144  // Create a single mask with only one pixel within the regions
145  mitk::Image::Pointer mask1 = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Pic3D.nrrd"));
146  mitk::CastToItkImage(mask1,m_ItkMask);
147  m_ItkMask->FillBuffer(0);
148  MaskType::IndexType index;
149  index[0]=88;index[1]=81;index[2]=13;
150  m_ItkMask->SetPixel(index, 1);
151  MITK_INFO << "Pixel Value: "<<m_ItkImage->GetPixel(index);
152  mitk::CastToMitkImage(m_ItkMask, m_Mask);
153 
154  // Create a mask with a covered region
155  mitk::Image::Pointer lmask1 = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Pic3D.nrrd"));
156  mitk::CastToItkImage(lmask1,m_ItkMask1);
157  m_ItkMask1->FillBuffer(0);
158  int range=2;
159  for (int x = 88-range;x < 88+range+1;++x)
160  {
161  for (int y=81-range;y<81+range+1;++y)
162  {
163  for (int z=13-range;z<13+range+1;++z)
164  {
165  index[0] = x;
166  index[1] = y;
167  index[2] = z;
168  //MITK_INFO << "Pixel: " <<m_ItkImage->GetPixel(index);
169  m_ItkMask1->SetPixel(index, 1);
170  }
171  }
172  }
173  mitk::CastToMitkImage(m_ItkMask1, m_Mask1);
174 
175  m_GradientImage=GenerateGradientWithDimXImage<unsigned char>(5,5,5);
176  m_GradientMask = GenerateMaskImage<unsigned char>(5,5,5);
177  }
178 
179  void FirstOrder_SinglePoint()
180  {
181  mitk::GIFFirstOrderStatistics::Pointer calculator = mitk::GIFFirstOrderStatistics::New();
182  //calculator->SetHistogramSize(4096);
183  //calculator->SetUseCtRange(true);
184  auto features = calculator->CalculateFeatures(m_Image, m_Mask);
185 
186  std::map<std::string, double> results;
187  for (auto iter=features.begin(); iter!=features.end();++iter)
188  {
189  results[(*iter).first]=(*iter).second;
190  MITK_INFO << (*iter).first << " : " << (*iter).second;
191  }
192 
193  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The range of a single pixel should be 0",0.0, results["FirstOrder Range"], 0);
194  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The uniformity of a single pixel should be 1",1.0, results["FirstOrder Uniformity"], 0);
195  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The entropy of a single pixel should be 0",0.0, results["FirstOrder Entropy"], 0);
196  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Root-Means-Square of a single pixel with (-352) should be 352",352.0, results["FirstOrder RMS"], 0.01);
197  CPPUNIT_ASSERT_EQUAL_MESSAGE("The Kurtosis of a single pixel should be undefined",results["FirstOrder Kurtosis"]==results["FirstOrder Kurtosis"], false);
198  CPPUNIT_ASSERT_EQUAL_MESSAGE("The Skewness of a single pixel should be undefined",results["FirstOrder Skewness"]==results["FirstOrder Skewness"], false);
199  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Mean absolute deviation of a single pixel with (-352) should be 0",0, results["FirstOrder Mean absolute deviation"], 0.0);
200  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Covered image intensity range of a single pixel with (-352) should be 0",0, results["FirstOrder Covered Image Intensity Range"], 0.0);
201  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Minimum of a single pixel with (-352) should be -352",-352, results["FirstOrder Minimum"], 0.0);
202  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Maximum of a single pixel with (-352) should be -352",-352, results["FirstOrder Maximum"], 0.0);
203  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Mean of a single pixel with (-352) should be -352",-352, results["FirstOrder Mean"], 0.0);
204  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Variance (corrected) of a single pixel with (-352) should be 0",0, results["FirstOrder Variance"], 0.0);
205  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Sum of a single pixel with (-352) should be -352",-352, results["FirstOrder Sum"], 0.0);
206  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Median of a single pixel with (-352) should be -352",-352, results["FirstOrder Median"], 0.0);
207  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Standard deviation (corrected) of a single pixel with (-352) should be -352",0, results["FirstOrder Standard deviation"], 0.0);
208  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The number of voxels of a single pixel should be 1",1, results["FirstOrder No. of Voxel"], 0.0);
209  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Energy of a single pixel should be 352*352",352*352, results["FirstOrder Energy"], 0.0);
210  // MITK_ASSERT_EQUAL(results["FirstOrder Range"]==0.0,true,"The range of a single pixel should be 0");
211  }
212 
213  void FirstOrder_QubicArea()
214  {
215  mitk::GIFFirstOrderStatistics::Pointer calculator = mitk::GIFFirstOrderStatistics::New();
216  //calculator->SetHistogramSize(4096);
217  //calculator->SetUseCtRange(true);
218  auto features = calculator->CalculateFeatures(m_Image, m_Mask1);
219 
220  std::map<std::string, double> results;
221  for (auto iter=features.begin(); iter!=features.end();++iter)
222  {
223  results[(*iter).first]=(*iter).second;
224  MITK_INFO << (*iter).first << " : " << (*iter).second;
225  }
226 
227  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The range should be 981",981, results["FirstOrder Range"], 0);
228  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Root-Means-Square of a single pixel with (-352) should be 352",402.895778, results["FirstOrder RMS"], 0.01);
229  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Minimum of a single pixel with (-352) should be -352",-937, results["FirstOrder Minimum"], 0.0);
230  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Maximum of a single pixel with (-352) should be -352",44, results["FirstOrder Maximum"], 0.0);
231  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Mean of a single pixel with (-352) should be -352",-304.448, results["FirstOrder Mean"], 0.0);
232  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Sum of a single pixel with (-352) should be -352",-38056, results["FirstOrder Sum"], 0.0);
233  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Median of a single pixel with (-352) should be -352",-202, results["FirstOrder Median"], 0.0);
234  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The number of voxels of a single pixel should be 1",125, results["FirstOrder No. of Voxel"], 0.0);
235  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Standard deviation (corrected) of a single pixel with (-352) should be -352",264.949066, results["FirstOrder Standard deviation"], 0.000001);
236  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Energy of a single pixel should be 352*352",20290626, results["FirstOrder Energy"], 0.0);
237  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The uniformity of a single pixel should be 1",0.0088960, results["FirstOrder Uniformity"], 0.0000001);
238  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The entropy of a single pixel should be 0",-6.853784285, results["FirstOrder Entropy"], 0.000000005);
239  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Variance (corrected) of a single pixel with (-352) should be 0",70198.0074, results["FirstOrder Variance"], 0.0001);
240  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Kurtosis of a single pixel should be 0",2.63480121, results["FirstOrder Kurtosis"], 0.0001);
241  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Skewness of a single pixel should be 0",-0.91817318, results["FirstOrder Skewness"], 0.00001);
242  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Mean absolute deviation of a single pixel with (-352) should be 0",219.348608, results["FirstOrder Mean absolute deviation"], 0.000001);
243  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Covered image intensity range of a single pixel with (-352) should be 0",0.41149329, results["FirstOrder Covered Image Intensity Range"], 0.000001);
244  }
245 
246  void RunLenght_QubicArea()
247  {
248  mitk::GIFGreyLevelRunLength::Pointer calculator = mitk::GIFGreyLevelRunLength::New();
249  //calculator->SetHistogramSize(4096);
250  auto features = calculator->CalculateFeatures(m_Image, m_Mask1);
251 
252  std::map<std::string, double> results;
253  for (auto iter=features.begin(); iter!=features.end();++iter)
254  {
255  results[(*iter).first]=(*iter).second;
256  MITK_INFO << (*iter).first << " : " << (*iter).second;
257  }
258  }
259 
260  void Coocurrence_QubicArea()
261  {
262  /*
263  * Expected Matrix: (Direction 0,0,1)
264  * |------------------------|
265  * | 20 | 0 | 0 | 0 | 0 |
266  * |------------------------|
267  * | 0 | 20 | 0 | 0 | 0 |
268  * |------------------------|
269  * | 0 | 0 | 20 | 0 | 0 |
270  * |------------------------|
271  * | 0 | 0 | 0 | 20 | 0 |
272  * |------------------------|
273  * | 0 | 0 | 0 | 0 | 20 |
274  * |------------------------|
275 
276  * Expected Matrix: (Direction (1,0,0),(0,1,0))
277  * |------------------------|
278  * | 20 | 0 | 0 | 0 | 0 |
279  * |------------------------|
280  * | 20 | 0 | 0 | 0 | 0 |
281  * |------------------------|
282  * | 20 | 0 | 0 | 0 | 0 |
283  * |------------------------|
284  * | 20 | 0 | 0 | 0 | 0 |
285  * |------------------------|
286  * | 20 | 0 | 0 | 0 | 0 |
287  * |------------------------|
288  */
289 
290  mitk::GIFCooccurenceMatrix::Pointer calculator = mitk::GIFCooccurenceMatrix::New();
291  //calculator->SetHistogramSize(4096);
292  //calculator->SetUseCtRange(true);
293  //calculator->SetRange(981);
294  calculator->SetDirection(1);
295  auto features = calculator->CalculateFeatures(m_GradientImage, m_GradientMask);
296 
297  std::map<std::string, double> results;
298  for (auto iter=features.begin(); iter!=features.end();++iter)
299  {
300  results[(*iter).first]=(*iter).second;
301  MITK_INFO << (*iter).first << " : " << (*iter).second;
302  }
303  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean energy value should be 0.2",0.2, results["co-occ. (1) Energy Means"], mitk::eps);
304  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean entropy value should be 0.2",2.321928, results["co-occ. (1) Entropy Means"], 0.000001);
305  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean contrast value should be 0.0",0, results["co-occ. (1) Contrast Means"], mitk::eps);
306  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean dissimilarity value should be 0.0",0, results["co-occ. (1) Dissimilarity Means"], mitk::eps);
307  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean homogenity1 value should be 1.0",1, results["co-occ. (1) Homogeneity1 Means"], mitk::eps);
308  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean InverseDifferenceMoment value should be 1.0",1, results["co-occ. (1) InverseDifferenceMoment Means"], mitk::eps);
309  }
310 };
311 
312 MITK_TEST_SUITE_REGISTRATION(mitkGlobalFeatures)
static mitk::Image::Pointer GenerateMaskImage(unsigned int dimX, unsigned int dimY, unsigned int dimZ, float spacingX=1, float spacingY=1, float spacingZ=1)
MITK_TEST_SUITE_REGISTRATION(mitkImageToItk)
#define MITK_INFO
Definition: mitkLogMacros.h:18
itk::Image< unsigned char, 3 > ImageType
#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.
static mitk::Image::Pointer GenerateGradientWithDimXImage(unsigned int dimX, unsigned int dimY, unsigned int dimZ, float spacingX=1, float spacingY=1, float spacingZ=1)
Test fixture for parameterized tests.
mitk::Image::Pointer image
static Pointer New()
void CastToMitkImage(const itk::SmartPointer< ItkOutputImageType > &itkimage, itk::SmartPointer< mitk::Image > &mitkoutputimage)
Cast an itk::Image (with a specific type) to an mitk::Image.
Definition: mitkImageCast.h:74
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
MITKCORE_EXPORT const ScalarType eps