diff --git a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp index 89ec5d87a7..76808d4051 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp +++ b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp @@ -1,302 +1,345 @@ /*=================================================================== 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() : mitk::NavigationDataToNavigationDataFilter() {} -mitk::NavigationDataEvaluationFilter::~NavigationDataEvaluationFilter() -{ -} +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); + // first copy outputs to inputs + mitk::NavigationData *output = this->GetOutput(i); assert(output); - const mitk::NavigationData* input = this->GetInput(i); + const mitk::NavigationData *input = this->GetInput(i); assert(input); - if (input->IsDataValid() == false) { output->SetDataValid(false); } - else { output->Graft(input); } + if (input->IsDataValid() == false) + { + output->SetDataValid(false); + } + else + { + output->Graft(input); + } - //then save statistics + // 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()); + 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()); + 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; + 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])); + 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])); + 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])); + 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::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]))); + 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]))); + 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); + 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)); + } + return returnValue; +} + double mitk::NavigationDataEvaluationFilter::GetPositionErrorMean(int input) { - mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[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])); + 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])); + 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])); + 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])); + 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])); + 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])); + 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; + return (m_InvalidSamples[input] / (m_InvalidSamples[input] + ((double)m_LoggedPositions[input].size()))) * 100.0; } mitk::Quaternion mitk::NavigationDataEvaluationFilter::GetMean(std::vector list) { - //calculate mean + // 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)); + 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 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() + 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) +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 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); + 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 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); + if (m_LoggedQuaternions[input].size() <= i) + returnValue.fill(0); + else + returnValue = m_LoggedQuaternions[input].at(i); return returnValue; } diff --git a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.h b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.h index 6ea124513f..d23664b800 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.h +++ b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.h @@ -1,125 +1,131 @@ /*=================================================================== 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. ===================================================================*/ #ifndef MITKNavigationDataEvaluationFilter_H_HEADER_INCLUDED_ #define MITKNavigationDataEvaluationFilter_H_HEADER_INCLUDED_ #include #include #include #include namespace mitk { /**Documentation * \brief NavigationDataEvaluationFilter calculates statistical data (mean value, mean error, etc.) on the input navigation data. * Input navigation data are set 1:1 on output navigation data. * * \ingroup IGT */ class MITKIGT_EXPORT NavigationDataEvaluationFilter : public NavigationDataToNavigationDataFilter { public: mitkClassMacro(NavigationDataEvaluationFilter, NavigationDataToNavigationDataFilter); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** @brief Resets all statistics and starts again. */ void ResetStatistic(); /** @return Returns the number of analysed navigation datas for the specified input (without invalid samples). */ int GetNumberOfAnalysedNavigationData(int input); /** @return Returns the number of invalid samples for the specified input. Invalid samples are ignored for the statistical calculation.*/ int GetNumberOfInvalidSamples(int input); /** @return Returns the percentage of invalid samples in relation to all samples for the specified input.*/ double GetPercentageOfInvalidSamples(int input); /** @return Returns the mean position of the specified input since the start of the statistic (last call of ResetStatistic()) */ mitk::Point3D GetPositionMean(int input); /** @return Returns the standard derivation of each component (x, y and z) of the specified input since the start of the statistic (last call of ResetStatistic()) */ mitk::Vector3D GetPositionStandardDeviation(int input); /** @return Returns the sample standard derivation of each component (x, y and z) of the specified input since the start of the statistic (last call of ResetStatistic()) */ mitk::Vector3D GetPositionSampleStandardDeviation(int input); /** @return Returns the mean quaternion of the specified input since the start of the statistic (last call of ResetStatistic()) */ mitk::Quaternion GetQuaternionMean(int input); /** @return Returns the standard derivation of each component of the specified input since the start of the statistic (last call of ResetStatistic()) */ mitk::Quaternion GetQuaternionStandardDeviation(int input); /** @return Returns the mean euler angles (theta_x, theta_y, theta_z) of the specified input since the start of the statistic (last call of ResetStatistic()) */ mitk::Vector3D GetEulerAnglesMean(int input); /** @return Returns the RMS of the error of the euler angles (theta_x, theta_y, theta_z) in radians of the specified input since the start of the statistic (last call of ResetStatistic()) */ double GetEulerAnglesRMS(int input); /** @return Returns the RMS of the error of the euler angles (theta_x, theta_y, theta_z) in degree of the specified input since the start of the statistic (last call of ResetStatistic()) */ double GetEulerAnglesRMSDegree(int input); + /** @return Returns the RSM of the error of point [0,0,1] in mm, assuming that + * the tool axis is defined along the Z-axis and that the tool + * was rotated around its own axis to check the axis error. Returns + * -1 if there was an error during calculation. + */ + double GetToolAxisRSME(int input); /** @return Returns the mean distance to the mean postion (=mean error) to the specified input. */ double GetPositionErrorMean(int input); /** @return Returns the standard derivation of the errors of all positions to the specified input. */ double GetPositionErrorStandardDeviation(int input); /** @return Returns the sample standard derivation of the errors of all positions to the specified input. */ double GetPositionErrorSampleStandardDeviation(int input); /** @return Returns the RMS of the errors of all positions to the specified input. */ double GetPositionErrorRMS(int input); /** @return Returns the median of the errors of all positions to the specified input. */ double GetPositionErrorMedian(int input); /** @return Returns the maximum of the errors of all positions to the specified input. */ double GetPositionErrorMax(int input); /** @return Returns the minimum of the errors of all positions to the specified input. */ double GetPositionErrorMin(int input); /** @return Returns a logged point on position i of the specified input. If there is no point on position i the method returns [0,0,0] */ mitk::Point3D GetLoggedPosition(unsigned int i, int input); /** @return Returns a logged orientation on position i of the specified input. If there is no orientation on position i the method returns [0,0,0,0] */ mitk::Quaternion GetLoggedOrientation(unsigned int i, int input); protected: NavigationDataEvaluationFilter(); virtual ~NavigationDataEvaluationFilter(); /**Documentation * \brief filter execute method * * transforms navigation data */ virtual void GenerateData() override; /** @brief Creates the member variables which store all the statistical data for every input. */ void CreateMembersForAllInputs(); std::map > m_LoggedPositions; //a map here, to have one list for every navigation data std::map > m_LoggedQuaternions; std::map m_InvalidSamples; mitk::Quaternion GetMean(std::vector list); mitk::PointSet::Pointer VectorToPointSet(std::vector pSet); mitk::PointSet::Pointer VectorToPointSet(std::vector pSet); /** @brief Converts a list of quaterions to a list of euler angles (theta_x, theta_y, theta_z) */ std::vector QuaternionsToEulerAngles(std::vector quaterions); //in radians std::vector QuaternionsToEulerAnglesGrad(std::vector quaterions); //in degree }; } // namespace mitk #endif /* MITKNavigationDataEvaluationFilter_H_HEADER_INCLUDED_ */ diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp index bfb530814c..ec2be18a1a 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp @@ -1,1357 +1,1370 @@ /*========================================================================= 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 // Blueberry #include #include // Qmitk #include "QmitkIGTTrackingDataEvaluationView.h" #include "QmitkStdMultiWidget.h" // Qt #include #include #include // MITK #include "mitkNavigationDataCSVSequentialPlayer.h" +#include #include #include +#include +#include #include #include #include -#include -#include -#include // ITK #include // VNL #include // vtk headers #include #include #include const std::string QmitkIGTTrackingDataEvaluationView::VIEW_ID = "org.mitk.views.igttrackingdataevaluation"; QmitkIGTTrackingDataEvaluationView::QmitkIGTTrackingDataEvaluationView() : QmitkFunctionality(), m_Controls(0), m_MultiWidget(nullptr), m_scalingfactor(1) { m_CSVtoXMLInputFilenameVector = std::vector(); m_CSVtoXMLOutputFilenameVector = std::vector(); } QmitkIGTTrackingDataEvaluationView::~QmitkIGTTrackingDataEvaluationView() {} void QmitkIGTTrackingDataEvaluationView::OnLoadMITKPresets() { m_Controls->m_ScalingFactor->setValue(1.0); m_Controls->m_SeparatorSign->setText(";"); m_Controls->m_SampleCount->setValue(1.0); m_Controls->m_HeaderRow->setChecked(true); m_Controls->m_RigthHanded->setChecked(true); m_Controls->m_XPos->setValue(3); m_Controls->m_YPos->setValue(4); m_Controls->m_ZPos->setValue(5); m_Controls->m_UseQuats->setChecked(true); m_Controls->m_Qx->setValue(6); m_Controls->m_Qy->setValue(7); m_Controls->m_Qz->setValue(8); m_Controls->m_Qr->setValue(9); } void QmitkIGTTrackingDataEvaluationView::OnLoadPolhemusPresets() { m_Controls->m_ScalingFactor->setValue(10.0); m_Controls->m_SeparatorSign->setText(","); m_Controls->m_SampleCount->setValue(24.0); m_Controls->m_HeaderRow->setChecked(false); m_Controls->m_RigthHanded->setChecked(true); m_Controls->m_XPos->setValue(4); m_Controls->m_YPos->setValue(5); m_Controls->m_ZPos->setValue(6); m_Controls->m_UseEuler->setChecked(true); m_Controls->m_Azimuth->setValue(11); m_Controls->m_Elevation->setValue(12); m_Controls->m_Roll->setValue(13); m_Controls->m_Degrees->setChecked(true); } void QmitkIGTTrackingDataEvaluationView::CreateQtPartControl(QWidget *parent) { // build up qt view, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkIGTTrackingDataEvaluationViewControls; m_Controls->setupUi(parent); connect(m_Controls->m_LoadInputFileList, SIGNAL(clicked()), this, SLOT(OnLoadFileList())); connect(m_Controls->m_StartEvaluation, SIGNAL(clicked()), this, SLOT(OnEvaluateData())); connect(m_Controls->m_AddToCurrentList, SIGNAL(clicked()), this, SLOT(OnAddToCurrentList())); connect(m_Controls->m_GeneratePointSetOfMeanPositions, SIGNAL(clicked()), this, SLOT(OnGeneratePointSet())); connect(m_Controls->m_GenerateRotationLines, SIGNAL(clicked()), this, SLOT(OnGenerateRotationLines())); connect(m_Controls->m_GeneratePointSet, SIGNAL(clicked()), this, SLOT(OnGenerateGroundTruthPointSet())); connect(m_Controls->m_Convert, SIGNAL(clicked()), this, SLOT(OnConvertCSVtoXMLFile())); connect(m_Controls->m_loadCSVtoXMLInputList, SIGNAL(clicked()), this, SLOT(OnCSVtoXMLLoadInputList())); connect(m_Controls->m_loadCSVtoXMLOutputList, SIGNAL(clicked()), this, SLOT(OnCSVtoXMLLoadOutputList())); connect(m_Controls->m_loadMITKPresets, SIGNAL(clicked()), this, SLOT(OnLoadMITKPresets())); connect(m_Controls->m_loadPolhemusPresets, SIGNAL(clicked()), this, SLOT(OnLoadPolhemusPresets())); connect(m_Controls->m_OrientationCalculationGenerateReference, SIGNAL(clicked()), this, SLOT(OnOrientationCalculation_CalcRef())); connect(m_Controls->m_OrientationCalculationWriteOrientationsToFile, SIGNAL(clicked()), this, SLOT(OnOrientationCalculation_CalcOrientandWriteToFile())); connect(m_Controls->m_GeneratePointSetsOfSinglePositions, SIGNAL(clicked()), this, SLOT(OnGeneratePointSetsOfSinglePositions())); connect(m_Controls->m_StartEvaluationAll, SIGNAL(clicked()), this, SLOT(OnEvaluateDataAll())); connect(m_Controls->m_GridMatching, SIGNAL(clicked()), this, SLOT(OnPerfomGridMatching())); connect(m_Controls->m_ComputeRotation, SIGNAL(clicked()), this, SLOT(OnComputeRotation())); // initialize data storage combo boxes m_Controls->m_ReferencePointSetComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ReferencePointSetComboBox->SetAutoSelectNewItems(true); m_Controls->m_ReferencePointSetComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); m_Controls->m_MeasurementPointSetComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MeasurementPointSetComboBox->SetAutoSelectNewItems(true); m_Controls->m_MeasurementPointSetComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); - //initialize output filename + // initialize output filename std::stringstream outputFilename; outputFilename << mitk::IOUtil::GetTempPath() << "results"; m_Controls->m_OutputFilename->setText(outputFilename.str().c_str()); } } void QmitkIGTTrackingDataEvaluationView::OnComputeRotation() { // Get all data from UI auto EvaluationDataCollection = GetAllDataFromUIList(); // Compute mean Quaternions auto OrientationVector = GetMeanOrientationsOfAllData(EvaluationDataCollection); // Compute Rotations itk::Vector rotationVec; // adapt for Aurora 5D tools: [0,0,1000] rotationVec[0] = m_Controls->m_rotVecX->value(); // X rotationVec[1] = m_Controls->m_rotVecY->value(); // Y rotationVec[2] = m_Controls->m_rotVecZ->value(); // Z std::vector allOrientationErrors; for (std::vector::size_type i = 0; i < OrientationVector.size() - 1; ++i) { double AngleBetweenTwoQuaternions = mitk::StaticIGTHelperFunctions::GetAngleBetweenTwoQuaterions( OrientationVector.at(i), OrientationVector.at(i + 1), rotationVec); double AngularError = fabs(AngleBetweenTwoQuaternions - 11.25); std::stringstream description; description << "Rotation Error ROT" << (i + 1) << " / ROT" << (i + 2); allOrientationErrors.push_back({AngularError, description.str()}); MITK_INFO << description.str() << ": " << AngularError; } // compute statistics std::vector orientationErrorStatistics; orientationErrorStatistics = mitk::HummelProtocolEvaluation::ComputeStatistics(allOrientationErrors); MITK_INFO << "## Rotation error statistics: ##"; for (auto stat : orientationErrorStatistics) { MITK_INFO << stat.description << ": " << stat.distanceError; } // write results to file allOrientationErrors.insert( allOrientationErrors.end(), orientationErrorStatistics.begin(), orientationErrorStatistics.end()); allOrientationErrors.push_back({rotationVec[0], "Rot Vector [x]"}); allOrientationErrors.push_back({rotationVec[1], "Rot Vector [y]"}); allOrientationErrors.push_back({rotationVec[2], "Rot Vector [z]"}); std::stringstream filenameOrientationStat; filenameOrientationStat << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".orientationStatistics.csv"; MITK_INFO << "Writing output to file " << filenameOrientationStat.str(); writeToFile(filenameOrientationStat.str(), allOrientationErrors); } void QmitkIGTTrackingDataEvaluationView::OnPerfomGridMatching() { mitk::PointSet::Pointer reference = dynamic_cast(m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()); mitk::PointSet::Pointer measurement = dynamic_cast(m_Controls->m_MeasurementPointSetComboBox->GetSelectedNode()->GetData()); // convert point sets to vtk poly data vtkSmartPointer sourcePoints = vtkSmartPointer::New(); vtkSmartPointer targetPoints = vtkSmartPointer::New(); for (int i = 0; i < reference->GetSize(); i++) { double point[3] = {reference->GetPoint(i)[0], reference->GetPoint(i)[1], reference->GetPoint(i)[2]}; sourcePoints->InsertNextPoint(point); double point_targets[3] = {measurement->GetPoint(i)[0], measurement->GetPoint(i)[1], measurement->GetPoint(i)[2]}; targetPoints->InsertNextPoint(point_targets); } // compute transform vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->SetModeToRigidBody(); transform->Modified(); transform->Update(); // compute FRE of transform double FRE = mitk::StaticIGTHelperFunctions::ComputeFRE(reference, measurement, transform); MITK_INFO << "FRE after grid matching: " + QString::number(FRE) + " mm"; // convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); itk::Matrix rotationDouble = itk::Matrix(); itk::Vector translationDouble = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); for (int k = 0; k < 3; k++) for (int l = 0; l < 3; l++) { rotationFloat[k][l] = m->GetElement(k, l); rotationDouble[k][l] = m->GetElement(k, l); } for (int k = 0; k < 3; k++) { translationFloat[k] = m->GetElement(k, 3); translationDouble[k] = m->GetElement(k, 3); } // create affine transform 3D mitk::AffineTransform3D::Pointer mitkTransform = mitk::AffineTransform3D::New(); mitkTransform->SetMatrix(rotationDouble); mitkTransform->SetOffset(translationDouble); mitk::NavigationData::Pointer transformNavigationData = mitk::NavigationData::New(mitkTransform); m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform( mitkTransform); m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()->GetGeometry()->Modified(); // write to file std::stringstream filename; filename << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".GridMatchingResult.csv"; MITK_INFO << "Writing output to file " << filename.str(); std::vector FRE_Error; FRE_Error.push_back({FRE, "FRE after grid matching [mm]"}); writeToFile(filename.str(), FRE_Error); GlobalReinit(); } void QmitkIGTTrackingDataEvaluationView::OnOrientationCalculation_CalcRef() { if (m_FilenameVector.size() != 3) { MessageBox("Need exactly three points as reference, aborting!"); return; } // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector[i]); // check if the stream is valid and skip file if not // create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); // connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); // update pipline until number of samples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) myEvaluationFilter->Update(); // store mean position as reference switch (i) { case 0: m_RefPoint1 = myEvaluationFilter->GetPositionMean(0); break; case 1: m_RefPoint2 = myEvaluationFilter->GetPositionMean(0); break; case 2: m_RefPoint3 = myEvaluationFilter->GetPositionMean(0); break; } } MessageBox("Created Reference!"); } void QmitkIGTTrackingDataEvaluationView::OnOrientationCalculation_CalcOrientandWriteToFile() { // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); // open file header QString outputname = QString(m_FilenameVector.at(i).c_str()) + "_orientationFile.csv"; m_CurrentWriteFile.open(outputname.toStdString().c_str(), std::ios::out); if (m_CurrentWriteFile.bad()) { MessageBox("Error: Can't open output file!"); return; } // write header to file m_CurrentWriteFile << "Nr;Calypso_Time;Valid_Reference;MeasureTool_Measurement-Tool[x];MeasureTool_Measurement-" "Tool[y];MeasureTool_Measurement-Tool[z];MeasureTool_Measurement-Tool[qx];MeasureTool_" "Measurement-Tool[qy];MeasureTool_Measurement-Tool[qz];MeasureTool_Measurement-Tool[qr]\n"; // update pipeline until number of samples is reached int step = 0; mitk::Point3D point1, point2, point3; mitk::Quaternion current_orientation; for (int j = 0; !myPlayer->IsAtEnd(); j++) { myPlayer->Update(); mitk::NavigationData::Pointer currentNavData = myPlayer->GetOutput(0); switch (step) { case 0: step++; point1 = currentNavData->GetPosition(); break; case 1: step++; point2 = currentNavData->GetPosition(); break; case 2: step = 0; point3 = currentNavData->GetPosition(); // compute transform from reference to current points if (point1[0] == 0 && point1[1] == 0 && point1[2] == 0 && point2[0] == 0 && point2[1] == 0 && point2[2] == 0 && point3[0] == 0 && point3[1] == 0 && point3[2] == 0) current_orientation.fill(0); else { vtkSmartPointer transform = vtkSmartPointer::New(); vtkSmartPointer sourcePoints = vtkSmartPointer::New(); double sourcepoint1[3] = {point1[0], point1[1], point1[2]}; double sourcepoint2[3] = {point2[0], point2[1], point2[2]}; double sourcepoint3[3] = {point3[0], point3[1], point3[2]}; sourcePoints->InsertNextPoint(sourcepoint1); sourcePoints->InsertNextPoint(sourcepoint2); sourcePoints->InsertNextPoint(sourcepoint3); vtkSmartPointer targetPoints = vtkSmartPointer::New(); double targetpoint1[3] = {m_RefPoint1[0], m_RefPoint1[1], m_RefPoint1[2]}; double targetpoint2[3] = {m_RefPoint2[0], m_RefPoint2[1], m_RefPoint2[2]}; double targetpoint3[3] = {m_RefPoint3[0], m_RefPoint3[1], m_RefPoint3[2]}; targetPoints->InsertNextPoint(targetpoint1); targetPoints->InsertNextPoint(targetpoint2); targetPoints->InsertNextPoint(targetpoint3); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->Modified(); transform->Update(); mitk::Transform::Pointer newTransform = mitk::Transform::New(); newTransform->SetMatrix(transform->GetMatrix()); current_orientation = newTransform->GetOrientation(); // add pointset with the three positions if ((j > 15) && (j < 18)) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); newPointSet->InsertPoint(0, point1); newPointSet->InsertPoint(1, point2); newPointSet->InsertPoint(2, point3); QString name = QString(m_FilenameVector.at(i).c_str()); newNode->SetName(name.toStdString().c_str()); newNode->SetData(newPointSet); newNode->SetFloatProperty("pointsize", 0.1); this->GetDataStorage()->Add(newNode); } } break; } m_CurrentWriteFile << i << ";"; m_CurrentWriteFile << currentNavData->GetTimeStamp() << ";"; // IMPORTANT: change to GetIGTTimeStamp in new version! m_CurrentWriteFile << "true;"; m_CurrentWriteFile << currentNavData->GetPosition()[0] << ";"; m_CurrentWriteFile << currentNavData->GetPosition()[1] << ";"; m_CurrentWriteFile << currentNavData->GetPosition()[2] << ";"; m_CurrentWriteFile << current_orientation.x() << ";"; m_CurrentWriteFile << current_orientation.y() << ";"; m_CurrentWriteFile << current_orientation.z() << ";"; m_CurrentWriteFile << current_orientation.r() << ";"; m_CurrentWriteFile << "\n"; } // close output file m_CurrentWriteFile.close(); } - //MessageBox("Finished!"); + // MessageBox("Finished!"); } void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetNotAvailable() { m_MultiWidget = nullptr; } bool QmitkIGTTrackingDataEvaluationView::OnAddToCurrentList() { // read in files QStringList files = QFileDialog::getOpenFileNames(nullptr, "Select one or more files to open", "/", "CSV (*.csv)"); if (files.isEmpty()) return false; // reset results this->GetDataStorage()->Remove(m_PointSetDataNode); m_PointSetDataNode = nullptr; m_PointSetMeanPositions = nullptr; for (mitk::DataNode::Pointer d : m_rotationLines) { this->GetDataStorage()->Remove(d); } m_rotationLines = std::vector(); for (int i = 0; i < files.size(); i++) { std::string tmp = files.at(i).toStdString().c_str(); m_FilenameVector.push_back(tmp); } // fill list at GUI m_Controls->m_FileList->clear(); for (unsigned int i = 0; i < m_FilenameVector.size(); i++) { new QListWidgetItem(tr(m_FilenameVector.at(i).c_str()), m_Controls->m_FileList); } return true; } void QmitkIGTTrackingDataEvaluationView::OnLoadFileList() { std::vector tempOld = m_FilenameVector; m_FilenameVector = std::vector(); m_FilenameVector.clear(); // load/add new data if (!OnAddToCurrentList()) { m_FilenameVector = tempOld; } } void QmitkIGTTrackingDataEvaluationView::OnEvaluateDataAll() { if (m_PointSetMeanPositions.IsNull()) { this->OnGeneratePointSet(); } std::vector results5cm, results15cm, results30cm, resultsAccum; mitk::HummelProtocolEvaluation::HummelProtocolMeasurementVolume volume; if (m_Controls->m_standardVolume->isChecked()) { volume = mitk::HummelProtocolEvaluation::standard; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); mitk::HummelProtocolEvaluation::Evaluate15cmDistances(m_PointSetMeanPositions, volume, results15cm); mitk::HummelProtocolEvaluation::Evaluate30cmDistances(m_PointSetMeanPositions, volume, results30cm); mitk::HummelProtocolEvaluation::EvaluateAccumulatedDistances(m_PointSetMeanPositions, volume, resultsAccum); } else if (m_Controls->m_smallVolume->isChecked()) { volume = mitk::HummelProtocolEvaluation::small; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); } else if (m_Controls->m_mediumVolume->isChecked()) { volume = mitk::HummelProtocolEvaluation::medium; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); } else if (m_Controls->m_medium5x6Volume->isChecked()) { volume = mitk::HummelProtocolEvaluation::medium5x6; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); } // write results to file std::stringstream filename5cm; filename5cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results5cm.csv"; MITK_INFO << "Writing output to file " << filename5cm.str(); writeToFile(filename5cm.str(), results5cm); std::stringstream filename15cm; filename15cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results15cm.csv"; MITK_INFO << "Writing output to file " << filename15cm.str(); writeToFile(filename15cm.str(), results15cm); std::stringstream filename30cm; filename30cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results30cm.csv"; MITK_INFO << "Writing output to file " << filename30cm.str(); writeToFile(filename30cm.str(), results30cm); std::stringstream filenameAccum; filenameAccum << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".resultsAccumDist.csv"; MITK_INFO << "Writing output to file " << filenameAccum.str(); writeToFile(filenameAccum.str(), resultsAccum); } void QmitkIGTTrackingDataEvaluationView::OnEvaluateData() { // open output file std::stringstream outputfilename; outputfilename << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".csv"; m_CurrentWriteFile.open(outputfilename.str(), std::ios::out); if (m_CurrentWriteFile.bad()) { MessageBox("Error: Can't open output file!"); return; } std::vector jitterValues; // write output file header WriteHeader(); // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); // create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); // connect pipeline myEvaluationFilter->SetInput(0, myPlayer->GetOutput(0)); if (myPlayer->GetNumberOfSnapshots() < m_Controls->m_NumberOfSamples->value()) { MITK_WARN << "Number of snapshots (" << myPlayer->GetNumberOfSnapshots() << ") smaller than number of samples to evaluate (" << m_Controls->m_NumberOfSamples->value() << ") ! Cannot proceed!"; return; } // update pipline until number of samples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) myEvaluationFilter->Update(); MITK_INFO << "Jitter (RMS) on position " << i << ": " << myEvaluationFilter->GetPositionErrorRMS(0); // store all jitter values in separate vector for statistics jitterValues.push_back({myEvaluationFilter->GetPositionErrorRMS(0), "RMS"}); // write result to output file WriteDataSet(myEvaluationFilter, m_FilenameVector.at(i)); } // close output file for single data m_CurrentWriteFile.close(); // compute statistics std::vector jitterStatistics = mitk::HummelProtocolEvaluation::ComputeStatistics(jitterValues); MITK_INFO << "## Jitter (RMS) statistics: ##"; for (auto jitterStat : jitterStatistics) { MITK_INFO << jitterStat.description << ": " << jitterStat.distanceError; } // write statistic results to separate file std::stringstream filenameJitterStat; filenameJitterStat << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".resultsJitterStatistics.csv"; MITK_INFO << "Writing output to file " << filenameJitterStat.str(); writeToFile(filenameJitterStat.str(), jitterStatistics); // calculate angles if option is on if (m_Controls->m_settingDifferenceAngles->isChecked() || m_Controls->m_DifferencesSLERP->isChecked()) CalculateDifferenceAngles(); - //MessageBox("Finished!"); + // MessageBox("Finished!"); } void QmitkIGTTrackingDataEvaluationView::OnGeneratePointSetsOfSinglePositions() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { // create point set for this file mitk::PointSet::Pointer thisPointSet = mitk::PointSet::New(); // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); // update pipline until number of samlples is reached and store every single point for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) { myPlayer->Update(); mitk::Point3D thisPoint = myPlayer->GetOutput()->GetPosition(); thisPoint[0] *= m_scalingfactor; thisPoint[1] *= m_scalingfactor; thisPoint[2] *= m_scalingfactor; thisPointSet->InsertPoint(j, thisPoint); } // add point set to data storage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString name = this->m_Controls->m_prefix->text() + QString("PointSet_of_All_Positions_") + QString::number(i); newNode->SetName(name.toStdString()); newNode->SetData(thisPointSet); this->GetDataStorage()->Add(newNode); } } void QmitkIGTTrackingDataEvaluationView::OnGeneratePointSet() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); mitk::PointSet::Pointer generatedPointSet = mitk::PointSet::New(); // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); // create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); // connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } // update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) { myEvaluationFilter->Update(); } // add mean position to point set mitk::Point3D meanPos = myEvaluationFilter->GetPositionMean(0); if (m_scalingfactor != 1) { meanPos[0] *= m_scalingfactor; meanPos[1] *= m_scalingfactor; meanPos[2] *= m_scalingfactor; } generatedPointSet->InsertPoint(i, meanPos); } // add point set to data storage m_PointSetDataNode = mitk::DataNode::New(); QString name = this->m_Controls->m_prefix->text() + "PointSet_of_Mean_Positions"; m_PointSetDataNode->SetName(name.toStdString()); m_PointSetDataNode->SetData(generatedPointSet); m_PointSetDataNode->SetFloatProperty("pointsize", 5); this->GetDataStorage()->Add(m_PointSetDataNode); m_PointSetMeanPositions = generatedPointSet; GlobalReinit(); } void QmitkIGTTrackingDataEvaluationView::OnGenerateRotationLines() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); - for (mitk::DataNode::Pointer d : m_rotationLines) {this->GetDataStorage()->Remove(d);} + for (mitk::DataNode::Pointer d : m_rotationLines) + { + this->GetDataStorage()->Remove(d); + } m_rotationLines = std::vector(); // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); // create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); // connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } // update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) myEvaluationFilter->Update(); // create line from mean pos to a second point which lies along the sensor (1,0,0 in tool coordinates for aurora) mitk::Point3D meanPos = myEvaluationFilter->GetPositionMean(0); if (m_scalingfactor != 1) { meanPos[0] *= m_scalingfactor; meanPos[1] *= m_scalingfactor; meanPos[2] *= m_scalingfactor; } mitk::Point3D secondPoint; mitk::Point3D thirdPoint; mitk::Point3D fourthPoint; mitk::FillVector3D(secondPoint, 2, 0, 0); // X vnl_vector secondPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * secondPoint.GetVnlVector() + meanPos.GetVnlVector(); mitk::Point3D secondPointTransformedMITK; mitk::FillVector3D( secondPointTransformedMITK, secondPointTransformed[0], secondPointTransformed[1], secondPointTransformed[2]); mitk::FillVector3D(thirdPoint, 0, 4, 0); // Y vnl_vector thirdPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * thirdPoint.GetVnlVector() + meanPos.GetVnlVector(); mitk::Point3D thirdPointTransformedMITK; mitk::FillVector3D( thirdPointTransformedMITK, thirdPointTransformed[0], thirdPointTransformed[1], thirdPointTransformed[2]); mitk::FillVector3D(fourthPoint, 0, 0, 6); // Z vnl_vector fourthPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * fourthPoint.GetVnlVector() + meanPos.GetVnlVector(); mitk::Point3D fourthPointTransformedMITK; mitk::FillVector3D( fourthPointTransformedMITK, fourthPointTransformed[0], fourthPointTransformed[1], fourthPointTransformed[2]); mitk::PointSet::Pointer rotationLine = mitk::PointSet::New(); rotationLine->InsertPoint(0, secondPointTransformedMITK); rotationLine->InsertPoint(1, meanPos); rotationLine->InsertPoint(2, thirdPointTransformedMITK); rotationLine->InsertPoint(3, meanPos); rotationLine->InsertPoint(4, fourthPointTransformedMITK); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString nodeName = this->m_Controls->m_prefix->text() + "RotationLineNumber" + QString::number(i); newNode->SetName(nodeName.toStdString()); newNode->SetData(rotationLine); newNode->SetBoolProperty("show contour", true); newNode->SetFloatProperty("pointsize", 0.5); this->GetDataStorage()->Add(newNode); m_rotationLines.push_back(newNode); } this->GlobalReinit(); } void QmitkIGTTrackingDataEvaluationView::OnGenerateGroundTruthPointSet() { mitk::PointSet::Pointer generatedPointSet = mitk::PointSet::New(); int currentPointID = 0; mitk::Point3D currentPoint; mitk::FillVector3D(currentPoint, 0, 0, 0); for (int i = 0; i < m_Controls->m_PointNumber2->value(); i++) { for (int j = 0; j < m_Controls->m_PointNumber1->value(); j++) { generatedPointSet->InsertPoint(currentPointID, currentPoint); currentPointID++; currentPoint[1] += m_Controls->m_PointDistance->value(); } currentPoint[1] = 0; currentPoint[2] += m_Controls->m_PointDistance->value(); } mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString nodeName = "GroundTruthPointSet_" + QString::number(m_Controls->m_PointNumber1->value()) + "x" + QString::number(m_Controls->m_PointNumber2->value()) + "_(" + QString::number(m_Controls->m_PointDistance->value()) + "mm)"; newNode->SetName(nodeName.toStdString()); newNode->SetData(generatedPointSet); newNode->SetFloatProperty("pointsize", 5); this->GetDataStorage()->Add(newNode); } void QmitkIGTTrackingDataEvaluationView::OnConvertCSVtoXMLFile() { if (m_Controls->m_ConvertSingleFile->isChecked()) { // convert one file int lines = ConvertOneFile(this->m_Controls->m_InputCSV->text().toStdString(), this->m_Controls->m_OutputXML->text().toStdString()); QString result = "Converted one file with" + QString::number(lines) + " data sets"; MessageBox(result.toStdString()); } else // converte file list { if (m_CSVtoXMLInputFilenameVector.empty() || m_CSVtoXMLOutputFilenameVector.empty()) { MessageBox("Error: one list is not loaded!"); return; } else if (m_CSVtoXMLInputFilenameVector.size() != m_CSVtoXMLOutputFilenameVector.size()) { MessageBox("Error: lists do not have the same number of files!"); return; } for (std::size_t i = 0; i < m_CSVtoXMLInputFilenameVector.size(); ++i) { ConvertOneFile(m_CSVtoXMLInputFilenameVector.at(i), m_CSVtoXMLOutputFilenameVector.at(i)); } QString result = "Converted " + QString::number(m_CSVtoXMLInputFilenameVector.size()) + " files from file list!"; MessageBox(result.toStdString()); } } int QmitkIGTTrackingDataEvaluationView::ConvertOneFile(std::string inputFilename, std::string outputFilename) { std::vector myNavigationDatas = GetNavigationDatasFromFile(inputFilename); mitk::NavigationDataRecorderDeprecated::Pointer myRecorder = mitk::NavigationDataRecorderDeprecated::New(); myRecorder->SetFileName(outputFilename.c_str()); mitk::NavigationData::Pointer input = mitk::NavigationData::New(); if (m_Controls->m_ConvertCSV->isChecked()) myRecorder->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); myRecorder->AddNavigationData(input); myRecorder->StartRecording(); for (std::size_t i = 0; i < myNavigationDatas.size(); ++i) { input->Graft(myNavigationDatas.at(i)); myRecorder->Update(); } myRecorder->StopRecording(); return myNavigationDatas.size(); } void QmitkIGTTrackingDataEvaluationView::OnCSVtoXMLLoadInputList() { // read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_CSVtoXMLInputFilenameVector = this->GetFileContentLineByLine(filename.toStdString()); m_Controls->m_labelCSVtoXMLInputList->setText("READY"); } void QmitkIGTTrackingDataEvaluationView::OnCSVtoXMLLoadOutputList() { // read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_CSVtoXMLOutputFilenameVector = this->GetFileContentLineByLine(filename.toStdString()); m_Controls->m_labelCSVtoXMLOutputList->setText("READY"); } void QmitkIGTTrackingDataEvaluationView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkIGTTrackingDataEvaluationView::WriteHeader() { m_CurrentWriteFile << "Filename;"; m_CurrentWriteFile << "N;"; m_CurrentWriteFile << "N_invalid;"; m_CurrentWriteFile << "Percentage_invalid;"; if (m_Controls->m_settingPosMean->isChecked()) { m_CurrentWriteFile << "Position_Mean[x];"; m_CurrentWriteFile << "Position_Mean[y];"; m_CurrentWriteFile << "Position_Mean[z];"; } if (m_Controls->m_settingPosStabw->isChecked()) { m_CurrentWriteFile << "Position_StandDev[x];"; m_CurrentWriteFile << "Position_StandDev[y];"; m_CurrentWriteFile << "Position_StandDev[z];"; } if (m_Controls->m_settingPosSampleStabw->isChecked()) { m_CurrentWriteFile << "Position_SampleStandDev[x];"; m_CurrentWriteFile << "Position_SampleStandDev[y];"; m_CurrentWriteFile << "Position_SampleStandDev[z];"; } if (m_Controls->m_settingQuaternionMean->isChecked()) { m_CurrentWriteFile << "Quaternion_Mean[qx];"; m_CurrentWriteFile << "Quaternion_Mean[qy];"; m_CurrentWriteFile << "Quaternion_Mean[qz];"; m_CurrentWriteFile << "Quaternion_Mean[qr];"; } if (m_Controls->m_settionQuaternionStabw->isChecked()) { m_CurrentWriteFile << "Quaternion_StandDev[qx];"; m_CurrentWriteFile << "Quaternion_StandDev[qy];"; m_CurrentWriteFile << "Quaternion_StandDev[qz];"; m_CurrentWriteFile << "Quaternion_StandDev[qr];"; } if (m_Controls->m_settingPosErrorMean->isChecked()) m_CurrentWriteFile << "PositionError_Mean;"; if (m_Controls->m_settingPosErrorStabw->isChecked()) m_CurrentWriteFile << "PositionError_StandDev;"; if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) m_CurrentWriteFile << "PositionError_SampleStandDev;"; if (m_Controls->m_settingPosErrorRMS->isChecked()) m_CurrentWriteFile << "PositionError_RMS;"; if (m_Controls->m_settingPosErrorMedian->isChecked()) m_CurrentWriteFile << "PositionError_Median;"; if (m_Controls->m_settingPosErrorMinMax->isChecked()) { m_CurrentWriteFile << "PositionError_Max;"; m_CurrentWriteFile << "PositionError_Min;"; } if (m_Controls->m_settingEulerMean->isChecked()) { m_CurrentWriteFile << "Euler_tx;"; m_CurrentWriteFile << "Euler_ty;"; m_CurrentWriteFile << "Euler_tz;"; } + if (m_Controls->m_toolAxisRSME->isChecked()) + { + m_CurrentWriteFile << "Tool Axis RMS Error [mm];"; + } + if (m_Controls->m_settingEulerRMS->isChecked()) { m_CurrentWriteFile << "EulerErrorRMS (rad);"; m_CurrentWriteFile << "EulerErrorRMS (grad);"; } m_CurrentWriteFile << "\n"; } void QmitkIGTTrackingDataEvaluationView::WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter, std::string dataSetName) { if (myEvaluationFilter->GetNumberOfOutputs() == 0) m_CurrentWriteFile << "Error: no input \n"; else { m_CurrentWriteFile << dataSetName << ";"; m_CurrentWriteFile << myEvaluationFilter->GetNumberOfAnalysedNavigationData(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetNumberOfInvalidSamples(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPercentageOfInvalidSamples(0) << ";"; if (m_Controls->m_settingPosMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[2] << ";"; } if (m_Controls->m_settingPosStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[2] << ";"; } if (m_Controls->m_settingPosSampleStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[2] << ";"; } if (m_Controls->m_settingQuaternionMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).x() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).y() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).z() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).r() << ";"; } if (m_Controls->m_settionQuaternionStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).x() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).y() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).z() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).r() << ";"; } if (m_Controls->m_settingPosErrorMean->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMean(0) << ";"; if (m_Controls->m_settingPosErrorStabw->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorStandardDeviation(0) << ";"; if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorSampleStandardDeviation(0) << ";"; if (m_Controls->m_settingPosErrorRMS->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorRMS(0) << ";"; if (m_Controls->m_settingPosErrorMedian->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMedian(0) << ";"; if (m_Controls->m_settingPosErrorMinMax->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMax(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMin(0) << ";"; } if (m_Controls->m_settingEulerMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[2] << ";"; } + if (m_Controls->m_toolAxisRSME->isChecked()) + { + m_CurrentWriteFile << myEvaluationFilter->GetToolAxisRSME(0) << ";"; + } + if (m_Controls->m_settingEulerRMS->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesRMS(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesRMSDegree(0) << ";"; } m_CurrentWriteFile << "\n"; } } std::vector QmitkIGTTrackingDataEvaluationView::GetMeanOrientationsOfAllData( std::vector allData, bool useSLERP) { std::vector returnValue; for (auto dataSet : allData) { if (useSLERP) returnValue.push_back(GetSLERPAverage(dataSet)); else returnValue.push_back(dataSet->GetQuaternionMean(0)); } return returnValue; } std::vector QmitkIGTTrackingDataEvaluationView::GetAllDataFromUIList() { std::vector EvaluationDataCollection; // start loop and iterate through all files of list: store the evaluation data for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); // create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); // connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); // update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) myEvaluationFilter->Update(); myEvaluationFilter->SetInput(nullptr); myPlayer = nullptr; EvaluationDataCollection.push_back(myEvaluationFilter); } return EvaluationDataCollection; } void QmitkIGTTrackingDataEvaluationView::CalculateDifferenceAngles() { // Get all data from UI std::vector EvaluationDataCollection = GetAllDataFromUIList(); // calculation and writing of output data // open output file m_CurrentAngleDifferencesWriteFile.open( std::string((m_Controls->m_OutputFilename->text() + ".angledifferences.csv").toUtf8()).c_str(), std::ios::out); if (m_CurrentAngleDifferencesWriteFile.bad()) { MessageBox("Error: Can't open output file for angle differences calculation!"); return; } // write header WriteDifferenceAnglesHeader(); // compute angle differences QString pos1 = "invalid"; QString pos2 = "invalid"; // now iterate through all evaluation data and calculate the angles for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { pos1 = QString::fromStdString(itksys::SystemTools::GetFilenameWithoutLastExtension(m_FilenameVector.at(i))); for (std::size_t j = 0; j < m_FilenameVector.size(); ++j) { pos2 = QString::fromStdString(itksys::SystemTools::GetFilenameWithoutLastExtension(m_FilenameVector.at(j))); mitk::Quaternion q1; mitk::Quaternion q2; if (m_Controls->m_DifferencesSLERP->isChecked()) { // compute slerp average q1 = GetSLERPAverage(EvaluationDataCollection.at(i)); q2 = GetSLERPAverage(EvaluationDataCollection.at(j)); } else { // compute arithmetic average q1 = EvaluationDataCollection.at(i)->GetQuaternionMean(0); q2 = EvaluationDataCollection.at(j)->GetQuaternionMean(0); } itk::Vector rotationVec; // adapt for Aurora 5D tools: [0,0,1000] rotationVec[0] = 10000; // X rotationVec[1] = 0; // Y rotationVec[2] = 0; // Z double AngleBetweenTwoQuaternions = mitk::StaticIGTHelperFunctions::GetAngleBetweenTwoQuaterions(q1, q2, rotationVec); // write data set WriteDifferenceAnglesDataSet(pos1.toStdString(), pos2.toStdString(), i, j, AngleBetweenTwoQuaternions); } } // close output file m_CurrentAngleDifferencesWriteFile.close(); } void QmitkIGTTrackingDataEvaluationView::WriteDifferenceAnglesHeader() { m_CurrentAngleDifferencesWriteFile << "Name;Idx1;Idx2;Angle [Degree]\n"; } void QmitkIGTTrackingDataEvaluationView::WriteDifferenceAnglesDataSet( std::string pos1, std::string pos2, int idx1, int idx2, double angle) { m_CurrentAngleDifferencesWriteFile << "Angle between " << pos1 << " and " << pos2 << ";" << idx1 << ";" << idx2 << ";" << angle << "\n"; MITK_INFO << "Angle: " << angle; } std::vector QmitkIGTTrackingDataEvaluationView::GetNavigationDatasFromFile( std::string filename) { std::vector returnValue = std::vector(); std::vector fileContentLineByLine = GetFileContentLineByLine(filename); for (std::size_t i = 1; i < fileContentLineByLine.size(); ++i) // skip header so start at 1 { returnValue.push_back(GetNavigationDataOutOfOneLine(fileContentLineByLine.at(i))); } return returnValue; } std::vector QmitkIGTTrackingDataEvaluationView::GetFileContentLineByLine(std::string filename) { std::vector readData = std::vector(); // save old locale char *oldLocale; oldLocale = setlocale(LC_ALL, 0); // define own locale std::locale C("C"); setlocale(LC_ALL, "C"); // read file std::ifstream file; file.open(filename.c_str(), std::ios::in); if (file.good()) { // read out file file.seekg(0L, std::ios::beg); // move to begin of file while (!file.eof()) { std::string buffer; std::getline(file, buffer); // read out file line by line if (buffer.size() > 0) readData.push_back(buffer); } } file.close(); // switch back to old locale setlocale(LC_ALL, oldLocale); return readData; } mitk::NavigationData::Pointer QmitkIGTTrackingDataEvaluationView::GetNavigationDataOutOfOneLine(std::string line) { mitk::NavigationData::Pointer returnValue = mitk::NavigationData::New(); QString myLine = QString(line.c_str()); QStringList myLineList = myLine.split(';'); mitk::Point3D position; mitk::Quaternion orientation; bool valid = false; if (myLineList.at(2).toStdString() == "1") valid = true; position[0] = myLineList.at(3).toDouble(); position[1] = myLineList.at(4).toDouble(); position[2] = myLineList.at(5).toDouble(); orientation[0] = myLineList.at(6).toDouble(); orientation[1] = myLineList.at(7).toDouble(); orientation[2] = myLineList.at(8).toDouble(); orientation[3] = myLineList.at(9).toDouble(); returnValue->SetDataValid(valid); returnValue->SetPosition(position); returnValue->SetOrientation(orientation); return returnValue; } mitk::Quaternion QmitkIGTTrackingDataEvaluationView::GetSLERPAverage( mitk::NavigationDataEvaluationFilter::Pointer evaluationFilter) { mitk::Quaternion average; // build a vector of quaternions from the evaulation filter (caution always takes the first (0) input of the filter std::vector quaternions = std::vector(); for (int i = 0; i < evaluationFilter->GetNumberOfAnalysedNavigationData(0); i++) { mitk::Quaternion currentq = evaluationFilter->GetLoggedOrientation(i, 0); quaternions.push_back(currentq); } // compute the slerp average using the quaternion averaging class mitk::QuaternionAveraging::Pointer myAverager = mitk::QuaternionAveraging::New(); average = myAverager->CalcAverage(quaternions); return average; } void QmitkIGTTrackingDataEvaluationView::writeToFile( std::string filename, std::vector values) { std::fstream currentFile; currentFile.open(filename.c_str(), std::ios::out); if (currentFile.bad()) { MITK_WARN << "Cannot open file, aborting!"; return; } currentFile << "Description" << ";" << "Error[mm]" << "\n"; for (auto currentError : values) { currentFile << currentError.description << ";" << currentError.distanceError << "\n"; } currentFile.close(); } mitk::NavigationDataCSVSequentialPlayer::Pointer QmitkIGTTrackingDataEvaluationView::ConstructNewNavigationDataPlayer() { bool rightHanded = m_Controls->m_RigthHanded->isChecked(); QString separator = m_Controls->m_SeparatorSign->text(); QChar sepaSign = separator.at(0); // char separatorSign; char separatorSign = sepaSign.toLatin1(); // std::string separatorSign = m_Controls->m_SeparatorSign->text().toStdString(); int sampleCount = m_Controls->m_SampleCount->value(); bool headerRow = m_Controls->m_HeaderRow->isChecked(); int xPos = m_Controls->m_XPos->value(); int yPos = m_Controls->m_YPos->value(); int zPos = m_Controls->m_ZPos->value(); bool useQuats = m_Controls->m_UseQuats->isChecked(); int qx = m_Controls->m_Qx->value(); int qy = m_Controls->m_Qy->value(); int qz = m_Controls->m_Qz->value(); int qr = m_Controls->m_Qr->value(); int azimuth = m_Controls->m_Azimuth->value(); int elevation = m_Controls->m_Elevation->value(); int roll = m_Controls->m_Roll->value(); bool eulersInRad = m_Controls->m_Radiants->isChecked(); // need to find the biggest column number to determine the minimal number of columns the .csv file has to have int allInts[] = {xPos, yPos, zPos, qx, qy, qr, azimuth, elevation, roll}; int minNumberOfColumns = (*std::max_element(allInts, allInts + 9) + 1); // size needs to be +1 because columns start at 0 but size at 1 mitk::NavigationDataCSVSequentialPlayer::Pointer navDataPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); navDataPlayer->SetOptions(rightHanded, separatorSign, sampleCount, headerRow, xPos, yPos, zPos, useQuats, qx, qy, qz, qr, azimuth, elevation, roll, eulersInRad, minNumberOfColumns); return navDataPlayer; } void QmitkIGTTrackingDataEvaluationView::GlobalReinit() { // Global reinit // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New( mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetSubset(pred); // calculate bounding geometry of these nodes mitk::TimeGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } 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 296aa515fd..37ec958796 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,1700 +1,1716 @@ QmitkIGTTrackingDataEvaluationViewControls 0 0 383 - 658 + 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 - 498 + 551 General Number of samples to analyze: Qt::Horizontal 60 20 1000000 150 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 - 262 + 324 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 - 4 + 3 Z - 5 + 4 X - 3 + 2 Coordinate: Colum number: Use Quaternions for Orientation true Qr - 8 + 7 Qy - 9 + 8 - 7 + 6 - 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 - 287 - 512 + 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 + + + + + + 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