Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.