diff --git a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp index 76808d4051..e1307d2823 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp +++ b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp @@ -1,345 +1,369 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataEvaluationFilter.h" #include #define _USE_MATH_DEFINES #include mitk::NavigationDataEvaluationFilter::NavigationDataEvaluationFilter() : mitk::NavigationDataToNavigationDataFilter() {} mitk::NavigationDataEvaluationFilter::~NavigationDataEvaluationFilter() {} void mitk::NavigationDataEvaluationFilter::GenerateData() { this->CreateOutputsForAllInputs(); // make sure that we have the same number of outputs as inputs this->CreateMembersForAllInputs(); /* update outputs with tracking data from tools */ for (unsigned int i = 0; i < this->GetNumberOfOutputs(); ++i) { // first copy outputs to inputs mitk::NavigationData *output = this->GetOutput(i); assert(output); const mitk::NavigationData *input = this->GetInput(i); assert(input); if (input->IsDataValid() == false) { output->SetDataValid(false); } else { output->Graft(input); } // then save statistics if (input->IsDataValid()) { m_LoggedPositions[i].push_back(input->GetPosition()); m_LoggedQuaternions[i].push_back(input->GetOrientation()); } else { m_InvalidSamples[i]++; } } } void mitk::NavigationDataEvaluationFilter::CreateMembersForAllInputs() { while (this->m_LoggedPositions.size() < this->GetNumberOfInputs()) { std::pair> newElement(m_LoggedPositions.size(), std::vector()); m_LoggedPositions.insert(newElement); } while (this->m_LoggedQuaternions.size() < this->GetNumberOfInputs()) { std::pair> newElement(m_LoggedQuaternions.size(), std::vector()); m_LoggedQuaternions.insert(newElement); } while (this->m_InvalidSamples.size() < this->GetNumberOfInputs()) { std::pair newElement(m_InvalidSamples.size(), 0); m_InvalidSamples.insert(newElement); } } void mitk::NavigationDataEvaluationFilter::ResetStatistic() { for (unsigned int i = 0; i < m_LoggedPositions.size(); i++) m_LoggedPositions[i] = std::vector(); for (unsigned int i = 0; i < m_LoggedQuaternions.size(); i++) m_LoggedQuaternions[i] = std::vector(); for (unsigned int i = 0; i < m_InvalidSamples.size(); i++) m_InvalidSamples[i] = 0; } int mitk::NavigationDataEvaluationFilter::GetNumberOfAnalysedNavigationData(int input) { return this->m_LoggedPositions[input].size(); } mitk::Point3D mitk::NavigationDataEvaluationFilter::GetPositionMean(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionMean(); } mitk::Vector3D mitk::NavigationDataEvaluationFilter::GetPositionStandardDeviation(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionStandardDeviation(); } mitk::Vector3D mitk::NavigationDataEvaluationFilter::GetPositionSampleStandardDeviation(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionSampleStandardDeviation(); } mitk::Quaternion mitk::NavigationDataEvaluationFilter::GetQuaternionMean(int input) { return GetMean(m_LoggedQuaternions[input]); } mitk::Quaternion mitk::NavigationDataEvaluationFilter::GetQuaternionStandardDeviation(int input) { mitk::Quaternion returnValue; std::vector list1 = std::vector(); std::vector list2 = std::vector(); std::vector list3 = std::vector(); std::vector list4 = std::vector(); for (unsigned int i = 0; i < m_LoggedQuaternions[input].size(); i++) { list1.push_back(m_LoggedQuaternions[input].at(i)[0]); list2.push_back(m_LoggedQuaternions[input].at(i)[1]); list3.push_back(m_LoggedQuaternions[input].at(i)[2]); list4.push_back(m_LoggedQuaternions[input].at(i)[3]); } mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(); returnValue[0] = myCalculator->GetStabw(list1); returnValue[1] = myCalculator->GetStabw(list2); returnValue[2] = myCalculator->GetStabw(list3); returnValue[3] = myCalculator->GetStabw(list4); return returnValue; } mitk::Vector3D mitk::NavigationDataEvaluationFilter::GetEulerAnglesMean(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(QuaternionsToEulerAngles(m_LoggedQuaternions[input]))); mitk::Vector3D returnValue; returnValue[0] = myCalculator->GetPositionMean()[0]; returnValue[1] = myCalculator->GetPositionMean()[1]; returnValue[2] = myCalculator->GetPositionMean()[2]; return returnValue; } double mitk::NavigationDataEvaluationFilter::GetEulerAnglesRMS(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(QuaternionsToEulerAngles(m_LoggedQuaternions[input]))); return myCalculator->GetPositionErrorRMS(); } double mitk::NavigationDataEvaluationFilter::GetEulerAnglesRMSDegree(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(QuaternionsToEulerAnglesGrad(m_LoggedQuaternions[input]))); return myCalculator->GetPositionErrorRMS(); } double mitk::NavigationDataEvaluationFilter::GetToolAxisRSME(int input) { double returnValue = -1; - mitk::NavigationData::Pointer evaluationPoint = mitk::NavigationData::New(); - mitk::Point3D point; - mitk::FillVector3D(point, 0, 0, 1); - evaluationPoint->SetPosition(point); + mitk::Point3D evaluationPoint; + mitk::FillVector3D(evaluationPoint, 0, 0, 1); + + //compute mean transformed point + mitk::Point3D meanTransformedPoint; + mitk::FillVector3D(meanTransformedPoint, 0, 0, 0); + std::vector transformedPoints; for (int i = 0; i < m_LoggedPositions[input].size(); i++) { mitk::NavigationData::Pointer currentTransform = mitk::NavigationData::New(); currentTransform->SetPosition(m_LoggedPositions[input].at(i)); currentTransform->SetOrientation(m_LoggedQuaternions[input].at(i)); + mitk::NavigationData::Pointer transformedPoint = mitk::NavigationData::New(); + transformedPoint->SetPosition(evaluationPoint); + transformedPoint->Compose(currentTransform); + meanTransformedPoint[0] += transformedPoint->GetPosition()[0]; + meanTransformedPoint[1] += transformedPoint->GetPosition()[1]; + meanTransformedPoint[2] += transformedPoint->GetPosition()[2]; + transformedPoints.push_back(transformedPoint->GetPosition()); + } + meanTransformedPoint[0] /= m_LoggedPositions[input].size(); + meanTransformedPoint[1] /= m_LoggedPositions[input].size(); + meanTransformedPoint[2] /= m_LoggedPositions[input].size(); + + + //compute RMS of error values + returnValue = 0; + for (mitk::Point3D transformedPoint : transformedPoints) + { + double currentError = transformedPoint.EuclideanDistanceTo(meanTransformedPoint); + returnValue += pow(currentError,2); } + returnValue /= transformedPoints.size(); + returnValue = sqrt(returnValue); return returnValue; } double mitk::NavigationDataEvaluationFilter::GetPositionErrorMean(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorMean(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorStandardDeviation(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorStandardDeviation(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorSampleStandardDeviation(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorSampleStandardDeviation(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorRMS(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorRMS(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorMedian(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorMedian(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorMax(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorMax(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorMin(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorMin(); } int mitk::NavigationDataEvaluationFilter::GetNumberOfInvalidSamples(int input) { return m_InvalidSamples[input]; } double mitk::NavigationDataEvaluationFilter::GetPercentageOfInvalidSamples(int input) { return (m_InvalidSamples[input] / (m_InvalidSamples[input] + ((double)m_LoggedPositions[input].size()))) * 100.0; } mitk::Quaternion mitk::NavigationDataEvaluationFilter::GetMean(std::vector list) { // calculate mean mitk::Quaternion mean; mean[0] = 0; mean[1] = 0; mean[2] = 0; mean[3] = 0; for (unsigned int i = 0; i < list.size(); i++) { mean[0] += list.at(i)[0]; mean[1] += list.at(i)[1]; mean[2] += list.at(i)[2]; mean[3] += list.at(i)[3]; } mean[0] /= list.size(); mean[1] /= list.size(); mean[2] /= list.size(); mean[3] /= list.size(); return mean; } mitk::PointSet::Pointer mitk::NavigationDataEvaluationFilter::VectorToPointSet(std::vector pSet) { mitk::PointSet::Pointer returnValue = mitk::PointSet::New(); for (unsigned int i = 0; i < pSet.size(); i++) returnValue->InsertPoint(i, pSet.at(i)); return returnValue; } mitk::PointSet::Pointer mitk::NavigationDataEvaluationFilter::VectorToPointSet(std::vector pSet) { mitk::PointSet::Pointer returnValue = mitk::PointSet::New(); for (unsigned int i = 0; i < pSet.size(); i++) { mitk::Point3D thisPoint; thisPoint[0] = pSet.at(i)[0]; thisPoint[1] = pSet.at(i)[1]; thisPoint[2] = pSet.at(i)[2]; returnValue->InsertPoint(i, thisPoint); } return returnValue; } std::vector mitk::NavigationDataEvaluationFilter::QuaternionsToEulerAngles( std::vector quaterions) { std::vector returnValue = std::vector(); for (unsigned int i = 0; i < quaterions.size(); i++) { mitk::Vector3D eulerAngles; mitk::Quaternion currentQuaternion = quaterions.at(i); currentQuaternion .normalize(); // must be normalized due to the documentation of the vnl method rotation_euler_angles() eulerAngles[0] = currentQuaternion.rotation_euler_angles()[0]; eulerAngles[1] = currentQuaternion.rotation_euler_angles()[1]; eulerAngles[2] = currentQuaternion.rotation_euler_angles()[2]; returnValue.push_back(eulerAngles); } return returnValue; } std::vector mitk::NavigationDataEvaluationFilter::QuaternionsToEulerAnglesGrad( std::vector quaterions) { double PI = M_PI; std::vector returnValue = std::vector(); std::vector eulerAnglesRadians = QuaternionsToEulerAngles(quaterions); for (unsigned int i = 0; i < eulerAnglesRadians.size(); i++) { mitk::Vector3D currentAngles; currentAngles[0] = (eulerAnglesRadians.at(i)[0] / PI) * 180; currentAngles[1] = (eulerAnglesRadians.at(i)[1] / PI) * 180; currentAngles[2] = (eulerAnglesRadians.at(i)[2] / PI) * 180; returnValue.push_back(currentAngles); } return returnValue; } mitk::Point3D mitk::NavigationDataEvaluationFilter::GetLoggedPosition(unsigned int i, int input) { mitk::Point3D returnValue; if (m_LoggedPositions[input].size() <= i) returnValue.Fill(0); else returnValue = m_LoggedPositions[input].at(i); return returnValue; } mitk::Quaternion mitk::NavigationDataEvaluationFilter::GetLoggedOrientation(unsigned int i, int input) { mitk::Quaternion returnValue; if (m_LoggedQuaternions[input].size() <= i) returnValue.fill(0); else returnValue = m_LoggedQuaternions[input].at(i); return returnValue; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationViewControls.ui b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationViewControls.ui index 37ec958796..b30a9022b0 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationViewControls.ui @@ -1,1716 +1,1719 @@ QmitkIGTTrackingDataEvaluationViewControls 0 0 383 711 0 0 QmitkTemplate 0 Evaluation Input File List (recorded tracking data / *.csv): Qt::Horizontal 40 20 120 0 Load New List Qt::Horizontal 40 20 120 0 Add To Current List Qt::Horizontal (1) - VISUALIZATION - of all data sets: Generate PointSet of Mean Positions Generate PointSets of Single Positions Generate Lines for Rotation Qt::Horizontal (2) - JITTER - Evaluation per file / data set: 0 0 16777215 16777215 COMPUTE RESULTS PER DATA SET Qt::Horizontal (3) - ACCURACY - Evaluation of all data sets: 0 0 16777215 16777215 COMPUTE RESULTS OF ALL DATA Qt::Horizontal (4) - GRID MATCHING - Evaluation of all data sets: Reference PointSet: Qt::Horizontal 40 20 150 0 Measurement PointSet: Qt::Horizontal 40 20 150 0 0 0 16777215 16777215 PERFOM GRID MATCHING Qt::Horizontal (5) - ROTATION - Evaluation of all data sets: 0 0 16777215 16777215 COMPUTE ROTATION ERRORS Qt::Vertical QSizePolicy::Expanding 20 220 Settings 0 0 356 551 General Number of samples to analyze: Qt::Horizontal 60 20 1000000 - 150 + 100 Qt::Horizontal Tracking Volume (culumns x rows on Hummel Board): Standard Volume (10 X 9 Positions) true Medium Volume (5 X 5 Positions) Medium Volume (6 X 5 Positions) Small Volume (4 X 3 Positions) Qt::Horizontal Rotation Evaluation: Rotation Vector: Qt::Horizontal 40 20 X 99999 1 Qt::Horizontal 40 20 Y 99999 Qt::Horizontal 40 20 Z 99999 0 Qt::Horizontal Result CSV Filename: D:/tmp/output.csv Prefix for Data Nodes: Qt::Vertical 20 40 0 0 - 324 + 262 765 .csv file input options Presets Load MITK tracking data csv file presets Load Polhemus csv file presets File Options: Scaling factor to convert to mm : Qt::Horizontal 38 20 1.000000000000000 Separator in the csv file: Qt::Horizontal 60 20 0 0 40 16777215 ; 1 Use every n-th smaple n: Qt::Horizontal 40 20 1 The csv file has a header row true Type of Coordinate System: Left handed Right handed true Position and Orientation Options: Y 3 Z 4 X 2 Coordinate: Colum number: Use Quaternions for Orientation true Qr 7 Qy 8 6 5 Qx Qz Quaternion component: Column number: Use Euler Angles for Orientation Column number: Azimuth -1 Roll Angle: -1 Elevation -1 Unity for Euler Angles: Radiants true Degrees false 0 0 341 568 Output per data set Position Mean (x,y,z) true Standard Deviation (x,y,z) Sample Standard Deviation (x,y,z) Orientation Quaternion Mean (qx,qy,qz,qr) Quaternion Mean (SLERP) Quaternion Standard Deviation (qx,qy,qz,qr) Euler Mean (tx,ty,tz) Difference Angles to all other Positions Difference Angles to all other Positions (SLERP) Position Error Mean Standard Deviation Sample Standard Deviation RMS true Median Min/Max Tool Axis Error Tool Axis RSME at Z=1.0 + + true + Orientation Error Euler RMS Tools Point Set Ground Truth Generator Generate 1 999 10 X 1 999 9 Point Set Qt::Horizontal 40 20 Inter Point Distance (in mm): Qt::Horizontal 40 20 1 99999 50 Qt::Horizontal 40 20 Generate Result CSV File to NavigationData Converter Convert Single File true Input CSV Logging File: C:/Tools/test.csv Output Navigation Data File: C:/Tools/testoutput.xml Qt::Horizontal Convert File List <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-style:italic;">(use text files with a complete filename in every line)</span></p></body></html> not loaded Qt::Horizontal 40 20 100 0 Load Input List not loaded Qt::Horizontal 40 20 100 0 Load Output List Qt::Horizontal Qt::Horizontal 40 20 Output Format XML true CSV Qt::Horizontal 40 20 Convert Orientation Calculation (out of three positions) Qt::Horizontal 40 20 Generate Reference From Current List Qt::Horizontal 40 20 Write Orientation Quaternions To File Qt::Vertical 20 632 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h