PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkSpacingCalibAlgoTest.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 "vtkPlusHTMLGenerator.h"
17 #include "vtkIGSIOSequenceIO.h"
19 #include "vtkXMLDataElement.h"
20 #include "vtkXMLUtilities.h"
21 #include "vtksys/CommandLineArguments.hxx"
22 #include "vtksys/SystemTools.hxx"
23 
24 // define tolerance used for comparing double numbers
25 #ifndef _WIN32
26  const double DOUBLE_DIFF = LINUXTOLERANCE;
27 #else
28  const double DOUBLE_DIFF = 0.0001;
29 #endif
30 
31 //----------------------------------------------------------------------------
32 int main(int argc, char **argv)
33 {
34  int numberOfFailures(0);
35 
36  bool printHelp(false);
37 
38  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
39 
40  vtksys::CommandLineArguments args;
41  args.Initialize(argc, argv);
42  std::vector<std::string> inputSequenceMetafiles;
43  std::string inputBaselineFileName("");
44  std::string inputConfigFileName("");
45 
46  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
47  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
48  args.AddArgument("--source-seq-files", vtksys::CommandLineArguments::MULTI_ARGUMENT, &inputSequenceMetafiles, "Input sequence metafile(s) name with path");
49  args.AddArgument("--baseline-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputBaselineFileName, "Input xml baseline file name with path");
50  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFileName, "Input xml config file name with path");
51 
52  if ( !args.Parse() )
53  {
54  std::cerr << "Problem parsing arguments" << std::endl;
55  std::cout << "Help: " << args.GetHelp() << std::endl;
56  exit(EXIT_FAILURE);
57  }
58 
59  if ( printHelp )
60  {
61  std::cout << args.GetHelp() << std::endl;
62  exit(EXIT_SUCCESS);
63  }
64 
65  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
66 
67  if ( inputSequenceMetafiles.empty() || inputConfigFileName.empty() || inputBaselineFileName.empty() )
68  {
69  std::cerr << "input-translation-sequence-metafile, input-baseline-file-name and input-config-file-name are required arguments!" << std::endl;
70  std::cout << "Help: " << args.GetHelp() << std::endl;
71  exit(EXIT_FAILURE);
72  }
73 
74  // Read configuration
75  vtkSmartPointer<vtkXMLDataElement> configRootElement = vtkSmartPointer<vtkXMLDataElement>::New();
76  if (PlusXmlUtils::ReadDeviceSetConfigurationFromFile(configRootElement, inputConfigFileName.c_str())==PLUS_FAIL)
77  {
78  LOG_ERROR("Unable to read configuration from file " << inputConfigFileName.c_str());
79  return EXIT_FAILURE;
80  }
81 
83 
84  PlusFidPatternRecognition patternRecognition;
85  patternRecognition.ReadConfiguration(configRootElement);
86 
87  LOG_INFO("Reading metafiles:");
88 
89  vtkSmartPointer<vtkIGSIOTrackedFrameList> trackedFrameList = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
90  for ( unsigned int i = 0; i < inputSequenceMetafiles.size(); ++i )
91  {
92  LOG_INFO("Reading " << inputSequenceMetafiles[i] << " ...");
93  vtkSmartPointer<vtkIGSIOTrackedFrameList> tfList = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
94  if( vtkIGSIOSequenceIO::Read(inputSequenceMetafiles[i], tfList) != PLUS_SUCCESS )
95  {
96  LOG_ERROR("Failed to read sequence metafile: " << inputSequenceMetafiles[i]);
97  return EXIT_FAILURE;
98  }
99 
100  if ( trackedFrameList->AddTrackedFrameList(tfList) != PLUS_SUCCESS )
101  {
102  LOG_ERROR("Failed to add tracked frame list to container!");
103  return EXIT_FAILURE;
104  }
105  }
106 
107  LOG_INFO("Testing image data segmentation...");
108  int numberOfSuccessfullySegmentedImages = 0;
110  patternRecognition.RecognizePattern(trackedFrameList, error, &numberOfSuccessfullySegmentedImages);
111  LOG_INFO("Segmentation success rate: " << numberOfSuccessfullySegmentedImages << " out of " << trackedFrameList->GetNumberOfTrackedFrames()
112  << " (" << (100.0 * numberOfSuccessfullySegmentedImages ) / trackedFrameList->GetNumberOfTrackedFrames() << "%)");
113 
114  LOG_INFO("Testing spacing computation...");
115  vtkSmartPointer<vtkPlusSpacingCalibAlgo> spacingCalibAlgo = vtkSmartPointer<vtkPlusSpacingCalibAlgo>::New();
116  spacingCalibAlgo->SetInputs(trackedFrameList, patternRecognition.GetFidLineFinder()->GetNWires());
117 
118  double spacing[2]={0};
119  if ( spacingCalibAlgo->GetSpacing(spacing) != PLUS_SUCCESS )
120  {
121  LOG_ERROR("Spacing calibration failed!");
122  numberOfFailures++;
123  }
124  else
125  {
126  LOG_INFO("Spacing: " << std::fixed << spacing[0] << " " << spacing[1] << " mm/px");
127  }
128 
129  // Get calibration error
130  double errorMean(0), errorStdev(0);
131  if ( spacingCalibAlgo->GetError(errorMean, errorStdev) != PLUS_SUCCESS )
132  {
133  LOG_ERROR("Failed to get spacing calibration error!");
134  numberOfFailures++;
135  }
136  else
137  {
138  LOG_INFO("Spacing calibration error - mean: " << std::fixed << errorMean << " stdev: " << errorStdev);
139  }
140 
141  LOG_INFO("Testing report table generation and saving into file...");
142  vtkTable* reportTable = spacingCalibAlgo->GetReportTable();
143  if ( reportTable != NULL )
144  {
145  if ( vtkPlusLogger::Instance()->GetLogLevel() >= vtkPlusLogger::LOG_LEVEL_DEBUG )
146  {
147  reportTable->Dump(25);
148  }
149  }
150  else
151  {
152  LOG_ERROR("Failed to get report table!");
153  numberOfFailures++;
154  }
155 
156  LOG_INFO("Testing HTML report generation...");
157  vtkSmartPointer<vtkPlusHTMLGenerator> htmlGenerator = vtkSmartPointer<vtkPlusHTMLGenerator>::New();
158  htmlGenerator->SetBaseFilename("SpacingCalibrationReport");
159  htmlGenerator->SetTitle("Spacing Calibration Test Report");
160  spacingCalibAlgo->GenerateReport(htmlGenerator);
161  htmlGenerator->SaveHtmlPageAutoFilename();
162 
163  std::ostringstream spacingCalibAlgoStream;
164  spacingCalibAlgo->PrintSelf(spacingCalibAlgoStream, vtkIndent(0));
165  LOG_DEBUG("SpacingCalibAlgo::PrintSelf: "<< spacingCalibAlgoStream.str());
166 
167 
168  //*********************************************************************
169  // Save results to file
170 
171  const char calibResultSaveFilename[]="SpacingCalibrationResults.xml";
172  LOG_INFO("Save calibration results to XML file: "<<calibResultSaveFilename);
173  std::ofstream outFile;
174  outFile.open(calibResultSaveFilename);
175  outFile << "<CalibrationResults>" << std::endl;
176  outFile << " <SpacingCalibrationResult " << std::fixed << std::setprecision(8)
177  << "Spacing=\""<<spacing[0]<<" "<<spacing[1]<<"\" "
178  << "ErrorMean=\""<<errorMean<<"\" "
179  << "ErrorStdev=\""<<errorStdev<<"\" "
180  << " />" << std::endl;
181  outFile << "</CalibrationResults>" << std::endl;
182  outFile.close();
183 
184  //*********************************************************************
185  // Compare result to baseline
186 
187  LOG_INFO("Comparing result with baseline...");
188 
189  vtkSmartPointer<vtkXMLDataElement> xmlBaseline = vtkSmartPointer<vtkXMLDataElement>::Take(
190  vtkXMLUtilities::ReadElementFromFile(inputBaselineFileName.c_str()));
191 
192  vtkXMLDataElement* xmlSpacingCalibrationBaseline = NULL;
193  if ( xmlBaseline != NULL )
194  {
195  xmlSpacingCalibrationBaseline = xmlBaseline->FindNestedElementWithName("SpacingCalibrationResult");
196  }
197  else
198  {
199  LOG_ERROR("Failed to read baseline file!");
200  numberOfFailures++;
201  }
202 
203  if ( xmlSpacingCalibrationBaseline == NULL )
204  {
205  LOG_ERROR("Unable to find SpacingCalibrationResult XML data element in baseline: " << inputBaselineFileName);
206  numberOfFailures++;
207  }
208  else
209  {
210  // Compare Spacing to baseline
211  double baseSpacing[2]={0};
212  if ( !xmlSpacingCalibrationBaseline->GetVectorAttribute( "Spacing", 2, baseSpacing) )
213  {
214  LOG_ERROR("Unable to find Spacing XML data element in baseline.");
215  numberOfFailures++;
216  }
217  else
218  {
219  if ( fabs(baseSpacing[0] - spacing[0]) > DOUBLE_DIFF
220  || fabs(baseSpacing[1] - spacing[1]) > DOUBLE_DIFF )
221  {
222  LOG_ERROR("Spacing result in pixel differ from baseline: current(" << spacing[0] << ", " << spacing[1]
223  << ") base (" << baseSpacing[0] << ", " << baseSpacing[1] << ").");
224  numberOfFailures++;
225  }
226  }
227 
228  // Compare errorMean
229  double baseErrorMean=0;
230  if ( !xmlSpacingCalibrationBaseline->GetScalarAttribute("ErrorMean", baseErrorMean) )
231  {
232  LOG_ERROR("Unable to find ErrorMean XML data element in baseline.");
233  numberOfFailures++;
234  }
235  else
236  {
237  if ( fabs(baseErrorMean - errorMean) > DOUBLE_DIFF )
238  {
239  LOG_ERROR("Spacing mean error differ from baseline: current(" << errorMean << ") base (" << baseErrorMean << ").");
240  numberOfFailures++;
241  }
242  }
243 
244  // Compare errorStdev
245  double baseErrorStdev=0;
246  if ( !xmlSpacingCalibrationBaseline->GetScalarAttribute("ErrorStdev", baseErrorStdev) )
247  {
248  LOG_ERROR("Unable to find ErrorStdev XML data element in baseline.");
249  numberOfFailures++;
250  }
251  else
252  {
253  if ( fabs(baseErrorStdev - errorStdev) > DOUBLE_DIFF )
254  {
255  LOG_ERROR("Spacing stdev of error differ from baseline: current(" << errorStdev << ") base (" << baseErrorStdev << ").");
256  numberOfFailures++;
257  }
258  }
259  }
260 
261 
262  if ( numberOfFailures > 0 )
263  {
264  LOG_INFO("Test failed!");
265  return EXIT_FAILURE;
266  }
267 
268  LOG_INFO("Test finished successfully!");
269  return EXIT_SUCCESS;
270 }
for i
#define PLUS_FAIL
Definition: PlusCommon.h:43
const double DOUBLE_DIFF
static vtkPlusConfig * GetInstance()
std::vector< PlusNWire > GetNWires()
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
int main(int argc, char **argv)
static vtkIGSIOLogger * Instance()
PlusFidLineFinder * GetFidLineFinder()
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