PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
ProbeCalibration.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 =========================================================Plus=header=end*/
6 
13 #include "PlusConfigure.h"
14 
16 #include "PlusMath.h"
17 #include "vtkCallbackCommand.h"
18 #include "vtkCommand.h"
19 #include "vtkMath.h"
20 #include "vtkMatrix4x4.h"
22 #include "vtkIGSIOSequenceIO.h"
23 #include "vtkSmartPointer.h"
24 #include "vtkIGSIOTrackedFrameList.h"
25 #include "vtkTransform.h"
26 #include "vtkIGSIOTransformRepository.h"
27 #include "vtkIGSIOTransformRepository.h"
28 #include "vtkXMLDataElement.h"
29 #include "vtkXMLUtilities.h"
30 #include "vtksys/CommandLineArguments.hxx"
31 #include "vtksys/SystemTools.hxx"
32 #include <iostream>
33 #include <stdlib.h>
34 
35 #ifndef _WIN32
36 const double ERROR_THRESHOLD = LINUXTOLERANCEPERCENT;
37 #else
38 const double ERROR_THRESHOLD = 0.05;
39 #endif
40 
41 int CompareCalibrationResultsWithBaseline(const char* baselineFileName, const char* currentResultFileName, double translationErrorThreshold, double rotationErrorThreshold);
42 
43 int main(int argc, char* argv[])
44 {
45 
46  bool printHelp(false);
47  std::string inputCalibrationSeqMetafile;
48  std::string inputValidationSeqMetafile;
49 
50  std::string inputConfigFileName;
51  std::string inputBaselineFileName;
52  std::string resultConfigFileName;
53 
54 #ifndef _WIN32
55  double inputTranslationErrorThreshold(LINUXTOLERANCE * 2); // *PE* methods on linux can have up to about 0.7mm translation error
56  double inputRotationErrorThreshold(LINUXTOLERANCE);
57 #else
58  double inputTranslationErrorThreshold(1e-10);
59  double inputRotationErrorThreshold(1e-10);
60 #endif
61 
62  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
63 
64  vtksys::CommandLineArguments args;
65  args.Initialize(argc, argv);
66 
67  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
68 
69  args.AddArgument("--calibration-seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputCalibrationSeqMetafile, "Sequence metafile name of input calibration dataset.");
70  args.AddArgument("--validation-seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputValidationSeqMetafile, "Sequence metafile name of input validation dataset. Optional, if not specified then the calibration error will be computed from the calibration dataset.");
71 
72  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFileName, "Configuration file name)");
73  args.AddArgument("--baseline-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputBaselineFileName, "Name of file storing baseline calibration results. Optional.");
74 
75  args.AddArgument("--translation-error-threshold", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputTranslationErrorThreshold, "Translation error threshold in mm. Used for baseline comparison.");
76  args.AddArgument("--rotation-error-threshold", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputRotationErrorThreshold, "Rotation error threshold in degrees. Used for baseline comparison.");
77 
78  args.AddArgument("--output-config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &resultConfigFileName, "Result configuration file name. Optional.");
79 
80  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
81 
82  if (!args.Parse())
83  {
84  std::cerr << "Problem parsing arguments" << std::endl;
85  std::cout << "Help: " << args.GetHelp() << std::endl;
86  exit(EXIT_FAILURE);
87  }
88 
89  if (printHelp)
90  {
91  std::cout << args.GetHelp() << std::endl;
92  exit(EXIT_SUCCESS);
93  }
94 
95  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
96 
97  LOG_INFO("Read configuration file...");
98 
99  // Read configuration
100  vtkSmartPointer<vtkXMLDataElement> configRootElement = vtkSmartPointer<vtkXMLDataElement>::New();
101  if (PlusXmlUtils::ReadDeviceSetConfigurationFromFile(configRootElement, inputConfigFileName.c_str()) == PLUS_FAIL)
102  {
103  LOG_ERROR("Unable to read configuration from file " << inputConfigFileName.c_str());
104  return EXIT_FAILURE;
105  }
107 
108  // Read coordinate definitions
109  vtkSmartPointer<vtkIGSIOTransformRepository> transformRepository = vtkSmartPointer<vtkIGSIOTransformRepository>::New();
110  if (transformRepository->ReadConfiguration(configRootElement) != PLUS_SUCCESS)
111  {
112  LOG_ERROR("Failed to read CoordinateDefinitions!");
113  return EXIT_FAILURE;
114  }
115 
116  vtkSmartPointer<vtkPlusProbeCalibrationAlgo> freehandCalibration = vtkSmartPointer<vtkPlusProbeCalibrationAlgo>::New();
117  freehandCalibration->ReadConfiguration(configRootElement);
118 
119  PlusFidPatternRecognition patternRecognition;
121  patternRecognition.ReadConfiguration(configRootElement);
122 
123  // Load and segment calibration image
124  LOG_INFO("Read calibration sequence file...");
125  vtkSmartPointer<vtkIGSIOTrackedFrameList> calibrationTrackedFrameList = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
126  if (vtkIGSIOSequenceIO::Read(inputCalibrationSeqMetafile, calibrationTrackedFrameList) != PLUS_SUCCESS)
127  {
128  LOG_ERROR("Reading calibration images from '" << inputCalibrationSeqMetafile << "' failed!");
129  return EXIT_FAILURE;
130  }
131 
132  LOG_INFO("Segment fiducials...");
133  int numberOfSuccessfullySegmentedCalibrationImages = 0;
134  if (patternRecognition.RecognizePattern(calibrationTrackedFrameList, error, &numberOfSuccessfullySegmentedCalibrationImages) != PLUS_SUCCESS)
135  {
136  LOG_ERROR("Error occured during segmentation of calibration images!");
137  return EXIT_FAILURE;
138  }
139 
140  LOG_INFO("Segmentation success rate of calibration images: " << numberOfSuccessfullySegmentedCalibrationImages << " out of " << calibrationTrackedFrameList->GetNumberOfTrackedFrames());
141 
142  if (!inputValidationSeqMetafile.empty())
143  {
144  // Load and segment validation image
145  LOG_INFO("Read validation sequence file...");
146  vtkSmartPointer<vtkIGSIOTrackedFrameList> validationTrackedFrameList = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
147  if (vtkIGSIOSequenceIO::Read(inputValidationSeqMetafile, validationTrackedFrameList) != PLUS_SUCCESS)
148  {
149  LOG_ERROR("Reading validation images from '" << inputValidationSeqMetafile << "' failed!");
150  return EXIT_FAILURE;
151  }
152  LOG_INFO("Segment fiducials...");
153  int numberOfSuccessfullySegmentedValidationImages = 0;
154  if (patternRecognition.RecognizePattern(validationTrackedFrameList, error, &numberOfSuccessfullySegmentedValidationImages) != PLUS_SUCCESS)
155  {
156  LOG_ERROR("Error occured during segmentation of validation images!");
157  return EXIT_FAILURE;
158  }
159 
160  LOG_INFO("Segmentation success rate of validation images: " << numberOfSuccessfullySegmentedValidationImages << " out of " << validationTrackedFrameList->GetNumberOfTrackedFrames());
161 
162  // Calibrate using independent data for validation
163  LOG_INFO("Calibrate...");
164  if (freehandCalibration->Calibrate(validationTrackedFrameList, calibrationTrackedFrameList, transformRepository, patternRecognition.GetFidLineFinder()->GetNWires()) != PLUS_SUCCESS)
165  {
166  LOG_ERROR("Calibration failed!");
167  return EXIT_FAILURE;
168  }
169 
170  }
171  else
172  {
173  LOG_INFO("Validation data set is not provided, therefore error is computed from the calibration data set");
174  // Calibrate using the same data for calibration and validation
175  LOG_INFO("Calibrate...");
176  if (freehandCalibration->Calibrate(calibrationTrackedFrameList, calibrationTrackedFrameList, transformRepository, patternRecognition.GetFidLineFinder()->GetNWires()) != PLUS_SUCCESS)
177  {
178  LOG_ERROR("Calibration failed!");
179  return EXIT_FAILURE;
180  }
181  }
182 
183  // Save result to configuration file
184  if (!resultConfigFileName.empty())
185  {
186  LOG_INFO("Save results to: " << resultConfigFileName);
187  if (transformRepository->WriteConfiguration(vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationData()) != PLUS_SUCCESS)
188  {
189  LOG_ERROR("Unable to save freehand calibration result in configuration XML tree!");
190  return EXIT_FAILURE;
191  }
192 
193  igsioCommon::XML::PrintXML(resultConfigFileName.c_str(), vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationData());
194  }
195 
196  if (!inputBaselineFileName.empty())
197  {
198  LOG_INFO("Compare with baseline: " << inputBaselineFileName);
199  // Compare results to baseline
200  std::string currentConfigFileName = vtkPlusConfig::GetInstance()->GetOutputPath(
201  vtkPlusConfig::GetInstance()->GetApplicationStartTimestamp() + ".Calibration.results.xml");
202  if (CompareCalibrationResultsWithBaseline(inputBaselineFileName.c_str(), currentConfigFileName.c_str(), inputTranslationErrorThreshold, inputRotationErrorThreshold) != 0)
203  {
204  LOG_ERROR("Comparison of calibration data to baseline failed");
205  std::cout << "Exit failure!!!" << std::endl;
206 
207  return EXIT_FAILURE;
208  }
209  }
210 
211  std::cout << "Calibration has been completed successfully" << std::endl;
212  return EXIT_SUCCESS;
213 }
214 
215 //-------------------------------------------------------------------------------------------------
216 
217 // return the number of differences
218 int CompareCalibrationResultsWithBaseline(const char* baselineFileName, const char* currentResultFileName, double translationErrorThreshold, double rotationErrorThreshold)
219 {
220  int numberOfFailures = 0;
221 
222 #ifndef _WIN32
223  double absoluteErrorTolerance = LINUXTOLERANCE * 2; // *PE* methods on linux can have up to about 0.7mm translation error
224 #else
225  double absoluteErrorTolerance = 50;
226 #endif
227 
228  vtkSmartPointer<vtkXMLDataElement> baselineRootElem = vtkSmartPointer<vtkXMLDataElement>::Take(
229  vtkXMLUtilities::ReadElementFromFile(baselineFileName));
230  vtkSmartPointer<vtkXMLDataElement> currentRootElem = vtkSmartPointer<vtkXMLDataElement>::Take(
231  vtkXMLUtilities::ReadElementFromFile(currentResultFileName));
232 
233  // check to make sure we have the right element
234  if (baselineRootElem == NULL)
235  {
236  LOG_ERROR("Reading baseline data file failed: " << baselineFileName);
237  return ++numberOfFailures;
238  }
239  if (currentRootElem == NULL)
240  {
241  LOG_ERROR("Reading newly generated data file failed: " << currentResultFileName);
242  return ++numberOfFailures;
243  }
244 
245  {
246  //<CalibrationResults>
247  vtkXMLDataElement* calibrationResultsBaseline = baselineRootElem->FindNestedElementWithName("CalibrationResults");
248  vtkXMLDataElement* calibrationResults = currentRootElem->FindNestedElementWithName("CalibrationResults");
249 
250  if (calibrationResultsBaseline == NULL)
251  {
252  LOG_ERROR("Reading baseline CalibrationResults tag failed: " << baselineFileName);
253  return ++numberOfFailures;
254  }
255 
256  if (calibrationResults == NULL)
257  {
258  LOG_ERROR("Reading current CalibrationResults tag failed: " << currentResultFileName);
259  return ++numberOfFailures;
260  }
261 
262  {
263  // <Transform>
264  vtkXMLDataElement* transformBaseline = calibrationResultsBaseline->FindNestedElementWithName("Transform");
265  vtkXMLDataElement* transform = calibrationResults->FindNestedElementWithName("Transform");
266 
267  if (transformBaseline == NULL)
268  {
269  LOG_ERROR("Reading baseline Transform tag failed: " << baselineFileName);
270  return ++numberOfFailures;
271  }
272 
273  if (transform == NULL)
274  {
275  LOG_ERROR("Reading current Transform tag failed: " << currentResultFileName);
276  return ++numberOfFailures;
277  }
278 
279  // ImageToProbe
280  double blTransformImageToProbe[16];
281  double cTransformImageToProbe[16];
282  const char* blFrom = transformBaseline->GetAttribute("From");
283  const char* cFrom = transform->GetAttribute("From");
284  const char* blTo = transformBaseline->GetAttribute("To");
285  const char* cTo = transform->GetAttribute("To");
286 
287  if (STRCASECMP(blFrom, "Image") != 0 || STRCASECMP(blTo, "Probe"))
288  {
289  LOG_ERROR("Baseline From and To tags are invalid!");
290  numberOfFailures++;
291  }
292  else if (STRCASECMP(cFrom, "Image") != 0 || STRCASECMP(cTo, "Probe"))
293  {
294  LOG_ERROR("Current From and To tags are invalid!");
295  numberOfFailures++;
296  }
297  else if (!transformBaseline->GetVectorAttribute("Matrix", 16, blTransformImageToProbe))
298  {
299  LOG_ERROR("Baseline Matrix tag is missing");
300  numberOfFailures++;
301  }
302  else if (!transform->GetVectorAttribute("Matrix", 16, cTransformImageToProbe))
303  {
304  LOG_ERROR("Current Matrix tag is missing");
305  numberOfFailures++;
306  }
307  else
308  {
309  vtkSmartPointer<vtkMatrix4x4> baseTransMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
310  vtkSmartPointer<vtkMatrix4x4> currentTransMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
311  for (int i = 0; i < 4; i++)
312  {
313  for (int j = 0; j < 4; j++)
314  {
315  baseTransMatrix->SetElement(i, j, blTransformImageToProbe[4 * i + j]);
316  currentTransMatrix->SetElement(i, j, cTransformImageToProbe[4 * i + j]);
317  }
318  }
319 
320  double translationError = igsioMath::GetPositionDifference(baseTransMatrix, currentTransMatrix);
321  if (translationError > translationErrorThreshold)
322  {
323  LOG_ERROR("TransformImageToProbe translation difference (compared to baseline) is higher than expected: " << translationError << " mm (threshold: " << translationErrorThreshold << " mm). ");
324  numberOfFailures++;
325  }
326 
327  double rotationError = igsioMath::GetOrientationDifference(baseTransMatrix, currentTransMatrix);
328  if (rotationError > rotationErrorThreshold)
329  {
330  LOG_ERROR("TransformImageToProbe rotation difference (compared to baseline) is higher than expected: " << rotationError << " degree (threshold: " << rotationErrorThreshold << " degree). ");
331  numberOfFailures++;
332  }
333  }
334  } // </Transforms>
335  } // </CalibrationResults>
336 
337 
338  {
339  // <ErrorReport>
340  vtkXMLDataElement* errorReportBaseline = baselineRootElem->FindNestedElementWithName("ErrorReport");
341  vtkXMLDataElement* errorReport = currentRootElem->FindNestedElementWithName("ErrorReport");
342 
343  if (errorReportBaseline == NULL)
344  {
345  LOG_ERROR("Reading baseline ErrorReports tag failed: " << baselineFileName);
346  return ++numberOfFailures;
347  }
348 
349  if (errorReport == NULL)
350  {
351  LOG_ERROR("Reading current ErrorReports tag failed: " << currentResultFileName);
352  return ++numberOfFailures;
353  }
354 
355  {
356  // <ReprojectionError3DStatistics>
357  vtkXMLDataElement* reprojectionError3DStatisticsBaseline = errorReportBaseline->FindNestedElementWithName("ReprojectionError3DStatistics");
358  vtkXMLDataElement* reprojectionError3DStatistics = errorReport->FindNestedElementWithName("ReprojectionError3DStatistics");
359 
360  if (reprojectionError3DStatisticsBaseline == NULL || reprojectionError3DStatistics == NULL)
361  {
362  LOG_ERROR("Reading ReprojectionError3DStatistics tag failed");
363  return ++numberOfFailures;
364  }
365 
366  double blReprojectionError3DValidationMeanMm = 0.0;
367  double blReprojectionError3DValidationStdDevMm = 0.0;
368  if (! reprojectionError3DStatisticsBaseline->GetScalarAttribute("ValidationMeanMm", blReprojectionError3DValidationMeanMm)
369  || ! reprojectionError3DStatisticsBaseline->GetScalarAttribute("ValidationStdDevMm", blReprojectionError3DValidationStdDevMm))
370  {
371  LOG_ERROR("Reading baseline validation ReprojectionError3DStatistics statistics failed: " << baselineFileName);
372  return ++numberOfFailures;
373  }
374 
375  double cReprojectionError3DValidationMeanMm = 0.0;
376  double cReprojectionError3DValidationStdDevMm = 0.0;
377  if (! reprojectionError3DStatistics->GetScalarAttribute("ValidationMeanMm", cReprojectionError3DValidationMeanMm)
378  || ! reprojectionError3DStatistics->GetScalarAttribute("ValidationStdDevMm", cReprojectionError3DValidationStdDevMm))
379  {
380  LOG_ERROR("Reading current validation ReprojectionError3DStatistics statistics failed: " << currentResultFileName);
381  return ++numberOfFailures;
382  }
383 
384  double ratioValidationMean = 1.0 * blReprojectionError3DValidationMeanMm / cReprojectionError3DValidationMeanMm;
385  double absoluteErrorValidationMean = fabs(blReprojectionError3DValidationMeanMm - cReprojectionError3DValidationMeanMm);
386  if ((ratioValidationMean > 1 + ERROR_THRESHOLD || ratioValidationMean < 1 - ERROR_THRESHOLD) && (absoluteErrorValidationMean > absoluteErrorTolerance))
387  {
388  LOG_ERROR("ReprojectionError3DStatistics/ValidationMeanMm mismatch: current=" << cReprojectionError3DValidationMeanMm << ", baseline=" << blReprojectionError3DValidationMeanMm);
389  return ++numberOfFailures;
390  }
391  double ratioValidationStdDev = 1.0 * blReprojectionError3DValidationStdDevMm / cReprojectionError3DValidationStdDevMm;
392  double absoluteErrorValidationStdDev = fabs(blReprojectionError3DValidationStdDevMm - cReprojectionError3DValidationStdDevMm);
393  if ((ratioValidationStdDev > 1 + ERROR_THRESHOLD || ratioValidationStdDev < 1 - ERROR_THRESHOLD) && (absoluteErrorValidationStdDev > absoluteErrorTolerance))
394  {
395  LOG_ERROR("ReprojectionError3DStatistics/ValidationStdDevMm mismatch: current=" << cReprojectionError3DValidationStdDevMm << ", baseline=" << blReprojectionError3DValidationStdDevMm);
396  return ++numberOfFailures;
397  }
398 
399  double blReprojectionError3DCalibrationMeanMm = 0.0;
400  double blReprojectionError3DCalibrationStdDevMm = 0.0;
401  if (! reprojectionError3DStatisticsBaseline->GetScalarAttribute("CalibrationMeanMm", blReprojectionError3DCalibrationMeanMm)
402  || ! reprojectionError3DStatisticsBaseline->GetScalarAttribute("CalibrationStdDevMm", blReprojectionError3DCalibrationStdDevMm))
403  {
404  LOG_ERROR("Reading baseline calibration ReprojectionError3DStatistics statistics failed: " << baselineFileName);
405  return ++numberOfFailures;
406  }
407 
408  double cReprojectionError3DCalibrationMeanMm = 0.0;
409  double cReprojectionError3DCalibrationStdDevMm = 0.0;
410  if (! reprojectionError3DStatistics->GetScalarAttribute("CalibrationMeanMm", cReprojectionError3DCalibrationMeanMm)
411  || ! reprojectionError3DStatistics->GetScalarAttribute("CalibrationStdDevMm", cReprojectionError3DCalibrationStdDevMm))
412  {
413  LOG_ERROR("Reading current calibration ReprojectionError3DStatistics statistics failed: " << currentResultFileName);
414  return ++numberOfFailures;
415  }
416 
417  double ratioCalibrationMean = 1.0 * blReprojectionError3DCalibrationMeanMm / cReprojectionError3DCalibrationMeanMm;
418  double absoluteErrorCalibrationMean = fabs(blReprojectionError3DCalibrationMeanMm - cReprojectionError3DCalibrationMeanMm);
419  if ((ratioCalibrationMean > 1 + ERROR_THRESHOLD || ratioCalibrationMean < 1 - ERROR_THRESHOLD) && (absoluteErrorCalibrationMean > absoluteErrorTolerance))
420  {
421  LOG_ERROR("ReprojectionError3DStatistics/CalibrationMeanMm mismatch: current=" << cReprojectionError3DCalibrationMeanMm << ", baseline=" << blReprojectionError3DCalibrationMeanMm);
422  return ++numberOfFailures;
423  }
424  double ratioCalibrationStdDev = 1.0 * blReprojectionError3DCalibrationStdDevMm / cReprojectionError3DCalibrationStdDevMm;
425  double absoluteErrorCalibrationStdDev = fabs(blReprojectionError3DCalibrationStdDevMm - cReprojectionError3DCalibrationStdDevMm);
426  if ((ratioCalibrationStdDev > 1 + ERROR_THRESHOLD || ratioCalibrationStdDev < 1 - ERROR_THRESHOLD) && (absoluteErrorCalibrationStdDev > absoluteErrorTolerance))
427  {
428  LOG_ERROR("ReprojectionError3DStatistics/CalibrationStdDevMm mismatch: current=" << cReprojectionError3DCalibrationStdDevMm << ", baseline=" << blReprojectionError3DCalibrationStdDevMm);
429  return ++numberOfFailures;
430  }
431  } // </ReprojectionError3DStatistics>
432 
433  {
434  // <ReprojectionError2DStatistics>
435  vtkXMLDataElement* reprojectionError2DStatisticsBaseline = errorReportBaseline->FindNestedElementWithName("ReprojectionError2DStatistics");
436  vtkXMLDataElement* reprojectionError2DStatistics = errorReport->FindNestedElementWithName("ReprojectionError2DStatistics");
437 
438  if (reprojectionError2DStatisticsBaseline == NULL || reprojectionError2DStatistics == NULL)
439  {
440  LOG_ERROR("Reading ReprojectionError2DStatistics tag failed");
441  return ++numberOfFailures;
442  }
443 
444  // <Wire>
445  for (int wireIndex = 0; wireIndex < reprojectionError2DStatisticsBaseline->GetNumberOfNestedElements(); ++wireIndex)
446  {
447  vtkXMLDataElement* wireBaseline = reprojectionError2DStatisticsBaseline->GetNestedElement(wireIndex);
448  vtkXMLDataElement* wire = reprojectionError2DStatistics->GetNestedElement(wireIndex);
449  if (!wireBaseline || !wire || STRCASECMP(wireBaseline->GetName(), "Wire") != 0 || STRCASECMP(wire->GetName(), "Wire") != 0)
450  {
451  LOG_ERROR("Invalid Wire element in ReprojectionError2DStatistics");
452  ++numberOfFailures;
453  continue;
454  }
455 
456  if (STRCASECMP(wireBaseline->GetAttribute("Name"), wire->GetAttribute("Name")) != 0)
457  {
458  LOG_ERROR("Wire name mismatch: " << wireBaseline->GetAttribute("Name") << " <> " << wire->GetAttribute("Name"));
459  ++numberOfFailures;
460  continue;
461  }
462 
463  double blValidationMeanPx[2];
464  double blValidationStdDevPx[2];
465  if (! wireBaseline->GetVectorAttribute("ValidationMeanPx", 2, blValidationMeanPx)
466  || ! wireBaseline->GetVectorAttribute("ValidationStdDevPx", 2, blValidationStdDevPx))
467  {
468  LOG_ERROR("Reading baseline validation ReprojectionError2DStatistics failed for wire " << wireIndex);
469  ++numberOfFailures;
470  continue;
471  }
472 
473  double cValidationMeanPx[2];
474  double cValidationStdDevPx[2];
475  if (! wire->GetVectorAttribute("ValidationMeanPx", 2, cValidationMeanPx)
476  || ! wire->GetVectorAttribute("ValidationStdDevPx", 2, cValidationStdDevPx))
477  {
478  LOG_ERROR("Reading current validation ReprojectionError2DStatistics failed for wire " << wireIndex);
479  ++numberOfFailures;
480  continue;
481  }
482 
483  for (int i = 0; i < 2; i++)
484  {
485  double ratioMean = 1.0 * blValidationMeanPx[i] / cValidationMeanPx[i];
486  double absoluteErrorMean = fabs(blValidationMeanPx[i] - cValidationMeanPx[i]);
487  if ((ratioMean > 1 + ERROR_THRESHOLD || ratioMean < 1 - ERROR_THRESHOLD) && (absoluteErrorMean > absoluteErrorTolerance))
488  {
489  LOG_ERROR("ValidationMeanPx mismatch for wire " << wireIndex << ": current=" << cValidationMeanPx[i] << ", baseline=" << blValidationMeanPx[i]);
490  return ++numberOfFailures;
491  }
492  double ratioStdDev = 1.0 * blValidationStdDevPx[i] / cValidationStdDevPx[i];
493  double absoluteErrorStdDev = fabs(blValidationStdDevPx[i] - cValidationStdDevPx[i]);
494  if ((ratioStdDev > 1 + ERROR_THRESHOLD || ratioStdDev < 1 - ERROR_THRESHOLD) && (absoluteErrorStdDev > absoluteErrorTolerance))
495  {
496  LOG_ERROR("ValidationStdDevPx mismatch for wire " << wireIndex << ": current=" << cValidationStdDevPx[i] << ", baseline=" << blValidationStdDevPx[i]);
497  return ++numberOfFailures;
498  }
499  }
500 
501  double blCalibrationMeanPx[2];
502  double blCalibrationStdDevPx[2];
503  if (! wireBaseline->GetVectorAttribute("CalibrationMeanPx", 2, blCalibrationMeanPx)
504  || ! wireBaseline->GetVectorAttribute("CalibrationStdDevPx", 2, blCalibrationStdDevPx))
505  {
506  LOG_ERROR("Reading baseline calibration ReprojectionError2DStatistics failed for wire " << wireIndex);
507  ++numberOfFailures;
508  continue;
509  }
510 
511  double cCalibrationMeanPx[2];
512  double cCalibrationStdDevPx[2];
513  if (! wire->GetVectorAttribute("CalibrationMeanPx", 2, cCalibrationMeanPx)
514  || ! wire->GetVectorAttribute("CalibrationStdDevPx", 2, cCalibrationStdDevPx))
515  {
516  LOG_ERROR("Reading current calibration ReprojectionError2DStatistics failed for wire " << wireIndex);
517  ++numberOfFailures;
518  continue;
519  }
520 
521  for (int i = 0; i < 2; i++)
522  {
523  double ratioMean = 1.0 * blCalibrationMeanPx[i] / cCalibrationMeanPx[i];
524  double absoluteErrorMean = fabs(blCalibrationMeanPx[i] - cCalibrationMeanPx[i]);
525  if ((ratioMean > 1 + ERROR_THRESHOLD || ratioMean < 1 - ERROR_THRESHOLD) && (absoluteErrorMean > absoluteErrorTolerance))
526  {
527  LOG_ERROR("CalibrationMeanPx mismatch for wire " << wireIndex << ": current=" << cCalibrationMeanPx[i] << ", baseline=" << blCalibrationMeanPx[i]);
528  return ++numberOfFailures;
529  }
530  double ratioStdDev = 1.0 * blCalibrationStdDevPx[i] / cCalibrationStdDevPx[i];
531  double absoluteErrorStdDev = fabs(blCalibrationStdDevPx[i] - cCalibrationStdDevPx[i]);
532  if ((ratioStdDev > 1 + ERROR_THRESHOLD || ratioStdDev < 1 - ERROR_THRESHOLD) && (absoluteErrorStdDev > absoluteErrorTolerance))
533  {
534  LOG_ERROR("CalibrationStdDevPx mismatch for wire " << wireIndex << ": current=" << cCalibrationStdDevPx[i] << ", baseline=" << blCalibrationStdDevPx[i]);
535  return ++numberOfFailures;
536  }
537  }
538  } // </Wire>
539  } // </ReprojectionError2DStatistics>
540 
541  {
542  // <ValidationData>
543  vtkXMLDataElement* validationDataBaseline = errorReportBaseline->FindNestedElementWithName("ValidationData");
544  vtkXMLDataElement* validationData = errorReport->FindNestedElementWithName("ValidationData");
545 
546  if (validationDataBaseline == NULL || validationData == NULL)
547  {
548  LOG_ERROR("Reading ValidationData tag failed");
549  return ++numberOfFailures;
550  }
551 
552  for (int frameIndex = 0; frameIndex < validationDataBaseline->GetNumberOfNestedElements(); ++frameIndex) // <Frame>
553  {
554  vtkXMLDataElement* frameBaseline = validationDataBaseline->GetNestedElement(frameIndex);
555  vtkXMLDataElement* frame = validationData->GetNestedElement(frameIndex);
556  if (!frameBaseline || !frame || STRCASECMP(frameBaseline->GetName(), "Frame") != 0 || STRCASECMP(frame->GetName(), "Frame") != 0)
557  {
558  LOG_ERROR("Invalid Frame element #" << frameIndex);
559  ++numberOfFailures;
560  continue;
561  }
562 
563  const char* segmentationStatusBaseline = frameBaseline->GetAttribute("SegmentationStatus");
564  const char* segmentationStatus = frame->GetAttribute("SegmentationStatus");
565 
566  if (STRCASECMP(segmentationStatusBaseline, segmentationStatus) != 0)
567  {
568  LOG_ERROR("SegmentationStatus mismatch in Frame #" << frameIndex << ": current=" << segmentationStatus << ", baseline=" << segmentationStatusBaseline);
569  ++numberOfFailures;
570  continue;
571  }
572 
573  if (igsioCommon::IsEqualInsensitive(segmentationStatusBaseline, "OK"))
574  {
575  {
576  // <SegmentedPoints>
577  vtkXMLDataElement* segmentedPointsBaseline = frameBaseline->FindNestedElementWithName("SegmentedPoints");
578  vtkXMLDataElement* segmentedPoints = frame->FindNestedElementWithName("SegmentedPoints");
579 
580  if (segmentedPointsBaseline == NULL || segmentedPoints == NULL)
581  {
582  LOG_ERROR("Reading SegmentedPoints tag in Frame #" << frameIndex << "failed");
583  ++numberOfFailures;
584  continue;
585  }
586 
587  // <Point>
588  for (int pointIndex = 0; pointIndex < segmentedPointsBaseline->GetNumberOfNestedElements(); ++pointIndex)
589  {
590  vtkXMLDataElement* pointBaseline = segmentedPointsBaseline->GetNestedElement(pointIndex);
591  vtkXMLDataElement* point = segmentedPoints->GetNestedElement(pointIndex);
592  if (!pointBaseline || !point || STRCASECMP(pointBaseline->GetName(), "Point") != 0 || STRCASECMP(point->GetName(), "Point") != 0)
593  {
594  LOG_ERROR("Invalid Point element in Frame #" << frameIndex);
595  ++numberOfFailures;
596  continue;
597  }
598 
599  if (STRCASECMP(pointBaseline->GetAttribute("WireName"), point->GetAttribute("WireName")) != 0)
600  {
601  LOG_ERROR("Wire name mismatch: " << pointBaseline->GetAttribute("Name") << " <> " << point->GetAttribute("Name"));
602  ++numberOfFailures;
603  continue;
604  }
605 
606  double blPosition[3];
607  double cPosition[3];
608  if (! pointBaseline->GetVectorAttribute("Position", 3, blPosition)
609  || ! point->GetVectorAttribute("Position", 3, cPosition))
610  {
611  LOG_ERROR("Reading Position of Point #" << pointIndex << " in Frame #" << frameIndex << "failed!");
612  ++numberOfFailures;
613  continue;
614  }
615 
616  for (int i = 0; i < 3; i++)
617  {
618  double ratio = 1.0 * blPosition[i] / cPosition[i];
619  double absoluteError = fabs(blPosition[i] - cPosition[i]);
620  if ((ratio > 1 + ERROR_THRESHOLD || ratio < 1 - ERROR_THRESHOLD) && (absoluteError > absoluteErrorTolerance))
621  {
622  LOG_ERROR("Position component " << i << " mismatch: current=" << cPosition[i] << ", baseline=" << blPosition[i] << " (point " << pointIndex << " in frame " << frameIndex << ")");
623  ++numberOfFailures;
624  continue;
625  }
626  }
627  }
628  } // </SegmentedPoints>
629 
630  {
631  // <ReprojectionError3DList>
632  vtkXMLDataElement* reprojectionError3DListBaseline = frameBaseline->FindNestedElementWithName("ReprojectionError3DList");
633  vtkXMLDataElement* reprojectionError3DList = frame->FindNestedElementWithName("ReprojectionError3DList");
634 
635  if (reprojectionError3DListBaseline == NULL || reprojectionError3DList == NULL)
636  {
637  LOG_ERROR("Reading ReprojectionError3DList tag in Frame #" << frameIndex << " failed");
638  ++numberOfFailures;
639  continue;
640  }
641 
642  // <ReprojectionError3D>
643  for (int reprojectionError3DIndex = 0; reprojectionError3DIndex < reprojectionError3DListBaseline->GetNumberOfNestedElements(); ++reprojectionError3DIndex)
644  {
645  vtkXMLDataElement* reprojectionError3DBaseline = reprojectionError3DListBaseline->GetNestedElement(reprojectionError3DIndex);
646  vtkXMLDataElement* reprojectionError3D = reprojectionError3DList->GetNestedElement(reprojectionError3DIndex);
647  if (!reprojectionError3DBaseline || !reprojectionError3D || STRCASECMP(reprojectionError3DBaseline->GetName(), "ReprojectionError3D") != 0 || STRCASECMP(reprojectionError3D->GetName(), "ReprojectionError3D") != 0)
648  {
649  LOG_ERROR("Invalid ReprojectionError3D element in Frame #" << frameIndex);
650  ++numberOfFailures;
651  continue;
652  }
653 
654  if (STRCASECMP(reprojectionError3DBaseline->GetAttribute("WireName"), reprojectionError3D->GetAttribute("WireName")) != 0)
655  {
656  LOG_ERROR("Wire name mismatch: " << reprojectionError3DBaseline->GetAttribute("Name") << " <> " << reprojectionError3D->GetAttribute("Name"));
657  ++numberOfFailures;
658  continue;
659  }
660 
661  double blErrorMm = 0.0;
662  double cErrorMm = 0.0;
663  if (! reprojectionError3DBaseline->GetScalarAttribute("ErrorMm", blErrorMm)
664  || ! reprojectionError3D->GetScalarAttribute("ErrorMm", cErrorMm))
665  {
666  LOG_ERROR("Reading ErrorMm in ReprojectionError3D #" << reprojectionError3DIndex << " in Frame #" << frameIndex << "failed!");
667  ++numberOfFailures;
668  continue;
669  }
670 
671  double ratio = 1.0 * blErrorMm / cErrorMm;
672  double absoluteError = fabs(blErrorMm - cErrorMm);
673  if (ratio > 1 + ERROR_THRESHOLD || ratio < 1 - ERROR_THRESHOLD || absoluteError > absoluteErrorTolerance)
674  {
675  LOG_ERROR("ErrorMm mismatch: current=" << cErrorMm << ", baseline=" << blErrorMm << " (error index " << reprojectionError3DIndex << " in frame " << frameIndex << ")");
676  ++numberOfFailures;
677  continue;
678  }
679  }
680  } // </ReprojectionError3DList>
681 
682  {
683  // <ReprojectionError2DList>
684  vtkXMLDataElement* reprojectionError2DListBaseline = frameBaseline->FindNestedElementWithName("ReprojectionError2DList");
685  vtkXMLDataElement* reprojectionError2DList = frame->FindNestedElementWithName("ReprojectionError2DList");
686 
687  if (reprojectionError2DListBaseline == NULL || reprojectionError2DList == NULL)
688  {
689  LOG_ERROR("Reading ReprojectionError2DList tag in Frame #" << frameIndex << "failed");
690  ++numberOfFailures;
691  continue;
692  }
693 
694  // <ReprojectionError2D>
695  for (int reprojectionError2DIndex = 0; reprojectionError2DIndex < reprojectionError2DListBaseline->GetNumberOfNestedElements(); ++reprojectionError2DIndex)
696  {
697  vtkXMLDataElement* reprojectionError2DBaseline = reprojectionError2DListBaseline->GetNestedElement(reprojectionError2DIndex);
698  vtkXMLDataElement* reprojectionError2D = reprojectionError2DList->GetNestedElement(reprojectionError2DIndex);
699  if (!reprojectionError2DBaseline || !reprojectionError2D || STRCASECMP(reprojectionError2DBaseline->GetName(), "ReprojectionError2D") != 0 || STRCASECMP(reprojectionError2D->GetName(), "ReprojectionError2D") != 0)
700  {
701  LOG_ERROR("Invalid ReprojectionError2D element in Frame #" << frameIndex);
702  ++numberOfFailures;
703  continue;
704  }
705 
706  if (STRCASECMP(reprojectionError2DBaseline->GetAttribute("WireName"), reprojectionError2D->GetAttribute("WireName")) != 0)
707  {
708  LOG_ERROR("Wire name mismatch: " << reprojectionError2DBaseline->GetAttribute("Name") << " <> " << reprojectionError2D->GetAttribute("Name"));
709  ++numberOfFailures;
710  continue;
711  }
712 
713  double blErrorPx[2];
714  double cErrorPx[2];
715  if (! reprojectionError2DBaseline->GetVectorAttribute("ErrorPx", 2, blErrorPx)
716  || ! reprojectionError2D->GetVectorAttribute("ErrorPx", 2, cErrorPx))
717  {
718  LOG_ERROR("Reading ErrorPx of reprojectionError2D #" << reprojectionError2DIndex << " in Frame #" << frameIndex << "failed!");
719  ++numberOfFailures;
720  continue;
721  }
722 
723  for (int i = 0; i < 2; i++)
724  {
725  double ratio = 1.0 * blErrorPx[i] / cErrorPx[i];
726  double absoluteError = fabs(blErrorPx[i] - cErrorPx[i]);
727  if ((ratio > 1 + ERROR_THRESHOLD || ratio < 1 - ERROR_THRESHOLD) && (absoluteError > absoluteErrorTolerance))
728  {
729  LOG_ERROR("ErrorPx component " << i << " mismatch: current=" << cErrorPx[i] << ", baseline=" << blErrorPx[i] << " (error index " << reprojectionError2DIndex << " in frame " << frameIndex << ")");
730  ++numberOfFailures;
731  continue;
732  }
733  }
734  }
735  } // </ReprojectionError2DList>
736  } // If SegmentationStatus is OK
737  } // </Frame>
738  } // </ValidationData>
739 
740  {
741  // <CalibrationData>
742  vtkXMLDataElement* calibrationDataBaseline = errorReportBaseline->FindNestedElementWithName("CalibrationData");
743  vtkXMLDataElement* calibrationData = errorReport->FindNestedElementWithName("CalibrationData");
744 
745  if (calibrationDataBaseline == NULL || calibrationData == NULL)
746  {
747  LOG_ERROR("Reading CalibrationData tag failed");
748  return ++numberOfFailures;
749  }
750 
751  for (int frameIndex = 0; frameIndex < calibrationDataBaseline->GetNumberOfNestedElements(); ++frameIndex) // <Frame>
752  {
753  vtkXMLDataElement* frameBaseline = calibrationDataBaseline->GetNestedElement(frameIndex);
754  vtkXMLDataElement* frame = calibrationData->GetNestedElement(frameIndex);
755  if (!frameBaseline || !frame || STRCASECMP(frameBaseline->GetName(), "Frame") != 0 || STRCASECMP(frame->GetName(), "Frame") != 0)
756  {
757  LOG_ERROR("Invalid Frame element #" << frameIndex);
758  ++numberOfFailures;
759  continue;
760  }
761 
762  const char* segmentationStatusBaseline = frameBaseline->GetAttribute("SegmentationStatus");
763  const char* segmentationStatus = frame->GetAttribute("SegmentationStatus");
764 
765  if (STRCASECMP(segmentationStatusBaseline, segmentationStatus) != 0)
766  {
767  LOG_ERROR("SegmentationStatus mismatch in Frame #" << frameIndex << ": current=" << segmentationStatus << ", baseline=" << segmentationStatusBaseline);
768  ++numberOfFailures;
769  continue;
770  }
771 
772  if (igsioCommon::IsEqualInsensitive(segmentationStatusBaseline, "OK"))
773  {
774  {
775  // <SegmentedPoints>
776  vtkXMLDataElement* segmentedPointsBaseline = frameBaseline->FindNestedElementWithName("SegmentedPoints");
777  vtkXMLDataElement* segmentedPoints = frame->FindNestedElementWithName("SegmentedPoints");
778 
779  if (segmentedPointsBaseline == NULL || segmentedPoints == NULL)
780  {
781  LOG_ERROR("Reading SegmentedPoints tag in Frame #" << frameIndex << "failed");
782  ++numberOfFailures;
783  continue;
784  }
785 
786  // <Point>
787  for (int pointIndex = 0; pointIndex < segmentedPointsBaseline->GetNumberOfNestedElements(); ++pointIndex)
788  {
789  vtkXMLDataElement* pointBaseline = segmentedPointsBaseline->GetNestedElement(pointIndex);
790  vtkXMLDataElement* point = segmentedPoints->GetNestedElement(pointIndex);
791  if (!pointBaseline || !point || STRCASECMP(pointBaseline->GetName(), "Point") != 0 || STRCASECMP(point->GetName(), "Point") != 0)
792  {
793  LOG_ERROR("Invalid Point element in Frame #" << frameIndex);
794  ++numberOfFailures;
795  continue;
796  }
797 
798  if (STRCASECMP(pointBaseline->GetAttribute("WireName"), point->GetAttribute("WireName")) != 0)
799  {
800  LOG_ERROR("Wire name mismatch: " << pointBaseline->GetAttribute("Name") << " <> " << point->GetAttribute("Name"));
801  ++numberOfFailures;
802  continue;
803  }
804 
805  double blPosition[3];
806  double cPosition[3];
807  if (! pointBaseline->GetVectorAttribute("Position", 3, blPosition)
808  || ! point->GetVectorAttribute("Position", 3, cPosition))
809  {
810  LOG_ERROR("Reading Position of Point #" << pointIndex << " in Frame #" << frameIndex << "failed!");
811  ++numberOfFailures;
812  continue;
813  }
814 
815  for (int i = 0; i < 3; i++)
816  {
817  double ratio = 1.0 * blPosition[i] / cPosition[i];
818  double absoluteError = fabs(blPosition[i] - cPosition[i]);
819  if ((ratio > 1 + ERROR_THRESHOLD || ratio < 1 - ERROR_THRESHOLD) && (absoluteError > absoluteErrorTolerance))
820  {
821  LOG_ERROR("Position component " << i << " mismatch: current=" << cPosition[i] << ", baseline=" << blPosition[i] << " (point " << pointIndex << " in frame " << frameIndex << ")");
822  ++numberOfFailures;
823  continue;
824  }
825  }
826  }
827  } // </SegmentedPoints>
828 
829  {
830  // <MiddleWires>
831  vtkXMLDataElement* middleWiresBaseline = frameBaseline->FindNestedElementWithName("MiddleWires");
832  vtkXMLDataElement* middleWires = frame->FindNestedElementWithName("MiddleWires");
833 
834  if (middleWiresBaseline == NULL || middleWires == NULL)
835  {
836  LOG_ERROR("Reading MiddleWires tag in Frame #" << frameIndex << "failed");
837  ++numberOfFailures;
838  continue;
839  }
840 
841  // <MiddleWire>
842  for (int middleWireIndex = 0; middleWireIndex < middleWiresBaseline->GetNumberOfNestedElements(); ++middleWireIndex)
843  {
844  vtkXMLDataElement* middleWireBaseline = middleWiresBaseline->GetNestedElement(middleWireIndex);
845  vtkXMLDataElement* middleWire = middleWires->GetNestedElement(middleWireIndex);
846  if (!middleWireBaseline || !middleWire || STRCASECMP(middleWireBaseline->GetName(), "MiddleWire") != 0 || STRCASECMP(middleWire->GetName(), "MiddleWire") != 0)
847  {
848  LOG_ERROR("Invalid MiddleWire element in Frame #" << frameIndex);
849  ++numberOfFailures;
850  continue;
851  }
852 
853  double blPositionInImageFrame[3];
854  double cPositionInImageFrame[3];
855  if (! middleWireBaseline->GetVectorAttribute("PositionInImageFrame", 3, blPositionInImageFrame)
856  || ! middleWire->GetVectorAttribute("PositionInImageFrame", 3, cPositionInImageFrame))
857  {
858  LOG_ERROR("Reading PositionInImageFrame of MiddleWire #" << middleWireIndex << " in Frame #" << frameIndex << "failed!");
859  ++numberOfFailures;
860  continue;
861  }
862 
863  for (int i = 0; i < 3; i++)
864  {
865  double ratio = 1.0 * blPositionInImageFrame[i] / cPositionInImageFrame[i];
866  double absoluteError = fabs(blPositionInImageFrame[i] - cPositionInImageFrame[i]);
867  if ((ratio > 1 + ERROR_THRESHOLD || ratio < 1 - ERROR_THRESHOLD) && (absoluteError > absoluteErrorTolerance))
868  {
869  LOG_ERROR("PositionInImageFrame component " << i << " mismatch: current=" << cPositionInImageFrame[i] << ", baseline=" << blPositionInImageFrame[i] << " (middleWire " << middleWireIndex << " in frame " << frameIndex << ")");
870  ++numberOfFailures;
871  continue;
872  }
873  }
874 
875  double blPositionInProbeFrame[3];
876  double cPositionInProbeFrame[3];
877  if (! middleWireBaseline->GetVectorAttribute("PositionInProbeFrame", 3, blPositionInProbeFrame)
878  || ! middleWire->GetVectorAttribute("PositionInProbeFrame", 3, cPositionInProbeFrame))
879  {
880  LOG_ERROR("Reading PositionInProbeFrame of MiddleWire #" << middleWireIndex << " in Frame #" << frameIndex << "failed!");
881  ++numberOfFailures;
882  continue;
883  }
884 
885  for (int i = 0; i < 3; i++)
886  {
887  double ratio = 1.0 * blPositionInProbeFrame[i] / cPositionInProbeFrame[i];
888  double absoluteError = fabs(blPositionInProbeFrame[i] - cPositionInProbeFrame[i]);
889  if ((ratio > 1 + ERROR_THRESHOLD || ratio < 1 - ERROR_THRESHOLD) && (absoluteError > absoluteErrorTolerance))
890  {
891  LOG_ERROR("PositionInProbeFrame component " << i << " mismatch: current=" << cPositionInProbeFrame[i] << ", baseline=" << blPositionInProbeFrame[i] << " (middleWire " << middleWireIndex << " in frame " << frameIndex << ")");
892  ++numberOfFailures;
893  continue;
894  }
895  }
896  }
897  } // </MiddleWires>
898 
899  {
900  // <ReprojectionError3DList>
901  vtkXMLDataElement* reprojectionError3DListBaseline = frameBaseline->FindNestedElementWithName("ReprojectionError3DList");
902  vtkXMLDataElement* reprojectionError3DList = frame->FindNestedElementWithName("ReprojectionError3DList");
903 
904  if (reprojectionError3DListBaseline == NULL || reprojectionError3DList == NULL)
905  {
906  LOG_ERROR("Reading ReprojectionError3DList tag in Frame #" << frameIndex << " failed");
907  ++numberOfFailures;
908  continue;
909  }
910 
911  // <ReprojectionError3D>
912  for (int reprojectionError3DIndex = 0; reprojectionError3DIndex < reprojectionError3DListBaseline->GetNumberOfNestedElements(); ++reprojectionError3DIndex)
913  {
914  vtkXMLDataElement* reprojectionError3DBaseline = reprojectionError3DListBaseline->GetNestedElement(reprojectionError3DIndex);
915  vtkXMLDataElement* reprojectionError3D = reprojectionError3DList->GetNestedElement(reprojectionError3DIndex);
916  if (!reprojectionError3DBaseline || !reprojectionError3D || STRCASECMP(reprojectionError3DBaseline->GetName(), "ReprojectionError3D") != 0 || STRCASECMP(reprojectionError3D->GetName(), "ReprojectionError3D") != 0)
917  {
918  LOG_ERROR("Invalid ReprojectionError3D element in Frame #" << frameIndex);
919  ++numberOfFailures;
920  continue;
921  }
922 
923  if (STRCASECMP(reprojectionError3DBaseline->GetAttribute("WireName"), reprojectionError3D->GetAttribute("WireName")) != 0)
924  {
925  LOG_ERROR("Wire name mismatch: " << reprojectionError3DBaseline->GetAttribute("Name") << " <> " << reprojectionError3D->GetAttribute("Name"));
926  ++numberOfFailures;
927  continue;
928  }
929 
930  double blErrorMm = 0.0;
931  double cErrorMm = 0.0;
932  if (! reprojectionError3DBaseline->GetScalarAttribute("ErrorMm", blErrorMm)
933  || ! reprojectionError3D->GetScalarAttribute("ErrorMm", cErrorMm))
934  {
935  LOG_ERROR("Reading ErrorMm in ReprojectionError3D #" << reprojectionError3DIndex << " in Frame #" << frameIndex << "failed!");
936  ++numberOfFailures;
937  continue;
938  }
939 
940  double ratio = 1.0 * blErrorMm / cErrorMm;
941  double absoluteError = fabs(blErrorMm - cErrorMm);
942  if ((ratio > 1 + ERROR_THRESHOLD || ratio < 1 - ERROR_THRESHOLD) && (absoluteError > absoluteErrorTolerance))
943  {
944  LOG_ERROR("ErrorMm mismatch: current=" << cErrorMm << ", baseline=" << blErrorMm << " (error index " << reprojectionError3DIndex << " in frame " << frameIndex << ")");
945  ++numberOfFailures;
946  continue;
947  }
948  }
949  } // </ReprojectionError3DList>
950 
951  {
952  // <ReprojectionError2DList>
953  vtkXMLDataElement* reprojectionError2DListBaseline = frameBaseline->FindNestedElementWithName("ReprojectionError2DList");
954  vtkXMLDataElement* reprojectionError2DList = frame->FindNestedElementWithName("ReprojectionError2DList");
955 
956  if (reprojectionError2DListBaseline == NULL || reprojectionError2DList == NULL)
957  {
958  LOG_ERROR("Reading ReprojectionError2DList tag in Frame #" << frameIndex << "failed");
959  ++numberOfFailures;
960  continue;
961  }
962 
963  // <ReprojectionError2D>
964  for (int reprojectionError2DIndex = 0; reprojectionError2DIndex < reprojectionError2DListBaseline->GetNumberOfNestedElements(); ++reprojectionError2DIndex)
965  {
966  vtkXMLDataElement* reprojectionError2DBaseline = reprojectionError2DListBaseline->GetNestedElement(reprojectionError2DIndex);
967  vtkXMLDataElement* reprojectionError2D = reprojectionError2DList->GetNestedElement(reprojectionError2DIndex);
968  if (!reprojectionError2DBaseline || !reprojectionError2D || STRCASECMP(reprojectionError2DBaseline->GetName(), "ReprojectionError2D") != 0 || STRCASECMP(reprojectionError2D->GetName(), "ReprojectionError2D") != 0)
969  {
970  LOG_ERROR("Invalid ReprojectionError2D element in Frame #" << frameIndex);
971  ++numberOfFailures;
972  continue;
973  }
974 
975  if (STRCASECMP(reprojectionError2DBaseline->GetAttribute("WireName"), reprojectionError2D->GetAttribute("WireName")) != 0)
976  {
977  LOG_ERROR("Wire name mismatch: " << reprojectionError2DBaseline->GetAttribute("Name") << " <> " << reprojectionError2D->GetAttribute("Name"));
978  ++numberOfFailures;
979  continue;
980  }
981 
982  double blErrorPx[2];
983  double cErrorPx[2];
984  if (! reprojectionError2DBaseline->GetVectorAttribute("ErrorPx", 2, blErrorPx)
985  || ! reprojectionError2D->GetVectorAttribute("ErrorPx", 2, cErrorPx))
986  {
987  LOG_ERROR("Reading ErrorPx of reprojectionError2D #" << reprojectionError2DIndex << " in Frame #" << frameIndex << "failed!");
988  ++numberOfFailures;
989  continue;
990  }
991 
992  for (int i = 0; i < 2; i++)
993  {
994  double ratio = 1.0 * blErrorPx[i] / cErrorPx[i];
995  double absoluteError = fabs(blErrorPx[i] - cErrorPx[i]);
996  if ((ratio > 1 + ERROR_THRESHOLD || ratio < 1 - ERROR_THRESHOLD) && (absoluteError > absoluteErrorTolerance))
997  {
998  LOG_ERROR("ErrorPx component " << i << " mismatch: current=" << cErrorPx[i] << ", baseline=" << blErrorPx[i] << " (error index " << reprojectionError2DIndex << " in frame " << frameIndex << ")");
999  ++numberOfFailures;
1000  continue;
1001  }
1002  }
1003  }
1004  } // </ReprojectionError2DList>
1005  } // If SegmentationStatus is OK
1006  } // </Frame>
1007  } // </CalibrationData>
1008  } // </ErrorReport>
1009 
1010  return numberOfFailures;
1011 }
std::string GetOutputPath(const std::string &subPath)
const double ERROR_THRESHOLD
for i
#define PLUS_FAIL
Definition: PlusCommon.h:43
static vtkPlusConfig * GetInstance()
std::vector< PlusNWire > GetNWires()
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
int main(int argc, char *argv[])
int CompareCalibrationResultsWithBaseline(const char *baselineFileName, const char *currentResultFileName, double translationErrorThreshold, double rotationErrorThreshold)
static vtkIGSIOLogger * Instance()
PlusFidLineFinder * GetFidLineFinder()
virtual vtkXMLDataElement * GetDeviceSetConfigurationData()
PlusStatus RecognizePattern(vtkIGSIOTrackedFrameList *trackedFrameList, PatternRecognitionError &patternRecognitionError, int *numberOfSuccessfullySegmentedImages=NULL, std::vector< unsigned int > *segmentedFramesIndices=NULL)
void SetDeviceSetConfigurationData(vtkXMLDataElement *deviceSetConfigurationData)
PlusStatus ReadConfiguration(vtkXMLDataElement *rootConfigElement)
static PlusStatus ReadDeviceSetConfigurationFromFile(vtkXMLDataElement *config, const char *filename)
Definition: PlusXmlUtils.h:23