Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
itkEvaluateDirectionImagesFilter.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 #ifndef __itkEvaluateDirectionImagesFilter_cpp
18 #define __itkEvaluateDirectionImagesFilter_cpp
19 
21 #include <itkImageRegionConstIterator.h>
22 #include <itkImageRegionIterator.h>
23 #include <itkImageDuplicator.h>
24 #include <boost/progress.hpp>
25 
26 #define _USE_MATH_DEFINES
27 #include <math.h>
28 
29 namespace itk {
30 
31 template< class PixelType >
34  m_ImageSet(NULL),
35  m_ReferenceImageSet(NULL),
36  m_IgnoreMissingDirections(false),
37  m_IgnoreEmptyVoxels(false),
38  m_Eps(0.0001)
39 {
40  this->SetNumberOfIndexedOutputs(2);
41 }
42 
43 template< class PixelType >
45 {
46  if (m_ImageSet.IsNull() || m_ReferenceImageSet.IsNull())
47  return;
48 
51 
52  for (unsigned int i=0; i<m_ImageSet->Size(); i++)
53  {
55  duplicator->SetInputImage( m_ImageSet->GetElement(i) );
56  duplicator->Update();
57  set1->InsertElement(i, dynamic_cast<DirectionImageType*>(duplicator->GetOutput()));
58  }
59  for (unsigned int i=0; i<m_ReferenceImageSet->Size(); i++)
60  {
62  duplicator->SetInputImage( m_ReferenceImageSet->GetElement(i) );
63  duplicator->Update();
64  set2->InsertElement(i, dynamic_cast<DirectionImageType*>(duplicator->GetOutput()));
65  }
66 
67  m_ImageSet = set1;
68  m_ReferenceImageSet = set2;
69 
70  // angular error image
71  typename OutputImageType::Pointer outputImage = OutputImageType::New();
72  outputImage->SetOrigin( m_ReferenceImageSet->GetElement(0)->GetOrigin() );
73  outputImage->SetRegions( m_ReferenceImageSet->GetElement(0)->GetLargestPossibleRegion() );
74  outputImage->SetSpacing( m_ReferenceImageSet->GetElement(0)->GetSpacing() );
75  outputImage->SetDirection( m_ReferenceImageSet->GetElement(0)->GetDirection() );
76  outputImage->Allocate();
77  outputImage->FillBuffer(0.0);
78  this->SetNthOutput(0, outputImage);
79 
80  // length error image
81  outputImage = OutputImageType::New();
82  outputImage->SetOrigin( m_ReferenceImageSet->GetElement(0)->GetOrigin() );
83  outputImage->SetRegions( m_ReferenceImageSet->GetElement(0)->GetLargestPossibleRegion() );
84  outputImage->SetSpacing( m_ReferenceImageSet->GetElement(0)->GetSpacing() );
85  outputImage->SetDirection( m_ReferenceImageSet->GetElement(0)->GetDirection() );
86  outputImage->Allocate();
87  outputImage->FillBuffer(0.0);
88  this->SetNthOutput(1, outputImage);
89 
90  if (m_MaskImage.IsNull())
91  {
92  m_MaskImage = UCharImageType::New();
93  m_MaskImage->SetOrigin( outputImage->GetOrigin() );
94  m_MaskImage->SetRegions( outputImage->GetLargestPossibleRegion() );
95  m_MaskImage->SetSpacing( outputImage->GetSpacing() );
96  m_MaskImage->SetDirection( outputImage->GetDirection() );
97  m_MaskImage->Allocate();
98  m_MaskImage->FillBuffer(1);
99  }
100 
101  m_MeanAngularError = 0.0;
102  m_MedianAngularError = 0;
103  m_MaxAngularError = 0.0;
104  m_MinAngularError = itk::NumericTraits<float>::max();
105  m_VarAngularError = 0.0;
106  m_AngularErrorVector.clear();
107 
108  m_MeanLengthError = 0.0;
109  m_MedianLengthError = 0;
110  m_MaxLengthError = 0.0;
111  m_MinLengthError = itk::NumericTraits<float>::max();
112  m_VarLengthError = 0.0;
113  m_LengthErrorVector.clear();
114 
115  if (m_ImageSet.IsNull() || m_ReferenceImageSet.IsNull())
116  return;
117 
118  outputImage = static_cast< OutputImageType* >(this->ProcessObject::GetOutput(0));
119  typename OutputImageType::Pointer outputImage2 = static_cast< OutputImageType* >(this->ProcessObject::GetOutput(1));
120 
121  ImageRegionIterator< OutputImageType > oit(outputImage, outputImage->GetLargestPossibleRegion());
122  ImageRegionIterator< OutputImageType > oit2(outputImage2, outputImage2->GetLargestPossibleRegion());
123  ImageRegionIterator< UCharImageType > mit(m_MaskImage, m_MaskImage->GetLargestPossibleRegion());
124 
125  int numTestImages = m_ImageSet->Size();
126  int numReferenceImages = m_ReferenceImageSet->Size();
127  int maxNumDirections = std::max(numReferenceImages, numTestImages);
128 
129  // matrix containing the angular error between the directions
130  vnl_matrix< float > diffM; diffM.set_size(maxNumDirections, maxNumDirections);
131 
132  boost::progress_display disp(outputImage->GetLargestPossibleRegion().GetSize()[0]*outputImage->GetLargestPossibleRegion().GetSize()[1]*outputImage->GetLargestPossibleRegion().GetSize()[2]);
133  while( !oit.IsAtEnd() )
134  {
135  ++disp;
136  if( mit.Get()!=1 )
137  {
138  ++oit;
139  ++oit2;
140  ++mit;
141  continue;
142  }
143  typename OutputImageType::IndexType index = oit.GetIndex();
144 
145  float maxAngularError = 1.0;
146 
147  diffM.fill(10); // initialize with invalid error value
148 
149  // get number of valid directions (length > 0)
150  int numRefDirs = 0;
151  int numTestDirs = 0;
152  std::vector< vnl_vector_fixed< PixelType, 3 > > testDirs;
153  std::vector< vnl_vector_fixed< PixelType, 3 > > refDirs;
154  for (int i=0; i<numReferenceImages; i++)
155  {
156  vnl_vector_fixed< PixelType, 3 > refDir = m_ReferenceImageSet->GetElement(i)->GetPixel(index).GetVnlVector();
157  if (refDir.magnitude() > m_Eps )
158  {
159  refDir.normalize();
160  refDirs.push_back(refDir);
161  numRefDirs++;
162  }
163  }
164  for (int i=0; i<numTestImages; i++)
165  {
166  vnl_vector_fixed< PixelType, 3 > testDir = m_ImageSet->GetElement(i)->GetPixel(index).GetVnlVector();
167  if (testDir.magnitude() > m_Eps )
168  {
169  testDir.normalize();
170  testDirs.push_back(testDir);
171  numTestDirs++;
172  }
173  }
174 
175  if (m_IgnoreEmptyVoxels && (numRefDirs==0 || numTestDirs==0) )
176  {
177  ++oit;
178  ++oit2;
179  ++mit;
180  continue;
181  }
182 
183  // i: index of reference direction
184  // j: index of test direction
185  for (int i=0; i<maxNumDirections; i++) // for each reference direction
186  {
187  bool missingDir = false;
188  vnl_vector_fixed< PixelType, 3 > refDir;
189 
190  if (i<numRefDirs) // normalize if not null
191  refDir = refDirs.at(i);
192  else if (m_IgnoreMissingDirections)
193  continue;
194  else
195  missingDir = true;
196 
197  for (int j=0; j<maxNumDirections; j++) // and each test direction
198  {
199  vnl_vector_fixed< PixelType, 3 > testDir;
200  if (j<numTestDirs) // normalize if not null
201  testDir = testDirs.at(j);
202  else if (m_IgnoreMissingDirections || missingDir)
203  continue;
204  else
205  missingDir = true;
206 
207  // found missing direction
208  if (missingDir)
209  {
210  diffM[i][j] = -1;
211  continue;
212  }
213 
214  // calculate angle between directions
215  diffM[i][j] = fabs(dot_product(refDir, testDir));
216 
217  if (diffM[i][j] < maxAngularError)
218  maxAngularError = diffM[i][j];
219 
220  if (diffM[i][j]>1.0)
221  diffM[i][j] = 1.0;
222  }
223  }
224 
225  float angularError = 0.0;
226  float lengthError = 0.0;
227  int counter = 0;
228  vnl_matrix< float > diffM_copy = diffM;
229  for (int k=0; k<maxNumDirections; k++)
230  {
231  float error = -1;
232  int a,b; a=-1; b=-1;
233  bool missingDir = false;
234 
235  // i: index of reference direction
236  // j: index of test direction
237  // find smalles error between two directions (large value -> small error)
238  for (int i=0; i<maxNumDirections; i++)
239  for (int j=0; j<maxNumDirections; j++)
240  {
241  if (diffM[i][j]>error && diffM[i][j]<2) // found valid error entry
242  {
243  error = diffM[i][j];
244  a = i;
245  b = j;
246  missingDir = false;
247  }
248  else if (diffM[i][j]<0 && error<0) // found missing direction
249  {
250  a = i;
251  b = j;
252  missingDir = true;
253  }
254  }
255 
256  if (a<0 || b<0 || (m_IgnoreMissingDirections && missingDir))
257  continue; // no more directions found
258 
259  if (a>=numRefDirs && b>=numTestDirs)
260  {
261  MITK_INFO << "ERROR: missing test and reference direction. should not be possible. check code.";
262  continue;
263  }
264 
265  // remove processed directions from error matrix
266  diffM.set_row(a, 10.0);
267  diffM.set_column(b, 10.0);
268 
269  if (a>=numRefDirs) // missing reference direction (find next closest)
270  {
271  for (int i=0; i<numRefDirs; i++)
272  if (diffM_copy[i][b]>error)
273  {
274  error = diffM_copy[i][b];
275  a = i;
276  }
277  }
278  else if (b>=numTestDirs) // missing test direction (find next closest)
279  {
280  for (int i=0; i<numTestDirs; i++)
281  if (diffM_copy[a][i]>error)
282  {
283  error = diffM_copy[a][i];
284  b = i;
285  }
286  }
287 
288  float refLength = 0;
289  float testLength = 1;
290 
291  if (a>=numRefDirs || b>=numTestDirs || error<0)
292  error = 0;
293  else
294  {
295  refLength = m_ReferenceImageSet->GetElement(a)->GetPixel(index).GetVnlVector().magnitude();
296  testLength = m_ImageSet->GetElement(b)->GetPixel(index).GetVnlVector().magnitude();
297  }
298 
299  m_LengthErrorVector.push_back( fabs(refLength-testLength) );
300  m_AngularErrorVector.push_back( acos(error)*180.0/M_PI );
301 
302  m_MeanAngularError += m_AngularErrorVector.back();
303  m_MeanLengthError += m_LengthErrorVector.back();
304 
305  angularError += m_AngularErrorVector.back();
306  lengthError += m_LengthErrorVector.back();
307  counter++;
308  }
309 
310  if (counter>0)
311  {
312  lengthError /= counter;
313  angularError /= counter;
314  }
315  oit2.Set(lengthError);
316  oit.Set(angularError);
317 
318  ++oit;
319  ++oit2;
320  ++mit;
321  }
322 
323  std::sort( m_AngularErrorVector.begin(), m_AngularErrorVector.end() );
324  m_MeanAngularError /= m_AngularErrorVector.size(); // mean
325  for (unsigned int i=0; i<m_AngularErrorVector.size(); i++)
326  {
327  float temp = m_AngularErrorVector.at(i) - m_MeanAngularError;
328  m_VarAngularError += temp*temp;
329 
330  if ( m_AngularErrorVector.at(i)>m_MaxAngularError )
331  m_MaxAngularError = m_AngularErrorVector.at(i);
332  if ( m_AngularErrorVector.at(i)<m_MinAngularError )
333  m_MinAngularError = m_AngularErrorVector.at(i);
334  }
335  if (m_AngularErrorVector.size()>1)
336  {
337  m_VarAngularError /= (m_AngularErrorVector.size()-1); // variance
338 
339  // median
340  if (m_AngularErrorVector.size()%2 == 0)
341  m_MedianAngularError = 0.5*( m_AngularErrorVector.at( m_AngularErrorVector.size()/2 ) + m_AngularErrorVector.at( m_AngularErrorVector.size()/2+1 ) );
342  else
343  m_MedianAngularError = m_AngularErrorVector.at( (m_AngularErrorVector.size()+1)/2 ) ;
344  }
345 
346  std::sort( m_LengthErrorVector.begin(), m_LengthErrorVector.end() );
347  m_MeanLengthError /= m_LengthErrorVector.size(); // mean
348  for (unsigned int i=0; i<m_LengthErrorVector.size(); i++)
349  {
350  float temp = m_LengthErrorVector.at(i) - m_MeanLengthError;
351  m_VarLengthError += temp*temp;
352 
353  if ( m_LengthErrorVector.at(i)>m_MaxLengthError )
354  m_MaxLengthError = m_LengthErrorVector.at(i);
355  if ( m_LengthErrorVector.at(i)<m_MinLengthError )
356  m_MinLengthError = m_LengthErrorVector.at(i);
357  }
358  if (m_LengthErrorVector.size()>1)
359  {
360  m_VarLengthError /= (m_LengthErrorVector.size()-1); // variance
361 
362  // median
363  if (m_LengthErrorVector.size()%2 == 0)
364  m_MedianLengthError = 0.5*( m_LengthErrorVector.at( m_LengthErrorVector.size()/2 ) + m_LengthErrorVector.at( m_LengthErrorVector.size()/2+1 ) );
365  else
366  m_MedianLengthError = m_LengthErrorVector.at( (m_LengthErrorVector.size()+1)/2 ) ;
367  }
368 }
369 
370 }
371 
372 #endif // __itkEvaluateDirectionImagesFilter_cpp
itk::SmartPointer< Self > Pointer
#define MITK_INFO
Definition: mitkLogMacros.h:22
static T max(T x, T y)
Definition: svm.cpp:70
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.