7 #include "PlusConfigure.h" 11 #include <vnl/vnl_inverse.h> 13 #include "vtkIGSIOTrackedFrameList.h" 14 #include "igsioTrackedFrame.h" 15 #include "vtkIGSIOTransformRepository.h" 20 #include "vtkObjectFactory.h" 21 #include "vtkMatrix4x4.h" 23 #include "vtkXMLUtilities.h" 24 #include "vtkXMLDataElement.h" 26 #include "vtkTransform.h" 28 #include "vtksys/SystemTools.hxx" 29 #include "vtkPoints.h" 41 this->Superclass::PrintSelf(os, indent);
46 : CalibrationDate(NULL)
47 , ImageCoordinateFrame(NULL)
48 , ProbeCoordinateFrame(NULL)
49 , PhantomCoordinateFrame(NULL)
50 , ReferenceCoordinateFrame(NULL)
70 LOG_TRACE(
"vtkPlusProbeCalibrationAlgo::ReadConfiguration");
71 XML_FIND_NESTED_ELEMENT_REQUIRED(probeCalibrationElement, aConfig,
"vtkPlusProbeCalibrationAlgo");
81 LOG_ERROR(
"vtkPlusProbeCalibrationOptimizerAlgo is not well specified in vtkPlusProbeCalibrationOptimizerAlgo element of the configuration!");
91 LOG_TRACE(
"vtkPlusProbeCalibrationAlgo::Calibrate");
93 return Calibrate(validationTrackedFrameList, -1, -1, calibrationTrackedFrameList, -1, -1, transformRepository, nWires);
101 const unsigned int numberOfNWiresOnEachFrame = this->
NWires.size();
103 const unsigned int m = numberOfFrames * numberOfNWiresOnEachFrame;
108 LOG_ERROR(
"Unable to perform calibration - there are " << numberOfFrames <<
" frames with segmented points and minimum " <<
MIN_NUMBER_OF_VALID_CALIBRATION_FRAMES <<
" frames are needed");
112 vnl_sparse_matrix<double> middleWireIntersectionPointsPos_Image(m, n);
114 int outputColumnIndex = 0;
117 for (
unsigned int nWireIndex = 0; nWireIndex < numberOfNWiresOnEachFrame; ++nWireIndex)
120 middleWireIntersectionPointsPos_Image(outputColumnIndex, 0) = middleWireIntersectionPointPos_Image[0];
121 middleWireIntersectionPointsPos_Image(outputColumnIndex, 1) = middleWireIntersectionPointPos_Image[1];
122 middleWireIntersectionPointsPos_Image(outputColumnIndex, 2) = middleWireIntersectionPointPos_Image[2];
123 middleWireIntersectionPointsPos_Image(outputColumnIndex, 3) = middleWireIntersectionPointPos_Image[3];
129 imageToProbeTransformMatrix.fill(0);
131 for (
int row = 0; row < n; ++row)
133 vnl_vector<double> probePositionRowVector(m, 0);
138 for (
unsigned int nWireIndex = 0; nWireIndex < numberOfNWiresOnEachFrame; ++nWireIndex)
147 vnl_vector<unsigned int> nonOutliers(m);
148 for (
unsigned int i = 0;
i < m; ++
i)
150 nonOutliers.put(
i,
i);
153 vnl_vector<double> resultVector(n, 0);
156 LOG_ERROR(
"Failed to run LSQRMinimize!");
161 for (
unsigned int pointIndex = 0; pointIndex < m; pointIndex++)
163 bool validPoint =
false;
164 for (
unsigned int validPointListIndex = 0; validPointListIndex < nonOutliers.size(); validPointListIndex++)
166 if (nonOutliers.get(validPointListIndex) == pointIndex)
174 outliers.insert(pointIndex);
179 imageToProbeTransformMatrix.set_row(row, resultVector);
183 imageToProbeTransformMatrix(3, 0) = 0;
184 imageToProbeTransformMatrix(3, 1) = 0;
185 imageToProbeTransformMatrix(3, 2) = 0;
186 imageToProbeTransformMatrix(3, 3) = 1;
191 double xVector[3] = {imageToProbeTransformMatrix(0, 0), imageToProbeTransformMatrix(1, 0), imageToProbeTransformMatrix(2, 0)};
192 double yVector[3] = {imageToProbeTransformMatrix(0, 1), imageToProbeTransformMatrix(1, 1), imageToProbeTransformMatrix(2, 1)};
193 double zVector[3] = {0, 0, 0};
194 vtkMath::Cross(xVector, yVector, zVector);
195 vtkMath::Normalize(zVector);
196 double normZ = (vtkMath::Norm(xVector) + vtkMath::Norm(yVector)) / 2;
197 vtkMath::MultiplyScalar(zVector, normZ);
198 imageToProbeTransformMatrix(0, 2) = zVector[0];
199 imageToProbeTransformMatrix(1, 2) = zVector[1];
200 imageToProbeTransformMatrix(2, 2) = zVector[2];
202 LOG_DEBUG(outliers.size() <<
" outliers points were found");
208 PlusStatus vtkPlusProbeCalibrationAlgo::Calibrate(vtkIGSIOTrackedFrameList* validationTrackedFrameList,
int validationStartFrame,
int validationEndFrame, vtkIGSIOTrackedFrameList* calibrationTrackedFrameList,
int calibrationStartFrame,
int calibrationEndFrame, vtkIGSIOTransformRepository* transformRepository,
const std::vector<PlusNWire>& nWires)
210 LOG_TRACE(
"vtkPlusProbeCalibrationAlgo::Calibrate(validation: " << validationStartFrame <<
"-" << validationEndFrame <<
", calibration: " << calibrationStartFrame <<
"-" << calibrationEndFrame <<
")");
213 if (validationStartFrame < 0)
215 validationStartFrame = 0;
219 if (vtkIGSIOTrackedFrameList::VerifyProperties(validationTrackedFrameList, US_IMG_ORIENT_MF, US_IMG_BRIGHTNESS) !=
PLUS_SUCCESS)
221 LOG_ERROR(
"Failed to perform calibration - validation tracked frame list is invalid");
224 if (vtkIGSIOTrackedFrameList::VerifyProperties(calibrationTrackedFrameList, US_IMG_ORIENT_MF, US_IMG_BRIGHTNESS) !=
PLUS_SUCCESS)
226 LOG_ERROR(
"Failed to perform calibration - calibration tracked frame list is invalid");
230 int numberOfValidationFrames = validationTrackedFrameList->GetNumberOfTrackedFrames();
231 if (validationEndFrame < 0 || validationEndFrame >= numberOfValidationFrames)
233 validationEndFrame = numberOfValidationFrames;
236 if (calibrationStartFrame < 0)
238 calibrationStartFrame = 0;
241 int numberOfCalibrationFrames = calibrationTrackedFrameList->GetNumberOfTrackedFrames();
242 if (calibrationEndFrame < 0 || calibrationEndFrame >= numberOfCalibrationFrames)
244 calibrationEndFrame = numberOfCalibrationFrames;
254 for (
int frameNumber = validationStartFrame; frameNumber < validationEndFrame; ++frameNumber)
256 LOG_DEBUG(
"\n----------------------------------");
257 LOG_DEBUG(
"Add frame #" << frameNumber <<
" for validation data");
260 LOG_ERROR(
"Add validation position failed on frame #" << frameNumber);
267 for (
int frameNumber = calibrationStartFrame; frameNumber < calibrationEndFrame; ++frameNumber)
269 LOG_DEBUG(
"\n----------------------------------");
270 LOG_DEBUG(
"Add frame #" << frameNumber <<
" for calibration data");
273 LOG_ERROR(
"Add calibration position failed on frame #" << frameNumber);
282 LOG_ERROR(
"Unable to perform calibration - calibration data is empty!");
286 vnl_matrix_fixed<double, 4, 4> imageToProbeTransformMatrix;
287 std::set<int> outliers;
290 LOG_ERROR(
"Calibration with linear least squares method failed");
298 LOG_INFO(
"Additional calibration optimization is requested");
307 LOG_INFO(
"Image to probe transform matrix = ");
313 LOG_ERROR(
"Failed to compute validation 3D reprojection errors!");
323 LOG_ERROR(
"Failed to compute calibration 3D reprojection errors!");
332 LOG_ERROR(
"Failed to compute validation 2D reprojection errors!");
335 for (
unsigned int wire = 0; wire < this->
NWires.size() * 3; ++wire)
337 LOG_INFO(
"Validation 2D Reprojection Error (IPE) for wire " << this->
NWires[wire / 3].GetWires()[wire % 3].GetName() <<
": " 340 <<
"StdDev: (" << this->PreProcessedWirePositions[
VALIDATION_ALL].NWireErrors.ReprojectionError2DStdDevs[wire][0] <<
"px, " 341 << this->PreProcessedWirePositions[
VALIDATION_ALL].NWireErrors.ReprojectionError2DStdDevs[wire][1] <<
"px)");
346 LOG_ERROR(
"Failed to compute calibration 2D reprojection errors!");
349 for (
unsigned int wire = 0; wire < this->
NWires.size() * 3; ++wire)
351 LOG_INFO(
"Calibration 2D Reprojection Error (IPE) for wire " << this->
NWires[wire / 3].GetWires()[wire % 3].GetName() <<
": " 354 << this->PreProcessedWirePositions[
CALIBRATION_ALL].NWireErrors.ReprojectionError2DStdDevs[wire][0] <<
"px, " 355 << this->PreProcessedWirePositions[
CALIBRATION_ALL].NWireErrors.ReprojectionError2DStdDevs[wire][1] <<
"px)");
361 LOG_ERROR(
"Failed to save report!");
371 LOG_TRACE(
"vtkPlusProbeCalibrationAlgo::AddPositionsPerImage(type=" << datasetType <<
")");
374 std::vector<vnl_vector<double> > segmentedWireIntersectionPointsPos_Image;
376 vtkPoints* segmentedPointsVtk = trackedFrame->GetFiducialPointsCoordinatePx();
377 if (segmentedPointsVtk == NULL)
379 LOG_WARNING(
"Segmentation has not been run on frame!");
382 if (segmentedPointsVtk->GetNumberOfPoints() == 0)
384 LOG_DEBUG(
"Segmentation failed on frame, so it will be ignored");
387 if (segmentedPointsVtk->GetNumberOfPoints() % 3 != 0)
389 LOG_ERROR(
"Frame does not contain N-Wires only!");
393 for (
int wire = 0; wire < segmentedPointsVtk->GetNumberOfPoints(); wire++)
395 vnl_vector<double> vnlPoint(4, 0);
396 double* point = segmentedPointsVtk->GetPoint(wire);
397 vnlPoint[0] = point[0];
398 vnlPoint[1] = point[1];
401 segmentedWireIntersectionPointsPos_Image.push_back(vnlPoint);
406 vnl_matrix_fixed<double, 4, 4> phantomToProbeTransformMatrix;
409 vtkSmartPointer<vtkMatrix4x4> probeToReferenceVtkTransformMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
410 transformRepository->SetTransforms(*trackedFrame);
411 ToolStatus status(TOOL_INVALID);
412 if (transformRepository->GetTransform(probeToReferenceTransformName, probeToReferenceVtkTransformMatrix, &status) !=
PLUS_SUCCESS || status != TOOL_OK)
414 std::string transformName;
415 probeToReferenceTransformName.GetTransformName(transformName);
416 LOG_ERROR(
"Cannot get frame transform '" << transformName <<
"' from tracked frame!");
422 vtkSmartPointer<vtkMatrix4x4> phantomToReferenceTransformMatrixVtk = vtkSmartPointer<vtkMatrix4x4>::New();
423 if (transformRepository->GetTransform(phantomToReferenceTransformName, phantomToReferenceTransformMatrixVtk, &status) !=
PLUS_SUCCESS || status != TOOL_OK)
425 LOG_ERROR(
"No valid transform found from phantom to reference");
429 vnl_matrix_fixed<double, 4, 4> phantomToReferenceTransformMatrix;
433 vnl_matrix_fixed<double, 4, 4> probeToReferenceTransformMatrix;
436 vnl_matrix_fixed<double, 4, 4> referenceToProbeTransformMatrix = vnl_inverse(probeToReferenceTransformMatrix);
439 vnl_vector<double> lastRow(4, 0);
441 referenceToProbeTransformMatrix.set_row(3, lastRow);
442 LOG_DEBUG(
"Reference to probe transform = \n" << referenceToProbeTransformMatrix);
444 phantomToProbeTransformMatrix = referenceToProbeTransformMatrix * phantomToReferenceTransformMatrix;
453 vtkSmartPointer<vtkMatrix4x4> probeToPhantomVtkTransformMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
455 ToolStatus status(TOOL_INVALID);
456 if (transformRepository->GetTransform(probeToPhantomTransformName, probeToPhantomVtkTransformMatrix, &status) !=
PLUS_SUCCESS || status != TOOL_OK)
458 std::string transformName;
459 probeToPhantomTransformName.GetTransformName(transformName);
460 LOG_ERROR(
"Cannot get frame transform '" << transformName <<
"' from tracked frame!");
464 vnl_matrix_fixed<double, 4, 4> probeToPhantomTransformMatrix;
471 std::vector< vnl_vector_fixed<double, 4> > middleWireIntersectionPointsPos_Phantom;
472 for (
unsigned int nWireIndex = 0; nWireIndex < this->
NWires.size(); ++nWireIndex)
474 int wire1Index = nWireIndex * 3 + 0;
475 int wire2Index = nWireIndex * 3 + 1;
476 int wire3Index = nWireIndex * 3 + 2;
479 vnl_vector<double> wire12vector_Image = segmentedWireIntersectionPointsPos_Image[wire2Index] - segmentedWireIntersectionPointsPos_Image[wire1Index];
480 vnl_vector<double> wire13vector_Image = segmentedWireIntersectionPointsPos_Image[wire3Index] - segmentedWireIntersectionPointsPos_Image[wire1Index];
481 double alpha = (double)wire12vector_Image.magnitude() / wire13vector_Image.magnitude();
484 vnl_vector_fixed<double, 4> middleWireIntersectionPointPos_Phantom(4);
485 vnl_vector_fixed<double, 4> intersectPosW12_Phantom(this->
NWires[nWireIndex].IntersectPosW12[0], this->
NWires[nWireIndex].IntersectPosW12[1], this->
NWires[nWireIndex].IntersectPosW12[2], 1.0);
486 vnl_vector_fixed<double, 4> intersectPosW32_Phantom(this->
NWires[nWireIndex].IntersectPosW32[0], this->
NWires[nWireIndex].IntersectPosW32[1], this->
NWires[nWireIndex].IntersectPosW32[2], 1.0);
487 middleWireIntersectionPointPos_Phantom = intersectPosW12_Phantom +
alpha * (intersectPosW32_Phantom - intersectPosW12_Phantom);
489 LOG_DEBUG(
"NWire #" << nWireIndex);
490 LOG_DEBUG(
" Segmented point #" << wire1Index <<
" = " << segmentedWireIntersectionPointsPos_Image[wire1Index]);
491 LOG_DEBUG(
" Segmented point #" << wire2Index <<
" = " << segmentedWireIntersectionPointsPos_Image[wire2Index] <<
" (middle wire)");
492 LOG_DEBUG(
" Segmented point #" << wire3Index <<
" = " << segmentedWireIntersectionPointsPos_Image[wire3Index]);
493 LOG_DEBUG(
" Alpha = " <<
alpha);
494 LOG_DEBUG(
" Middle wire position in phantom frame = " << middleWireIntersectionPointPos_Phantom);
498 vnl_vector<double> middleWireIntersectionPointPos_Probe = phantomToProbeTransformMatrix * middleWireIntersectionPointPos_Phantom;
500 LOG_DEBUG(
" Middle wire position in probe frame = " << middleWireIntersectionPointPos_Probe);
521 vnl_matrix_fixed<double, 3, 3> imageToProbeTransformMatrixRot = imageToProbeTransformMatrix.extract(3, 3);
523 vnl_vector_fixed<double, 3> xVector = imageToProbeTransformMatrixRot.get_column(0);
524 vnl_vector_fixed<double, 3> yVector = imageToProbeTransformMatrixRot.get_column(1);
527 double angleXYdeg = fabs(vtkMath::DegreesFromRadians(acos(dot_product<double, 3>(xVector, yVector))));
528 const double angleToleranceDeg = 1.0;
529 if (fabs(angleXYdeg - 90.0) > angleToleranceDeg)
531 LOG_WARNING(
"ImageToProbe transformation matrix X and Y axes are not orthogonal. XY axis angle = " << angleXYdeg <<
" deg");
538 vtkSmartPointer<vtkMatrix4x4> imageToProbeMatrixVtk = vtkSmartPointer<vtkMatrix4x4>::New();
541 transformRepository->SetTransform(imageToProbeTransformName, imageToProbeMatrixVtk);
542 transformRepository->SetTransformPersistent(imageToProbeTransformName,
true);
543 transformRepository->SetTransformDate(imageToProbeTransformName, vtkIGSIOAccurateTimer::GetInstance()->GetDateAndTimeString().c_str());
546 this->
SetCalibrationDate(vtksys::SystemTools::GetCurrentDateTime(
"%Y.%m.%d %X").c_str());
552 LOG_TRACE(
"vtkPlusProbeCalibrationAlgo::ComputeReprojectionErrors3D");
554 std::vector<double> reprojectionErrors;
555 ComputeError3d(reprojectionErrors, datasetType, imageToProbeTransformMatrix);
557 int numberOfNWiresPerFrame = this->
NWires.size();
560 for (
unsigned int frameIndex = 0; frameIndex < reprojectionErrors.size() / numberOfNWiresPerFrame; frameIndex++)
562 for (
int nWireIndex = 0; nWireIndex < numberOfNWiresPerFrame; nWireIndex++)
571 this->PreProcessedWirePositions[datasetType].NWireErrors.ReprojectionError3DStdDev);
579 LOG_TRACE(
"vtkPlusProbeCalibrationAlgo::ComputeReprojectionErrors2D");
583 double errorMean = 0.0;
584 double errorStdev = 0.0;
586 &(this->PreProcessedWirePositions[datasetType].NWireErrors.ReprojectionError2Ds));
592 for (
int wire = 0; wire < numberOfWires; wire++)
594 std::vector<double> xErrors;
595 std::vector<double> yErrors;
596 for (
int frameIndex = 0; frameIndex < numberOfFrames; frameIndex++)
601 double xErrorMean = 0.0;
602 double xErrorStdev = 0.0;
603 igsioMath::ComputeMeanAndStdev(xErrors, xErrorMean, xErrorStdev);
604 double yErrorMean = 0.0;
605 double yErrorStdev = 0.0;
606 igsioMath::ComputeMeanAndStdev(yErrors, yErrorMean, yErrorStdev);
607 vnl_vector_fixed<double, 2> errorMean(xErrorMean, yErrorMean);
609 vnl_vector_fixed<double, 2> errorStdev(xErrorStdev, yErrorStdev);
619 LOG_TRACE(
"vtkPlusProbeCalibrationAlgo::GetResultString");
621 std::ostringstream matrixStringStream;
622 matrixStringStream <<
"Image to probe transform:" << std::endl;
626 matrixStringStream << std::endl;
630 matrixStringStream <<
"Image pixel size (mm):" << std::endl;
631 matrixStringStream <<
" " << std::fixed << std::setprecision(precision + 1) << pixelSizeX <<
" x " << pixelSizeY << std::endl;
633 std::ostringstream errorsStringStream;
635 errorsStringStream << std::fixed << std::setprecision(precision) <<
"3D Reprojection Error (mm)" << std::endl <<
639 errorsStringStream <<
"2D Reprojection Errors (px)" << std::endl;;
640 for (
unsigned int wire = 0; wire < this->
NWires.size() * 3; ++wire)
642 errorsStringStream << std::fixed << std::setprecision(precision - 1) <<
643 "Wire #" << wire <<
" (" << this->
NWires[wire / 3].GetWires()[wire % 3].GetName() <<
")" << std::endl <<
650 std::ostringstream resultStringStream;
651 resultStringStream << matrixStringStream.str() << std::endl << errorsStringStream.str();
655 return resultStringStream.str();
661 LOG_TRACE(
"vtkPlusProbeCalibrationAlgo::SaveCalibrationResultsAndErrorReportsToXML");
663 std::string calibrationResultFileName = std::string(
vtkPlusConfig::GetInstance()->GetApplicationStartTimestamp()) +
".Calibration.results.xml";
667 vtkSmartPointer<vtkXMLDataElement> probeCalibrationResult = vtkSmartPointer<vtkXMLDataElement>::New();
669 probeCalibrationResult->SetName(
"ProbeCalibrationResult");
670 probeCalibrationResult->SetAttribute(
"version",
"2.0");
673 vtkSmartPointer<vtkXMLDataElement> calibrationFile = vtkSmartPointer<vtkXMLDataElement>::New();
674 calibrationFile->SetName(
"CalibrationFile");
676 calibrationFile->SetAttribute(
"FileName", calibrationResultFileName.c_str());
678 PlusStatus status = this->
GetXMLCalibrationResultAndErrorReport(validationTrackedFrameList, validationStartFrame, validationEndFrame, calibrationTrackedFrameList, calibrationStartFrame, calibrationEndFrame, probeCalibrationResult);
682 probeCalibrationResult->AddNestedElement(calibrationFile);
683 igsioCommon::XML::PrintXML(calibrationResultFileNameWithPath.c_str(), probeCalibrationResult);
692 LOG_TRACE(
"vtkPlusProbeCalibrationAlgo::GetXMLCalibrationResultAndErrorReport");
694 std::string calibrationResultFileName = std::string(
vtkPlusConfig::GetInstance()->GetApplicationStartTimestamp()) +
".Calibration.results.xml";
697 if (probeCalibrationResult == NULL)
699 LOG_ERROR(
"Unable to get xml calibration result and error report - xml data element is NULL");
703 if (validationTrackedFrameList == NULL)
705 LOG_ERROR(
"Unable to get xml calibration result and error report - validationTrackedFrameList is NULL");
709 if (calibrationTrackedFrameList == NULL)
711 LOG_ERROR(
"Unable to get xml calibration result and error report - calibrationTrackedFrameList is NULL");
716 vtkSmartPointer<vtkXMLDataElement> calibrationResults = vtkSmartPointer<vtkXMLDataElement>::New();
717 calibrationResults->SetName(
"CalibrationResults");
720 vtkSmartPointer<vtkXMLDataElement> imageToProbeTransformElement = vtkSmartPointer<vtkXMLDataElement>::New();
721 imageToProbeTransformElement->SetName(
"Transform");
725 imageToProbeTransformElement->SetVectorAttribute(
"Matrix", 16, imageToProbeTransformVector);
727 calibrationResults->AddNestedElement(imageToProbeTransformElement);
731 vtkSmartPointer<vtkXMLDataElement> errorReport = vtkSmartPointer<vtkXMLDataElement>::New();
732 errorReport->SetName(
"ErrorReport");
735 vtkSmartPointer<vtkXMLDataElement> reprojectionError3DStatistics = vtkSmartPointer<vtkXMLDataElement>::New();
736 reprojectionError3DStatistics->SetName(
"ReprojectionError3DStatistics");
738 reprojectionError3DStatistics->SetDoubleAttribute(
"ValidationStdDevMm", this->
PreProcessedWirePositions[VALIDATION_ALL].NWireErrors.ReprojectionError3DStdDev);
740 reprojectionError3DStatistics->SetDoubleAttribute(
"CalibrationStdDevMm", this->
PreProcessedWirePositions[CALIBRATION_ALL].NWireErrors.ReprojectionError3DStdDev);
743 vtkSmartPointer<vtkXMLDataElement> reprojectionError2DStatistics = vtkSmartPointer<vtkXMLDataElement>::New();
744 reprojectionError2DStatistics->SetName(
"ReprojectionError2DStatistics");
746 for (
unsigned int wire = 0; wire < this->
NWires.size() * 3; ++wire)
748 vtkSmartPointer<vtkXMLDataElement> wireElem = vtkSmartPointer<vtkXMLDataElement>::New();
749 wireElem->SetName(
"Wire");
750 wireElem->SetAttribute(
"Name", this->
NWires[wire / 3].GetWires()[wire % 3].GetName().c_str());
756 wireElem->SetVectorAttribute(
"ValidationMeanPx", 2, validationMean2D);
757 wireElem->SetVectorAttribute(
"ValidationStdDevPx", 2, validationStdDev2D);
758 wireElem->SetVectorAttribute(
"CalibrationMeanPx", 2, calibrationMean2D);
759 wireElem->SetVectorAttribute(
"CalibrationStdDevPx", 2, calibrationStdDev2D);
761 reprojectionError2DStatistics->AddNestedElement(wireElem);
765 vtkSmartPointer<vtkXMLDataElement> validationData = vtkSmartPointer<vtkXMLDataElement>::New();
766 validationData->SetName(
"ValidationData");
768 int numberOfSegmentedFramesSoFar = 0;
769 for (
int frameNumber = validationStartFrame; frameNumber < validationEndFrame; ++frameNumber)
771 vtkPoints* segmentedPointsVtk = validationTrackedFrameList->GetTrackedFrame(frameNumber)->GetFiducialPointsCoordinatePx();
774 vtkSmartPointer<vtkXMLDataElement> frame = vtkSmartPointer<vtkXMLDataElement>::New();
775 frame->SetName(
"Frame");
776 frame->SetIntAttribute(
"Index", frameNumber);
778 if (segmentedPointsVtk == NULL)
780 frame->SetAttribute(
"SegmentationStatus",
"HasNotBeenRun");
781 validationData->AddNestedElement(frame);
784 if (segmentedPointsVtk->GetNumberOfPoints() == 0)
786 frame->SetAttribute(
"SegmentationStatus",
"Failed");
787 validationData->AddNestedElement(frame);
790 if (segmentedPointsVtk->GetNumberOfPoints() % 3 != 0)
792 frame->SetAttribute(
"SegmentationStatus",
"InvalidPatterns");
793 validationData->AddNestedElement(frame);
796 frame->SetAttribute(
"SegmentationStatus",
"OK");
799 vtkSmartPointer<vtkXMLDataElement> segmentedWireIntersectionPointsPos_Image = vtkSmartPointer<vtkXMLDataElement>::New();
800 segmentedWireIntersectionPointsPos_Image->SetName(
"SegmentedPoints");
802 int numberOfSegmentedPoints = segmentedPointsVtk->GetNumberOfPoints();
803 for (
int wire = 0; wire < numberOfSegmentedPoints; wire++)
806 segmentedPointsVtk->GetPoint(wire, point);
808 vtkSmartPointer<vtkXMLDataElement> pointElement = vtkSmartPointer<vtkXMLDataElement>::New();
809 pointElement->SetName(
"Point");
810 pointElement->SetAttribute(
"WireName", this->
NWires[wire / 3].GetWires()[wire % 3].GetName().c_str());
811 pointElement->SetVectorAttribute(
"Position", 3, point);
812 segmentedWireIntersectionPointsPos_Image->AddNestedElement(pointElement);
816 vtkSmartPointer<vtkXMLDataElement> reprojectionError3Ds = vtkSmartPointer<vtkXMLDataElement>::New();
817 reprojectionError3Ds->SetName(
"ReprojectionError3DList");
819 for (
int nWire = 0; nWire < numberOfSegmentedPoints / 3; ++nWire)
821 vtkSmartPointer<vtkXMLDataElement> reprojectionError3DElement = vtkSmartPointer<vtkXMLDataElement>::New();
822 reprojectionError3DElement->SetName(
"ReprojectionError3D");
823 reprojectionError3DElement->SetAttribute(
"WireName", this->
NWires[nWire].GetWires()[1].GetName().c_str());
824 reprojectionError3DElement->SetDoubleAttribute(
"ErrorMm", this->
PreProcessedWirePositions[VALIDATION_ALL].NWireErrors.ReprojectionError3Ds[nWire][numberOfSegmentedFramesSoFar]);
825 reprojectionError3Ds->AddNestedElement(reprojectionError3DElement);
829 vtkSmartPointer<vtkXMLDataElement> reprojectionError2Ds = vtkSmartPointer<vtkXMLDataElement>::New();
830 reprojectionError2Ds->SetName(
"ReprojectionError2DList");
832 for (
int wire = 0; wire < numberOfSegmentedPoints; ++wire)
835 vtkSmartPointer<vtkXMLDataElement> reprojectionError2DElement = vtkSmartPointer<vtkXMLDataElement>::New();
836 reprojectionError2DElement->SetName(
"ReprojectionError2D");
837 reprojectionError2DElement->SetAttribute(
"WireName", this->
NWires[wire / 3].GetWires()[wire % 3].GetName().c_str());
838 reprojectionError2DElement->SetVectorAttribute(
"ErrorPx", 2, reprojectionError2D);
839 reprojectionError2Ds->AddNestedElement(reprojectionError2DElement);
842 frame->AddNestedElement(segmentedWireIntersectionPointsPos_Image);
843 frame->AddNestedElement(reprojectionError3Ds);
844 frame->AddNestedElement(reprojectionError2Ds);
846 vtkSmartPointer<vtkXMLDataElement> trackedFrame = vtkSmartPointer<vtkXMLDataElement>::New();
847 if (validationTrackedFrameList->GetTrackedFrame(frameNumber)->PrintToXML(trackedFrame, std::vector<igsioTransformName>()) ==
PLUS_SUCCESS)
849 frame->AddNestedElement(trackedFrame);
852 validationData->AddNestedElement(frame);
854 numberOfSegmentedFramesSoFar++;
858 vtkSmartPointer<vtkXMLDataElement> calibrationData = vtkSmartPointer<vtkXMLDataElement>::New();
859 calibrationData->SetName(
"CalibrationData");
861 numberOfSegmentedFramesSoFar = 0;
862 for (
int frameNumber = calibrationStartFrame; frameNumber < calibrationEndFrame; ++frameNumber)
864 vtkPoints* segmentedPointsVtk = calibrationTrackedFrameList->GetTrackedFrame(frameNumber)->GetFiducialPointsCoordinatePx();
867 vtkSmartPointer<vtkXMLDataElement> frame = vtkSmartPointer<vtkXMLDataElement>::New();
868 frame->SetName(
"Frame");
869 frame->SetIntAttribute(
"Index", frameNumber);
871 if (segmentedPointsVtk == NULL)
873 frame->SetAttribute(
"SegmentationStatus",
"HasNotBeenRun");
874 calibrationData->AddNestedElement(frame);
877 if (segmentedPointsVtk->GetNumberOfPoints() == 0)
879 frame->SetAttribute(
"SegmentationStatus",
"Failed");
880 calibrationData->AddNestedElement(frame);
883 if (segmentedPointsVtk->GetNumberOfPoints() % 3 != 0)
885 frame->SetAttribute(
"SegmentationStatus",
"InvalidPatterns");
886 calibrationData->AddNestedElement(frame);
889 frame->SetAttribute(
"SegmentationStatus",
"OK");
892 vtkSmartPointer<vtkXMLDataElement> segmentedWireIntersectionPointsPos_Image = vtkSmartPointer<vtkXMLDataElement>::New();
893 segmentedWireIntersectionPointsPos_Image->SetName(
"SegmentedPoints");
895 int numberOfSegmentedPoints = segmentedPointsVtk->GetNumberOfPoints();
896 for (
int wire = 0; wire < numberOfSegmentedPoints; wire++)
899 segmentedPointsVtk->GetPoint(wire, point);
901 vtkSmartPointer<vtkXMLDataElement> pointElement = vtkSmartPointer<vtkXMLDataElement>::New();
902 pointElement->SetName(
"Point");
903 pointElement->SetAttribute(
"WireName", this->
NWires[wire / 3].GetWires()[wire % 3].GetName().c_str());
904 pointElement->SetVectorAttribute(
"Position", 3, point);
905 segmentedWireIntersectionPointsPos_Image->AddNestedElement(pointElement);
909 vtkSmartPointer<vtkXMLDataElement> middleWires = vtkSmartPointer<vtkXMLDataElement>::New();
910 middleWires->SetName(
"MiddleWires");
914 vtkSmartPointer<vtkXMLDataElement> middleWire = vtkSmartPointer<vtkXMLDataElement>::New();
915 middleWire->SetName(
"MiddleWire");
917 double middleWirePositionInImageFrame[4];
918 double middleWirePositionInProbeFrame[4];
919 for (
int k = 0; k < 4; ++k)
924 middleWire->SetVectorAttribute(
"PositionInImageFrame", 4, middleWirePositionInImageFrame);
925 middleWire->SetVectorAttribute(
"PositionInProbeFrame", 4, middleWirePositionInProbeFrame);
926 middleWires->AddNestedElement(middleWire);
930 vtkSmartPointer<vtkXMLDataElement> reprojectionError3Ds = vtkSmartPointer<vtkXMLDataElement>::New();
931 reprojectionError3Ds->SetName(
"ReprojectionError3DList");
933 for (
int nWire = 0; nWire < numberOfSegmentedPoints / 3; ++nWire)
935 vtkSmartPointer<vtkXMLDataElement> reprojectionError3DElement = vtkSmartPointer<vtkXMLDataElement>::New();
936 reprojectionError3DElement->SetName(
"ReprojectionError3D");
937 reprojectionError3DElement->SetAttribute(
"WireName", this->
NWires[nWire].GetWires()[1].GetName().c_str());
938 reprojectionError3DElement->SetDoubleAttribute(
"ErrorMm", this->
PreProcessedWirePositions[CALIBRATION_ALL].NWireErrors.ReprojectionError3Ds[nWire][numberOfSegmentedFramesSoFar]);
939 reprojectionError3Ds->AddNestedElement(reprojectionError3DElement);
943 vtkSmartPointer<vtkXMLDataElement> reprojectionError2Ds = vtkSmartPointer<vtkXMLDataElement>::New();
944 reprojectionError2Ds->SetName(
"ReprojectionError2DList");
946 for (
int wire = 0; wire < numberOfSegmentedPoints; ++wire)
949 vtkSmartPointer<vtkXMLDataElement> reprojectionError2DElement = vtkSmartPointer<vtkXMLDataElement>::New();
950 reprojectionError2DElement->SetName(
"ReprojectionError2D");
951 reprojectionError2DElement->SetAttribute(
"WireName", this->
NWires[wire / 3].GetWires()[wire % 3].GetName().c_str());
952 reprojectionError2DElement->SetVectorAttribute(
"ErrorPx", 2, reprojectionError2D);
953 reprojectionError2Ds->AddNestedElement(reprojectionError2DElement);
956 frame->AddNestedElement(segmentedWireIntersectionPointsPos_Image);
957 frame->AddNestedElement(middleWires);
958 frame->AddNestedElement(reprojectionError3Ds);
959 frame->AddNestedElement(reprojectionError2Ds);
961 vtkSmartPointer<vtkXMLDataElement> trackedFrame = vtkSmartPointer<vtkXMLDataElement>::New();
962 if (calibrationTrackedFrameList->GetTrackedFrame(frameNumber)->PrintToXML(trackedFrame, std::vector<igsioTransformName>()) ==
PLUS_SUCCESS)
964 frame->AddNestedElement(trackedFrame);
967 calibrationData->AddNestedElement(frame);
969 numberOfSegmentedFramesSoFar++;
972 errorReport->AddNestedElement(reprojectionError3DStatistics);
973 errorReport->AddNestedElement(reprojectionError2DStatistics);
974 errorReport->AddNestedElement(validationData);
975 errorReport->AddNestedElement(calibrationData);
977 probeCalibrationResult->AddNestedElement(calibrationResults);
978 probeCalibrationResult->AddNestedElement(errorReport);
997 bool outlier =
false;
998 for (
unsigned int nWireIndex = 0; nWireIndex < this->
NWires.size(); ++nWireIndex)
1000 if (outliers.find(frameIndex * this->NWires.size() + nWireIndex) != outliers.end())
1020 double wireP0[3] = {aLineEndPoint1[0], aLineEndPoint1[1], aLineEndPoint1[2]};
1021 double wireP1[3] = {aLineEndPoint2[0], aLineEndPoint2[1], aLineEndPoint2[2]};
1022 double segmentedPoint[3] = {aPoint(0), aPoint(1), aPoint(2)};
1023 double distanceToWire = sqrt(vtkLine::DistanceToLine(segmentedPoint, wireP0, wireP1));
1024 return distanceToWire;
1035 double& errorMean,
double& errorStDev,
double& errorRms,
1036 std::vector< std::vector< vnl_vector_fixed<double, 2> > >* reprojectionError2Ds )
1038 std::vector<double> reprojectionErrors;
1040 int nWires = this->
NWires.size();
1042 vnl_vector_fixed<double, 4> segmentedInPhantomFrame_vnl;
1043 segmentedInPhantomFrame_vnl(3) = 1;
1044 vnl_vector_fixed<double, 4> wireFrontPoint_Phantom;
1045 vnl_vector_fixed<double, 4> wireBackPoint_Phantom;
1046 wireFrontPoint_Phantom(3) = 1;
1047 wireBackPoint_Phantom(3) = 1;
1048 vnl_vector_fixed<double, 4> wireFrontPoint_Image;
1049 vnl_vector_fixed<double, 4> wireBackPoint_Image;
1050 wireFrontPoint_Image(3) = 1;
1051 wireBackPoint_Image(3) = 1;
1054 if (reprojectionError2Ds != NULL)
1056 reprojectionError2Ds->clear();
1057 reprojectionError2Ds->resize(this->
NWires.size() * 3);
1060 for (
int frameIndex = 0; frameIndex < numberOfFrames; frameIndex++)
1063 vnl_matrix_fixed<double, 4, 4> phantomToImageTransform_vnl = vnl_inverse(imageToProbeMatrix) * vnl_inverse(probeToPhantomTransform_vnl);
1064 vtkSmartPointer<vtkMatrix4x4> phantomToImageTransform = vtkSmartPointer<vtkMatrix4x4>::New();
1067 double normalVector[3] = { 0.0, 0.0, 1.0 };
1068 double origin[3] = { 0.0, 0.0, 0.0 };
1070 for (
int nWireIndex = 0; nWireIndex < nWires; nWireIndex++)
1072 for (
int wireIndex = 0; wireIndex < 3; wireIndex++)
1078 double wireEndPointFrontInImageFrame[4] = {0};
1079 double wireEndPointBackInImageFrame[4] = {0};
1080 phantomToImageTransform->MultiplyPoint(wireEndPointFrontInPhantomFrame, wireEndPointFrontInImageFrame);
1081 phantomToImageTransform->MultiplyPoint(wireEndPointBackInPhantomFrame, wireEndPointBackInImageFrame);
1083 double computedPositionInImagePlane[3];
1087 if ((! vtkPlane::IntersectWithLine(wireEndPointFrontInImageFrame, wireEndPointBackInImageFrame, normalVector, origin,
t, computedPositionInImagePlane))
1088 && (wireEndPointFrontInImageFrame[3] * wireEndPointBackInImageFrame[3] < 0))
1090 LOG_WARNING(
"Image plane and wire are parallel!");
1091 if (reprojectionError2Ds != NULL)
1093 vnl_vector_fixed<double, 2> reprojectionError2D(2, DBL_MAX);
1094 (*reprojectionError2Ds)[nWireIndex * 3 + wireIndex].push_back(reprojectionError2D);
1102 vnl_vector_fixed<double, 2> reprojectionError2D;
1103 reprojectionError2D[0] = segmentedPoint_Image[0] - computedPositionInImagePlane[0];
1104 reprojectionError2D[1] = segmentedPoint_Image[1] - computedPositionInImagePlane[1];
1106 if (reprojectionError2Ds != NULL)
1108 (*reprojectionError2Ds)[nWireIndex * 3 + wireIndex].push_back(reprojectionError2D);
1110 reprojectionErrors.push_back(reprojectionError2D.magnitude());
1115 igsioMath::ComputeMeanAndStdev(reprojectionErrors, errorMean, errorStDev);
1116 igsioMath::ComputeRms(reprojectionErrors, errorRms);
1122 reprojectionErrors.clear();
1124 vnl_vector_fixed<double, 4> segmentedInProbeFrame_vnl;
1125 vnl_vector_fixed<double, 4> pointErrorVector;
1126 for (
int frameIndex = 0; frameIndex < numberOfFrames; frameIndex++)
1128 for (
unsigned int nWireIndex = 0; nWireIndex < this->
NWires.size(); nWireIndex++)
1134 reprojectionErrors.push_back(pointErrorVector.magnitude());
1142 std::vector<double> reprojectionErrors;
1144 igsioMath::ComputeMeanAndStdev(reprojectionErrors, errorMean, errorStDev);
1145 igsioMath::ComputeRms(reprojectionErrors, errorRms);
vnl_matrix_fixed< double, 4, 4 > ImageToProbeTransformMatrix
vtkPlusProbeCalibrationOptimizerAlgo * Optimizer
char * ImageCoordinateFrame
double ReprojectionError3DMean
std::string GetOutputPath(const std::string &subPath)
char * ReferenceCoordinateFrame
std::string GetResultString(int precision=3)
static PlusStatus LSQRMinimize(const std::vector< std::vector< double > > &aMatrix, const std::vector< double > &bVector, vnl_vector< double > &resultVector, double *mean=NULL, double *stdev=NULL, vnl_vector< unsigned int > *notOutliersIndices=NULL)
void ComputeError2d(const vnl_matrix_fixed< double, 4, 4 > &imageToProbeMatrix, double &errorMean, double &errorStDev, double &errorRms)
PlusStatus ComputeImageToProbeTransformByLinearLeastSquaresMethod(vnl_matrix_fixed< double, 4, 4 > &imageToProbeTransformMatrix, std::set< int > &outliers)
PlusStatus Calibrate(vtkIGSIOTrackedFrameList *validationTrackedFrameList, int validationStartFrame, int validationEndFrame, vtkIGSIOTrackedFrameList *calibrationTrackedFrameList, int calibrationStartFrame, int calibrationEndFrame, vtkIGSIOTransformRepository *transformRepository, const std::vector< PlusNWire > &nWires)
static const double DEFAULT_ERROR_CONFIDENCE_INTERVAL
double ReprojectionError3DStdDev
std::vector< vnl_vector_fixed< double, 2 > > ReprojectionError2DMeans
void SetImageToProbeSeedTransform(const vnl_matrix_fixed< double, 4, 4 > &imageToProbeTransformMatrix)
double GetCalibrationReprojectionError3DStdDev()
void SetProbeCalibrationAlgo(vtkPlusProbeCalibrationAlgo *probeCalibrationAlgo)
char * PhantomCoordinateFrame
PreProcessedWirePositionIdType
PlusStatus SaveCalibrationResultAndErrorReportToXML(vtkIGSIOTrackedFrameList *validationTrackedFrameList, int validationStartFrame, int validationEndFrame, vtkIGSIOTrackedFrameList *calibrationTrackedFrameList, int calibrationStartFrame, int calibrationEndFrame)
vnl_matrix_fixed< double, 4, 4 > GetOptimizedImageToProbeTransformMatrix()
void UpdateNonOutlierData(const std::set< int > &outliers)
static vtkPlusConfig * GetInstance()
static const int MIN_NUMBER_OF_VALID_CALIBRATION_FRAMES
static void PrintMatrix(vnl_matrix_fixed< double, 4, 4 > matrix, std::ostringstream &stream, int precision=3)
virtual ~vtkPlusProbeCalibrationAlgo()
std::vector< NWirePositionType > FramePositions
PlusStatus ComputeReprojectionErrors3D(PreProcessedWirePositionIdType datasetType, const vnl_matrix_fixed< double, 4, 4 > &imageToProbeTransformMatrix)
double ErrorConfidenceLevel
std::vector< vnl_vector_fixed< double, 4 > > MiddleWireIntersectionPointsPos_Probe
static void ConvertVtkMatrixToVnlMatrix(const vtkMatrix4x4 *inVtkMatrix, vnl_matrix_fixed< double, 4, 4 > &outVnlMatrix)
std::vector< std::vector< double > > ReprojectionError3Ds
virtual void SetCalibrationDate(const char *)
double GetValidationReprojectionError3DStdDev()
PlusStatus ComputeReprojectionErrors2D(PreProcessedWirePositionIdType datasetType, const vnl_matrix_fixed< double, 4, 4 > &imageToProbeTransformMatrix)
void GetImageToProbeTransformMatrix(vtkMatrix4x4 *imageToProbeMatrix)
PlusStatus ReadConfiguration(vtkXMLDataElement *aConfig)
char * ProbeCoordinateFrame
std::vector< std::vector< vnl_vector_fixed< double, 2 > > > ReprojectionError2Ds
Initial translation vector alpha
void SetAndValidateImageToProbeTransform(const vnl_matrix_fixed< double, 4, 4 > &imageToProbeTransformMatrix, vtkIGSIOTransformRepository *transformRepository)
NWireErrorType NWireErrors
static void LogMatrix(const vnl_matrix_fixed< double, 4, 4 > &matrix, int precision=3)
void ComputeError3d(const vnl_matrix_fixed< double, 4, 4 > &imageToProbeMatrix, double &errorMean, double &errorStDev, double &errorRms)
std::vector< vnl_vector_fixed< double, 2 > > ReprojectionError2DStdDevs
std::vector< vnl_vector_fixed< double, 4 > > AllWiresIntersectionPointsPos_Image
PlusStatus GetXMLCalibrationResultAndErrorReport(vtkIGSIOTrackedFrameList *validationTrackedFrameList, int validationStartFrame, int validationEndFrame, vtkIGSIOTrackedFrameList *calibrationTrackedFrameList, int calibrationStartFrame, int calibrationEndFrame, vtkXMLDataElement *probeCalibrationResult)
static vtkPlusProbeCalibrationOptimizerAlgo * New()
PreProcessedWirePositionsType PreProcessedWirePositions[LAST_PREPROCESSED_WIRE_POS_ID]
static double PointToWireDistance(const vnl_double_3 &aPoint, const vnl_double_3 &aLineEndPoint1, const vnl_double_3 &aLineEndPoint2)
PlusStatus ReadConfiguration(vtkXMLDataElement *aConfig)
double GetValidationReprojectionError3DMean()
vtkStandardNewMacro(vtkPlusProbeCalibrationAlgo)
vnl_matrix_fixed< double, 4, 4 > ProbeToPhantomTransform
PlusStatus AddPositionsPerImage(igsioTrackedFrame *trackedFrame, vtkIGSIOTransformRepository *transformRepository, PreProcessedWirePositionIdType datasetType)
static void ConvertVnlMatrixToVtkMatrix(const vnl_matrix_fixed< double, 4, 4 > &inVnlMatrix, vtkMatrix4x4 *outVtkMatrix)
vtkPlusProbeCalibrationAlgo()
PlusStatus GetCalibrationReport(std::vector< double > *calibError, std::vector< double > *validError, vnl_matrix_fixed< double, 4, 4 > *imageToProbeTransformMatrix)
std::vector< PlusNWire > NWires
virtual void PrintSelf(ostream &os, vtkIndent indent)
Probe calibration algorithm class.
double GetCalibrationReprojectionError3DMean()