PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPhantomRegistrationLandmarkDetectionTest.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 #include "PlusMath.h"
15 #include "igsioTrackedFrame.h"
16 #include "vtkAxis.h"
17 #include "vtkChartXY.h"
18 #include "vtkContextScene.h"
19 #ifdef PLUS_RENDERING_ENABLED
20 #include "vtkContextView.h"
21 #endif
22 #include "vtkPlusDataCollector.h"
23 #include "vtkDirectory.h"
24 #include "vtkDoubleArray.h"
26 #include "vtkMath.h"
27 #include "vtkMatrix4x4.h"
28 #include "vtkPNGWriter.h"
30 #include "vtkPlot.h"
31 #include "vtkPlusChannel.h"
32 #include "vtkPlusConfig.h"
34 #include "vtkRenderWindow.h"
35 #include "vtkRenderer.h"
36 #include "vtkPlusSavedDataSource.h"
37 #include "vtkIGSIOSequenceIO.h"
38 #include "vtkIGSIOMetaImageSequenceIO.h"
39 #include "vtkSmartPointer.h"
40 #include "vtkTable.h"
41 #include "vtkIGSIOTrackedFrameList.h"
42 #include "vtkTransform.h"
43 #include "vtkIGSIOTransformRepository.h"
44 #include "vtkWindowToImageFilter.h"
45 #include "vtkXMLDataElement.h"
46 #include "vtkXMLUtilities.h"
47 #include "vtksys/CommandLineArguments.hxx"
48 #include "vtksys/SystemTools.hxx"
49 #include <iostream>
50 #include <stdlib.h>
51 
53 const double ERROR_THRESHOLD_MM = 0.1; // error threshold
54 const double ERROR_THRESHOLD_DEG = 0.2; // error threshold
55 
56 PlusStatus CompareRegistrationResultsWithBaseline(const char* baselineFileName, const char* currentResultFileName, const char* phantomCoordinateFrame, const char* referenceCoordinateFrame);
57 
58 //-----------------------------------------------------------------------------
59 PlusStatus ConstructTableSignal(std::deque<double>& x, std::deque<double>& y, vtkTable* table)
60 {
61  // Clear table
62  while (table->GetNumberOfColumns() > 0)
63  {
64  table->RemoveColumn(0);
65  }
66 
67  // Create array corresponding to the time values of the tracker plot
68  vtkSmartPointer<vtkDoubleArray> arrX = vtkSmartPointer<vtkDoubleArray>::New();
69  table->AddColumn(arrX);
70 
71  // Create array corresponding to the metric values of the tracker plot
72  vtkSmartPointer<vtkDoubleArray> arrY = vtkSmartPointer<vtkDoubleArray>::New();
73  table->AddColumn(arrY);
74 
75  // Set the tracker data
76  table->SetNumberOfRows(x.size());
77  for (unsigned int i = 0; i < x.size(); ++i)
78  {
79  table->SetValue(i, 0, x.at(i));
80  table->SetValue(i, 1, y.at(i));
81  }
82 
83  return PLUS_SUCCESS;
84 }
85 //----------------------------------------------------------------------------
86 void SaveMetricPlot(const char* filename, vtkTable* stylusRef, vtkTable* stylusTipRef, vtkTable* stylusTipSpeed, std::string& xAxisLabel,
87  std::string& yAxisLabel)
88 {
89 #ifdef PLUS_RENDERING_ENABLED
90  // Set up the view
91  vtkSmartPointer<vtkContextView> view = vtkSmartPointer<vtkContextView>::New();
92  view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
93  vtkSmartPointer<vtkChartXY> chart = vtkSmartPointer<vtkChartXY>::New();
94  view->GetScene()->AddItem(chart);
95 
96  // Add the two line plots
97  vtkPlot* StylusRefLine = chart->AddPlot(vtkChart::POINTS);
98  StylusRefLine->SetInputData(stylusRef, 0, 1);
99  StylusRefLine->SetColor(0, 0, 1);
100  StylusRefLine->SetWidth(0.3);
101 
102  vtkPlot* StylusTipRefLine = chart->AddPlot(vtkChart::POINTS);
103  StylusTipRefLine->SetInputData(stylusTipRef, 0, 1);
104  StylusTipRefLine->SetColor(0, 1, 0);
105  StylusTipRefLine->SetWidth(0.3);
106 
107  vtkPlot* StylusTipFromLandmarkLine = chart->AddPlot(vtkChart::LINE);
108  StylusTipFromLandmarkLine->SetInputData(stylusTipSpeed, 0, 1);
109  StylusTipFromLandmarkLine->SetColor(1, 0, 0);
110  StylusTipFromLandmarkLine->SetWidth(1.0);
111 
112  chart->SetShowLegend(true);
113  chart->GetAxis(vtkAxis::LEFT)->SetTitle(yAxisLabel.c_str());
114  chart->GetAxis(vtkAxis::BOTTOM)->SetTitle(xAxisLabel.c_str());
115 
116  // Render plot and save it to file
117  vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
118  renderWindow->AddRenderer(view->GetRenderer());
119  renderWindow->SetSize(1600, 1200);
120  renderWindow->OffScreenRenderingOn();
121 
122  vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
123  windowToImageFilter->SetInput(renderWindow);
124  windowToImageFilter->Update();
125 
126  vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
127  writer->SetFileName(filename);
128  writer->SetInputData(windowToImageFilter->GetOutput());
129  writer->Write();
130 #else
131  LOG_ERROR("Function not available when VTK_RENDERING_BACKEND is None!");
132 #endif
133 }
134 
135 PlusStatus ConstructSignalPlot(vtkIGSIOTrackedFrameList* trackedStylusTipFrames, std::string intermediateFileOutputDirectory, vtkXMLDataElement* aConfig)
136 {
137  double signalTimeRangeMin = trackedStylusTipFrames->GetTrackedFrame(0)->GetTimestamp();
138  double signalTimeRangeMax = trackedStylusTipFrames->GetTrackedFrame(trackedStylusTipFrames->GetNumberOfTrackedFrames() - 1)->GetTimestamp();
139  std::deque<double> signalTimestamps;
140  std::deque<double> signalValues;
141 
143  //std::string filenameTracked=intermediateFileOutputDirectory + "\\EightLandmarksPointsTracked.mha";
144  //trackedStylusTipFrames->SaveTrackerDataOnlyToSequenceMetafile(filenameTracked.c_str(),false);
145 
146  LOG_INFO("Range [" << signalTimeRangeMin << "-" << signalTimeRangeMax << "] " << (signalTimeRangeMax - signalTimeRangeMin) << "[s]");
147  double frequency = 1 / (trackedStylusTipFrames->GetTrackedFrame(1)->GetTimestamp() - trackedStylusTipFrames->GetTrackedFrame(0)->GetTimestamp());
148  LOG_INFO("Frequency first frames = " << frequency << " Frequency average frame = " << trackedStylusTipFrames->GetNumberOfTrackedFrames() / (signalTimeRangeMax - signalTimeRangeMin));
149 
150  vtkSmartPointer<vtkPlusReadTrackedSignals> trackerDataMetricExtractor = vtkSmartPointer<vtkPlusReadTrackedSignals>::New();
151 
152  trackerDataMetricExtractor->SetTrackerFrames(trackedStylusTipFrames);
153  trackerDataMetricExtractor->SetSignalTimeRange(signalTimeRangeMin, signalTimeRangeMax);
154  trackerDataMetricExtractor->ReadConfiguration(aConfig);
155 
156  if (trackerDataMetricExtractor->Update() != PLUS_SUCCESS)
157  {
158  LOG_ERROR("Failed to get line positions from video frames");
159  return PLUS_FAIL;
160  }
161  trackerDataMetricExtractor->GetTimestamps(signalTimestamps);
162  trackerDataMetricExtractor->GetSignalStylusTipSpeed(signalValues);
163  vtkSmartPointer<vtkTable> stylusTipSpeedTable = vtkSmartPointer<vtkTable>::New();
164  ConstructTableSignal(signalTimestamps, signalValues, stylusTipSpeedTable);
165  stylusTipSpeedTable->GetColumn(0)->SetName("Time [s]");
166  stylusTipSpeedTable->GetColumn(1)->SetName("stylusTipSpeed");
167 
168  trackerDataMetricExtractor->GetSignalStylusRef(signalValues);
169  vtkSmartPointer<vtkTable> stylusRefTable = vtkSmartPointer<vtkTable>::New();
170  ConstructTableSignal(signalTimestamps, signalValues, stylusRefTable);
171  stylusRefTable->GetColumn(0)->SetName("Time [s]");
172  stylusRefTable->GetColumn(1)->SetName("stylusRef");
173 
174  trackerDataMetricExtractor->GetSignalStylusTipRef(signalValues);
175  vtkSmartPointer<vtkTable> stylusTipRefTable = vtkSmartPointer<vtkTable>::New();
176  ConstructTableSignal(signalTimestamps, signalValues, stylusTipRefTable);
177  stylusTipRefTable->GetColumn(0)->SetName("Time [s]");
178  stylusTipRefTable->GetColumn(1)->SetName("stylusTipRef");
179 
180  if (stylusTipSpeedTable->GetNumberOfColumns() != 2)
181  {
182  LOG_ERROR("Error in constructing the vtk tables that are to hold fixed signal. Table has " <<
183  stylusTipSpeedTable->GetNumberOfColumns() << " columns, but should have two columns");
184  return PLUS_FAIL;
185  }
186 
187  std::string filename = intermediateFileOutputDirectory /*+ "\\StylusTracked.png"*/;
188  std::string xLabel = "Time [s]";
189  std::string yLabel = "Position Metric";
190 
191 #ifdef PLUS_RENDERING_ENABLED
192  SaveMetricPlot(filename.c_str(), stylusRefTable, stylusTipRefTable, stylusTipSpeedTable, xLabel, yLabel);
193 #endif
194  return PLUS_SUCCESS;
195 }
196 
197 int main(int argc, char* argv[])
198 {
199  std::string inputConfigFileName;
200  std::string inputBaselineFileName;
201  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
202  std::string inputTrackedStylusTipSequence;
203  std::string intermediateFileOutputDirectory;
204  bool plotSignal(false);
205  vtksys::CommandLineArguments cmdargs;
206  double accumulatedError = 0.0;
207  int succesfulDatasets = 0;
208 
209  cmdargs.Initialize(argc, argv);
210  cmdargs.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFileName, "Configuration file name");
211  cmdargs.AddArgument("--baseline-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputBaselineFileName, "Name of file storing baseline calibration results");
212  cmdargs.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
213  cmdargs.AddArgument("--seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputTrackedStylusTipSequence, "Input tracker sequence metafile name (or directory) with path");
214  cmdargs.AddArgument("--intermediate-file-output-dir", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &intermediateFileOutputDirectory, "Directory into which the intermediate files are written");
215  cmdargs.AddArgument("--plot-signal", vtksys::CommandLineArguments::NO_ARGUMENT, &plotSignal, "Run test without plotting the signal.");
216  if (!cmdargs.Parse())
217  {
218  std::cerr << "Problem parsing arguments" << std::endl;
219  std::cout << "Help: " << cmdargs.GetHelp() << std::endl;
220  exit(EXIT_FAILURE);
221  }
222  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
223  LOG_INFO("Initialize");
224 
225  // Read LandmarkDetection configuration
226  vtkSmartPointer<vtkXMLDataElement> configLandmarkDetection = vtkSmartPointer<vtkXMLDataElement>::Take(vtkXMLUtilities::ReadElementFromFile(inputConfigFileName.c_str()));
227  if (configLandmarkDetection == NULL)
228  {
229  LOG_ERROR("Unable to read LandmarkDetection configuration from file " << inputConfigFileName.c_str());
230  exit(EXIT_FAILURE);
231  }
232  vtkPlusConfig::GetInstance()->SetDeviceSetConfigurationData(configLandmarkDetection);
233  if (intermediateFileOutputDirectory.empty())
234  {
235  intermediateFileOutputDirectory = vtkPlusConfig::GetInstance()->GetOutputDirectory();
236  }
237 
238  //--------------------------------------------------------------------------------------------------------------------------------------
239  // Initialize data collection
240  vtkSmartPointer<vtkPlusDataCollector> dataCollector = vtkSmartPointer<vtkPlusDataCollector>::New();
241  if (dataCollector->ReadConfiguration(configLandmarkDetection) != PLUS_SUCCESS)
242  {
243  LOG_ERROR("Unable to parse configuration from file " << inputConfigFileName.c_str());
244  exit(EXIT_FAILURE);
245  }
246  if (dataCollector->Connect() != PLUS_SUCCESS)
247  {
248  LOG_ERROR("Data collector was unable to connect to devices!");
249  exit(EXIT_FAILURE);
250  }
251  if (dataCollector->Start() != PLUS_SUCCESS)
252  {
253  LOG_ERROR("Unable to start data collection!");
254  exit(EXIT_FAILURE);
255  }
256  vtkPlusChannel* aChannel(NULL);
257  vtkPlusDevice* aDevice(NULL);
258  if (dataCollector->GetDevice(aDevice, std::string("TrackerDevice")) != PLUS_SUCCESS)
259  {
260  LOG_ERROR("Unable to locate device by ID: \'TrackerDevice\'");
261  exit(EXIT_FAILURE);
262  }
263  if (aDevice->GetOutputChannelByName(aChannel, "TrackerStream") != PLUS_SUCCESS)
264  {
265  LOG_ERROR("Unable to locate channel by ID: \'TrackerStream\'");
266  exit(EXIT_FAILURE);
267  }
268  if (aChannel->GetTrackingDataAvailable() == false)
269  {
270  LOG_ERROR("Channel \'" << aChannel->GetChannelId() << "\' is not tracking!");
271  exit(EXIT_FAILURE);
272  }
273  if (aChannel->GetTrackingDataAvailable() == false)
274  {
275  LOG_ERROR("Data collector is not tracking!");
276  exit(EXIT_FAILURE);
277  }
278  // Read coordinate definitions
279  vtkSmartPointer<vtkIGSIOTransformRepository> transformRepository = vtkSmartPointer<vtkIGSIOTransformRepository>::New();
280  if (transformRepository->ReadConfiguration(configLandmarkDetection) != PLUS_SUCCESS)
281  {
282  LOG_ERROR("Failed to read CoordinateDefinitions!");
283  exit(EXIT_FAILURE);
284  }
285  if (transformRepository->ReadConfiguration(configLandmarkDetection) != PLUS_SUCCESS)
286  {
287  LOG_ERROR("Failed to read CoordinateDefinitions!");
288  exit(EXIT_FAILURE);
289  }
290 
291  // Initialize fake tracker
292  vtkPlusSavedDataSource* trackerDevice = dynamic_cast<vtkPlusSavedDataSource*>(aDevice);
293  if (trackerDevice == NULL)
294  {
295  LOG_ERROR("Invalid tracker object!");
296  exit(EXIT_FAILURE);
297  }
298 
299  std::string extension = vtksys::SystemTools::GetFilenameExtension(inputTrackedStylusTipSequence);
300  int numberFiles = 0;
301  vtkSmartPointer<vtkDirectory> myDir = vtkSmartPointer<vtkDirectory>::New();
302 
303  if (vtkIGSIOMetaImageSequenceIO::CanReadFile(inputTrackedStylusTipSequence))
304  {
305  LOG_INFO("Only one sequence" << extension);
306  numberFiles = 1;
307  }
308  else
309  {
310  myDir->Open(inputTrackedStylusTipSequence.c_str());
311  numberFiles = myDir->GetNumberOfFiles();
312  }
313  // Get each file name in the directory
314  for (int i = 0; i < numberFiles; i++)
315  {
316  std::string fileString;
317  if (numberFiles == 1)
318  {
319  fileString = inputTrackedStylusTipSequence;
320  }
321  else
322  {
323  fileString = inputTrackedStylusTipSequence;
324  fileString += "\\";
325  fileString += myDir->GetFile(i);
326  }
327  //extension = vtksys::SystemTools::GetFilenameExtension(fileString);
328  if (vtkIGSIOMetaImageSequenceIO::CanReadFile(fileString))
329  {
330  vtkSmartPointer<vtkIGSIOTrackedFrameList> trackedStylusTipFrames = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
331  if (!fileString.empty())
332  {
333  trackedStylusTipFrames->SetValidationRequirements(REQUIRE_UNIQUE_TIMESTAMP | REQUIRE_TRACKING_OK);
334  LOG_INFO("Read stylus tracker data from " << fileString);
335  if (vtkIGSIOSequenceIO::Read(fileString, trackedStylusTipFrames) != PLUS_SUCCESS)
336  {
337  LOG_ERROR("Failed to read stylus data from sequence metafile: " << fileString << ". Exiting...");
338  exit(EXIT_FAILURE);
339  }
340  trackedStylusTipFrames->Register(NULL);
341  }
342  else
343  {
344  LOG_ERROR("Empty file name to read sequence metafile: ");
345  }
346 
347  //This is to construct a plot of the tracked stylus and stylus tip position norms.
348  fileString = intermediateFileOutputDirectory;
349  fileString += "\\";
350  if (numberFiles == 1)
351  {
352  fileString += vtksys::SystemTools::GetFilenameWithoutLastExtension(inputTrackedStylusTipSequence);
353  fileString += ".png";
354  }
355  else
356  {
357  fileString += vtksys::SystemTools::GetFilenameWithoutLastExtension(myDir->GetFile(i));
358  fileString += ".png";
359  }
360  if (plotSignal)
361  {
362  ConstructSignalPlot(trackedStylusTipFrames, fileString, configLandmarkDetection);
363  }
364 
365  //----------------------------------------------------------------------------------------------
366  // Initialize phantom registration
367  vtkSmartPointer<vtkPlusPhantomLandmarkRegistrationAlgo> phantomRegistration = vtkSmartPointer<vtkPlusPhantomLandmarkRegistrationAlgo>::New();
368  if (phantomRegistration == NULL)
369  {
370  LOG_ERROR("Unable to instantiate phantom registration algorithm class!");
371  exit(EXIT_FAILURE);
372  }
373  if (phantomRegistration->ReadConfiguration(configLandmarkDetection) != PLUS_SUCCESS)
374  {
375  LOG_ERROR("Unable to read phantom definition!");
376  exit(EXIT_FAILURE);
377  }
378  int numberOfExpectedLandmarks = phantomRegistration->GetDefinedLandmarks_Phantom()->GetNumberOfPoints();
379  if (numberOfExpectedLandmarks != 8)
380  {
381  LOG_ERROR("Number of defined landmarks should be 8 instead of " << numberOfExpectedLandmarks << "!");
382  exit(EXIT_FAILURE);
383  }
384  // Initialize Landmark detection
385  vtkSmartPointer<vtkPlusLandmarkDetectionAlgo> landmarkDetection = vtkSmartPointer<vtkPlusLandmarkDetectionAlgo>::New();
386  if (landmarkDetection == NULL)
387  {
388  LOG_ERROR("Unable to instantiate landmark detection algorithm class!");
389  exit(EXIT_FAILURE);
390  }
391  landmarkDetection->SetMinimumDistanceBetweenLandmarksMm(phantomRegistration->GetMinimunDistanceBetweenTwoLandmarksMm());
392  landmarkDetection->SetAcquisitionRate(1 / (trackedStylusTipFrames->GetTrackedFrame(1)->GetTimestamp() - trackedStylusTipFrames->GetTrackedFrame(0)->GetTimestamp()));
393  if (landmarkDetection->ReadConfiguration(configLandmarkDetection) != PLUS_SUCCESS)
394  {
395  LOG_ERROR("Unable to read Landmark detection configuration!");
396  exit(EXIT_FAILURE);
397  }
398 
399  // Check stylus tool
400  igsioTransformName stylusTipToReferenceTransformName(phantomRegistration->GetStylusTipCoordinateFrame(), phantomRegistration->GetReferenceCoordinateFrame());
401  igsioTransformName stylusToReferenceTransformName("Stylus", phantomRegistration->GetReferenceCoordinateFrame());
402  igsioTransformName stylusTipToStylusTransformName(phantomRegistration->GetStylusTipCoordinateFrame(), "Stylus");
403 
404  vtkSmartPointer<vtkMatrix4x4> stylusTipToStylusTransform = vtkSmartPointer<vtkMatrix4x4>::New();
405  ToolStatus status(TOOL_INVALID);
406  transformRepository->GetTransform(stylusTipToStylusTransformName, stylusTipToStylusTransform, &status);
407  double landmarkFound[3] = {0, 0, 0};
408 
409  if (status == TOOL_OK)
410  {
411  // Acquire positions for landmark detection
412  igsioTrackedFrame trackedFrame;
413  vtkSmartPointer<vtkMatrix4x4> stylusToReferenceMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
414  for (unsigned int j = 0; j < trackedStylusTipFrames->GetNumberOfTrackedFrames(); ++j)
415  {
416  //trackerDevice->SetCounter(j);
417  //aChannel->GetTrackedFrame((trackedStylusTipFrames->GetTrackedFrame(j)));
418 
419  if (transformRepository->SetTransforms(*(trackedStylusTipFrames->GetTrackedFrame(j))) != PLUS_SUCCESS)
420  {
421  LOG_ERROR("Failed to update transforms in repository with tracked frame!");
422  exit(EXIT_FAILURE);
423  }
424 
425  status = TOOL_INVALID;
426  if (transformRepository->GetTransform(stylusToReferenceTransformName, stylusToReferenceMatrix, &status) != PLUS_SUCCESS || status != TOOL_OK)
427  {
428  //LOG_ERROR("No valid transform found between stylus to reference!");
429  //exit(EXIT_FAILURE);
430  // There is no available transform for this frame; skip that frame
431  LOG_INFO("There is no available transform for this frame; skip frame " << trackedStylusTipFrames->GetTrackedFrame(j)->GetTimestamp() << " [s]")
432  continue;
433  }
434 
435  vtkSmartPointer<vtkMatrix4x4> stylusTipToReferenceTransformMatrix = vtkMatrix4x4::New();
436  vtkMatrix4x4::Multiply4x4(stylusToReferenceMatrix, stylusTipToStylusTransform, stylusTipToReferenceTransformMatrix);
437  int newLandmarkDetected = -1;
438  landmarkDetection->InsertNextStylusTipToReferenceTransform(stylusTipToReferenceTransformMatrix, newLandmarkDetected);
439  if (newLandmarkDetected > 0)
440  {
441  landmarkDetection->GetDetectedLandmarkPoints_Reference()->GetPoint(landmarkDetection->GetDetectedLandmarkPoints_Reference()->GetNumberOfPoints() - 1, landmarkFound);
442  // Add recorded point to algorithm
443  phantomRegistration->GetRecordedLandmarks_Reference()->InsertPoint(landmarkDetection->GetDetectedLandmarkPoints_Reference()->GetNumberOfPoints() - 1, landmarkFound);
444  phantomRegistration->GetRecordedLandmarks_Reference()->Modified();
445  LOG_INFO("\nLandmark found (" << landmarkFound[0] << ", " << landmarkFound[1] << ", " << landmarkFound[2] << ") at " << trackedStylusTipFrames->GetTrackedFrame(j)->GetTimestamp() << "[ms]" << "\nNumber of landmarks in phantonReg " << phantomRegistration->GetRecordedLandmarks_Reference()->GetNumberOfPoints());
446  vtkPlusLogger::PrintProgressbar((100.0 * newLandmarkDetected - 1) / numberOfExpectedLandmarks);
447 
448  if (newLandmarkDetected == numberOfExpectedLandmarks)
449  {
450  succesfulDatasets++;
451  //LOG_INFO("\nREgistration completed" );
452  break;
453  }
454  }
455 
456  }
457  }
458  else
459  {
460  LOG_ERROR("No valid transform found between stylus to stylus tip!");
461  }
462 
463  LOG_INFO(landmarkDetection->GetDetectedLandmarksString());
464 
465  if (phantomRegistration->LandmarkRegister(transformRepository) != PLUS_SUCCESS)
466  {
467  LOG_ERROR("Phantom registration failed!");
468  exit(EXIT_FAILURE);
469  }
470 
471  phantomRegistration->PrintRecordedLandmarks_Phantom();
472 
473  LOG_INFO("Registration error = " << phantomRegistration->GetRegistrationErrorMm());
474  accumulatedError += phantomRegistration->GetRegistrationErrorMm();
475  vtkPlusLogger::PrintProgressbar(100);
476 
477  if (numberFiles == 1)
478  {
479  // Save result
480  if (transformRepository->WriteConfiguration(configLandmarkDetection) != PLUS_SUCCESS)
481  {
482  LOG_ERROR("Failed to write phantom registration result to configuration element!");
483  exit(EXIT_FAILURE);
484  }
485 
486  std::string registrationResultFileName = "PhantomRegistrationAutoDetectLandmarkTest.xml";
487  vtksys::SystemTools::RemoveFile(registrationResultFileName.c_str());
488  igsioCommon::XML::PrintXML(registrationResultFileName.c_str(), configLandmarkDetection);
489 
490  if (CompareRegistrationResultsWithBaseline(inputBaselineFileName.c_str(), registrationResultFileName.c_str(), phantomRegistration->GetPhantomCoordinateFrame(), phantomRegistration->GetReferenceCoordinateFrame()) != PLUS_SUCCESS)
491  {
492  LOG_ERROR("Comparison of calibration data to baseline failed");
493  std::cout << "Exit failure!!!" << std::endl;
494  return EXIT_FAILURE;
495  }
496  }
497  }
498  }
499  LOG_INFO("AccumulatedError = " << accumulatedError << " Number of succesful registrations/datasets = " << succesfulDatasets << "/" << numberFiles - 2);
500  LOG_INFO("Exit success!!!");
501  return EXIT_SUCCESS;
502 }
503 
504 //-----------------------------------------------------------------------------
505 
506 // return the number of differences
507 PlusStatus CompareRegistrationResultsWithBaseline(const char* baselineFileName, const char* currentResultFileName, const char* phantomCoordinateFrame, const char* referenceCoordinateFrame)
508 {
509  if (baselineFileName == NULL)
510  {
511  LOG_ERROR("Unable to read the baseline configuration file - filename is NULL");
512  return PLUS_FAIL;
513  }
514 
515  if (currentResultFileName == NULL)
516  {
517  LOG_ERROR("Unable to read the current configuration file - filename is NULL");
518  return PLUS_FAIL;
519  }
520 
521  igsioTransformName tnPhantomToPhantomReference(phantomCoordinateFrame, referenceCoordinateFrame);
522 
523  // Load current phantom registration
524  vtkSmartPointer<vtkXMLDataElement> currentRootElem = vtkSmartPointer<vtkXMLDataElement>::Take(
525  vtkXMLUtilities::ReadElementFromFile(currentResultFileName));
526  if (currentRootElem == NULL)
527  {
528  LOG_ERROR("Unable to read the current configuration file: " << currentResultFileName);
529  return PLUS_FAIL;
530  }
531 
532  vtkSmartPointer<vtkIGSIOTransformRepository> currentTransformRepository = vtkSmartPointer<vtkIGSIOTransformRepository>::New();
533  if (currentTransformRepository->ReadConfiguration(currentRootElem) != PLUS_SUCCESS)
534  {
535  LOG_ERROR("Unable to read the current CoordinateDefinitions from configuration file: " << currentResultFileName);
536  return PLUS_FAIL;
537  }
538 
539  vtkSmartPointer<vtkMatrix4x4> currentMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
540  if (currentTransformRepository->GetTransform(tnPhantomToPhantomReference, currentMatrix) != PLUS_SUCCESS)
541  {
542  std::string strTransformName;
543  tnPhantomToPhantomReference.GetTransformName(strTransformName);
544  LOG_ERROR("Unable to get '" << strTransformName << "' coordinate definition from configuration file: " << currentResultFileName);
545  return PLUS_FAIL;
546  }
547 
548  // Load baseline phantom registration
549  vtkSmartPointer<vtkXMLDataElement> baselineRootElem = vtkSmartPointer<vtkXMLDataElement>::Take(
550  vtkXMLUtilities::ReadElementFromFile(baselineFileName));
551  if (baselineFileName == NULL)
552  {
553  LOG_ERROR("Unable to read the baseline configuration file: " << baselineFileName);
554  return PLUS_FAIL;
555  }
556 
557  vtkSmartPointer<vtkIGSIOTransformRepository> baselineTransformRepository = vtkSmartPointer<vtkIGSIOTransformRepository>::New();
558  if (baselineTransformRepository->ReadConfiguration(baselineRootElem) != PLUS_SUCCESS)
559  {
560  LOG_ERROR("Unable to read the baseline CoordinateDefinitions from configuration file: " << baselineFileName);
561  return PLUS_FAIL;
562  }
563 
564  vtkSmartPointer<vtkMatrix4x4> baselineMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
565  if (baselineTransformRepository->GetTransform(tnPhantomToPhantomReference, baselineMatrix) != PLUS_SUCCESS)
566  {
567  std::string strTransformName;
568  tnPhantomToPhantomReference.GetTransformName(strTransformName);
569  LOG_ERROR("Unable to get '" << strTransformName << "' coordinate definition from configuration file: " << baselineFileName);
570  return PLUS_FAIL;
571  }
572 
573  // Compare the transforms
574  double posDiff = igsioMath::GetPositionDifference(currentMatrix, baselineMatrix);
575  double orientDiff = igsioMath::GetOrientationDifference(currentMatrix, baselineMatrix);
576 
577  if (fabs(posDiff) > ERROR_THRESHOLD_MM || fabs(orientDiff) > ERROR_THRESHOLD_DEG)
578  {
579  LOG_ERROR("Transform mismatch (position difference: " << posDiff << " orientation difference: " << orientDiff);
580  return PLUS_FAIL;
581  }
582  LOG_INFO("Transform difference is acceptable (position difference: " << posDiff << " orientation difference: " << orientDiff);
583 
584  return PLUS_SUCCESS;
585 }
Abstract interface for tracker and video devices.
Definition: vtkPlusDevice.h:60
int main(int argc, char *argv[])
void SaveMetricPlot(const char *filename, vtkTable *stylusRef, vtkTable *stylusTipRef, vtkTable *stylusTipSpeed, std::string &xAxisLabel, std::string &yAxisLabel)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
PlusStatus ConstructSignalPlot(vtkIGSIOTrackedFrameList *trackedStylusTipFrames, std::string intermediateFileOutputDirectory, vtkXMLDataElement *aConfig)
bool GetTrackingDataAvailable()
for i
#define PLUS_FAIL
Definition: PlusCommon.h:43
PlusStatus CompareRegistrationResultsWithBaseline(const char *baselineFileName, const char *currentResultFileName, const char *phantomCoordinateFrame, const char *referenceCoordinateFrame)
static vtkPlusConfig * GetInstance()
PlusStatus ConstructTableSignal(std::deque< double > &x, std::deque< double > &y, vtkTable *table)
PlusStatus GetOutputChannelByName(vtkPlusChannel *&aChannel, const char *aChannelId)
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
std::string GetOutputDirectory()
virtual char * GetChannelId()
int x
Definition: phidget22.h:4265
Class for providing VTK video input interface from sequence fileAttributes:
static vtkIGSIOLogger * Instance()
Definition: ATC3DGm.h:319
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
Direction vectors of rods y
Definition: algo3.m:15
double frequency
Definition: phidget22.h:3246
void SetDeviceSetConfigurationData(vtkXMLDataElement *deviceSetConfigurationData)