PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusCompareVolumes.cxx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Visualization Toolkit
4  Module: vtkSimpleImageFilterExample.cxx
5 
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10  This software is distributed WITHOUT ANY WARRANTY; without even
11  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  PURPOSE. See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #include "PlusConfigure.h"
17 
18 #include "vtkPlusCompareVolumes.h"
19 
20 #include "igsioMath.h"
21 
22 #include "vtkImageData.h"
23 #include "vtkImageProgressIterator.h"
24 #include "vtkInformation.h"
25 #include "vtkInformationVector.h"
26 #include "vtkObjectFactory.h"
27 #include "vtkStreamingDemandDrivenPipeline.h"
28 #include <vector>
29 #include <list>
30 
31 static const int INPUT_GROUND_TRUTH_VOLUME = 0;
32 static const int INPUT_GROUND_TRUTH_VOLUME_ALPHA = 1;
33 static const int INPUT_TEST_VOLUME = 2;
34 static const int INPUT_TEST_VOLUME_ALPHA = 3;
35 static const int INPUT_SLICES_VOLUME_ALPHA = 4;
36 
37 static const int OUTPUT_ABS_DIFF_VOLUME = 1;
38 
40 
41 //----------------------------------------------------------------------------
42 void vtkPlusCompareVolumes::SetInputGT( vtkDataObject* input )
43 {
44  this->SetInputData( 0, input );
45 }
46 
47 //----------------------------------------------------------------------------
48 void vtkPlusCompareVolumes::SetInputGTAlpha( vtkDataObject* input )
49 {
50  this->SetInputData( 1, input );
51 }
52 
53 //----------------------------------------------------------------------------
54 void vtkPlusCompareVolumes::SetInputTest( vtkDataObject* input )
55 {
56  this->SetInputData( 2, input );
57 }
58 
59 //----------------------------------------------------------------------------
60 void vtkPlusCompareVolumes::SetInputTestAlpha( vtkDataObject* input )
61 {
62  this->SetInputData( 3, input );
63 }
64 
65 //----------------------------------------------------------------------------
66 void vtkPlusCompareVolumes::SetInputSliceAlpha( vtkDataObject* input )
67 {
68  this->SetInputData( 4, input );
69 }
70 
71 //----------------------------------------------------------------------------
73 {
74  return this->GetOutput( 0 );
75 }
76 
77 //----------------------------------------------------------------------------
79 {
80  return this->GetOutput( 1 );
81 }
82 
83 //----------------------------------------------------------------------------
85 {
86  return TrueHistogram;
87 }
88 
89 //----------------------------------------------------------------------------
91 {
92  return AbsoluteHistogram;
93 }
94 
95 //----------------------------------------------------------------------------
97 {
99 }
100 
101 //----------------------------------------------------------------------------
103 {
104  int index = value + 256;
105  TrueHistogram[index]++;
106 }
107 
108 //----------------------------------------------------------------------------
110 {
111  int index = value;
112  AbsoluteHistogram[index]++;
113 }
114 
115 //----------------------------------------------------------------------------
117 {
118  int index = value;
120 }
121 
122 //----------------------------------------------------------------------------
124 {
125  for ( int i = 0; i < 511; i++ )
126  {
127  TrueHistogram[i] = 0;
128  }
129 }
130 
131 //----------------------------------------------------------------------------
133 {
134  for ( int i = 0; i < 256; i++ )
135  {
136  AbsoluteHistogram[i] = 0;
137  }
138 }
139 
140 //----------------------------------------------------------------------------
142 {
143  for ( int i = 0; i < 256; i++ )
144  {
146  }
147 }
148 
150 {
151  this->SetNumberOfInputPorts( 5 );
152  this->SetNumberOfOutputPorts( 2 );
153  this->SetNumberOfThreads( 1 ); // TODO: Remove when vtkPlusCompareVolumesExecute is made thread-safe (e.g., simultaneous access to member variables are protected by locking)
154 }
155 
157  vtkInformation* vtkNotUsed( request ),
158  vtkInformationVector** vtkNotUsed( inputVector ),
159  vtkInformationVector* outputVector )
160 {
161  // get the info objects
162  vtkInformation* outInfo = outputVector->GetInformationObject( 0 ); // true difference image
163  vtkDataObject::SetPointDataActiveScalarInfo( outInfo, VTK_DOUBLE, 1 ); // this has been set to 1 output scalar, type VTK_DOUBLE
164  vtkInformation* outInfo2 = outputVector->GetInformationObject( 1 ); // absolute difference image
165  vtkDataObject::SetPointDataActiveScalarInfo( outInfo2, VTK_DOUBLE, 1 ); // this has been set to 1 output scalar, type VTK_DOUBLE
166  return 1;
167 }
168 
169 
170 template <class T>
172  vtkImageData* inData,
173  vtkImageData* outData,
174  T* gtPtr,
175  T* gtAlphaPtr,
176  T* testPtr,
177  T* testAlphaPtr,
178  T* slicesAlphaPtr,
179  double* outPtrTru,
180  double* outPtrAbs,
181  int outExt[6],
182  int id )
183 {
184 
185  vtkIdType inOffsets[3] = {0}; //x,y,z
186  inData->GetIncrements( inOffsets[0], inOffsets[1], inOffsets[2] );
187 
188  vtkIdType outOffsets[3] = {0}; //x,y,z
189  outData->GetIncrements( outOffsets[0], outOffsets[1], outOffsets[2] );
190 
191  int xtemp( 0 ), ytemp( 0 ), ztemp( 0 ); // indices for each of the axes
192  self->resetTrueHistogram(); // count inside the class variables
193  self->resetAbsoluteHistogramWithHoles();
194  self->resetAbsoluteHistogram();
195  std::vector<double> trueDifferences; // store all differences here
196  std::vector<double> absoluteDifferences;
197 
198  // same as absolute difference, but in hole voxels -
199  // this can be added to find the absolute error when
200  // we consider holes to be part of the image (and
201  // choose to not ignore them in the error computation)
202  // note these are not put into the histogram
203  std::vector<double> absoluteDifferencesInAllHoles;
204 
205  int countVisibleVoxels( 0 );
206  int countFilledHoles( 0 );
207  int countHoles( 0 );
208 
209  // iterate through all voxels
210  for ( ztemp = 0; ztemp <= outExt[5] - outExt[4]; ztemp++ )
211  {
212  for ( ytemp = 0; ytemp <= outExt[3] - outExt[2]; ytemp++ )
213  {
214  for ( xtemp = 0; xtemp <= outExt[1] - outExt[0]; xtemp++ )
215  {
216  int inIndex = inOffsets[0] * xtemp + inOffsets[1] * ytemp + inOffsets[2] * ztemp;
217  int outIndex = outOffsets[0] * xtemp + outOffsets[1] * ytemp + outOffsets[2] * ztemp;
218  if ( gtAlphaPtr[inIndex] != 0 )
219  {
220  countVisibleVoxels++;
221  if ( slicesAlphaPtr[inIndex] == 0 )
222  {
223  countHoles++;
224  double difference = ( double )gtPtr[inIndex] - testPtr[inIndex];
225  self->incAbsoluteHistogramWithHolesAtIndex( igsioMath::Round( fabs( difference ) ) );
226  absoluteDifferencesInAllHoles.push_back( fabs( difference ) );
227  if ( testAlphaPtr[inIndex] != 0 )
228  {
229  countFilledHoles++;
230  trueDifferences.push_back( difference );
231  self->incTrueHistogramAtIndex( igsioMath::Round( difference ) );
232  outPtrTru[outIndex] = difference; // cast to double to minimize precision loss
233  absoluteDifferences.push_back( fabs( difference ) );
234  self->incAbsoluteHistogramAtIndex( igsioMath::Round( fabs( difference ) ) );
235  outPtrAbs[outIndex] = fabs( difference );
236  }
237  }
238  else // not a hole, but these may still be different
239  {
240  //double difference = (double)gtPtr[inIndex] - testPtr[inIndex]; // cast to double to minimize precision loss
241  outPtrTru[outIndex] = 0.0; //difference;
242  outPtrAbs[outIndex] = 0.0; //abs(difference);
243  } // end slicesAlphaPtr check
244  }
245  else
246  {
247  outPtrTru[outIndex] = 0.0;
248  outPtrAbs[outIndex] = 0.0;
249  } // end gtAlphaPtr check
250  } // end x loop
251  } // end y loop
252  } // end z loop
253 
254  double absoluteMeanWithHoles( 0.0 ); // include holes in this computation
255  // on this iteration, add only holes
256  for ( unsigned int i = 0; i < absoluteDifferencesInAllHoles.size(); i++ )
257  {
258  absoluteMeanWithHoles += absoluteDifferencesInAllHoles[i];
259  }
260 
261  // mean calculations
262  double trueMean( 0.0 );
263  double absoluteMean( 0.0 ); // do not include holes in this computation
264  double rms( 0.0 );
265  for ( int i = 0; i < countFilledHoles; i++ )
266  {
267  trueMean += trueDifferences[i];
268  absoluteMean += absoluteDifferences[i];
269  rms += trueDifferences[i] * trueDifferences[i];
270  }
271 
272  // divide by the number of filled holes
273  if ( countFilledHoles != 0 )
274  {
275  trueMean /= countFilledHoles;
276  absoluteMean /= countFilledHoles;
277  rms = sqrt( rms / countFilledHoles );
278  }
279  else
280  {
281  trueMean = 0;
282  absoluteMean = 0;
283  rms = 0;
284  }
285 
286  // divide by the total number of holes
287  if ( countHoles != 0 )
288  {
289  absoluteMeanWithHoles /= countHoles;
290  }
291  else
292  {
293  absoluteMeanWithHoles = 0;
294  }
295 
296  // stdev calculations
297  double trueStdev = 0.0;
298  double absoluteStdev = 0.0;
299  for ( int i = 0; i < countFilledHoles; i++ )
300  {
301  trueStdev += pow( ( trueDifferences[i] - trueMean ), 2 );
302  absoluteStdev += pow( ( absoluteDifferences[i] - absoluteMean ), 2 );
303  }
304  if ( countFilledHoles != 0 )
305  {
306  trueStdev = sqrt( trueStdev / countFilledHoles );
307  absoluteStdev = sqrt( absoluteStdev / countFilledHoles );
308  }
309  else
310  {
311  trueStdev = 0;
312  absoluteStdev = 0;
313  }
314 
315  // need to sort, temporarily store in a list, sort, then assign back to vector <== THIS IS SLOW SLOW SLOW, as in about half a minute for this alone, so TODO: Make this faster
316  std::list<double> trueDifferencesList;
317  std::list<double> absoluteDifferencesList;
318  for ( int i = 0; i < countFilledHoles; i++ )
319  {
320  trueDifferencesList.push_front( trueDifferences.back() );
321  trueDifferences.pop_back();
322  absoluteDifferencesList.push_front( absoluteDifferences.back() );
323  absoluteDifferences.pop_back();
324  }
325  trueDifferencesList.sort();
326  absoluteDifferencesList.sort();
327  for ( int i = 0; i < countFilledHoles; i++ )
328  {
329  trueDifferences.push_back( trueDifferencesList.front() );
330  trueDifferencesList.pop_front();
331  absoluteDifferences.push_back( absoluteDifferencesList.front() );
332  absoluteDifferencesList.pop_front();
333  }
334 
335  double true5thPercentile( 0.0 );
336  double true95thPercentile( 0.0 );
337  double absolute5thPercentile( 0.0 );
338  double absolute95thPercentile( 0.0 );
339  double absoluteMedian( 0.0 );
340  double trueMedian( 0.0 );
341  double trueMinimum( 0.0 );
342  double trueMaximum( 0.0 );
343  double absoluteMinimum( 0.0 );
344  double absoluteMaximum( 0.0 );
345 
346  if ( countFilledHoles != 0 )
347  {
348  trueMinimum = trueDifferences[0];
349  trueMaximum = trueDifferences[countFilledHoles - 1];
350  absoluteMinimum = absoluteDifferences[0];
351  absoluteMaximum = absoluteDifferences[countFilledHoles - 1];
352 
353  // old median calculation
354  //double trueMedian = (countFilledHoles%2==0)?(trueDifferences[countFilledHoles/2]+trueDifferences[(countFilledHoles/2)-1])/2.0:trueDifferences[(countFilledHoles-1)/2];
355  //double absoluteMedian = (countFilledHoles%2==0)?(absoluteDifferences[countFilledHoles/2]+absoluteDifferences[(countFilledHoles/2)-1])/2.0:absoluteDifferences[(countFilledHoles-1)/2];
356 
357  double medianRank = ( countFilledHoles - 1 ) * 0.5;
358  double medianFraction = fmod( medianRank, 1.0 );
359  int medianFloor = ( int )floor( medianRank );
360  if ( medianFloor < 0 )
361  {
362  medianFloor = 0;
363  }
364  int medianCeil = ( int )ceil( medianRank );
365  if ( medianCeil > ( countFilledHoles - 1 ) )
366  {
367  medianCeil = ( countFilledHoles - 1 );
368  }
369  trueMedian = trueDifferences[medianFloor] * ( 1 - medianFraction ) + trueDifferences[medianCeil] * medianFraction;
370  absoluteMedian = absoluteDifferences[medianFloor] * ( 1 - medianFraction ) + absoluteDifferences[medianCeil] * medianFraction;
371 
372  double percentile5rank = ( countFilledHoles - 1 ) * 0.05;
373  double percentile5fraction = fmod( percentile5rank, 1.0 );
374  int percentile5floor = ( int )floor( percentile5rank );
375  if ( percentile5floor < 0 )
376  {
377  percentile5floor = 0;
378  }
379  int percentile5ceil = ( int )ceil( percentile5rank );
380  if ( percentile5ceil > ( countFilledHoles - 1 ) )
381  {
382  percentile5ceil = ( countFilledHoles - 1 );
383  }
384  true5thPercentile = trueDifferences[percentile5floor] * ( 1 - percentile5fraction ) + trueDifferences[percentile5ceil] * percentile5fraction;
385  absolute5thPercentile = absoluteDifferences[percentile5floor] * ( 1 - percentile5fraction ) + absoluteDifferences[percentile5ceil] * percentile5fraction;
386 
387  double percentile95rank = ( countFilledHoles - 1 ) * 0.95;
388  double percentile95fraction = fmod( percentile95rank, 1.0 );
389  int percentile95floor = ( int )floor( percentile95rank );
390  if ( percentile95floor < 0 )
391  {
392  percentile95floor = 0;
393  }
394  int percentile95ceil = ( int )ceil( percentile95rank );
395  if ( percentile95ceil > ( countFilledHoles - 1 ) )
396  {
397  percentile95ceil = ( countFilledHoles - 1 );
398  }
399  true95thPercentile = trueDifferences[percentile95floor] * ( 1 - percentile95fraction ) + trueDifferences[percentile95ceil] * percentile95fraction;
400  absolute95thPercentile = absoluteDifferences[percentile95floor] * ( 1 - percentile95fraction ) + absoluteDifferences[percentile95ceil] * percentile95fraction;
401  }
402 
403  self->SetNumberOfHoles( countHoles );
404  self->SetNumberVoxelsVisible( countVisibleVoxels );
405  self->SetNumberOfFilledHoles( countFilledHoles );
406 
407  self->SetTrue95thPercentile( true95thPercentile );
408  self->SetTrue5thPercentile( true5thPercentile );
409  self->SetTrueMaximum( trueMaximum );
410  self->SetTrueMinimum( trueMinimum );
411  self->SetTrueMedian( trueMedian );
412  self->SetTrueStdev( trueStdev );
413  self->SetTrueMean( trueMean );
414 
415  self->SetAbsolute95thPercentile( absolute95thPercentile );
416  self->SetAbsolute5thPercentile( absolute5thPercentile );
417  self->SetAbsoluteMaximum( absoluteMaximum );
418  self->SetAbsoluteMinimum( absoluteMinimum );
419  self->SetAbsoluteMedian( absoluteMedian );
420  self->SetAbsoluteStdev( absoluteStdev );
421  self->SetAbsoluteMean( absoluteMean );
422 
423  self->SetAbsoluteMeanWithHoles( absoluteMeanWithHoles );
424 
425  self->SetRMS( rms );
426 }
427 
429  vtkInformation* vtkNotUsed( request ),
430  vtkInformationVector** vtkNotUsed( inputVector ),
431  vtkInformationVector* vtkNotUsed( outputVector ),
432  vtkImageData** *inData,
433  vtkImageData** outData,
434  int outExt[6], int threadId )
435 {
436  if ( inData[INPUT_GROUND_TRUTH_VOLUME][0] == NULL
437  || inData[INPUT_GROUND_TRUTH_VOLUME_ALPHA][0] == NULL
438  || inData[INPUT_TEST_VOLUME][0] == NULL
439  || inData[INPUT_TEST_VOLUME_ALPHA][0] == NULL
440  || inData[INPUT_SLICES_VOLUME_ALPHA][0] == NULL )
441  {
442  vtkErrorMacro( << "Input must be specified." );
443  return;
444  }
445 
446  // this filter expects that all inputs are the same type as output.
447  if ( inData[INPUT_GROUND_TRUTH_VOLUME_ALPHA][0]->GetScalarType() != inData[INPUT_GROUND_TRUTH_VOLUME][0]->GetScalarType()
448  || inData[INPUT_TEST_VOLUME][0]->GetScalarType() != inData[INPUT_GROUND_TRUTH_VOLUME][0]->GetScalarType()
449  || inData[INPUT_TEST_VOLUME_ALPHA][0]->GetScalarType() != inData[INPUT_GROUND_TRUTH_VOLUME][0]->GetScalarType()
450  || inData[INPUT_SLICES_VOLUME_ALPHA][0]->GetScalarType() != inData[INPUT_GROUND_TRUTH_VOLUME][0]->GetScalarType() )
451  {
452  vtkErrorMacro( << "Execute: input ScalarTypes must match ScalarType "
453  << inData[INPUT_GROUND_TRUTH_VOLUME][0]->GetScalarType() );
454  return;
455  }
456 
457  vtkImageData* gtVolData = inData[INPUT_GROUND_TRUTH_VOLUME][0];
458  void* gtPtr = gtVolData->GetScalarPointer();
459  void* gtAlphaPtr = inData[INPUT_GROUND_TRUTH_VOLUME_ALPHA][0]->GetScalarPointer();
460  void* testPtr = inData[INPUT_TEST_VOLUME][0]->GetScalarPointer();
461  void* testAlphaPtr = inData[INPUT_TEST_VOLUME_ALPHA][0]->GetScalarPointer();
462  void* slicesAlphaPtr = inData[INPUT_SLICES_VOLUME_ALPHA][0]->GetScalarPointer();
463 
464  vtkImageData* outVolDataTru = inData[INPUT_GROUND_TRUTH_VOLUME][0];
465  double* outPtrTru = static_cast< double* >( outVolDataTru->GetScalarPointer() );
466  double* outPtrAbs = static_cast< double* >( outData[OUTPUT_ABS_DIFF_VOLUME]->GetScalarPointer() );
467 
468  switch ( gtVolData->GetScalarType() )
469  {
470  vtkTemplateMacro(
471  vtkPlusCompareVolumesExecute( this, gtVolData, outVolDataTru,
472  static_cast<VTK_TT*>( gtPtr ), static_cast<VTK_TT*>( gtAlphaPtr ),
473  static_cast<VTK_TT*>( testPtr ), static_cast<VTK_TT*>( testAlphaPtr ),
474  static_cast<VTK_TT*>( slicesAlphaPtr ),
475  outPtrTru, outPtrAbs, outExt, threadId )
476  );
477  default:
478  vtkErrorMacro( << "Execute: Unknown ScalarType" );
479  return;
480  }
481 }
482 
484 {
485  /*if (port == 1)
486  {
487  info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
488  }*/
489  info->Set( vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData" );
490  return 1;
491 }
vtkImageData * GetOutputAbsoluteDifferenceImage()
virtual void SetInputGT(vtkDataObject *input)
int
Definition: phidget22.h:3069
void incAbsoluteHistogramWithHolesAtIndex(int value)
vtkImageData * GetOutputTrueDifferenceImage()
void incAbsoluteHistogramAtIndex(int value)
for i
static const int INPUT_GROUND_TRUTH_VOLUME_ALPHA
virtual void SetInputTestAlpha(vtkDataObject *input)
virtual void SetInputTest(vtkDataObject *input)
int port
Definition: phidget22.h:2454
virtual int FillInputPortInformation(int port, vtkInformation *info)
static const int INPUT_SLICES_VOLUME_ALPHA
virtual int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *)
virtual void SetInputGTAlpha(vtkDataObject *input)
static const int INPUT_GROUND_TRUTH_VOLUME
void ThreadedRequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector, vtkImageData ***inData, vtkImageData **outData, int ext[6], int id)
void vtkPlusCompareVolumesExecute(vtkPlusCompareVolumes *self, vtkImageData *inData, vtkImageData *outData, T *gtPtr, T *gtAlphaPtr, T *testPtr, T *testAlphaPtr, T *slicesAlphaPtr, double *outPtrTru, double *outPtrAbs, int outExt[6], int id)
vtkStandardNewMacro(vtkPlusCompareVolumes)
const char const char * value
Definition: phidget22.h:5111
static const int OUTPUT_ABS_DIFF_VOLUME
static const int INPUT_TEST_VOLUME
static const int INPUT_TEST_VOLUME_ALPHA
void incTrueHistogramAtIndex(int value)
virtual void SetInputSliceAlpha(vtkDataObject *input)