diff --git a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp index d80a29b859..bf504724a0 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp +++ b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp @@ -1,298 +1,371 @@ /*=================================================================== 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::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::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])); + 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) { 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] / itk::Math::pi) * 180; currentAngles[1] = (eulerAnglesRadians.at(i)[1] / itk::Math::pi) * 180; currentAngles[2] = (eulerAnglesRadians.at(i)[2] / itk::Math::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 e68fda1857..41e0533724 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(); ~NavigationDataEvaluationFilter() override; /**Documentation * \brief filter execute method * * transforms navigation data */ 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 12da728a93..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,1169 +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 -//ITK +// ITK #include -//VNL +// VNL #include -//vtk headers +// vtk headers +#include #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) + : QmitkFunctionality(), m_Controls(0), m_MultiWidget(nullptr), m_scalingfactor(1) { m_CSVtoXMLInputFilenameVector = std::vector(); m_CSVtoXMLOutputFilenameVector = std::vector(); } -QmitkIGTTrackingDataEvaluationView::~QmitkIGTTrackingDataEvaluationView() +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_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_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 + // 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 + 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 + // Get all data from UI auto EvaluationDataCollection = GetAllDataFromUIList(); - //Compute mean Quaternions + // Compute mean Quaternions auto OrientationVector = GetMeanOrientationsOfAllData(EvaluationDataCollection); - //Compute Rotations + // 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 + // 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) + 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 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() }); + allOrientationErrors.push_back({AngularError, description.str()}); MITK_INFO << description.str() << ": " << AngularError; } - //compute statistics + // 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; } + 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]"}); + // 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"; + 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 + 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; iGetSize(); i++) + for (int i = 0; i < reference->GetSize(); i++) { - double point[3] = { reference->GetPoint(i)[0], reference->GetPoint(i)[1], reference->GetPoint(i)[2] }; + 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] }; + double point_targets[3] = {measurement->GetPoint(i)[0], measurement->GetPoint(i)[1], measurement->GetPoint(i)[2]}; targetPoints->InsertNextPoint(point_targets); } - //compute transform + // compute transform vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->SetModeToRigidBody(); transform->Modified(); transform->Update(); - //compute FRE of transform + // 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 + // 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++) + 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 + // 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()->SetIndexToWorldTransform( + mitkTransform); m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()->GetGeometry()->Modified(); - //write to file + // 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]" }); + 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 + // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { - //create navigation data player + // 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 + // check if the stream is valid and skip file if not - //create evaluation filter + // create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); - //connect pipeline + // 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 + // 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 + // 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; + 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 + // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { - //create navigation data player + // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); - //open file header + // 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"; + // 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 + // 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)) + 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 { - 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); + 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; + break; } m_CurrentWriteFile << i << ";"; - m_CurrentWriteFile << currentNavData->GetTimeStamp() << ";"; //IMPORTANT: change to GetIGTTimeStamp in new version! + 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 + // close output file m_CurrentWriteFile.close(); } - MessageBox("Finished!"); + // MessageBox("Finished!"); } void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetNotAvailable() { m_MultiWidget = nullptr; } -void QmitkIGTTrackingDataEvaluationView::OnAddToCurrentList() +bool QmitkIGTTrackingDataEvaluationView::OnAddToCurrentList() { - //read in files + // read in files QStringList files = QFileDialog::getOpenFileNames(nullptr, "Select one or more files to open", "/", "CSV (*.csv)"); - if (files.isEmpty()) return; + 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 + // 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); } + 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(); - OnAddToCurrentList(); + // load/add new data + if (!OnAddToCurrentList()) + { + m_FilenameVector = tempOld; + } } void QmitkIGTTrackingDataEvaluationView::OnEvaluateDataAll() { - std::vector results5cm, results15cm, results30cm, resultsAccum; + 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 + // 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 - m_CurrentWriteFile.open(std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str(), std::ios::out); + // 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 + // write output file header WriteHeader(); - //start loop and iterate through all files of list + // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { - //create navigation data player + // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); - //create evaluation filter + // create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); - //connect pipeline - for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++i) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } + // 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!"; + 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 + // update pipline until number of samples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) myEvaluationFilter->Update(); - //store all jitter values in separate vector for statistics - jitterValues.push_back({ myEvaluationFilter->GetPositionErrorRMS(0), "RMS" }); + 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 + // write result to output file WriteDataSet(myEvaluationFilter, m_FilenameVector.at(i)); } - //close output file for single data + // close output file for single data m_CurrentWriteFile.close(); - //compute statistics - std::vector jitterStatistics = mitk::HummelProtocolEvaluation::ComputeStatistics(jitterValues); + // compute statistics + std::vector jitterStatistics = + mitk::HummelProtocolEvaluation::ComputeStatistics(jitterValues); MITK_INFO << "## Jitter (RMS) statistics: ##"; - for (auto jitterStat : jitterStatistics) {MITK_INFO << jitterStat.description << ": " << jitterStat.distanceError;} + for (auto jitterStat : jitterStatistics) + { + MITK_INFO << jitterStat.description << ": " << jitterStat.distanceError; + } - //write statistic results to separate file + // write statistic results to separate file std::stringstream filenameJitterStat; - filenameJitterStat << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".resultsJitterStatistics.csv"; + 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(); + // 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 + // 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 + // create point set for this file mitk::PointSet::Pointer thisPointSet = mitk::PointSet::New(); - //create navigation data player + // 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 + // 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 + // 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 + // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { - //create navigation data player + // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); - //create evaluation filter + // 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)); } + // 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(); } + // 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 + // 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 - mitk::DataNode::Pointer newNode = mitk::DataNode::New(); + // add point set to data storage + m_PointSetDataNode = mitk::DataNode::New(); QString name = this->m_Controls->m_prefix->text() + "PointSet_of_Mean_Positions"; - newNode->SetName(name.toStdString()); - newNode->SetData(generatedPointSet); - newNode->SetFloatProperty("pointsize", 5); - this->GetDataStorage()->Add(newNode); + 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); + } + m_rotationLines = std::vector(); - //start loop and iterate through all files of list + // start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { - //create navigation data player + // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); - //create evaluation filter + // 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)); } + // 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 + // 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) + // 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::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( + 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::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( + 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::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::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)"; + 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()); + { // 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 + 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); + 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; + // 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; + // 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_settingPosErrorMean->isChecked()) + m_CurrentWriteFile << "PositionError_Mean;"; - if (m_Controls->m_settingPosErrorStabw->isChecked()) m_CurrentWriteFile << "PositionError_StandDev;"; + if (m_Controls->m_settingPosErrorStabw->isChecked()) + m_CurrentWriteFile << "PositionError_StandDev;"; - if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) m_CurrentWriteFile << "PositionError_SampleStandDev;"; + if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) + m_CurrentWriteFile << "PositionError_SampleStandDev;"; - if (m_Controls->m_settingPosErrorRMS->isChecked()) m_CurrentWriteFile << "PositionError_RMS;"; + if (m_Controls->m_settingPosErrorRMS->isChecked()) + m_CurrentWriteFile << "PositionError_RMS;"; - if (m_Controls->m_settingPosErrorMedian->isChecked()) m_CurrentWriteFile << "PositionError_Median;"; + 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) +void QmitkIGTTrackingDataEvaluationView::WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter, + std::string dataSetName) { - if (myEvaluationFilter->GetNumberOfOutputs() == 0) m_CurrentWriteFile << "Error: no input \n"; + 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_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 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)); + 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 + // 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 + // create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); - //create evaluation filter + // create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); - //connect pipeline + // 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 + // 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 + // 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); + // 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 + // write header WriteDifferenceAnglesHeader(); - //compute angle differences + // compute angle differences QString pos1 = "invalid"; QString pos2 = "invalid"; - //now iterate through all evaluation data and calculate the angles + // 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 + // compute slerp average q1 = GetSLERPAverage(EvaluationDataCollection.at(i)); q2 = GetSLERPAverage(EvaluationDataCollection.at(j)); } else { - //compute arithmetic average + // 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 + // 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 + // 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) +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"; + m_CurrentAngleDifferencesWriteFile << "Angle between " << pos1 << " and " << pos2 << ";" << idx1 << ";" << idx2 << ";" + << angle << "\n"; MITK_INFO << "Angle: " << angle; } -std::vector QmitkIGTTrackingDataEvaluationView::GetNavigationDatasFromFile(std::string filename) +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 + 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; + // save old locale + char *oldLocale; oldLocale = setlocale(LC_ALL, 0); - //define own locale + // define own locale std::locale C("C"); setlocale(LC_ALL, "C"); - //read file + // 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 + // 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); + 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 + // 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; + 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 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 + // 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 + // 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) +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"; + 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; + 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/QmitkIGTTrackingDataEvaluationView.h b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h index 28271da295..427df9c5f0 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h @@ -1,142 +1,153 @@ /*=================================================================== 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 QmitkIGTTrackingDataEvaluationView_h #define QmitkIGTTrackingDataEvaluationView_h #include #include -#include "ui_QmitkIGTTrackingDataEvaluationViewControls.h" #include "mitkHummelProtocolEvaluation.h" +#include "ui_QmitkIGTTrackingDataEvaluationViewControls.h" -#include #include "mitkNavigationDataCSVSequentialPlayer.h" - - +#include /*! \brief QmitkIGTTrackingDataEvaluationView - \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. + \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide + basic documentation. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkIGTTrackingDataEvaluationView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT - public: +public: + static const std::string VIEW_ID; + + QmitkIGTTrackingDataEvaluationView(); + virtual ~QmitkIGTTrackingDataEvaluationView(); - static const std::string VIEW_ID; + virtual void CreateQtPartControl(QWidget *parent); - QmitkIGTTrackingDataEvaluationView(); - virtual ~QmitkIGTTrackingDataEvaluationView(); + virtual void StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget); + virtual void StdMultiWidgetNotAvailable(); - virtual void CreateQtPartControl(QWidget *parent); +protected slots: - virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); - virtual void StdMultiWidgetNotAvailable(); + void OnLoadFileList(); + bool OnAddToCurrentList(); + void OnEvaluateData(); + void OnEvaluateDataAll(); + void OnGeneratePointSet(); + void OnGeneratePointSetsOfSinglePositions(); + void OnGenerateRotationLines(); + void OnGenerateGroundTruthPointSet(); + void OnConvertCSVtoXMLFile(); + void OnCSVtoXMLLoadInputList(); + void OnCSVtoXMLLoadOutputList(); + void OnPerfomGridMatching(); + void OnComputeRotation(); + void OnLoadMITKPresets(); + void OnLoadPolhemusPresets(); - protected slots: + /** Reads in exactly three position files als reference. */ + void OnOrientationCalculation_CalcRef(); + /** Uses always three positions (1,2,3: first orientation; 4,5,6: second orientation; and so on) in every file to + * calcualte a orientation. */ + void OnOrientationCalculation_CalcOrientandWriteToFile(); - void OnLoadFileList(); - void OnAddToCurrentList(); - void OnEvaluateData(); - void OnEvaluateDataAll(); - void OnGeneratePointSet(); - void OnGeneratePointSetsOfSinglePositions(); - void OnGenerateRotationLines(); - void OnGenerateGroundTruthPointSet(); - void OnConvertCSVtoXMLFile(); - void OnCSVtoXMLLoadInputList(); - void OnCSVtoXMLLoadOutputList(); - void OnPerfomGridMatching(); - void OnComputeRotation(); +protected: + Ui::QmitkIGTTrackingDataEvaluationViewControls *m_Controls; - /** Reads in exactly three position files als reference. */ - void OnOrientationCalculation_CalcRef(); - /** Uses always three positions (1,2,3: first orientation; 4,5,6: second orientation; and so on) in every file to calcualte a orientation. */ - void OnOrientationCalculation_CalcOrientandWriteToFile(); + QmitkStdMultiWidget *m_MultiWidget; + std::vector m_FilenameVector; - protected: + void MessageBox(std::string s); - Ui::QmitkIGTTrackingDataEvaluationViewControls* m_Controls; + std::fstream m_CurrentWriteFile; + void WriteHeader(); + void WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer evaluationFilter, std::string dataSetName); - QmitkStdMultiWidget* m_MultiWidget; + // members for orientation calculation + mitk::Point3D m_RefPoint1; + mitk::Point3D m_RefPoint2; + mitk::Point3D m_RefPoint3; - std::vector m_FilenameVector; + double m_scalingfactor; // scaling factor for visualization, 1 by default - void MessageBox(std::string s); + // angle diffrences: seperated file + std::fstream m_CurrentAngleDifferencesWriteFile; + void CalculateDifferenceAngles(); + void WriteDifferenceAnglesHeader(); + void WriteDifferenceAnglesDataSet(std::string pos1, std::string pos2, int idx1, int idx2, double angle); - std::fstream m_CurrentWriteFile; - void WriteHeader(); - void WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer evaluationFilter, std::string dataSetName); + void writeToFile(std::string filename, + std::vector values); - //members for orientation calculation - mitk::Point3D m_RefPoint1; - mitk::Point3D m_RefPoint2; - mitk::Point3D m_RefPoint3; + // different help methods to read a csv logging file + std::vector GetNavigationDatasFromFile(std::string filename); + std::vector GetFileContentLineByLine(std::string filename); + mitk::NavigationData::Pointer GetNavigationDataOutOfOneLine(std::string line); - double m_scalingfactor; //scaling factor for visualization, 1 by default + // help method to sonstruct the NavigationDataCSVSequentialPlayer filled with all the options from the UI + mitk::NavigationDataCSVSequentialPlayer::Pointer ConstructNewNavigationDataPlayer(); - //angle diffrences: seperated file - std::fstream m_CurrentAngleDifferencesWriteFile; - void CalculateDifferenceAngles(); - void WriteDifferenceAnglesHeader(); - void WriteDifferenceAnglesDataSet(std::string pos1, std::string pos2, int idx1, int idx2, double angle); + // CSV to XML members + std::vector m_CSVtoXMLInputFilenameVector; + std::vector m_CSVtoXMLOutputFilenameVector; - void writeToFile(std::string filename, std::vector values); + // returns the number of converted lines + int ConvertOneFile(std::string inputFilename, std::string outputFilename); - //different help methods to read a csv logging file - std::vector GetNavigationDatasFromFile(std::string filename); - std::vector GetFileContentLineByLine(std::string filename); - mitk::NavigationData::Pointer GetNavigationDataOutOfOneLine(std::string line); + /** @brief calculates the angle in the plane perpendicular to the rotation axis of the two quaterions. */ + double GetAngleBetweenTwoQuaterions(mitk::Quaternion a, mitk::Quaternion b); - //help method to sonstruct the NavigationDataCSVSequentialPlayer filled with all the options from the UI - mitk::NavigationDataCSVSequentialPlayer::Pointer ConstructNewNavigationDataPlayer(); + /** @brief calculates the slerp average of a set of quaternions which is stored in the navigation data evaluation + * filter */ + mitk::Quaternion GetSLERPAverage(mitk::NavigationDataEvaluationFilter::Pointer); - //CSV to XML members - std::vector m_CSVtoXMLInputFilenameVector; - std::vector m_CSVtoXMLOutputFilenameVector; + /** @brief Stores the mean positions of all evaluated data */ + mitk::PointSet::Pointer m_PointSetMeanPositions; - //returns the number of converted lines - int ConvertOneFile(std::string inputFilename, std::string outputFilename); + /** @brief Stores the mean positions of all evaluated data */ + mitk::DataNode::Pointer m_PointSetDataNode; - /** @brief calculates the angle in the plane perpendicular to the rotation axis of the two quaterions. */ - double GetAngleBetweenTwoQuaterions(mitk::Quaternion a, mitk::Quaternion b); + /** @return returns the mean orientation of all given data */ + std::vector GetMeanOrientationsOfAllData( + std::vector allData, bool useSLERP = false); - /** @brief calculates the slerp average of a set of quaternions which is stored in the navigation data evaluation filter */ - mitk::Quaternion GetSLERPAverage(mitk::NavigationDataEvaluationFilter::Pointer); + /** @return returns all data read from the data list as NavigationDataEvaluationFilters */ + std::vector GetAllDataFromUIList(); - /** @brief Stores the mean positions of all evaluated data */ - mitk::PointSet::Pointer m_PointSetMeanPositions; + std::vector m_rotationLines; - /** @return returns the mean orientation of all given data */ - std::vector GetMeanOrientationsOfAllData(std::vector allData, bool useSLERP = false); + /** Performs a global reinit on the view. */ + void GlobalReinit(); - /** @return returns all data read from the data list as NavigationDataEvaluationFilters */ - std::vector GetAllDataFromUIList(); }; #endif // _QMITKIGTTRACKINGDATAEVALUATIONVIEW_H_INCLUDED 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 2dd08f80f3..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,1780 +1,1719 @@ QmitkIGTTrackingDataEvaluationViewControls 0 0 - 448 - 955 + 383 + 711 0 0 QmitkTemplate 0 Evaluation - Input File List (recorded NavigationData / *.csv): + 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: - - - - - - Prefix for Data Nodes: - - - - - - - - Generate PointSet of Mean Positions Generate PointSets of Single Positions Generate Lines for Rotation Qt::Horizontal - (3) - JITTER - Evaluation per file / data set: + (2) - JITTER - Evaluation per file / data set: - - - - - Result CSV Filename: - - - - - - - D:/tmp/output.csv - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 220 - 0 - - - - - 200 - 50 - - - - COMPUTE RESULTS PER DATA SET - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + COMPUTE RESULTS PER DATA SET + + Qt::Horizontal (3) - ACCURACY - Evaluation of all data sets: - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 220 - 0 - - - - - 200 - 50 - - - - COMPUTE RESULTS OF ALL DATA - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + 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 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 220 - 0 - - - - - 200 - 50 - - - - PERFOM GRID MATCHING - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + PERFOM GRID MATCHING + + Qt::Horizontal (5) - ROTATION - Evaluation of all data sets: - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 220 - 0 - - - - - 200 - 50 - - - - COMPUTE ROTATION ERRORS - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + COMPUTE ROTATION ERRORS + + Qt::Vertical QSizePolicy::Expanding 20 220 Settings 0 0 - 409 - 768 + 356 + 551 General - - - - - - Scaling Factor for Visualization: - - - - - - - Qt::Horizontal - - - - 38 - 20 - - - - - - - - 1.000000000000000 - - - - - Number of samples to analyze: Qt::Horizontal 60 20 1000000 - 150 + 100 Qt::Horizontal - Tracking Volume: + 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 (3 X 4 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 - 10000 + 0 + + + + Qt::Horizontal + + + + + + + + + Result CSV Filename: + + + + + + + D:/tmp/output.csv + + + + + + + + + + + Prefix for Data Nodes: + + + + + + + + Qt::Vertical 20 40 0 0 - 286 - 746 + 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 - 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 - 343 - 607 + 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
diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp index d63b994090..2b025506bd 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp @@ -1,623 +1,625 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkIGTTrackingSemiAutomaticMeasurementView.h" #include "QmitkStdMultiWidget.h" // Qt #include #include #include #include // MITK #include #include #include #include "mitkHummelProtocolEvaluation.h" // POCO #include #include const std::string QmitkIGTTrackingSemiAutomaticMeasurementView::VIEW_ID = "org.mitk.views.igttrackingsemiautomaticmeasurement"; QmitkIGTTrackingSemiAutomaticMeasurementView::QmitkIGTTrackingSemiAutomaticMeasurementView() : QmitkFunctionality() , m_Controls(0) , m_MultiWidget(nullptr) { m_NextFile = 0; m_FilenameVector = std::vector(); m_Timer = new QTimer(this); m_logging = false; m_referenceValid = true; m_tracking = false; m_EvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); } QmitkIGTTrackingSemiAutomaticMeasurementView::~QmitkIGTTrackingSemiAutomaticMeasurementView() { } void QmitkIGTTrackingSemiAutomaticMeasurementView::CreateResults() { QString LogFileName = m_Controls->m_OutputPath->text() + "_results.log"; mitk::LoggingBackend::Unregister(); mitk::LoggingBackend::SetLogFile(LogFileName.toStdString().c_str()); mitk::LoggingBackend::Register(); double RMSmean = 0; for (std::size_t i = 0; i < m_RMSValues.size(); ++i) { MITK_INFO << "RMS at " << this->m_FilenameVector.at(i) << ": " << m_RMSValues.at(i); RMSmean += m_RMSValues.at(i); } RMSmean /= m_RMSValues.size(); MITK_INFO << "RMS mean over " << m_RMSValues.size() << " values: " << RMSmean; mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName("Tracking Results"); newNode->SetData(this->m_MeanPoints); this->GetDataStorage()->Add(newNode); std::vector results5cmDistances; if (m_Controls->m_mediumVolume->isChecked()) mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_MeanPoints, mitk::HummelProtocolEvaluation::medium, results5cmDistances); else if (m_Controls->m_smallVolume->isChecked()) mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_MeanPoints, mitk::HummelProtocolEvaluation::small, results5cmDistances); else if (m_Controls->m_standardVolume->isChecked()) mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_MeanPoints, mitk::HummelProtocolEvaluation::standard, results5cmDistances); } void QmitkIGTTrackingSemiAutomaticMeasurementView::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::QmitkIGTTrackingSemiAutomaticMeasurementViewControls; m_Controls->setupUi(parent); //buttons connect(m_Controls->m_LoadMeasurementToolStorage, SIGNAL(clicked()), this, SLOT(OnLoadMeasurementStorage())); connect(m_Controls->m_LoadReferenceToolStorage, SIGNAL(clicked()), this, SLOT(OnLoadReferenceStorage())); connect(m_Controls->m_StartTracking, SIGNAL(clicked()), this, SLOT(OnStartTracking())); connect(m_Controls->m_LoadList, SIGNAL(clicked()), this, SLOT(OnMeasurementLoadFile())); connect(m_Controls->m_StartNextMeasurement, SIGNAL(clicked()), this, SLOT(StartNextMeasurement())); connect(m_Controls->m_ReapeatLastMeasurement, SIGNAL(clicked()), this, SLOT(RepeatLastMeasurement())); connect(m_Controls->m_SetReference, SIGNAL(clicked()), this, SLOT(OnSetReference())); connect(m_Controls->m_UseReferenceTrackingSystem, SIGNAL(toggled(bool)), this, SLOT(OnUseReferenceToggled(bool))); connect(m_Controls->m_CreateResults, SIGNAL(clicked()), this, SLOT(CreateResults())); //event filter qApp->installEventFilter(this); //timers connect(m_Timer, SIGNAL(timeout()), this, SLOT(UpdateTimer())); } - //initialize some view + //initialize some views m_Controls->m_StopTracking->setEnabled(false); + m_Controls->m_ReferenceBox->setEnabled(false); + m_Controls->m_SetReference->setEnabled(false); } void QmitkIGTTrackingSemiAutomaticMeasurementView::StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnUseReferenceToggled(bool state) { if (state) { m_Controls->m_ReferenceBox->setEnabled(true); m_Controls->m_SetReference->setEnabled(true); } else { m_Controls->m_ReferenceBox->setEnabled(false); m_Controls->m_SetReference->setEnabled(false); } } void QmitkIGTTrackingSemiAutomaticMeasurementView::StdMultiWidgetNotAvailable() { m_MultiWidget = nullptr; } mitk::NavigationToolStorage::Pointer QmitkIGTTrackingSemiAutomaticMeasurementView::ReadStorage(std::string file) { mitk::NavigationToolStorage::Pointer returnValue; //initialize tool storage returnValue = mitk::NavigationToolStorage::New(); //read tool storage from disk mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(GetDataStorage()); returnValue = myDeserializer->Deserialize(file); if (returnValue.IsNull()) { QMessageBox msgBox; msgBox.setText(myDeserializer->GetErrorMessage().c_str()); msgBox.exec(); returnValue = nullptr; } return returnValue; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnSetReference() { //initialize reference m_ReferenceStartPositions = std::vector(); m_ReferenceTrackingDeviceSource->Update(); QString Label = "Positions At Start: "; for (unsigned int i = 0; i < m_ReferenceTrackingDeviceSource->GetNumberOfOutputs(); ++i) { mitk::Point3D position = m_ReferenceTrackingDeviceSource->GetOutput(i)->GetPosition(); Label = Label + "Tool" + QString::number(i) + ":[" + QString::number(position[0]) + ":" + QString::number(position[1]) + ":" + QString::number(position[1]) + "] "; m_ReferenceStartPositions.push_back(position); } m_Controls->m_ReferencePosAtStart->setText(Label); } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnLoadMeasurementStorage() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Toolfile"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_MeasurementStorage = ReadStorage(filename.toStdString()); //update label Poco::Path myPath = Poco::Path(filename.toStdString()); //use this to seperate filename from path QString toolLabel = QString("Tool Storage: ") + QString::number(m_MeasurementStorage->GetToolCount()) + " Tools from " + myPath.getFileName().c_str(); m_Controls->m_MeasurementToolStorageLabel->setText(toolLabel); //update status widget m_Controls->m_ToolStatusWidget->RemoveStatusLabels(); m_Controls->m_ToolStatusWidget->PreShowTools(m_MeasurementStorage); } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnLoadReferenceStorage() { //read in filename static QString oldFile; if (oldFile.isNull()) oldFile = "/"; QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Toolfile"), oldFile, tr("All Files (*.*)")); if (filename.isNull()) return; oldFile = filename; m_ReferenceStorage = ReadStorage(filename.toStdString()); //update label Poco::Path myPath = Poco::Path(filename.toStdString()); //use this to seperate filename from path QString toolLabel = QString("Tool Storage: ") + QString::number(m_ReferenceStorage->GetToolCount()) + " Tools from " + myPath.getFileName().c_str(); m_Controls->m_ReferenceToolStorageLabel->setText(toolLabel); } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnStartTracking() { //check if everything is ready to start tracking if (m_MeasurementStorage.IsNull()) { MessageBox("Error: No measurement tools loaded yet!"); return; } else if (m_ReferenceStorage.IsNull() && m_Controls->m_UseReferenceTrackingSystem->isChecked()) { MessageBox("Error: No refernce tools loaded yet!"); return; } else if (m_MeasurementStorage->GetToolCount() == 0) { MessageBox("Error: No way to track without tools!"); return; } else if (m_Controls->m_UseReferenceTrackingSystem->isChecked() && (m_ReferenceStorage->GetToolCount() == 0)) { MessageBox("Error: No way to track without tools!"); return; } //build the first IGT pipeline (MEASUREMENT) mitk::TrackingDeviceSourceConfigurator::Pointer myTrackingDeviceSourceFactory1 = mitk::TrackingDeviceSourceConfigurator::New(this->m_MeasurementStorage, this->m_Controls->m_MeasurementTrackingDeviceConfigurationWidget->GetTrackingDevice()); m_MeasurementTrackingDeviceSource = myTrackingDeviceSourceFactory1->CreateTrackingDeviceSource(this->m_MeasurementToolVisualizationFilter); if (m_MeasurementTrackingDeviceSource.IsNull()) { MessageBox(myTrackingDeviceSourceFactory1->GetErrorMessage()); return; } //connect the tool visualization widget for (unsigned int i = 0; i < m_MeasurementTrackingDeviceSource->GetNumberOfOutputs(); ++i) { m_Controls->m_ToolStatusWidget->AddNavigationData(m_MeasurementTrackingDeviceSource->GetOutput(i)); m_EvaluationFilter->SetInput(i, m_MeasurementTrackingDeviceSource->GetOutput(i)); } m_Controls->m_ToolStatusWidget->ShowStatusLabels(); m_Controls->m_ToolStatusWidget->SetShowPositions(true); m_Controls->m_ToolStatusWidget->SetShowQuaternions(true); //build the second IGT pipeline (REFERENCE) if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { mitk::TrackingDeviceSourceConfigurator::Pointer myTrackingDeviceSourceFactory2 = mitk::TrackingDeviceSourceConfigurator::New(this->m_ReferenceStorage, this->m_Controls->m_ReferenceDeviceConfigurationWidget->GetTrackingDevice()); m_ReferenceTrackingDeviceSource = myTrackingDeviceSourceFactory2->CreateTrackingDeviceSource(); if (m_ReferenceTrackingDeviceSource.IsNull()) { MessageBox(myTrackingDeviceSourceFactory2->GetErrorMessage()); return; } } //initialize tracking try { m_MeasurementTrackingDeviceSource->Connect(); m_MeasurementTrackingDeviceSource->StartTracking(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceTrackingDeviceSource->Connect(); m_ReferenceTrackingDeviceSource->StartTracking(); } } catch (...) { MessageBox("Error while starting the tracking device!"); return; } //set reference if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) OnSetReference(); //start timer m_Timer->start(1000 / (m_Controls->m_SamplingRate->value())); m_Controls->m_StartTracking->setEnabled(false); m_Controls->m_StartTracking->setEnabled(true); m_tracking = true; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnStopTracking() { if (this->m_logging) FinishMeasurement(); m_MeasurementTrackingDeviceSource->Disconnect(); m_MeasurementTrackingDeviceSource->StopTracking(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceTrackingDeviceSource->Disconnect(); m_ReferenceTrackingDeviceSource->StopTracking(); } m_Timer->stop(); m_Controls->m_StartTracking->setEnabled(true); m_Controls->m_StartTracking->setEnabled(false); m_tracking = false; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnMeasurementLoadFile() { m_FilenameVector = std::vector(); m_FilenameVector.clear(); m_NextFile = 0; //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; //define own locale std::locale C("C"); setlocale(LC_ALL, "C"); //read file std::ifstream file; file.open(filename.toStdString().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) m_FilenameVector.push_back(buffer); } } //fill list at GUI m_Controls->m_MeasurementList->clear(); for (unsigned int i = 0; i < m_FilenameVector.size(); i++) { new QListWidgetItem(tr(m_FilenameVector.at(i).c_str()), m_Controls->m_MeasurementList); } //update label next measurement std::stringstream label; label << "Next Measurement: " << m_FilenameVector.at(0); m_Controls->m_NextMeasurement->setText(label.str().c_str()); //reset results files m_MeanPoints = mitk::PointSet::New(); m_RMSValues = std::vector(); m_EvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); if (m_MeasurementToolVisualizationFilter.IsNotNull()) m_EvaluationFilter->SetInput(0, m_MeasurementToolVisualizationFilter->GetOutput(0)); } void QmitkIGTTrackingSemiAutomaticMeasurementView::UpdateTimer() { if (m_EvaluationFilter.IsNotNull() && m_logging) m_EvaluationFilter->Update(); else m_MeasurementToolVisualizationFilter->Update(); m_Controls->m_ToolStatusWidget->Refresh(); //update reference if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceTrackingDeviceSource->Update(); QString Label = "Current Positions: "; bool distanceThresholdExceeded = false; for (unsigned int i = 0; i < m_ReferenceTrackingDeviceSource->GetNumberOfOutputs(); ++i) { mitk::Point3D position = m_ReferenceTrackingDeviceSource->GetOutput(i)->GetPosition(); Label = Label + "Tool" + QString::number(i) + ":[" + QString::number(position[0]) + ":" + QString::number(position[1]) + ":" + QString::number(position[1]) + "] "; if (position.EuclideanDistanceTo(m_ReferenceStartPositions.at(i)) > m_Controls->m_ReferenceThreshold->value()) distanceThresholdExceeded = true; } m_Controls->m_ReferenceCurrentPos->setText(Label); if (distanceThresholdExceeded) { m_Controls->m_ReferenceOK->setText("NOT OK!"); m_referenceValid = false; } else { m_Controls->m_ReferenceOK->setText("OK"); m_referenceValid = true; } } //update logging if (m_logging) { //check for missing objects if (m_MeasurementLoggingFilterXML.IsNull() || m_MeasurementLoggingFilterCSV.IsNull() ) { return; } //log/measure m_MeasurementLoggingFilterXML->Update(); m_MeasurementLoggingFilterCSV->Update(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked() && m_ReferenceLoggingFilterXML.IsNotNull() && m_ReferenceLoggingFilterCSV.IsNotNull()) { m_ReferenceLoggingFilterXML->Update(); m_ReferenceLoggingFilterCSV->Update(); } m_loggedFrames++; LogAdditionalCSVFile(); //check if all frames are logged ... if yes finish the measurement if (m_loggedFrames > m_Controls->m_SamplesPerMeasurement->value()) { FinishMeasurement(); } //update logging label QString loggingLabel = "Collected Samples: " + QString::number(m_loggedFrames); m_Controls->m_CollectedSamples->setText(loggingLabel); } } void QmitkIGTTrackingSemiAutomaticMeasurementView::StartNextMeasurement() { if (this->m_NextFile >= static_cast(m_FilenameVector.size())) { MessageBox("Last Measurement reached!"); return; } m_loggedFrames = 0; m_logging = true; //check if directory exists, if not create one Poco::File myPath(std::string(m_Controls->m_OutputPath->text().toUtf8()).c_str()); if (!myPath.exists()) myPath.createDirectory(); QString LogFileName = m_Controls->m_OutputPath->text() + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".log"; mitk::LoggingBackend::Unregister(); mitk::LoggingBackend::SetLogFile(LogFileName.toStdString().c_str()); mitk::LoggingBackend::Register(); //initialize logging filters m_MeasurementLoggingFilterXML = mitk::NavigationDataRecorderDeprecated::New(); m_MeasurementLoggingFilterXML->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_MeasurementLoggingFilterCSV = mitk::NavigationDataRecorderDeprecated::New(); m_MeasurementLoggingFilterCSV->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_MeasurementLoggingFilterXML->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::xml); m_MeasurementLoggingFilterCSV->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); QString MeasurementFilenameXML = m_Controls->m_OutputPath->text() + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".xml"; QString MeasurementFilenameCSV = m_Controls->m_OutputPath->text() + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".csv"; m_MeasurementLoggingFilterXML->SetFileName(MeasurementFilenameXML.toStdString()); m_MeasurementLoggingFilterCSV->SetFileName(MeasurementFilenameCSV.toStdString()); m_MeasurementLoggingFilterXML->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); m_MeasurementLoggingFilterCSV->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceLoggingFilterXML = mitk::NavigationDataRecorderDeprecated::New(); m_ReferenceLoggingFilterXML->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_ReferenceLoggingFilterCSV = mitk::NavigationDataRecorderDeprecated::New(); m_ReferenceLoggingFilterCSV->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_ReferenceLoggingFilterXML->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::xml); m_ReferenceLoggingFilterCSV->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); QString ReferenceFilenameXML = m_Controls->m_OutputPath->text() + "Reference_" + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".xml"; QString ReferenceFilenameCSV = m_Controls->m_OutputPath->text() + "Reference_" + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".csv"; m_ReferenceLoggingFilterXML->SetFileName(ReferenceFilenameXML.toStdString()); m_ReferenceLoggingFilterCSV->SetFileName(ReferenceFilenameCSV.toStdString()); m_ReferenceLoggingFilterXML->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); m_ReferenceLoggingFilterCSV->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); } //start additional csv logging StartLoggingAdditionalCSVFile(m_FilenameVector.at(m_NextFile)); //connect filter for (unsigned int i = 0; i < m_MeasurementToolVisualizationFilter->GetNumberOfOutputs(); ++i) { m_MeasurementLoggingFilterXML->AddNavigationData(m_MeasurementToolVisualizationFilter->GetOutput(i)); m_MeasurementLoggingFilterCSV->AddNavigationData(m_MeasurementToolVisualizationFilter->GetOutput(i)); } if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) for (unsigned int i = 0; i < m_ReferenceTrackingDeviceSource->GetNumberOfOutputs(); ++i) { m_ReferenceLoggingFilterXML->AddNavigationData(m_ReferenceTrackingDeviceSource->GetOutput(i)); m_ReferenceLoggingFilterCSV->AddNavigationData(m_ReferenceTrackingDeviceSource->GetOutput(i)); } //start filter m_MeasurementLoggingFilterXML->StartRecording(); m_MeasurementLoggingFilterCSV->StartRecording(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceLoggingFilterXML->StartRecording(); m_ReferenceLoggingFilterCSV->StartRecording(); } //disable all buttons DisableAllButtons(); //update label next measurement std::stringstream label; if ((m_NextFile + 1) >= static_cast(m_FilenameVector.size())) label << "Next Measurement: "; else label << "Next Measurement: " << m_FilenameVector.at(m_NextFile + 1); m_Controls->m_NextMeasurement->setText(label.str().c_str()); //update label last measurement std::stringstream label2; label2 << "Last Measurement: " << m_FilenameVector.at(m_NextFile); m_Controls->m_LastMeasurement->setText(label2.str().c_str()); m_NextFile++; } void QmitkIGTTrackingSemiAutomaticMeasurementView::RepeatLastMeasurement() { m_NextFile--; StartNextMeasurement(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::DisableAllButtons() { m_Controls->m_LoadList->setEnabled(false); m_Controls->m_StartNextMeasurement->setEnabled(false); m_Controls->m_ReapeatLastMeasurement->setEnabled(false); m_Controls->m_SamplingRate->setEnabled(false); m_Controls->m_SamplesPerMeasurement->setEnabled(false); m_Controls->m_ReferenceThreshold->setEnabled(false); } void QmitkIGTTrackingSemiAutomaticMeasurementView::EnableAllButtons() { m_Controls->m_LoadList->setEnabled(true); m_Controls->m_StartNextMeasurement->setEnabled(true); m_Controls->m_ReapeatLastMeasurement->setEnabled(true); m_Controls->m_SamplingRate->setEnabled(true); m_Controls->m_SamplesPerMeasurement->setEnabled(true); m_Controls->m_ReferenceThreshold->setEnabled(true); } void QmitkIGTTrackingSemiAutomaticMeasurementView::FinishMeasurement() { m_logging = false; m_MeasurementLoggingFilterXML->StopRecording(); m_MeasurementLoggingFilterCSV->StopRecording(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceLoggingFilterXML->StopRecording(); m_ReferenceLoggingFilterCSV->StopRecording(); } StopLoggingAdditionalCSVFile(); int id = m_NextFile - 1; mitk::Point3D positionMean = m_EvaluationFilter->GetPositionMean(0); MITK_INFO << "Evaluated " << m_EvaluationFilter->GetNumberOfAnalysedNavigationData(0) << " samples."; double rms = m_EvaluationFilter->GetPositionErrorRMS(0); MITK_INFO << "RMS: " << rms; MITK_INFO << "Position Mean: " << positionMean; m_MeanPoints->SetPoint(id, positionMean); if (static_cast(m_RMSValues.size()) <= id) m_RMSValues.push_back(rms); else m_RMSValues[id] = rms; m_EvaluationFilter->ResetStatistic(); EnableAllButtons(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::StartLoggingAdditionalCSVFile(std::string filePostfix) { //write logfile header QString header = "Nr;MITK_Time;Valid_Reference;"; QString tool = QString("MeasureTool_") + QString(m_MeasurementTrackingDeviceSource->GetOutput(0)->GetName()); header = header + tool + "[x];" + tool + "[y];" + tool + "[z];" + tool + "[qx];" + tool + "[qy];" + tool + "[qz];" + tool + "[qr]\n"; //open logfile and write header m_logFileCSV.open(std::string(m_Controls->m_OutputPath->text().toUtf8()).append("/LogFileCombined").append(filePostfix.c_str()).append(".csv").c_str(), std::ios::out); m_logFileCSV << header.toStdString().c_str(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::LogAdditionalCSVFile() { mitk::Point3D pos = m_MeasurementTrackingDeviceSource->GetOutput(0)->GetPosition(); mitk::Quaternion rot = m_MeasurementTrackingDeviceSource->GetOutput(0)->GetOrientation(); std::string valid = ""; if (m_referenceValid) valid = "true"; else valid = "false"; std::stringstream timestamp; timestamp << m_MeasurementTrackingDeviceSource->GetOutput(0)->GetTimeStamp(); QString dataSet = QString::number(m_loggedFrames) + ";" + QString(timestamp.str().c_str()) + ";" + QString(valid.c_str()) + ";" + QString::number(pos[0]) + ";" + QString::number(pos[1]) + ";" + QString::number(pos[2]) + ";" + QString::number(rot.x()) + ";" + QString::number(rot.y()) + ";" + QString::number(rot.z()) + ";" + QString::number(rot.r()) + "\n"; m_logFileCSV << dataSet.toStdString(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::StopLoggingAdditionalCSVFile() { m_logFileCSV.close(); } bool QmitkIGTTrackingSemiAutomaticMeasurementView::eventFilter(QObject *, QEvent *ev) { if (ev->type() == QEvent::KeyPress) { QKeyEvent *k = (QKeyEvent *)ev; bool down = k->key() == 16777239; if (down && m_tracking && !m_logging) StartNextMeasurement(); } return false; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementViewControls.ui b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementViewControls.ui index b85fd511cb..2549f5fb45 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementViewControls.ui +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementViewControls.ui @@ -1,588 +1,591 @@ QmitkIGTTrackingSemiAutomaticMeasurementViewControls 0 0 419 931 0 0 QmitkTemplate 0 Tracking Initialization Measurement Tracking System Tool Storage: <none> Qt::Horizontal 40 20 Load Tool Storage Reference Trackingsystem Tool Storage: <none> Qt::Horizontal 40 20 Load Tool Storage Start Tracking Stop Tracking Qt::Vertical 20 40 Measurement Measurement List: Qt::Horizontal 40 20 Load List Output Path: C:/temp/ Last Measurement: <none> Next Measurement: <none> Collected Samples: <none> Qt::Horizontal 40 20 200 0 Start Next Measurement Qt::Horizontal 40 20 200 0 Repeat Last Measurement Qt::Horizontal 40 20 200 0 Create Results Qt::Vertical 20 281 Qt::Horizontal <!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-weight:600; text-decoration: underline;">Measurement Sensors:</span></p></body></html> Qt::Horizontal <!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-weight:600; text-decoration: underline;">Reference Sensors:</span></p></body></html> Set Reference Reference Postion: <none> Current Positions: <none> <!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:28pt; font-weight:600;">OK</span></p></body></html> Qt::AlignCenter Settings Sampling Rate (Times Per Second): Qt::Horizontal 40 20 999.000000000000000 15.000000000000000 Samples Per Measurement: Qt::Horizontal 40 20 1000 150 Threshold For Reference Tools: Qt::Horizontal 40 20 1.000000000000000 Use Reference Tracking System - true + false Tracking Volume Small Volume (3 X 4 Positions) + + true + Medium Volume (5 X 5 Positions) - true + false Standard Volume (10 X 9 Positions) Qt::Vertical 20 40 QmitkToolTrackingStatusWidget QWidget
QmitkToolTrackingStatusWidget.h
1
QmitkTrackingDeviceConfigurationWidget QWidget
QmitkTrackingDeviceConfigurationWidget.h
1
diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkHummelProtocolEvaluation.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkHummelProtocolEvaluation.cpp index d30c2104d8..da7e1f5177 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkHummelProtocolEvaluation.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkHummelProtocolEvaluation.cpp @@ -1,453 +1,521 @@ /*=================================================================== 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. ===================================================================*/ #define _USE_MATH_DEFINES #include "mitkHummelProtocolEvaluation.h" #include #include #include #include #include #include #include #include #include bool mitk::HummelProtocolEvaluation::Evaluate15cmDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector &Results) { if (m != mitk::HummelProtocolEvaluation::standard) { MITK_WARN << "15 cm distances are only evaluated for standard volumes, aborting!"; return false; } MITK_INFO << "########### 15 cm distance errors #############"; //convert measurements to matrix std::array ,9> matrix = ParseMatrixStandardVolume(p); //these are the variables for the results: std::vector distances; std::vector descriptions; //evaluation of rows int distanceCounter = 0; for (int row = 0; row < 9; row++) //rows for (int distance = 0; distance < 7; distance++) { distanceCounter++; mitk::Point3D point1 = p->GetPoint(row * 10 + distance); mitk::Point3D point2 = p->GetPoint(row * 10 + distance + 3); distances.push_back(point1.EuclideanDistanceTo(point2)); std::stringstream description; description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (distance + 1) << " to " << (row + 1) << "/" << (distance + 4); descriptions.push_back(description.str()); } //evaluation of columns for (int column = 0; column < 10; column++) for (int row = 0; row < 6; row++) { distanceCounter++; mitk::Point3D point1 = matrix[row][column]; mitk::Point3D point2 = matrix[row + 3][column]; distances.push_back(point1.EuclideanDistanceTo(point2)); std::stringstream description; description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (column + 1) << " to " << (row + 4) << "/" << (column + 1); descriptions.push_back(description.str()); } //compute all errors for (std::size_t i = 0; i < distances.size(); ++i) { HummelProtocolDistanceError currentError; currentError.distanceError = fabs(distances.at(i) - (double)150.0); currentError.description = descriptions.at(i); Results.push_back(currentError); MITK_INFO << "Error " << currentError.description << " : " << currentError.distanceError; } //compute statistics std::vector statistics = mitk::HummelProtocolEvaluation::ComputeStatistics(Results); for (auto currentError : statistics) { Results.push_back(currentError); MITK_INFO << currentError.description << " : " << currentError.distanceError; } return true; } bool mitk::HummelProtocolEvaluation::Evaluate30cmDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector &Results) { if (m != mitk::HummelProtocolEvaluation::standard) { MITK_WARN << "30 cm distances are only evaluated for standard volumes, aborting!"; return false; } MITK_INFO << "########### 30 cm distance errors #############"; //convert measurements to matrix std::array ,9> matrix = ParseMatrixStandardVolume(p); //these are the variables for the results: std::vector distances; std::vector descriptions; //evaluation of rows int distanceCounter = 0; for (int row = 0; row < 9; row++) //rows for (int distance = 0; distance < 4; distance++) { distanceCounter++; mitk::Point3D point1 = p->GetPoint(row * 10 + distance); mitk::Point3D point2 = p->GetPoint(row * 10 + distance + 6); distances.push_back(point1.EuclideanDistanceTo(point2)); std::stringstream description; description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (distance + 1) << " to " << (row + 1) << "/" << (distance + 7); descriptions.push_back(description.str()); } //evaluation of columns for (int column = 0; column < 10; column++) for (int row = 0; row < 3; row++) { distanceCounter++; mitk::Point3D point1 = matrix[row][column]; mitk::Point3D point2 = matrix[row + 6][column]; distances.push_back(point1.EuclideanDistanceTo(point2)); std::stringstream description; description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (column + 1) << " to " << (row + 7) << "/" << (column + 1); descriptions.push_back(description.str()); } //compute all errors for (std::size_t i = 0; i < distances.size(); ++i) { HummelProtocolDistanceError currentError; currentError.distanceError = fabs(distances.at(i) - (double)300.0); currentError.description = descriptions.at(i); Results.push_back(currentError); MITK_INFO << "Error " << currentError.description << " : " << currentError.distanceError; } //compute statistics std::vector statistics = mitk::HummelProtocolEvaluation::ComputeStatistics(Results); for (auto currentError : statistics) { Results.push_back(currentError); MITK_INFO << currentError.description << " : " << currentError.distanceError; } return true; } bool mitk::HummelProtocolEvaluation::EvaluateAccumulatedDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector &Results) { if (m != mitk::HummelProtocolEvaluation::standard) { MITK_WARN << "Accumulated distances are only evaluated for standard volumes, aborting!"; return false; } MITK_INFO << "########### accumulated distance errors #############"; int distanceCounter = 0; //evaluation of rows for (int row = 0; row < 9; row++) //rows for (int distance = 0; distance < 9; distance++) { distanceCounter++; mitk::Point3D point1 = p->GetPoint(row * 10); mitk::Point3D point2 = p->GetPoint(row * 10 + distance + 1); std::stringstream description; description << "Distance(" << distanceCounter << ") " << (row + 1) << "/1 to " << (row + 1) << "/" << (distance + 2); //compute error HummelProtocolDistanceError currentError; currentError.distanceError = fabs(point1.EuclideanDistanceTo(point2) - (double)(50.0*(distance+1))); currentError.description = description.str(); Results.push_back(currentError); MITK_INFO << "Error " << currentError.description << " : " << currentError.distanceError; } //compute statistics std::vector statistics = mitk::HummelProtocolEvaluation::ComputeStatistics(Results); for (auto currentError : statistics) { Results.push_back(currentError); MITK_INFO << currentError.description << " : " << currentError.distanceError; } return true; } bool mitk::HummelProtocolEvaluation::Evaluate5cmDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector &Results) { MITK_INFO << "########### 5 cm distance errors #############"; std::vector distances; std::vector descriptions; switch (m) { case small: if (p->GetSize() != 12) { MITK_WARN << "Wrong number of points: " << p->GetSize() << " (expected 12), aborting"; return false; } MITK_INFO << "Computing Hummel protocol distance errors for small measurement volumes (12 points)..."; //row 1 distances.push_back(p->GetPoint(0).EuclideanDistanceTo(p->GetPoint(1))); //0 descriptions.push_back("Distance 4/4 to 4/5"); distances.push_back(p->GetPoint(1).EuclideanDistanceTo(p->GetPoint(2))); //1 descriptions.push_back("Distance 4/5 to 4/6"); distances.push_back(p->GetPoint(2).EuclideanDistanceTo(p->GetPoint(3))); //2 descriptions.push_back("Distance 4/6 to 4/7"); //row 2 distances.push_back(p->GetPoint(4).EuclideanDistanceTo(p->GetPoint(5))); //3 descriptions.push_back("Distance 5/4 to 5/5"); distances.push_back(p->GetPoint(5).EuclideanDistanceTo(p->GetPoint(6))); //4 descriptions.push_back("Distance 5/5 to 5/6"); distances.push_back(p->GetPoint(6).EuclideanDistanceTo(p->GetPoint(7))); //5 descriptions.push_back("Distance 5/6 to 5/7"); //row 3 distances.push_back(p->GetPoint(8).EuclideanDistanceTo(p->GetPoint(9))); //6 descriptions.push_back("Distance 6/4 to 6/5"); distances.push_back(p->GetPoint(9).EuclideanDistanceTo(p->GetPoint(10))); //7 descriptions.push_back("Distance 6/5 to 6/6"); distances.push_back(p->GetPoint(10).EuclideanDistanceTo(p->GetPoint(11))); //8 descriptions.push_back("Distance 6/6 to 6/7"); //column 1 distances.push_back(p->GetPoint(0).EuclideanDistanceTo(p->GetPoint(4))); //9 descriptions.push_back("Distance 4/4 to 5/4"); distances.push_back(p->GetPoint(4).EuclideanDistanceTo(p->GetPoint(8))); //10 descriptions.push_back("Distance 5/4 to 6/4"); //column 2 distances.push_back(p->GetPoint(1).EuclideanDistanceTo(p->GetPoint(5))); //11 descriptions.push_back("Distance 4/5 to 5/5"); distances.push_back(p->GetPoint(5).EuclideanDistanceTo(p->GetPoint(9))); //12 descriptions.push_back("Distance 5/5 to 6/5"); //column 3 distances.push_back(p->GetPoint(2).EuclideanDistanceTo(p->GetPoint(6))); //13 descriptions.push_back("Distance 4/6 to 5/6"); distances.push_back(p->GetPoint(6).EuclideanDistanceTo(p->GetPoint(10))); //14 descriptions.push_back("Distance 5/6 to 6/6"); //column 4 distances.push_back(p->GetPoint(3).EuclideanDistanceTo(p->GetPoint(7))); //15 descriptions.push_back("Distance 4/7 to 5/7"); distances.push_back(p->GetPoint(7).EuclideanDistanceTo(p->GetPoint(11))); //16 descriptions.push_back("Distance 5/7 to 6/7"); break; case medium: { if (p->GetSize() != 25) { MITK_WARN << "Wrong number of points (expected 25), aborting"; return false; } MITK_INFO << "Computing Hummel protocol distance errors for medium measurement volumes (25 points)..."; int distanceCounter = 0; //convert measurements to matrix std::array, 5> matrix = ParseMatrixMediumVolume(p); //evaluation of rows for (int row = 0; row < 5; row++) //rows for (int distance = 0; distance < 4; distance++) { distanceCounter++; mitk::Point3D point1 = p->GetPoint(row * 5 + distance); mitk::Point3D point2 = p->GetPoint(row * 5 + distance + 1); distances.push_back(point1.EuclideanDistanceTo(point2)); std::stringstream description; description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (distance + 1) << " to " << (row + 1) << "/" << (distance + 2); descriptions.push_back(description.str()); } //evaluation of columns for (int column = 0; column < 5; column++) for (int row = 0; row < 4; row++) { distanceCounter++; mitk::Point3D point1 = matrix[row][column]; mitk::Point3D point2 = matrix[row + 1][column]; MITK_INFO << "Point 1:" << point1 << "/Point 2:" << point2 << "/Distance:" << point1.EuclideanDistanceTo(point2); distances.push_back(point1.EuclideanDistanceTo(point2)); std::stringstream description; description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (column + 1) << " to " << (row + 2) << "/" << (column + 1); descriptions.push_back(description.str()); } } break; +case medium5x6: +{ + if (p->GetSize() != 30) { + MITK_WARN << "Wrong number of points (expected 30), aborting"; + return false; + } + MITK_INFO << "Computing Hummel protocol distance errors for 5x6 medium measurement volumes (30 points)..."; + + int distanceCounter = 0; + + //convert measurements to matrix + std::array, 5> matrix = ParseMatrixMedium5x6Volume(p); + + /* Print out matrix for debugging + for (int row = 0; row < 5; row++) + { + for (int column = 0; column < 6; column++) + { + std::cout << matrix.at(row).at(column); + } + std::cout << "\n"; + } + */ + + //evaluation of rows + for (int row = 0; row < 5; row++) //rows + for (int distance = 0; distance < 5; distance++) + { + distanceCounter++; + mitk::Point3D point1 = p->GetPoint(row * 6 + distance); + mitk::Point3D point2 = p->GetPoint(row * 6 + distance + 1); + distances.push_back(point1.EuclideanDistanceTo(point2)); + std::stringstream description; + description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (distance + 1) << " to " << (row + 1) << "/" << (distance + 2); + descriptions.push_back(description.str()); + } + + //evaluation of columns + for (int column = 0; column < 6; column++) + for (int row = 0; row < 4; row++) + { + distanceCounter++; + mitk::Point3D point1 = matrix[row][column]; + mitk::Point3D point2 = matrix[row + 1][column]; + distances.push_back(point1.EuclideanDistanceTo(point2)); + std::stringstream description; + description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (column + 1) << " to " << (row + 2) << "/" << (column + 1); + descriptions.push_back(description.str()); + } +} +break; + case standard: { if (p->GetSize() != 90) { MITK_WARN << "Wrong number of points (expected 90), aborting"; return false; } MITK_INFO << "Computing Hummel protocol distance errors for standard measurement volumes (90 points)..."; int distanceCounter = 0; //convert measurements to matrix std::array, 9> matrix = ParseMatrixStandardVolume(p); //evaluation of rows for (int row = 0; row < 9; row++) //rows for (int distance = 0; distance < 9; distance++) { distanceCounter++; mitk::Point3D point1 = p->GetPoint(row * 10 + distance); mitk::Point3D point2 = p->GetPoint(row * 10 + distance + 1); distances.push_back(point1.EuclideanDistanceTo(point2)); std::stringstream description; description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (distance + 1) << " to " << (row + 1) << "/" << (distance + 2); descriptions.push_back(description.str()); } //evaluation of columns for (int column = 0; column < 10; column++) for (int row = 0; row < 8; row++) { distanceCounter++; mitk::Point3D point1 = matrix[row][column]; mitk::Point3D point2 = matrix[row + 1][column]; distances.push_back(point1.EuclideanDistanceTo(point2)); std::stringstream description; description << "Distance(" << distanceCounter << ") " << (row + 1) << "/" << (column + 1) << " to " << (row + 2) << "/" << (column + 1); descriptions.push_back(description.str()); } } break; } //compute all errors for (std::size_t i = 0; i < distances.size(); ++i) { HummelProtocolDistanceError currentError; currentError.distanceError = fabs(distances.at(i) - (double)50.0); currentError.description = descriptions.at(i); Results.push_back(currentError); MITK_INFO << "Error " << currentError.description << " : " << currentError.distanceError; } //compute statistics std::vector statistics = mitk::HummelProtocolEvaluation::ComputeStatistics(Results); for (auto currentError : statistics) { Results.push_back(currentError); MITK_INFO << currentError.description << " : " << currentError.distanceError; } return true; } std::array, 9> mitk::HummelProtocolEvaluation::ParseMatrixStandardVolume(mitk::PointSet::Pointer p) { std::array ,9> returnValue; if (p->GetSize() != 90) { MITK_WARN << "PointSet does not have the right size. Expected 90 got " << p->GetSize() << " ... aborting!"; return returnValue; } for (int row = 0; row < 9; row++) for (int column = 0; column < 10; column++) returnValue[row][column] = p->GetPoint(row * 10 + column); return returnValue; } +std::array, 5> mitk::HummelProtocolEvaluation::ParseMatrixMedium5x6Volume(mitk::PointSet::Pointer p) +{ + + std::array, 5> returnValue; + + if (p->GetSize() != 30) + { + MITK_WARN << "PointSet does not have the right size. Expected 30 got " << p->GetSize() << " ... aborting!"; + return returnValue; + } + for (int row = 0; row < 5; row++) + for (int column = 0; column < 6; column++) + returnValue[row][column] = p->GetPoint(row * 6 + column); + return returnValue; +} + std::array, 5> mitk::HummelProtocolEvaluation::ParseMatrixMediumVolume(mitk::PointSet::Pointer p) { std::array, 5> returnValue; if (p->GetSize() != 25) { MITK_WARN << "PointSet does not have the right size. Expected 25 got " << p->GetSize() << " ... aborting!"; return returnValue; } for (int row = 0; row < 5; row++) for (int column = 0; column < 5; column++) { returnValue[row][column] = p->GetPoint(row * 5 + column); //MITK_INFO << "m " << row << "/" << column << ":" << p->GetPoint(row * 5 + column); } return returnValue; } std::vector mitk::HummelProtocolEvaluation::ComputeStatistics(std::vector values) { std::vector returnValue; //convert input values to boost / using boost accumulators for statistics boost::accumulators::accumulator_set > > acc; for (mitk::HummelProtocolEvaluation::HummelProtocolDistanceError each : values) { acc(each.distanceError); } returnValue.push_back({ static_cast(values.size()), "N" }); returnValue.push_back({ boost::accumulators::mean(acc), "Mean" }); //double quantile25th = boost::accumulators::quantile(acc, boost::accumulators::quantile_probability = 0.25); //returnValue.push_back({ boost::accumulators::median(acc), "Median" }); //returnValue.push_back({ boost::accumulators::variance(acc), "Variance" }); returnValue.push_back({ boost::accumulators::min(acc), "Min" }); returnValue.push_back({ boost::accumulators::max(acc), "Max" }); //don't get the boost stuff working correctly, so computing the quantiles, median and standard deviation by myself: std::vector quantile; for (mitk::HummelProtocolEvaluation::HummelProtocolDistanceError each : values) {quantile.push_back(each.distanceError);} auto const Q1 = quantile.size() / 4; auto const Q2 = quantile.size() / 2; auto const Q3 = Q1 + Q2; std::sort(quantile.begin(),quantile.end()); returnValue.push_back({ quantile[Q1], "Quartile 1" }); returnValue.push_back({ quantile[Q2], "Median" }); returnValue.push_back({ quantile[Q3], "Quartile 3" }); double mean = boost::accumulators::mean(acc); double errorSum = 0; for (mitk::HummelProtocolEvaluation::HummelProtocolDistanceError each : values) { double error = pow((each.distanceError - mean),2); errorSum += error; } double variance = errorSum / values.size(); double sampleVariance = errorSum / (values.size()-1); double standardDev = sqrt(variance); double sampleStandardDev = sqrt(sampleVariance); returnValue.push_back({ variance, "Variance" }); returnValue.push_back({ sampleVariance, "Sample Variance" }); returnValue.push_back({ standardDev, "Standard Deviation" }); returnValue.push_back({ sampleStandardDev, "Sample Standard Deviation" }); return returnValue; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkHummelProtocolEvaluation.h b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkHummelProtocolEvaluation.h index d08a7d1c8c..3ceff58312 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkHummelProtocolEvaluation.h +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkHummelProtocolEvaluation.h @@ -1,96 +1,98 @@ /*=================================================================== 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 MITKHummelProtocolEvaluation_H_HEADER_INCLUDED_ #define MITKHummelProtocolEvaluation_H_HEADER_INCLUDED_ #include #include namespace mitk { /**Documentation * \brief Static methods for evaluations according to the assessment protocol * for EM trackers published by Hummel et al. 2005 [1]. * * [1] Hummel, J. et al. - Design and application of an assessment protocol for electromagnetic tracking systems. Med Phys 32(7), July 2005 * * \ingroup IGT */ class HummelProtocolEvaluation { public: /** Distance error with description. */ struct HummelProtocolDistanceError {double distanceError; std::string description;}; /** Tracking volumes for evaluation. * standard: The standard volume of 9 x 10 measurment points as described in [1] * small: A small volume in the center 3 x 4 measurement points, for smaller field generators [2] * [2] Maier-Hein, L. et al. - Standardized assessment of new electromagnetic field generators in an interventional radiology setting. Med Phys 39(6), June 2012 */ - enum HummelProtocolMeasurementVolume { small, medium, standard }; + enum HummelProtocolMeasurementVolume { small, medium, medium5x6, standard }; /** Evaluates the 5 cm distances as defined by the Hummel protocol [1,2]. * @return Returns true if evaluation was successfull, false if not. * @param[out] Results Please give an empty vector. The results will be added to this vector. */ static bool Evaluate5cmDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector &Results); /** Evaluates the 15 cm distances as defined by the Hummel protocol [1,2]. * @return Returns true if evaluation was successfull, false if not. * @param[out] Results Please give an empty vector. The results will be added to this vector. */ static bool Evaluate15cmDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector &Results); /** Evaluates the 30 cm distances as defined by the Hummel protocol [1,2]. * @return Returns true if evaluation was successfull, false if not. * @param[out] Results Please give an empty vector. The results will be added to this vector. */ static bool Evaluate30cmDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector &Results); /** Evaluates the accumulated distances as defined by the Hummel protocol [1,2]. * @return Returns true if evaluation was successfull, false if not. * @param[out] Results Please give an empty vector. The results will be added to this vector. */ static bool EvaluateAccumulatedDistances(mitk::PointSet::Pointer p, HummelProtocolMeasurementVolume m, std::vector &Results); /** Computes statistics (as mean, standard deviation, quantiles, min, max, etc.) on the given values. * The results are stored inside the return value. */ static std::vector ComputeStatistics(std::vector values); protected: /** Converts a pointset holding all measurement points of the hummel protocol in line-by-line order * to an array representing the hummel board. */ static std::array ,9> ParseMatrixStandardVolume(mitk::PointSet::Pointer p); //It would be really wonderfull if we could replace std::array ,9> by mitk::Matrix< mitk::Point3D, 9, 10 > but //unfortunatly this version does not compile under Linux. To be precise under Linux only matrices like this: mitk::Matriy compile //even the usage of a double pointer (eg mitk::Matrix) does not compile. We always got an error message saying: //vnl_c_vector.h:42:49: error: invalid use of incomplete type ‘class vnl_numeric_traits >’ //Under Windows this error does not appear there everything compiles fine. static std::array, 5> ParseMatrixMediumVolume(mitk::PointSet::Pointer p); + static std::array, 5> ParseMatrixMedium5x6Volume(mitk::PointSet::Pointer p); + }; } // namespace mitk #endif /* MITKHummelProtocolEvaluation_H_HEADER_INCLUDED_ */ diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.cpp index 563a0d7966..3fb0acbb95 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.cpp @@ -1,314 +1,323 @@ /*=================================================================== 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 "mitkNavigationDataCSVSequentialPlayer.h" #include #include #include #include mitk::NavigationDataCSVSequentialPlayer::NavigationDataCSVSequentialPlayer() - : mitk::NavigationDataPlayerBase() + : mitk::NavigationDataPlayerBase(), + m_numberOfReadErrorsInARow(0), + m_NavigationDatas(std::vector()), + m_CurrentPos(0), + m_Filetype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV) { - m_NavigationDatas = std::vector(); - m_CurrentPos = 0; - m_Filetype = mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV; - } mitk::NavigationDataCSVSequentialPlayer::~NavigationDataCSVSequentialPlayer() { } bool mitk::NavigationDataCSVSequentialPlayer::IsAtEnd() { return m_CurrentPos >= static_cast(m_NavigationDatas.size()); } void mitk::NavigationDataCSVSequentialPlayer:: SetFileName(const std::string& fileName) { this->SetNumberOfIndexedOutputs(1); FillOutputEmpty(0); MITK_INFO << "Reading file: " << fileName; m_NavigationDatas = GetNavigationDatasFromFile(fileName); this->Modified(); } void mitk::NavigationDataCSVSequentialPlayer::FillOutputEmpty(int number) { this->SetNthOutput(number, GetEmptyNavigationData()); } mitk::NavigationData::Pointer mitk::NavigationDataCSVSequentialPlayer::GetEmptyNavigationData() { mitk::NavigationData::Pointer emptyNd = mitk::NavigationData::New(); mitk::NavigationData::PositionType position; mitk::NavigationData::OrientationType orientation(0.0, 0.0, 0.0, 0.0); position.Fill(0.0); emptyNd->SetPosition(position); emptyNd->SetOrientation(orientation); emptyNd->SetDataValid(false); return emptyNd; } int mitk::NavigationDataCSVSequentialPlayer::GetNumberOfSnapshots() { return m_NavigationDatas.size(); } void mitk::NavigationDataCSVSequentialPlayer::GenerateData() { for (unsigned int index = 0; index < this->GetNumberOfOutputs(); index++) { mitk::NavigationData* output = this->GetOutput(index); - if (m_CurrentPos > static_cast(m_NavigationDatas.size())) + if (m_CurrentPos >= static_cast(m_NavigationDatas.size())) { FillOutputEmpty(index); return; } output->Graft(this->m_NavigationDatas.at(m_CurrentPos)); m_CurrentPos++; } } void mitk::NavigationDataCSVSequentialPlayer::UpdateOutputInformation() { this->Modified(); // make sure that we need to be updated Superclass::UpdateOutputInformation(); } std::vector mitk::NavigationDataCSVSequentialPlayer::GetNavigationDatasFromFile(std::string filename) { std::vector returnValue = std::vector(); std::vector fileContentLineByLine = GetFileContentLineByLine(filename); std::size_t i = m_HeaderRow ? 1 //file has a header row, so it has to be skipped when reading the NavigationDatas : 0; //file has no header row, so no need to skip the first row for ( ; i < fileContentLineByLine.size(); ++i) { returnValue.push_back(GetNavigationDataOutOfOneLine(fileContentLineByLine.at(i))); + if (m_numberOfReadErrorsInARow>5) + { + MITK_ERROR << "More than 5 read errors in a row, aborting! Is the csv file reader configured correctly?"; + m_numberOfReadErrorsInARow = 0; + return returnValue; + } } return returnValue; } std::vector mitk::NavigationDataCSVSequentialPlayer::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 int count = 0; while (!file.eof()) { std::string buffer; std::getline(file, buffer); // read out file line by line - readData.push_back(buffer); + if (!buffer.empty()) + { + readData.push_back(buffer); + //MITK_INFO << "Line: " << buffer; + } ++count; if (count == m_SampleCount) count = 0; } } file.close(); //switch back to old locale setlocale(LC_ALL, oldLocale); return readData; } mitk::NavigationData::Pointer mitk::NavigationDataCSVSequentialPlayer::GetNavigationDataOutOfOneLine(std::string line) { mitk::NavigationData::Pointer returnValue = mitk::NavigationData::New(); QString myLine = QString(line.c_str()); QStringList myLineList = myLine.split(m_SeparatorSign); mitk::Point3D position; mitk::Quaternion orientation; bool valid = false; //this is for custom csv files. You have adapt the column numbers to correctly //interpret your csv file. if (m_Filetype == mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV) { if (myLineList.size() < m_MinNumberOfColumns) { - MITK_ERROR << "Error: cannot read line: only found " << myLineList.size() << " fields. Last field: " << myLineList.at(myLineList.size() - 1).toStdString(); + MITK_WARN << "Cannot read line: only found " << myLineList.size() << " fields. Last field: " << myLineList.at(myLineList.size() - 1).toStdString(); returnValue = GetEmptyNavigationData(); + m_numberOfReadErrorsInARow++; return returnValue; } - valid = true; //if no valid flag is given: simply set to true + m_numberOfReadErrorsInARow = 0; + valid = true; //if no valid flag is given: simply set to true - //############# Variant for the Aurora measurements ############### - //############# (CUSTOM .csv files from MITK) ############### - - position[0] = myLineList.at(3).toDouble(); - position[1] = myLineList.at(4).toDouble(); - position[2] = myLineList.at(5).toDouble(); + position[0] = myLineList.at(m_XPos).toDouble(); + position[1] = myLineList.at(m_YPos).toDouble(); + position[2] = myLineList.at(m_ZPos).toDouble(); - orientation[0] = myLineList.at(6).toDouble(); //qx - orientation[1] = myLineList.at(7).toDouble(); //qy - orientation[2] = myLineList.at(8).toDouble(); //qz - orientation[3] = myLineList.at(9).toDouble(); //qr + orientation[0] = myLineList.at(m_Qx).toDouble(); // qx + orientation[1] = myLineList.at(m_Qy).toDouble(); // qy + orientation[2] = myLineList.at(m_Qz).toDouble(); // qz + orientation[3] = myLineList.at(m_Qr).toDouble(); // qr if(!m_RightHanded) //MITK uses a right handed coordinate system, so the position needs to be converted { position[0] = position[0]*(-1); } if (m_UseQuats) //Use Quaternions to construct the orientation of the NavigationData { orientation[0] = myLineList.at(m_Qx).toDouble(); //qx orientation[1] = myLineList.at(m_Qy).toDouble(); //qy orientation[2] = myLineList.at(m_Qz).toDouble(); //qz orientation[3] = myLineList.at(m_Qr).toDouble(); //qr } else //Use the Euler Angles to construct the orientation of the NavigationData { double azimuthAngle; double elevationAngle; double rollAngle; if(m_Azimuth < 0) //azimuth is not defined so set him to zero { azimuthAngle = 0; } else { azimuthAngle = myLineList.at(m_Azimuth).toDouble(); } if(m_Elevation < 0)// elevation is not defined so set him to zero { elevationAngle = 0; } else { elevationAngle = myLineList.at(m_Elevation).toDouble(); } if(m_Roll < 0) //roll is not defined so set him to zero { rollAngle = 0; } else { rollAngle = myLineList.at(m_Roll).toDouble(); } if (!m_EulersInRadiants) //the Euler Angles are in Degrees but MITK uses radiants so they need to be converted { azimuthAngle = azimuthAngle / 180 * itk::Math::pi; elevationAngle = elevationAngle / 180 * itk::Math::pi; rollAngle = rollAngle / 180 * itk::Math::pi; } vnl_quaternion eulerQuat(rollAngle, elevationAngle, azimuthAngle); orientation = eulerQuat; } if(!m_RightHanded) //MITK uses a right handed coordinate system, so the orientation needs to be converted { //code block for conversion from left-handed to right-handed mitk::Quaternion linksZuRechtsdrehend; double rotationAngle = -itk::Math::pi; double rotationAxis[3]; rotationAxis[0] = 0; rotationAxis[1] = 0; rotationAxis[2] = 1; linksZuRechtsdrehend[3] = cos(rotationAngle / 2); linksZuRechtsdrehend[0] = rotationAxis[0] * sin(rotationAngle / 2); linksZuRechtsdrehend[1] = rotationAxis[1] * sin(rotationAngle / 2); linksZuRechtsdrehend[2] = rotationAxis[2] * sin(rotationAngle / 2); orientation = orientation * linksZuRechtsdrehend; } } //this is for MITK csv files that have been recorded with the MITK //navigation data recorder. You can also use the navigation data player //class from the MITK-IGT module instead. else if (m_Filetype == mitk::NavigationDataCSVSequentialPlayer::NavigationDataCSV) { if (myLineList.size() < 8) { MITK_ERROR << "Error: cannot read line: only found " << myLineList.size() << " fields. Last field: " << myLineList.at(myLineList.size() - 1).toStdString(); returnValue = GetEmptyNavigationData(); return returnValue; } if (myLineList.at(3).toStdString() == "1") valid = true; position[0] = myLineList.at(2).toDouble(); position[1] = myLineList.at(3).toDouble(); position[2] = myLineList.at(4).toDouble(); orientation[0] = myLineList.at(5).toDouble(); //qx orientation[1] = myLineList.at(6).toDouble(); //qy orientation[2] = myLineList.at(7).toDouble(); //qz orientation[3] = myLineList.at(8).toDouble(); //qr } returnValue->SetDataValid(valid); returnValue->SetPosition(position); returnValue->SetOrientation(orientation); return returnValue; } void mitk::NavigationDataCSVSequentialPlayer::SetOptions(bool rightHanded, char separatorSign, int sampleCount, bool headerRow, int xPos, int yPos, int zPos, bool useQuats, int qx, int qy, int qz, int qr, int azimuth, int elevation, int roll, bool eulerInRadiants, int minNumberOfColumns) { m_RightHanded = rightHanded; m_SeparatorSign = separatorSign; m_SampleCount = sampleCount; m_HeaderRow = headerRow; m_XPos = xPos; m_YPos = yPos; m_ZPos = zPos; m_UseQuats = useQuats; m_Qx = qx; m_Qy = qy; m_Qz = qz; m_Qr = qr; m_Azimuth = azimuth; m_Elevation = elevation; m_Roll = roll; m_EulersInRadiants = eulerInRadiants; m_MinNumberOfColumns = minNumberOfColumns; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.h b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.h index 6976f05997..6cc89a61ad 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.h +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.h @@ -1,154 +1,155 @@ /*=================================================================== 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 MITKNavigationDataCSVSequentialPlayer_H_HEADER_INCLUDED_ #define MITKNavigationDataCSVSequentialPlayer_H_HEADER_INCLUDED_ #include #include "tinyxml.h" namespace mitk { /**Documentation * \brief This class is a NavigationDataPlayer which can play CSV formatted * files in sequential order, which means it doesn't care about timestamps and just * outputs the navigationdatas in their sequential order. * * It is thought to interpret custom csv files. To do so please adapt the column * numbers of position and orientation in the internal method GetNavigationDataOutOfOneLine(). * * So far only one (the first) tool is read in as required for the hummel protocol measurements. * * This class can also interpret MITK style csv files (set filetype to NavigationDataCSV), but * you can also use the MITK navigation data player class inside the MITK-IGT module which * is newer and better maintained. * * \ingroup IGT */ class NavigationDataCSVSequentialPlayer : public NavigationDataPlayerBase { public: mitkClassMacro(NavigationDataCSVSequentialPlayer, NavigationDataPlayerBase); itkNewMacro(Self); /** * \brief sets the file name and path (if XMLString is set, this is neglected) */ void SetFileName(const std::string& _FileName); /** * @brief SetOptions sets the options for reading out the data out of the correct postions of the file. They need to be set before using the player * @param rightHanded true if the used coordinate System is right handed, false if it is left handed * @param seperatorSign symbol that is used to separate the values in the .csv file * @param sampleCount every n-th sample in the file that should be used * @param headerRow true if the .csv file has a header row otherwise false * @param xPos number of the colum in the .csv file for the x-coordinates of the position * @param yPos number of the colum in the .csv file for the y-coordinates of the position * @param zPos number of the colum in the .csv file for the z-coordinates of the position * @param useQuats true if Quaternions are used to construct the orientation, false if Euler Angles are used * @param qx number of the column in the .csv file for the x component of the quaternion * @param qy number of the column in the .csv file for the y component of the quaternion * @param qz number of the column in the .csv file for the z component of the quaternion * @param qr number of the column in the .csv file for the r component of the quaternion * @param azimuth number of the colum in the .csv file for Azimuth (Euler Angles). Set < 0 if angle is not defined * @param elevatino number of the colum in the .csv file for Elevation (Euler Angles) Set < 0 if angle is not defined * @param roll number of the colum in the .csv file for Roll (Euler Angles) Set < 0 if angle is not defined * @param eulerInRadiants true if the Euler Angles in the .csv file are in radiants, false if they are in degrees * @param minNumberOfColumns */ void SetOptions(bool rightHanded, char seperatorSign, int sampleCount, bool headerRow, int xPos, int yPos, int zPos, bool useQuats, int qx, int qy, int qz, int qr, int azimuth, int elevatino, int roll, bool eulerInRadiants, int minNumberOfColums); /** * \brief returns the file name and path */ itkGetStringMacro(FileName); enum Filetype { NavigationDataCSV, //for csv files from the MITK navigation data player ManualLoggingCSV //for custum csv files }; /** * \brief Sets the file type. ManualLoggingCSV is default and is thought for your * custom csv files. You can also set it to NavigationDataCSV, then this * player interprets MITK style csv files. */ itkSetMacro(Filetype, Filetype); /** * \return Returns true if the player reached the end of the file. */ bool IsAtEnd(); /** * \brief Used for pipeline update just to tell the pipeline * that we always have to update */ virtual void UpdateOutputInformation(); int GetNumberOfSnapshots(); protected: NavigationDataCSVSequentialPlayer(); virtual ~NavigationDataCSVSequentialPlayer(); /// /// do the work here /// virtual void GenerateData(); std::string m_FileName; int m_CurrentPos; Filetype m_Filetype; //member for the navigation datas which were read (only one output is supported at the moment) std::vector m_NavigationDatas; std::vector GetNavigationDatasFromFile(std::string filename); std::vector GetFileContentLineByLine(std::string filename); mitk::NavigationData::Pointer GetNavigationDataOutOfOneLine(std::string line); + short m_numberOfReadErrorsInARow; //after a certain number of read errors, the software will abort void FillOutputEmpty(int number); mitk::NavigationData::Pointer GetEmptyNavigationData(); bool m_RightHanded; //true if the used coordinate System is right handed, false if it is left handed char m_SeparatorSign; //symbol that is used to separate the values in the .csv file int m_SampleCount; //every n-th sample in the file that should be used bool m_HeaderRow; //true if the .csv file has a header row otherwise false int m_XPos; //number of the colum in the .csv file for the x-coordinates of the position int m_YPos; //number of the colum in the .csv file for the y-coordinates of the position int m_ZPos; //number of the colum in the .csv file for the z-coordinates of the position bool m_UseQuats; //true if Quaternions are used to construct the orientation, false if Euler Angles are used int m_Qx; //number of the column in the .csv file for the x component of the quaternion int m_Qy; //number of the column in the .csv file for the y component of the quaternion int m_Qz; //number of the column in the .csv file for the z component of the quaternion int m_Qr; //number of the column in the .csv file for the r component of the quaternion int m_Azimuth; //number of the colum in the .csv file for Azimuth (Euler Angles) int m_Elevation; //number of the colum in the .csv file for Elevation (Euler Angles) int m_Roll; //number of the colum in the .csv file for Roll (Euler Angles) bool m_EulersInRadiants; // true if the Euler Angles in the .csv file are in radiants, false if they are in degrees int m_MinNumberOfColumns; //minimal number of columns the file has to have (e.g. if you read data from column 8 the file has to have at least 8 columns) }; } // namespace mitk #endif /* MITKNavigationDataCSVSequentialPlayer_H_HEADER_INCLUDED_ */ diff --git a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp index 65a4152199..20d1d0b6b6 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp @@ -1,830 +1,833 @@ /*=================================================================== 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 "QmitkUSNavigationMarkerPlacement.h" #include "ui_QmitkUSNavigationMarkerPlacement.h" #include "NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h" #include "NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.h" #include "NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.h" #include "SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h" #include "mitkAbstractUltrasoundTrackerDevice.h" #include "mitkIRenderingManager.h" #include "mitkNodeDisplacementFilter.h" #include "mitkTrackedUltrasound.h" #include #include "IO/mitkUSNavigationStepTimer.h" #include #include #include #include #include #include #include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "QmitkStdMultiWidgetEditor.h" #include "mitkCameraController.h" #include "mitkLayoutAnnotationRenderer.h" #include // scene serialization #include #include #include #include #include const std::string QmitkUSNavigationMarkerPlacement::VIEW_ID = "org.mitk.views.usmarkerplacement"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR = "Tumour"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE = "Target Surface"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_ZONES = "Zones"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS = "Targets"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS = "Target Paths"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS = "Reached Targets"; QmitkUSNavigationMarkerPlacement::QmitkUSNavigationMarkerPlacement() : m_Parent(nullptr), m_UpdateTimer(new QTimer(this)), m_ImageAndNavigationDataLoggingTimer(new QTimer(this)), m_StdMultiWidget(nullptr), m_CombinedModality(nullptr), m_ReinitAlreadyDone(false), m_IsExperimentRunning(false), m_CurrentApplicationName(), m_NavigationStepTimer(mitk::USNavigationStepTimer::New()), m_IconRunning(QPixmap(":/USNavigation/record.png")), m_IconNotRunning(QPixmap(":/USNavigation/record-gray.png")), m_ResultsDirectory(), m_ExperimentName(), m_ExperimentResultsSubDirectory(), m_NavigationStepNames(), m_LoggingBackend(), m_USImageLoggingFilter(mitk::USImageLoggingFilter::New()), m_NavigationDataRecorder(mitk::NavigationDataRecorder::New()), m_TargetNodeDisplacementFilter(nullptr), m_AblationZonesDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_ToolVisualizationFilter(nullptr), m_AblationZonesVector(), m_NeedleIndex(0), m_MarkerIndex(1), m_SceneNumber(1), m_WarnOverlay(mitk::TextAnnotation2D::New()), m_NavigationDataSource(nullptr), m_CurrentStorage(nullptr), m_ImageStreamNode(nullptr), ui(new Ui::QmitkUSNavigationMarkerPlacement) { connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(OnTimeout())); connect( m_ImageAndNavigationDataLoggingTimer, SIGNAL(timeout()), this, SLOT(OnImageAndNavigationDataLoggingTimeout())); // scale running (and not running) icon the specific height m_IconRunning = m_IconRunning.scaledToHeight(20, Qt::SmoothTransformation); m_IconNotRunning = m_IconNotRunning.scaledToHeight(20, Qt::SmoothTransformation); } QmitkUSNavigationMarkerPlacement::~QmitkUSNavigationMarkerPlacement() { this->GetDataStorage()->Remove(m_InstrumentNode); delete ui; } void QmitkUSNavigationMarkerPlacement::OnChangeAblationZone(int id, int newSize) { if ((static_cast(m_AblationZonesVector.size()) < id) || (id < 0)) { return; } MITK_INFO << "Ablation Zone " << id << " changed, new size: " << newSize; // create a vtk sphere with given radius vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(newSize / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); mitk::Surface::Pointer zoneSurface = dynamic_cast(m_AblationZonesVector.at(id)->GetData()); zoneSurface->SetVtkPolyData(vtkSphere->GetOutput()); } void QmitkUSNavigationMarkerPlacement::OnAddAblationZone(int size) { m_AblationZonesDisplacementFilter->SetInitialReferencePose( m_CombinedModality->GetNavigationDataSource()->GetOutput(m_MarkerIndex)); mitk::DataNode::Pointer NewAblationZone = mitk::DataNode::New(); mitk::Point3D origin = m_CombinedModality->GetNavigationDataSource()->GetOutput(m_NeedleIndex)->GetPosition(); MITK_INFO("USNavigationLogging") << "Ablation Zone Added, initial size: " << size << ", origin: " << origin; mitk::Surface::Pointer zone = mitk::Surface::New(); // create a vtk sphere with given radius vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(size / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); zone->SetVtkPolyData(vtkSphere->GetOutput()); // set vtk sphere and origin to data node (origin must be set // again, because of the new sphere set as data) NewAblationZone->SetData(zone); NewAblationZone->GetData()->GetGeometry()->SetOrigin(origin); mitk::Color SphereColor = mitk::Color(); // default color SphereColor[0] = 102; SphereColor[1] = 0; SphereColor[2] = 204; NewAblationZone->SetColor(SphereColor); NewAblationZone->SetOpacity(0.3); // set name of zone std::stringstream name; name << "Ablation Zone" << m_AblationZonesVector.size(); NewAblationZone->SetName(name.str()); // add zone to filter m_AblationZonesDisplacementFilter->AddNode(NewAblationZone); m_AblationZonesVector.push_back(NewAblationZone); this->GetDataStorage()->Add(NewAblationZone); } void QmitkUSNavigationMarkerPlacement::CreateQtPartControl(QWidget *parent) { m_Parent = parent; ui->setupUi(parent); connect(ui->startExperimentButton, SIGNAL(clicked()), this, SLOT(OnStartExperiment())); connect(ui->finishExperimentButton, SIGNAL(clicked()), this, SLOT(OnFinishExperiment())); connect(ui->m_enableNavigationLayout, SIGNAL(clicked()), this, SLOT(OnChangeLayoutClicked())); connect(ui->m_RenderWindowSelection, SIGNAL(valueChanged(int)), this, SLOT(OnRenderWindowSelection())); connect(ui->m_RefreshView, SIGNAL(clicked()), this, SLOT(OnRefreshView())); m_BaseNode = this->GetDataStorage()->GetNamedNode(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (m_BaseNode.IsNull()) { m_BaseNode = mitk::DataNode::New(); m_BaseNode->SetName(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); this->GetDataStorage()->Add(m_BaseNode); } connect(ui->m_CtToUsRegistrationWidget, SIGNAL(GetCursorPosition()), this, SLOT(OnGetCursorPosition())); connect(ui->m_CtToUsRegistrationWidget, SIGNAL(ActualizeCtToUsRegistrationWidget()), this, SLOT(OnActualizeCtToUsRegistrationWidget())); connect(ui->m_initializeCtToUsRegistration, SIGNAL(clicked()), this, SLOT(OnInitializeCtToUsRegistration())); connect(ui->m_initializeTargetMarking, SIGNAL(clicked()), this, SLOT(OnInitializeTargetMarking())); connect(ui->m_initializeCritStructureMarking, SIGNAL(clicked()), this, SLOT(OnInitializeCriticalStructureMarking())); connect(ui->m_initializeNavigation, SIGNAL(clicked()), this, SLOT(OnInitializeNavigation())); // indicate that no experiment is running at start ui->runningLabel->setPixmap(m_IconNotRunning); connect(ui->m_settingsWidget, SIGNAL(SettingsChanged(itk::SmartPointer)), this, SLOT(OnSettingsChanged(itk::SmartPointer))); } void QmitkUSNavigationMarkerPlacement::ReInitializeSettingsNodesAndImageStream() { //If update timer is not stopped (signals stopped), setting the m_CombinedModality // will cause a crash of the workbench in some times. m_UpdateTimer->blockSignals(true); m_UpdateTimer->stop(); m_SettingsNode = mitk::DataNode::New(); ui->m_settingsWidget->OnSetSettingsNode(m_SettingsNode, true); InitImageStream(); m_CombinedModality = ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality(); // Having set the m_CombinedModality reactivate the update timer again m_UpdateTimer->start(50); // every 50 Milliseconds = 20 Frames/Second m_UpdateTimer->blockSignals(false); } void QmitkUSNavigationMarkerPlacement::OnGetCursorPosition() { mitk::Point3D centroid = this->GetRenderWindowPart()->GetSelectedPosition(); ui->m_CtToUsRegistrationWidget->OnCalculateTRE(centroid); } void QmitkUSNavigationMarkerPlacement::OnActualizeCtToUsRegistrationWidget() { m_SettingsNode = mitk::DataNode::New(); ui->m_settingsWidget->OnSetSettingsNode(m_SettingsNode, true); this->InitImageStream(); if (ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality().IsNull()) { return; } ui->m_CtToUsRegistrationWidget->SetCombinedModality( ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality()); m_CombinedModality = ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality(); if (!m_StdMultiWidget) { // try to get the standard multi widget if it couldn't be got before mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); SetTwoWindowView(); } } else { this->OnRefreshView(); } m_UpdateTimer->start(50); // every 50 Milliseconds = 20 Frames/Second } void QmitkUSNavigationMarkerPlacement::OnInitializeCtToUsRegistration() { ui->m_CtToUsRegistrationWidget->SetDataStorage(this->GetDataStorage()); ui->m_CtToUsRegistrationWidget->OnSettingsChanged(m_SettingsNode); ui->m_CtToUsRegistrationWidget->OnActivateStep(); ui->m_CtToUsRegistrationWidget->OnStartStep(); ui->m_CtToUsRegistrationWidget->Update(); } - - void QmitkUSNavigationMarkerPlacement::OnInitializeTargetMarking() { ReInitializeSettingsNodesAndImageStream(); ui->m_TargetMarkingWidget->SetCombinedModality(m_CombinedModality); ui->m_TargetMarkingWidget->SetDataStorage(this->GetDataStorage()); ui->m_TargetMarkingWidget->OnSettingsChanged(m_SettingsNode); ui->m_TargetMarkingWidget->OnActivateStep(); ui->m_TargetMarkingWidget->OnStartStep(); ui->m_TargetMarkingWidget->Update(); + } void QmitkUSNavigationMarkerPlacement::OnInitializeCriticalStructureMarking() { ReInitializeSettingsNodesAndImageStream(); ui->m_CriticalStructuresWidget->SetCombinedModality(m_CombinedModality); ui->m_CriticalStructuresWidget->SetDataStorage(this->GetDataStorage()); ui->m_CriticalStructuresWidget->OnSettingsChanged(m_SettingsNode); ui->m_CriticalStructuresWidget->OnActivateStep(); ui->m_CriticalStructuresWidget->OnStartStep(); ui->m_CriticalStructuresWidget->Update(); } void QmitkUSNavigationMarkerPlacement::OnInitializeNavigation() { +<<<<<<< HEAD:Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp +======= + +>>>>>>> origin/T26372-AddAxisRSME:Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp ReInitializeSettingsNodesAndImageStream(); ui->m_NavigationWidget->SetCombinedModality(m_CombinedModality); ui->m_NavigationWidget->SetDataStorage(this->GetDataStorage()); ui->m_NavigationWidget->OnSettingsChanged(m_SettingsNode); ui->m_NavigationWidget->OnActivateStep(); ui->m_NavigationWidget->OnStartStep(); ui->m_NavigationWidget->Update(); // test if it is tracked US, if yes add visualization filter if (m_CombinedModality->GetIsTrackedUltrasoundActive()) { m_InstrumentNode = mitk::DataNode::New(); m_InstrumentNode->SetName("Tracked US Instrument"); m_InstrumentNode->SetData( m_CombinedModality->GetNavigationDataSource()->GetToolMetaData(0)->GetToolSurface()->Clone()); this->GetDataStorage()->Add(m_InstrumentNode); m_ToolVisualizationFilter = mitk::NavigationDataObjectVisualizationFilter::New(); m_ToolVisualizationFilter->ConnectTo(m_CombinedModality->GetNavigationDataSource()); m_ToolVisualizationFilter->SetRepresentationObject(0, m_InstrumentNode->GetData()); //caution: currently hard coded that instrument has id 0 //set dummy objects to avoid spamming of console mitk::Surface::Pointer dummyObject = mitk::Surface::New(); m_ToolVisualizationFilter->SetRepresentationObject(1, dummyObject); m_ToolVisualizationFilter->SetRepresentationObject(2, dummyObject); } } void QmitkUSNavigationMarkerPlacement::InitImageStream() { if (m_ImageStreamNode.IsNull()) { m_ImageStreamNode = mitk::DataNode::New(); m_ImageStreamNode->SetName("US Navigation Viewing Stream"); this->GetDataStorage()->Add(m_ImageStreamNode); } } void QmitkUSNavigationMarkerPlacement::OnCombinedModalityPropertyChanged(const std::string &key, const std::string &) { if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { m_ReinitAlreadyDone = false; this->ReinitOnImage(); if (m_CombinedModality.IsNotNull() && !m_CombinedModality->GetIsCalibratedForCurrentStatus()) { mitk::LayoutAnnotationRenderer::AddAnnotation( m_WarnOverlay.GetPointer(), "stdmulti.widget1", mitk::LayoutAnnotationRenderer::TopLeft); MITK_WARN << "No calibration available for the selected ultrasound image depth."; } } } void QmitkUSNavigationMarkerPlacement::SetFocus() { this->ReinitOnImage(); } void QmitkUSNavigationMarkerPlacement::OnTimeout() { if (m_CombinedModality.IsNull()) return; m_CombinedModality->Modified(); // shouldn't be nessecary ... fix in abstract ultrasound tracker device! m_CombinedModality->Update(); if (m_ToolVisualizationFilter.IsNotNull()) { m_ToolVisualizationFilter->Update(); } ui->m_CtToUsRegistrationWidget->Update(); ui->m_TargetMarkingWidget->Update(); ui->m_CriticalStructuresWidget->Update(); ui->m_NavigationWidget->Update(); mitk::Image::Pointer image = m_CombinedModality->GetOutput(); // make sure that always the current image is set to the data node if (image.IsNotNull() && m_ImageStreamNode->GetData() != image.GetPointer() && image->IsInitialized()) { m_ImageStreamNode->SetData(image); } if (!m_StdMultiWidget) { // try to get the standard multi widget if it couldn't be got before mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); SetTwoWindowView(); } this->CreateOverlays(); } if (m_CombinedModality.IsNotNull() && !this->m_CombinedModality->GetIsFreezed()) // if the combined modality is freezed: do nothing { m_AblationZonesDisplacementFilter->Update(); // update the 3D window only every fourth time to speed up the rendering (at least in 2D) this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); // make sure that a reinit was performed on the image this->ReinitOnImage(); } } void QmitkUSNavigationMarkerPlacement::OnEnableNavigationLayout() { MITK_INFO << "Navigation Layout"; // try to get the standard multi widget if it couldn't be got before mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::OnRenderWindowSelection() { SetTwoWindowView(); } void QmitkUSNavigationMarkerPlacement::OnRefreshView() { if (!ui->m_enableNavigationLayout->isChecked()) OnResetStandardLayout(); else { // Reinit the US Image Stream (this might be broken if there was a global reinit somewhere...) try { mitk::RenderingManager::GetInstance()->InitializeViews( // Reinit this ->GetDataStorage() // GetDataStorage ->GetNamedNode("US Viewing Stream - Image 0") ->GetData() ->GetTimeGeometry()); // GetNode } catch (...) { MITK_DEBUG << "No reinit possible"; } SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::SetTwoWindowView() { if (m_StdMultiWidget) { MITK_INFO << "m_StdMultiWidget exists and not null"; m_StdMultiWidget->DisableStandardLevelWindow(); int i, j, k; switch (this->ui->m_RenderWindowSelection->value()) { case 1: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4")) ->GetCameraController() ->SetViewToCaudal(); i = 2; j = 3; // other windows k = 1; break; case 2: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4")) ->GetCameraController() ->SetViewToSinister(); i = 1; j = 3; k = 2; break; case 3: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4")) ->GetCameraController() ->SetViewToAnterior(); i = 2; j = 1; k = 3; break; default: return; } m_StdMultiWidget->changeLayoutTo2DUpAnd3DDown(k); ////Crosshair invisible in 3D view this->GetDataStorage() ->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane") ->SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage() ->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane") ->SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage() ->GetNamedNode("stdmulti.widget" + std::to_string(k) + ".plane") ->SetBoolProperty("visible", true, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage() ->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane") ->SetIntProperty("Crosshair.Gap Size", 0); this->GetDataStorage() ->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane") ->SetIntProperty("Crosshair.Gap Size", 0); } } void QmitkUSNavigationMarkerPlacement::OnResetStandardLayout() { // reset render windows mitk::DataNode::Pointer widget1 = this->GetDataStorage()->GetNamedNode("stdmulti.widget1.plane"); if (widget1.IsNotNull()) { widget1->SetVisibility(true); } mitk::DataNode::Pointer widget2 = this->GetDataStorage()->GetNamedNode("stdmulti.widget2.plane"); if (widget2.IsNotNull()) { widget2->SetVisibility(true); } mitk::DataNode::Pointer widget3 = this->GetDataStorage()->GetNamedNode("stdmulti.widget3.plane"); if (widget3.IsNotNull()) { widget3->SetVisibility(true); } m_StdMultiWidget->changeLayoutToDefault(); } void QmitkUSNavigationMarkerPlacement::OnChangeLayoutClicked() { if (ui->m_enableNavigationLayout->isChecked()) OnEnableNavigationLayout(); else OnResetStandardLayout(); } void QmitkUSNavigationMarkerPlacement::OnImageAndNavigationDataLoggingTimeout() { // update filter for logging navigation data and ultrasound images if (m_CombinedModality.IsNotNull()) { m_NavigationDataRecorder->Update(); // get last messages for logging filer and store them std::vector messages = m_LoggingBackend.GetNavigationMessages(); std::string composedMessage = ""; for (std::size_t i = 0; i < messages.size(); i++) { composedMessage += messages.at(i); } m_USImageLoggingFilter->AddMessageToCurrentImage(composedMessage); m_LoggingBackend.ClearNavigationMessages(); // update logging filter m_USImageLoggingFilter->Update(); } } void QmitkUSNavigationMarkerPlacement::OnStartExperiment() { // get name for the experiment by a QInputDialog bool ok; if (m_ExperimentName.isEmpty()) { // default: current date m_ExperimentName = QString::number(QDateTime::currentDateTime().date().year()) + "_" + QString::number(QDateTime::currentDateTime().date().month()) + "_" + QString::number(QDateTime::currentDateTime().date().day()) + "_experiment_" + QString::number(QDateTime::currentDateTime().time().hour()) + "." + QString::number(QDateTime::currentDateTime().time().minute()); } m_ExperimentName = QInputDialog::getText( m_Parent, QString("Experiment Name"), QString("Name of the Experiment"), QLineEdit::Normal, m_ExperimentName, &ok); MITK_INFO("USNavigationLogging") << "Experiment started: " << m_ExperimentName.toStdString(); if (ok && !m_ExperimentName.isEmpty()) { // display error message and call the function recursivly if a directory // with the given name already exists QDir experimentResultsDir(m_ResultsDirectory + QDir::separator() + m_ExperimentName); if (experimentResultsDir.exists()) { QMessageBox::critical( m_Parent, "Results Directory Exists", "The result directory already exists.\nPlease choose an other name."); this->OnStartExperiment(); } else { QDir(m_ResultsDirectory).mkdir(m_ExperimentName); m_ExperimentResultsSubDirectory = m_ResultsDirectory + QDir::separator() + m_ExperimentName; // experiment is running now ui->runningLabel->setPixmap(m_IconRunning); // (re)start timer for navigation step durations m_NavigationStepTimer->Reset(); m_NavigationStepTimer->SetOutputFileName( QString(m_ExperimentResultsSubDirectory + QDir::separator() + QString("durations.cvs")).toStdString()); m_NavigationStepTimer->SetActiveIndex(0, "Initialization"); ui->finishExperimentButton->setEnabled(true); ui->startExperimentButton->setDisabled(true); // initialize and register logging backend QString loggingFilename = m_ExperimentResultsSubDirectory + QDir::separator() + "logging.txt"; m_LoggingBackend.SetOutputFileName(loggingFilename.toStdString()); mbilog::RegisterBackend(&m_LoggingBackend); // initialize and start navigation data recorder form xml recording m_NavigationDataRecorder->StartRecording(); m_IsExperimentRunning = true; m_ImageAndNavigationDataLoggingTimer->start(1000); } } } void QmitkUSNavigationMarkerPlacement::OnFinishExperiment() { this->WaitCursorOn(); MITK_INFO("USNavigationLogging") << "Experiment finished!"; MITK_INFO("USNavigationLogging") << "Position/Orientation of needle tip: " << (dynamic_cast( m_CombinedModality->GetTrackingDeviceDataSource()->GetOutput(0))) ->GetPosition(); MITK_INFO("USNavigationLogging") << "Position of target: " << m_TargetNodeDisplacementFilter->GetRawDisplacementNavigationData(0)->GetPosition(); MITK_INFO("USNavigationLogging") << "Total duration: " << m_NavigationStepTimer->GetTotalDuration(); m_ImageAndNavigationDataLoggingTimer->stop(); ui->runningLabel->setPixmap(m_IconNotRunning); m_NavigationStepTimer->Stop(); ui->finishExperimentButton->setDisabled(true); ui->startExperimentButton->setEnabled(true); MITK_INFO("USNavigationLogging") << "Writing logging data to " << m_ExperimentResultsSubDirectory.toStdString(); // save ultrasound images to the file system QDir(m_ExperimentResultsSubDirectory).mkdir("ImageStream"); m_USImageLoggingFilter->Update(); m_USImageLoggingFilter->SetImageFilesExtension(".jpg"); m_USImageLoggingFilter->SaveImages( QString(m_ExperimentResultsSubDirectory + QDir::separator() + "ImageStream" + QDir::separator()).toStdString()); m_USImageLoggingFilter = mitk::USImageLoggingFilter::New(); m_NavigationDataRecorder->StopRecording(); // Write data to csv and xml file mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.xml").toStdString().c_str())); mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.csv").toStdString().c_str())); // write logged navigation data messages to separate file std::stringstream csvNavigationMessagesFilename; csvNavigationMessagesFilename << m_ExperimentResultsSubDirectory.toStdString() << QDir::separator().toLatin1() << "CSVNavigationMessagesLogFile.csv"; MITK_INFO("USNavigationLogging") << "Writing logged navigation messages to separate csv file: " << csvNavigationMessagesFilename.str(); m_LoggingBackend.WriteCSVFileWithNavigationMessages(csvNavigationMessagesFilename.str()); mbilog::UnregisterBackend(&m_LoggingBackend); m_IsExperimentRunning = false; m_ImageAndNavigationDataLoggingTimer->stop(); m_CombinedModality = nullptr; // reset scene number for next experiment m_SceneNumber = 1; this->WaitCursorOff(); MITK_INFO("USNavigationLogging") << "Finished!"; } void QmitkUSNavigationMarkerPlacement::OnSettingsChanged(itk::SmartPointer settings) { // initialize gui according to the experiment mode setting bool experimentMode = false; settings->GetBoolProperty("settings.experiment-mode", experimentMode); ui->startExperimentButton->setVisible(experimentMode); ui->finishExperimentButton->setVisible(experimentMode); ui->runningLabel->setVisible(experimentMode); if (experimentMode && !m_IsExperimentRunning) { ui->runningLabel->setPixmap(m_IconNotRunning); } else if (!experimentMode) { if (m_IsExperimentRunning) { this->OnFinishExperiment(); } } // get the results directory from the settings and use home directory if // there is no results directory configured std::string resultsDirectory; if (settings->GetStringProperty("settings.experiment-results-directory", resultsDirectory)) { m_ResultsDirectory = QString::fromStdString(resultsDirectory); } else { m_ResultsDirectory = QDir::homePath(); } // make sure that the results directory exists QDir resultsDirectoryQDir = QDir(m_ResultsDirectory); if (!resultsDirectoryQDir.exists()) { resultsDirectoryQDir.mkpath(m_ResultsDirectory); } MITK_INFO("USNavigation") << "Results Directory: " << m_ResultsDirectory.toStdString(); } void QmitkUSNavigationMarkerPlacement::ReinitOnImage() { if (!m_ReinitAlreadyDone && m_CombinedModality.IsNotNull()) { // make sure that the output is already calibrated correctly // (if the zoom level was changed recently) m_CombinedModality->Modified(); m_CombinedModality->Update(); mitk::Image::Pointer image = m_CombinedModality->GetOutput(); if (image.IsNotNull() && image->IsInitialized()) { // make a reinit on the ultrasound image mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); if (renderWindow != NULL && image->GetTimeGeometry()->IsValid()) { renderWindow->GetRenderingManager()->InitializeViews( image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); renderWindow->GetRenderingManager()->RequestUpdateAll(); } this->RequestRenderWindowUpdate(); m_ReinitAlreadyDone = true; } } } void QmitkUSNavigationMarkerPlacement::Convert2DImagesTo3D(mitk::DataStorage::SetOfObjects::ConstPointer nodes) { for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); ++it) { if (it->Value()->GetData() && strcmp(it->Value()->GetData()->GetNameOfClass(), "Image") == 0) { // convert image to 3d image if it is 2d at the moment mitk::Image::Pointer image = dynamic_cast(it->Value()->GetData()); if (image.IsNotNull() && image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable()) { mitk::Convert2Dto3DImageFilter::Pointer convert2DTo3DImageFilter = mitk::Convert2Dto3DImageFilter::New(); convert2DTo3DImageFilter->SetInput(image); convert2DTo3DImageFilter->Update(); it->Value()->SetData(convert2DTo3DImageFilter->GetOutput()); } } } } void QmitkUSNavigationMarkerPlacement::CreateOverlays() { // initialize warning overlay (and do not display it, yet) m_WarnOverlay->SetText("Warning: No calibration available for current depth."); // set position and font size for the text overlay // (nonesense postition as a layouter is used, but it ignored // the overlay without setting a position here) mitk::Point2D overlayPosition; overlayPosition.SetElement(0, -50.0f); overlayPosition.SetElement(1, -50.0f); m_WarnOverlay->SetPosition2D(overlayPosition); m_WarnOverlay->SetFontSize(22); m_WarnOverlay->SetColor(1, 0, 0); // overlay should be red } void QmitkUSNavigationMarkerPlacement::UpdateToolStorage() { if (m_NavigationDataSource.IsNull()) { m_NavigationDataSource = m_CombinedModality->GetNavigationDataSource(); } if (m_NavigationDataSource.IsNull()) { MITK_WARN << "Found an invalid navigation data source object!"; } us::ModuleContext *context = us::GetModuleContext(); std::string id = m_NavigationDataSource->US_PROPKEY_ID; std::string filter = "(" + mitk::NavigationToolStorage::US_PROPKEY_SOURCE_ID + "=" + id + ")"; // Get Storage std::vector> refs = context->GetServiceReferences(); m_CurrentStorage = context->GetService(refs.front()); if (m_CurrentStorage.IsNull()) { MITK_WARN << "Found an invalid storage object!"; } else if (m_CurrentStorage->GetToolCount() != m_NavigationDataSource->GetNumberOfOutputs()) // there is something wrong with the storage { MITK_WARN << "Found a tool storage, but it has not the same number of tools like the NavigationDataSource. This " "storage won't be used because it isn't the right one."; m_CurrentStorage = NULL; } }