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 a9d6f7d2dd..48f35d3233 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,1252 +1,1277 @@ /*========================================================================= 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 "QmitkIGTTrackingDataEvaluationView.h" #include "QmitkStdMultiWidget.h" // Qt #include #include #include // MITK #include "mitkNavigationDataCSVSequentialPlayer.h" #include #include #include #include #include //ITK #include //VNL #include //vtk headers #include #include #include const std::string QmitkIGTTrackingDataEvaluationView::VIEW_ID = "org.mitk.views.igttrackingdataevaluation"; QmitkIGTTrackingDataEvaluationView::QmitkIGTTrackingDataEvaluationView() : QmitkFunctionality() , m_Controls(0) , m_MultiWidget(NULL) , m_scalingfactor(1) { m_CSVtoXMLInputFilenameVector = std::vector(); m_CSVtoXMLOutputFilenameVector = std::vector(); } QmitkIGTTrackingDataEvaluationView::~QmitkIGTTrackingDataEvaluationView() { } 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_StartEvaluationAll, SIGNAL(clicked()), this, SLOT(OnEvaluateDataAll())); connect(m_Controls->m_GridMatching, SIGNAL(clicked()), this, SLOT(OnPerfomGridMatching())); connect(m_Controls->m_ComputeRotation, SIGNAL(clicked()), this, SLOT(OnComputeRotation())); //initialize data storage combo boxes m_Controls->m_ReferencePointSetComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ReferencePointSetComboBox->SetAutoSelectNewItems(true); m_Controls->m_ReferencePointSetComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); m_Controls->m_MeasurementPointSetComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MeasurementPointSetComboBox->SetAutoSelectNewItems(true); m_Controls->m_MeasurementPointSetComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); } } void QmitkIGTTrackingDataEvaluationView::OnComputeRotation() { //Get all data from UI auto EvaluationDataCollection = GetAllDataFromUIList(); //Compute mean Quaternions auto OrientationVector = GetMeanOrientationsOfAllData(EvaluationDataCollection); //Compute Rotations itk::Vector rotationVec; //adapt for Aurora 5D tools: [0,0,1000] rotationVec[0] = 0; //X rotationVec[1] = 0; //Y rotationVec[2] = 10000; //Z std::vector allOrientationErrors; for (int i = 0; i < (OrientationVector.size() - 1); i++) { double AngleBetweenTwoQuaternions = mitk::StaticIGTHelperFunctions::GetAngleBetweenTwoQuaterions(OrientationVector.at(i), OrientationVector.at(i+1), rotationVec); double AngularError = abs(AngleBetweenTwoQuaternions - 11.25); std::stringstream description; description << "Rotation Error ROT" << (i + 1) << " / ROT" << (i + 2); allOrientationErrors.push_back({ AngularError, description.str() }); MITK_INFO << description.str() << ": " << AngularError; } //compute statistics std::vector orientationErrorStatistics; orientationErrorStatistics = mitk::HummelProtocolEvaluation::ComputeStatistics(allOrientationErrors); MITK_INFO << "## Rotation error statistics: ##"; for (auto stat : orientationErrorStatistics) { MITK_INFO << stat.description << ": " << stat.distanceError; } //write results to file allOrientationErrors.insert(allOrientationErrors.end(), orientationErrorStatistics.begin(), orientationErrorStatistics.end()); std::stringstream filenameOrientationStat; filenameOrientationStat << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".orientationStatistics.csv"; MITK_INFO << "Writing output to file " << filenameOrientationStat.str(); writeToFile(filenameOrientationStat.str(), allOrientationErrors); } void QmitkIGTTrackingDataEvaluationView::OnPerfomGridMatching() { mitk::PointSet::Pointer reference = dynamic_cast(m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()); mitk::PointSet::Pointer measurement = dynamic_cast(m_Controls->m_MeasurementPointSetComboBox->GetSelectedNode()->GetData()); //convert point sets to vtk poly data vtkSmartPointer sourcePoints = vtkSmartPointer::New(); vtkSmartPointer targetPoints = vtkSmartPointer::New(); for (int i = 0; iGetSize(); i++) { double point[3] = { reference->GetPoint(i)[0], reference->GetPoint(i)[1], reference->GetPoint(i)[2] }; sourcePoints->InsertNextPoint(point); double point_targets[3] = { measurement->GetPoint(i)[0], measurement->GetPoint(i)[1], measurement->GetPoint(i)[2] }; targetPoints->InsertNextPoint(point_targets); } //compute transform vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->SetModeToRigidBody(); transform->Modified(); transform->Update(); //compute FRE of transform double FRE = mitk::StaticIGTHelperFunctions::ComputeFRE(reference, measurement, transform); MITK_INFO << "FRE after grid matching: " + QString::number(FRE) + " mm"; //convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); itk::Matrix rotationDouble = itk::Matrix(); itk::Vector translationDouble = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); for (int k = 0; k<3; k++) for (int l = 0; l<3; l++) { rotationFloat[k][l] = m->GetElement(k, l); rotationDouble[k][l] = m->GetElement(k, l); } for (int k = 0; k<3; k++) { translationFloat[k] = m->GetElement(k, 3); translationDouble[k] = m->GetElement(k, 3); } //create affine transform 3D mitk::AffineTransform3D::Pointer mitkTransform = mitk::AffineTransform3D::New(); mitkTransform->SetMatrix(rotationDouble); mitkTransform->SetOffset(translationDouble); mitk::NavigationData::Pointer transformNavigationData = mitk::NavigationData::New(mitkTransform); m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(mitkTransform); m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()->GetGeometry()->Modified(); //write to file std::stringstream filename; filename << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".GridMatchingResult.csv"; MITK_INFO << "Writing output to file " << filename.str(); std::vector FRE_Error; FRE_Error.push_back({ FRE, "FRE after grid matching [mm]" }); writeToFile(filename.str(), FRE_Error); } void QmitkIGTTrackingDataEvaluationView::OnOrientationCalculation_CalcRef() { if (m_FilenameVector.size() != 3) { MessageBox("Need exactly three points as reference, aborting!"); return; } //start loop and iterate through all files of list for (int i = 0; i < m_FilenameVector.size(); i++) { //create navigation data player - mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); + mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //check if the stream is valid and skip file if not /* if (!myPlayer->GetStreamValid()) { MITK_ERROR << "Error in file " << m_FilenameVector.at(i) << ": " << myPlayer->GetErrorMessage() << " ; Skipping file!"; continue; } */ //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (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(); } //store mean position as reference switch (i) { case 0: m_RefPoint1 = myEvaluationFilter->GetPositionMean(0); break; case 1: m_RefPoint2 = myEvaluationFilter->GetPositionMean(0); break; case 2: m_RefPoint3 = myEvaluationFilter->GetPositionMean(0); break; } } MessageBox("Created Reference!"); } void QmitkIGTTrackingDataEvaluationView::OnOrientationCalculation_CalcOrientandWriteToFile() { //start loop and iterate through all files of list for (int i = 0; i < m_FilenameVector.size(); i++) { //create navigation data player - mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); + mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //check if the stream is valid and skip file if not /* if (!myPlayer->GetStreamValid()) { MITK_ERROR << "Error in file " << m_FilenameVector.at(i) << ": " << myPlayer->GetErrorMessage() << " ; Skipping file!"; continue; } */ //open file header QString outputname = QString(m_FilenameVector.at(i).c_str()) + "_orientationFile.csv"; m_CurrentWriteFile.open(outputname.toStdString().c_str(), std::ios::out); if (m_CurrentWriteFile.bad()) { MessageBox("Error: Can't open output file!"); return; } //write header to file m_CurrentWriteFile << "Nr;Calypso_Time;Valid_Reference;MeasureTool_Measurement-Tool[x];MeasureTool_Measurement-Tool[y];MeasureTool_Measurement-Tool[z];MeasureTool_Measurement-Tool[qx];MeasureTool_Measurement-Tool[qy];MeasureTool_Measurement-Tool[qz];MeasureTool_Measurement-Tool[qr]\n"; //update pipeline until number of samples is reached int step = 0; mitk::Point3D point1, point2, point3; mitk::Quaternion current_orientation; for (int j = 0; !myPlayer->IsAtEnd(); j++) { myPlayer->Update(); mitk::NavigationData::Pointer currentNavData = myPlayer->GetOutput(0); switch (step) { case 0: step++; point1 = currentNavData->GetPosition(); break; case 1: step++; point2 = currentNavData->GetPosition(); break; case 2: step = 0; point3 = currentNavData->GetPosition(); //compute transform from reference to current points if (point1[0] == 0 && point1[1] == 0 && point1[2] == 0 && point2[0] == 0 && point2[1] == 0 && point2[2] == 0 && point3[0] == 0 && point3[1] == 0 && point3[2] == 0 ) current_orientation.fill(0); else { /* Drehen um eine Achse um das "Umschlagen" zu vermeiden itk::Matrix rot180degreeAroundY; rot180degreeAroundY.Fill(0); rot180degreeAroundY[0][0] = -1; rot180degreeAroundY[1][1] = 1; rot180degreeAroundY[2][2] = -1; point1 = rot180degreeAroundY * point1; point2 = rot180degreeAroundY * point2; point3 = rot180degreeAroundY * point3; */ vtkSmartPointer transform = vtkSmartPointer::New(); vtkSmartPointer sourcePoints = vtkSmartPointer::New(); double sourcepoint1[3] = { point1[0], point1[1], point1[2] }; double sourcepoint2[3] = { point2[0], point2[1], point2[2] }; double sourcepoint3[3] = { point3[0], point3[1], point3[2] }; sourcePoints->InsertNextPoint(sourcepoint1); sourcePoints->InsertNextPoint(sourcepoint2); sourcePoints->InsertNextPoint(sourcepoint3); vtkSmartPointer targetPoints = vtkSmartPointer::New(); double targetpoint1[3] = { m_RefPoint1[0], m_RefPoint1[1], m_RefPoint1[2] }; double targetpoint2[3] = { m_RefPoint2[0], m_RefPoint2[1], m_RefPoint2[2] }; double targetpoint3[3] = { m_RefPoint3[0], m_RefPoint3[1], m_RefPoint3[2] }; targetPoints->InsertNextPoint(targetpoint1); targetPoints->InsertNextPoint(targetpoint2); targetPoints->InsertNextPoint(targetpoint3); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->Modified(); transform->Update(); mitk::Transform::Pointer newTransform = mitk::Transform::New(); newTransform->SetMatrix(transform->GetMatrix()); current_orientation = newTransform->GetOrientation(); //add pointset with the three positions if ((j > 15) && (j < 18)) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); newPointSet->InsertPoint(0, point1); newPointSet->InsertPoint(1, point2); newPointSet->InsertPoint(2, point3); QString name = QString(m_FilenameVector.at(i).c_str()); newNode->SetName(name.toStdString().c_str()); newNode->SetData(newPointSet); newNode->SetFloatProperty("pointsize", 0.1); this->GetDataStorage()->Add(newNode); } } break; } m_CurrentWriteFile << i << ";"; m_CurrentWriteFile << currentNavData->GetTimeStamp() << ";"; //IMPORTANT: change to GetIGTTimeStamp in new version! m_CurrentWriteFile << "true;"; m_CurrentWriteFile << currentNavData->GetPosition()[0] << ";"; m_CurrentWriteFile << currentNavData->GetPosition()[1] << ";"; m_CurrentWriteFile << currentNavData->GetPosition()[2] << ";"; m_CurrentWriteFile << current_orientation.x() << ";"; m_CurrentWriteFile << current_orientation.y() << ";"; m_CurrentWriteFile << current_orientation.z() << ";"; m_CurrentWriteFile << current_orientation.r() << ";"; m_CurrentWriteFile << "\n"; } //close output file m_CurrentWriteFile.close(); } MessageBox("Finished!"); } void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkIGTTrackingDataEvaluationView::OnAddToCurrentList() { //read in files QStringList files = QFileDialog::getOpenFileNames(NULL, "Select one or more files to open", "/", "CSV (*.csv)"); if (files.isEmpty()) return; for (int i = 0; i < files.size(); i++){ std::string tmp = files.at(i).toStdString().c_str(); m_FilenameVector.push_back(tmp); } /* //save old locale char * oldLocale; oldLocale = setlocale( LC_ALL, 0 ); //define own locale std::locale C("C"); setlocale( LC_ALL, "C" ); */ //TODO: check if this is needed here, and load old locale if yes /* //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) { std::string thisFilename = ""; if (m_Controls->m_AddPath->isChecked()) thisFilename = m_Controls->m_ListPath->text().toStdString(); thisFilename.append(buffer); m_FilenameVector.push_back(thisFilename); } } } */ //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); } } void QmitkIGTTrackingDataEvaluationView::OnLoadFileList() { m_FilenameVector = std::vector(); m_FilenameVector.clear(); OnAddToCurrentList(); } void QmitkIGTTrackingDataEvaluationView::OnEvaluateDataAll() { 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 { volume = mitk::HummelProtocolEvaluation::small; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); } //write results to file std::stringstream filename5cm; filename5cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results5cm.csv"; MITK_INFO << "Writing output to file " << filename5cm.str(); writeToFile(filename5cm.str(), results5cm); std::stringstream filename15cm; filename15cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results15cm.csv"; MITK_INFO << "Writing output to file " << filename15cm.str(); writeToFile(filename15cm.str(), results15cm); std::stringstream filename30cm; filename30cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results30cm.csv"; MITK_INFO << "Writing output to file " << filename30cm.str(); writeToFile(filename30cm.str(), results30cm); std::stringstream filenameAccum; filenameAccum << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".resultsAccumDist.csv"; MITK_INFO << "Writing output to file " << filenameAccum.str(); writeToFile(filenameAccum.str(), resultsAccum); } void QmitkIGTTrackingDataEvaluationView::OnEvaluateData() { //open output file m_CurrentWriteFile.open(std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str(), std::ios::out); if (m_CurrentWriteFile.bad()) { MessageBox("Error: Can't open output file!"); return; } std::vector jitterValues; //write output file header WriteHeader(); //start loop and iterate through all files of list for (int i = 0; i < m_FilenameVector.size(); i++) { //create navigation data player - mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); + mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //check if the stream is valid and skip file if not /* if (!myPlayer->GetStreamValid()) { MITK_ERROR << "Error in file " << m_FilenameVector.at(i) << ": " << myPlayer->GetErrorMessage() << " ; Skipping file!"; continue; } */ //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (int j = 0; j < myPlayer->GetNumberOfOutputs(); j++) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } if (myPlayer->GetNumberOfSnapshots() < m_Controls->m_NumberOfSamples->value()) { MITK_WARN << "Number of snapshots (" << myPlayer->GetNumberOfSnapshots() << ") smaller than number of samples to evaluate (" << m_Controls->m_NumberOfSamples->value() << ") ! Cannot proceed!"; return; } //update pipline until number of samples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) { myEvaluationFilter->Update(); //Debug output: //std::cout.precision(5); //std::cout << "Euler " << j << ";" << myPlayer->GetOutput()->GetOrientation().rotation_euler_angles()[0] << ";" << myPlayer->GetOutput()->GetOrientation().rotation_euler_angles()[1] << ";" << myPlayer->GetOutput()->GetOrientation().rotation_euler_angles()[2] << "\n"; } //store all jitter values in separate vector for statistics jitterValues.push_back({ myEvaluationFilter->GetPositionErrorRMS(0), "RMS" }); //write result to output file WriteDataSet(myEvaluationFilter, m_FilenameVector.at(i)); } //close output file for single data m_CurrentWriteFile.close(); //compute statistics std::vector jitterStatistics = mitk::HummelProtocolEvaluation::ComputeStatistics(jitterValues); MITK_INFO << "## Jitter (RMS) statistics: ##"; for (auto jitterStat : jitterStatistics) {MITK_INFO << jitterStat.description << ": " << jitterStat.distanceError;} //write statistic results to separate file std::stringstream filenameJitterStat; filenameJitterStat << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".resultsJitterStatistics.csv"; MITK_INFO << "Writing output to file " << filenameJitterStat.str(); writeToFile(filenameJitterStat.str(), jitterStatistics); //calculate angles if option is on if (m_Controls->m_settingDifferenceAngles->isChecked() || m_Controls->m_DifferencesSLERP->isChecked()) CalculateDifferenceAngles(); MessageBox("Finished!"); } void QmitkIGTTrackingDataEvaluationView::OnGeneratePointSetsOfSinglePositions() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); //start loop and iterate through all files of list for (int i = 0; i < m_FilenameVector.size(); i++) { //create point set for this file mitk::PointSet::Pointer thisPointSet = mitk::PointSet::New(); //create navigation data player - mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); + mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //check if the stream is valid and skip file if not /* if (!myPlayer->GetStreamValid()) { MITK_ERROR << "Error in file " << m_FilenameVector.at(i) << ": " << myPlayer->GetErrorMessage() << " ; Skipping file!"; continue; } */ //update pipline until number of samlples is reached and store every single point for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) { myPlayer->Update(); mitk::Point3D thisPoint = myPlayer->GetOutput()->GetPosition(); thisPoint[0] *= m_scalingfactor; thisPoint[1] *= m_scalingfactor; thisPoint[2] *= m_scalingfactor; thisPointSet->InsertPoint(j, thisPoint); } //add point set to data storage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString name = this->m_Controls->m_prefix->text() + QString("PointSet_of_All_Positions_") + QString::number(i); newNode->SetName(name.toStdString()); newNode->SetData(thisPointSet); this->GetDataStorage()->Add(newNode); } } void QmitkIGTTrackingDataEvaluationView::OnGeneratePointSet() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); mitk::PointSet::Pointer generatedPointSet = mitk::PointSet::New(); //start loop and iterate through all files of list for (int i = 0; i < m_FilenameVector.size(); i++) { //create navigation data player - mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); + mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //check if the stream is valid and skip file if not /* if (!myPlayer->GetStreamValid()) { MITK_ERROR << "Error in file " << m_FilenameVector.at(i) << ": " << myPlayer->GetErrorMessage() << " ; Skipping file!"; continue; } */ //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (int j = 0; j < myPlayer->GetNumberOfOutputs(); j++) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } //update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) { myEvaluationFilter->Update(); } //add mean position to point set mitk::Point3D meanPos = myEvaluationFilter->GetPositionMean(0); if (m_scalingfactor != 1) { meanPos[0] *= m_scalingfactor; meanPos[1] *= m_scalingfactor; meanPos[2] *= m_scalingfactor; } generatedPointSet->InsertPoint(i, meanPos); } //add point set to data storage mitk::DataNode::Pointer newNode = 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_PointSetMeanPositions = generatedPointSet; } void QmitkIGTTrackingDataEvaluationView::OnGenerateRotationLines() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); //start loop and iterate through all files of list for (int i = 0; i < m_FilenameVector.size(); i++) { //create navigation data player - mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); + mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //check if the stream is valid and skip file if not /* if (!myPlayer->GetStreamValid()) { MITK_ERROR << "Error in file " << m_FilenameVector.at(i) << ": " << myPlayer->GetErrorMessage() << " ; Skipping file!"; } else */ { //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (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(); /* if (!myPlayer->GetStreamValid()) { MITK_ERROR << "Error in file " << m_FilenameVector.at(i) << ": " << myPlayer->GetErrorMessage() << " ; Skipping file!"; continue; } */ } //if (!myPlayer->IsAtEnd()) continue; //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.Get_vnl_vector() + meanPos.Get_vnl_vector(); mitk::Point3D secondPointTransformedMITK; mitk::FillVector3D(secondPointTransformedMITK, secondPointTransformed[0], secondPointTransformed[1], secondPointTransformed[2]); mitk::FillVector3D(thirdPoint, 0, 4, 0); //Y vnl_vector thirdPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * thirdPoint.Get_vnl_vector() + meanPos.Get_vnl_vector(); mitk::Point3D thirdPointTransformedMITK; mitk::FillVector3D(thirdPointTransformedMITK, thirdPointTransformed[0], thirdPointTransformed[1], thirdPointTransformed[2]); mitk::FillVector3D(fourthPoint, 0, 0, 6); //Z vnl_vector fourthPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * fourthPoint.Get_vnl_vector() + meanPos.Get_vnl_vector(); mitk::Point3D fourthPointTransformedMITK; mitk::FillVector3D(fourthPointTransformedMITK, fourthPointTransformed[0], fourthPointTransformed[1], fourthPointTransformed[2]); mitk::PointSet::Pointer rotationLine = mitk::PointSet::New(); rotationLine->InsertPoint(0, secondPointTransformedMITK); rotationLine->InsertPoint(1, meanPos); rotationLine->InsertPoint(2, thirdPointTransformedMITK); rotationLine->InsertPoint(3, meanPos); rotationLine->InsertPoint(4, fourthPointTransformedMITK); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString nodeName = this->m_Controls->m_prefix->text() + "RotationLineNumber" + QString::number(i); newNode->SetName(nodeName.toStdString()); newNode->SetData(rotationLine); newNode->SetBoolProperty("show contour", true); newNode->SetFloatProperty("pointsize", 0.5); this->GetDataStorage()->Add(newNode); } } } void QmitkIGTTrackingDataEvaluationView::OnGenerateGroundTruthPointSet() { mitk::PointSet::Pointer generatedPointSet = mitk::PointSet::New(); int currentPointID = 0; mitk::Point3D currentPoint; mitk::FillVector3D(currentPoint, 0, 0, 0); for (int i = 0; i < m_Controls->m_PointNumber2->value(); i++) { for (int j = 0; j < m_Controls->m_PointNumber1->value(); j++) { generatedPointSet->InsertPoint(currentPointID, currentPoint); currentPointID++; currentPoint[1] += m_Controls->m_PointDistance->value(); } currentPoint[1] = 0; currentPoint[2] += m_Controls->m_PointDistance->value(); } mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString nodeName = "GroundTruthPointSet_" + QString::number(m_Controls->m_PointNumber1->value()) + "x" + QString::number(m_Controls->m_PointNumber2->value()) + "_(" + QString::number(m_Controls->m_PointDistance->value()) + "mm)"; newNode->SetName(nodeName.toStdString()); newNode->SetData(generatedPointSet); newNode->SetFloatProperty("pointsize", 5); this->GetDataStorage()->Add(newNode); } void QmitkIGTTrackingDataEvaluationView::OnConvertCSVtoXMLFile() { if (m_Controls->m_ConvertSingleFile->isChecked()) { //convert one file int lines = ConvertOneFile(this->m_Controls->m_InputCSV->text().toStdString(), this->m_Controls->m_OutputXML->text().toStdString()); QString result = "Converted one file with" + QString::number(lines) + " data sets"; MessageBox(result.toStdString()); } else //converte file list { if (m_CSVtoXMLInputFilenameVector.empty() || m_CSVtoXMLOutputFilenameVector.empty()) { MessageBox("Error: one list is not loaded!"); return; } else if (m_CSVtoXMLInputFilenameVector.size() != m_CSVtoXMLOutputFilenameVector.size()) { MessageBox("Error: lists do not have the same number of files!"); return; } for (int i = 0; i < m_CSVtoXMLInputFilenameVector.size(); i++) { int lines = ConvertOneFile(m_CSVtoXMLInputFilenameVector.at(i), m_CSVtoXMLOutputFilenameVector.at(i)); } QString result = "Converted " + QString::number(m_CSVtoXMLInputFilenameVector.size()) + " files from file list!"; MessageBox(result.toStdString()); } } int QmitkIGTTrackingDataEvaluationView::ConvertOneFile(std::string inputFilename, std::string outputFilename) { std::vector myNavigationDatas = GetNavigationDatasFromFile(inputFilename); mitk::NavigationDataRecorderDeprecated::Pointer myRecorder = mitk::NavigationDataRecorderDeprecated::New(); myRecorder->SetFileName(outputFilename.c_str()); mitk::NavigationData::Pointer input = mitk::NavigationData::New(); if (m_Controls->m_ConvertCSV->isChecked()) myRecorder->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); myRecorder->AddNavigationData(input); myRecorder->StartRecording(); for (int 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(NULL, 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(NULL, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_CSVtoXMLOutputFilenameVector = this->GetFileContentLineByLine(filename.toStdString()); m_Controls->m_labelCSVtoXMLOutputList->setText("READY"); } void QmitkIGTTrackingDataEvaluationView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkIGTTrackingDataEvaluationView::WriteHeader() { m_CurrentWriteFile << "Filename;"; m_CurrentWriteFile << "N;"; m_CurrentWriteFile << "N_invalid;"; m_CurrentWriteFile << "Percentage_invalid;"; if (m_Controls->m_settingPosMean->isChecked()) { m_CurrentWriteFile << "Position_Mean[x];"; m_CurrentWriteFile << "Position_Mean[y];"; m_CurrentWriteFile << "Position_Mean[z];"; } if (m_Controls->m_settingPosStabw->isChecked()) { m_CurrentWriteFile << "Position_StandDev[x];"; m_CurrentWriteFile << "Position_StandDev[y];"; m_CurrentWriteFile << "Position_StandDev[z];"; } if (m_Controls->m_settingPosSampleStabw->isChecked()) { m_CurrentWriteFile << "Position_SampleStandDev[x];"; m_CurrentWriteFile << "Position_SampleStandDev[y];"; m_CurrentWriteFile << "Position_SampleStandDev[z];"; } if (m_Controls->m_settingQuaternionMean->isChecked()) { m_CurrentWriteFile << "Quaternion_Mean[qx];"; m_CurrentWriteFile << "Quaternion_Mean[qy];"; m_CurrentWriteFile << "Quaternion_Mean[qz];"; m_CurrentWriteFile << "Quaternion_Mean[qr];"; } if (m_Controls->m_settionQuaternionStabw->isChecked()) { m_CurrentWriteFile << "Quaternion_StandDev[qx];"; m_CurrentWriteFile << "Quaternion_StandDev[qy];"; m_CurrentWriteFile << "Quaternion_StandDev[qz];"; m_CurrentWriteFile << "Quaternion_StandDev[qr];"; } if (m_Controls->m_settingPosErrorMean->isChecked()) m_CurrentWriteFile << "PositionError_Mean;"; if (m_Controls->m_settingPosErrorStabw->isChecked()) m_CurrentWriteFile << "PositionError_StandDev;"; if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) m_CurrentWriteFile << "PositionError_SampleStandDev;"; if (m_Controls->m_settingPosErrorRMS->isChecked()) m_CurrentWriteFile << "PositionError_RMS;"; if (m_Controls->m_settingPosErrorMedian->isChecked()) m_CurrentWriteFile << "PositionError_Median;"; if (m_Controls->m_settingPosErrorMinMax->isChecked()) { m_CurrentWriteFile << "PositionError_Max;"; m_CurrentWriteFile << "PositionError_Min;"; } if (m_Controls->m_settingEulerMean->isChecked()) { m_CurrentWriteFile << "Euler_tx;"; m_CurrentWriteFile << "Euler_ty;"; m_CurrentWriteFile << "Euler_tz;"; } if (m_Controls->m_settingEulerRMS->isChecked()) { m_CurrentWriteFile << "EulerErrorRMS (rad);"; m_CurrentWriteFile << "EulerErrorRMS (grad);"; } m_CurrentWriteFile << "\n"; } void QmitkIGTTrackingDataEvaluationView::WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter, std::string dataSetName) { if (myEvaluationFilter->GetNumberOfOutputs() == 0) m_CurrentWriteFile << "Error: no input \n"; else { m_CurrentWriteFile << dataSetName << ";"; m_CurrentWriteFile << myEvaluationFilter->GetNumberOfAnalysedNavigationData(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetNumberOfInvalidSamples(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPercentageOfInvalidSamples(0) << ";"; if (m_Controls->m_settingPosMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[2] << ";"; } if (m_Controls->m_settingPosStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[2] << ";"; } if (m_Controls->m_settingPosSampleStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[2] << ";"; } if (m_Controls->m_settingQuaternionMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).x() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).y() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).z() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).r() << ";"; } if (m_Controls->m_settionQuaternionStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).x() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).y() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).z() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).r() << ";"; } if (m_Controls->m_settingPosErrorMean->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMean(0) << ";"; if (m_Controls->m_settingPosErrorStabw->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorStandardDeviation(0) << ";"; if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorSampleStandardDeviation(0) << ";"; if (m_Controls->m_settingPosErrorRMS->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorRMS(0) << ";"; if (m_Controls->m_settingPosErrorMedian->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMedian(0) << ";"; if (m_Controls->m_settingPosErrorMinMax->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMax(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMin(0) << ";"; } if (m_Controls->m_settingEulerMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[2] << ";"; } if (m_Controls->m_settingEulerRMS->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesRMS(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesRMSDegree(0) << ";"; } m_CurrentWriteFile << "\n"; } } std::vector QmitkIGTTrackingDataEvaluationView::GetMeanOrientationsOfAllData(std::vector allData, bool useSLERP) { std::vector returnValue; for (auto dataSet : allData) { if (useSLERP) returnValue.push_back(GetSLERPAverage(dataSet)); else returnValue.push_back(dataSet->GetQuaternionMean(0)); } return returnValue; } std::vector QmitkIGTTrackingDataEvaluationView::GetAllDataFromUIList() { std::vector EvaluationDataCollection; //start loop and iterate through all files of list: store the evaluation data for (int i = 0; i < m_FilenameVector.size(); i++) { //create navigation data player - mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); + mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //check if the stream is valid and skip file if not /* if (!myPlayer->GetStreamValid()) { MITK_ERROR << "Error in file " << m_FilenameVector.at(i) << ": " << myPlayer->GetErrorMessage() << " ; Skipping file!"; } else */ { //connect pipeline for (int j = 0; j < myPlayer->GetNumberOfOutputs(); j++) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } //update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) { myEvaluationFilter->Update(); } } myEvaluationFilter->SetInput(NULL); myPlayer = NULL; EvaluationDataCollection.push_back(myEvaluationFilter); } return EvaluationDataCollection; } void QmitkIGTTrackingDataEvaluationView::CalculateDifferenceAngles() { //Get all data from UI std::vector EvaluationDataCollection = GetAllDataFromUIList(); //calculation and writing of output data //open output file m_CurrentAngleDifferencesWriteFile.open(std::string((m_Controls->m_OutputFilename->text() + ".angledifferences.csv").toUtf8()).c_str(), std::ios::out); if (m_CurrentAngleDifferencesWriteFile.bad()) { MessageBox("Error: Can't open output file for angle differences calculation!"); return; } //write header WriteDifferenceAnglesHeader(); //compute angle differences QString pos1 = "invalid"; QString pos2 = "invalid"; //now iterate through all evaluation data and calculate the angles for (int i = 0; i < m_FilenameVector.size(); i++) { pos1 = QString::fromStdString(itksys::SystemTools::GetFilenameWithoutLastExtension(m_FilenameVector.at(i))); for (int j = 0; j < m_FilenameVector.size(); j++) { pos2 = QString::fromStdString(itksys::SystemTools::GetFilenameWithoutLastExtension(m_FilenameVector.at(j))); mitk::Quaternion q1; mitk::Quaternion q2; if (m_Controls->m_DifferencesSLERP->isChecked()) { //compute slerp average q1 = GetSLERPAverage(EvaluationDataCollection.at(i)); q2 = GetSLERPAverage(EvaluationDataCollection.at(j)); } else { //compute arithmetic average q1 = EvaluationDataCollection.at(i)->GetQuaternionMean(0); q2 = EvaluationDataCollection.at(j)->GetQuaternionMean(0); } itk::Vector rotationVec; //adapt for Aurora 5D tools: [0,0,1000] rotationVec[0] = 10000; //X rotationVec[1] = 0; //Y rotationVec[2] = 0; //Z double AngleBetweenTwoQuaternions = mitk::StaticIGTHelperFunctions::GetAngleBetweenTwoQuaterions(q1, q2, rotationVec); //write data set WriteDifferenceAnglesDataSet(pos1.toStdString(), pos2.toStdString(), i, j, AngleBetweenTwoQuaternions); } } //close output file m_CurrentAngleDifferencesWriteFile.close(); } void QmitkIGTTrackingDataEvaluationView::WriteDifferenceAnglesHeader() { m_CurrentAngleDifferencesWriteFile << "Name;Idx1;Idx2;Angle [Degree]\n"; } void QmitkIGTTrackingDataEvaluationView::WriteDifferenceAnglesDataSet(std::string pos1, std::string pos2, int idx1, int idx2, double angle) { //double PI = 3.1415926535897932384626433832795; //double angle_degree = angle * 180 / PI; m_CurrentAngleDifferencesWriteFile << "Angle between " << pos1 << " and " << pos2 << ";" << idx1 << ";" << idx2 << ";" << angle << "\n";//<< ";" << angle_degree << "\n"; MITK_INFO << "Angle: " << angle; } std::vector QmitkIGTTrackingDataEvaluationView::GetNavigationDatasFromFile(std::string filename) { std::vector returnValue = std::vector(); std::vector fileContentLineByLine = GetFileContentLineByLine(filename); for (int i = 1; i < fileContentLineByLine.size(); i++) //skip header so start at 1 { returnValue.push_back(GetNavigationDataOutOfOneLine(fileContentLineByLine.at(i))); } return returnValue; } std::vector QmitkIGTTrackingDataEvaluationView::GetFileContentLineByLine(std::string filename) { std::vector readData = std::vector(); //save old locale char * oldLocale; oldLocale = setlocale(LC_ALL, 0); //define own locale std::locale C("C"); setlocale(LC_ALL, "C"); //read file std::ifstream file; file.open(filename.c_str(), std::ios::in); if (file.good()) { //read out file file.seekg(0L, std::ios::beg); // move to begin of file while (!file.eof()) { std::string buffer; std::getline(file, buffer); // read out file line by line if (buffer.size() > 0) readData.push_back(buffer); } } file.close(); //switch back to old locale setlocale(LC_ALL, oldLocale); return readData; } mitk::NavigationData::Pointer QmitkIGTTrackingDataEvaluationView::GetNavigationDataOutOfOneLine(std::string line) { mitk::NavigationData::Pointer returnValue = mitk::NavigationData::New(); QString myLine = QString(line.c_str()); QStringList myLineList = myLine.split(';'); mitk::Point3D position; mitk::Quaternion orientation; double time = myLineList.at(1).toDouble(); bool valid = false; if (myLineList.at(2).toStdString() == "1") valid = true; position[0] = myLineList.at(3).toDouble(); position[1] = myLineList.at(4).toDouble(); position[2] = myLineList.at(5).toDouble(); orientation[0] = myLineList.at(6).toDouble(); orientation[1] = myLineList.at(7).toDouble(); orientation[2] = myLineList.at(8).toDouble(); orientation[3] = myLineList.at(9).toDouble(); //returnValue->SetTimeStamp(time); returnValue->SetDataValid(valid); returnValue->SetPosition(position); returnValue->SetOrientation(orientation); return returnValue; } mitk::Quaternion QmitkIGTTrackingDataEvaluationView::GetSLERPAverage(mitk::NavigationDataEvaluationFilter::Pointer evaluationFilter) { mitk::Quaternion average; //build a vector of quaternions from the evaulation filter (caution always takes the first (0) input of the filter std::vector quaternions = std::vector(); for (int i = 0; i < evaluationFilter->GetNumberOfAnalysedNavigationData(0); i++) { mitk::Quaternion currentq = evaluationFilter->GetLoggedOrientation(i, 0); quaternions.push_back(currentq); } //compute the slerp average using the quaternion averaging class mitk::QuaternionAveraging::Pointer myAverager = mitk::QuaternionAveraging::New(); average = myAverager->CalcAverage(quaternions); return average; } void QmitkIGTTrackingDataEvaluationView::writeToFile(std::string filename, std::vector values) { std::fstream currentFile; currentFile.open(filename.c_str(), std::ios::out); if (currentFile.bad()) { MITK_WARN << "Cannot open file, aborting!"; return; } currentFile << "Description" << ";" << "Error[mm]" << "\n"; for (auto currentError : values) { currentFile << currentError.description << ";" << currentError.distanceError << "\n"; } currentFile.close(); } + +mitk::NavigationDataCSVSequentialPlayer::Pointer QmitkIGTTrackingDataEvaluationView::ConstructNewNavigationDataPlayer() +{ + bool rightHanded = m_Controls->m_RigthHanded->isChecked(); + 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(); + + 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); + return navDataPlayer; +} 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 f308daa9b5..28271da295 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,138 +1,142 @@ /*=================================================================== 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 +#include "mitkNavigationDataCSVSequentialPlayer.h" /*! \brief QmitkIGTTrackingDataEvaluationView \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: static const std::string VIEW_ID; QmitkIGTTrackingDataEvaluationView(); virtual ~QmitkIGTTrackingDataEvaluationView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); protected slots: 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(); /** 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(); protected: Ui::QmitkIGTTrackingDataEvaluationViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; std::vector m_FilenameVector; void MessageBox(std::string s); std::fstream m_CurrentWriteFile; void WriteHeader(); void WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer evaluationFilter, std::string dataSetName); //members for orientation calculation mitk::Point3D m_RefPoint1; mitk::Point3D m_RefPoint2; mitk::Point3D m_RefPoint3; double m_scalingfactor; //scaling factor for visualization, 1 by default //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); void writeToFile(std::string filename, std::vector values); //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); + //help method to sonstruct the NavigationDataCSVSequentialPlayer filled with all the options from the UI + mitk::NavigationDataCSVSequentialPlayer::Pointer ConstructNewNavigationDataPlayer(); + //CSV to XML members std::vector m_CSVtoXMLInputFilenameVector; std::vector m_CSVtoXMLOutputFilenameVector; //returns the number of converted lines int ConvertOneFile(std::string inputFilename, std::string outputFilename); /** @brief calculates the angle in the plane perpendicular to the rotation axis of the two quaterions. */ double GetAngleBetweenTwoQuaterions(mitk::Quaternion a, mitk::Quaternion b); /** @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); /** @brief Stores the mean positions of all evaluated data */ mitk::PointSet::Pointer m_PointSetMeanPositions; /** @return returns the mean orientation of all given data */ std::vector GetMeanOrientationsOfAllData(std::vector allData, bool useSLERP = false); /** @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 e42103eda5..dd6afdbdcd 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,1572 +1,1622 @@ QmitkIGTTrackingDataEvaluationViewControls 0 0 418 955 0 0 QmitkTemplate 1 Evaluation Input File List (recorded NavigationData / *.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: Result CSV Filename: D:/tmp/output.csv Qt::Horizontal 40 20 220 0 200 50 COMPUTE RESULTS PER DATA SET Qt::Horizontal 40 20 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 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 Qt::Horizontal (5) - ROTATION - Evaluation of all data sets: Qt::Horizontal 40 20 220 0 200 50 COMPUTE ROTATION ERRORS Qt::Horizontal 40 20 Qt::Vertical QSizePolicy::Expanding 20 220 Settings 0 -110 365 934 General General Options: Scaling Factor for Visualization: Qt::Horizontal 38 20 1.000000000000000 Number of samples to analyze: Qt::Horizontal 60 20 1000000 150 Tracking Volume: Standard Volume (10 X 9 Positions) true Small Volume (3 X 4 Positions) Type of coordinate System: Left handed Right handed true File Options: 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 Position and Orientation Options: Y - + + + 4 + + Z - + + + 5 + + X - + + + 3 + + Coordinate: Colum number: Use Quaternions for Orientation true Qr - + + + 8 + + Qy - + + + 9 + + - + + + 7 + + - + + + 6 + + Qx Qz Quaternion component: Column number: Use Euler Angles for Orientation Elevation - + + + -1 + + Roll - + + + -1 + + - + + + -1 + + Azimuth Angle: Column number: Unity for Euler Angles: - + - Degrees + Radiants true - + - Radiants + Degrees + + + false GeneralOptions GeneralOptions PositionAndOrientationOptions m_FileOptionsBox 0 0 396 811 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 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/mitkNavigationDataCSVSequentialPlayer.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.cpp index d03d7afcf1..1f66ed8b5b 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,325 +1,346 @@ /*=================================================================== 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 "mitkNavigationDataCSVSequentialPlayer.h" #include #include #include #include #include mitk::NavigationDataCSVSequentialPlayer::NavigationDataCSVSequentialPlayer() : mitk::NavigationDataPlayerBase() { m_NavigationDatas = std::vector(); m_CurrentPos = 0; m_Filetype = mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV; + } mitk::NavigationDataCSVSequentialPlayer::~NavigationDataCSVSequentialPlayer() { } bool mitk::NavigationDataCSVSequentialPlayer::IsAtEnd() { if (m_CurrentPos >= m_NavigationDatas.size()) return true; else return false; } void mitk::NavigationDataCSVSequentialPlayer:: SetFileName(const std::string& fileName) { this->SetNumberOfOutputs(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 > 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); for (int i = 1; (i < fileContentLineByLine.size()); i++) //skip header so start at 1 { returnValue.push_back(GetNavigationDataOutOfOneLine(fileContentLineByLine.at(i))); } 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; //int count2 = 0; while (!file.eof()) { std::string buffer; std::getline(file, buffer); // read out file line by line //for Polhemus tracker: just take every 24th sample if (count == 0) if (buffer.size() > 0) { //MITK_INFO << "read(" << count2 << "): " << buffer.substr(0,30); //count2++; readData.push_back(buffer); } count++; if (count == 24) 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(','); mitk::Point3D position; mitk::Quaternion orientation; bool valid = false; double time; //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() < 10) { MITK_ERROR << "Error: cannot read line: only found " << myLineList.size() << " fields. Last field: " << myLineList.at(myLineList.size() - 1).toStdString(); returnValue = GetEmptyNavigationData(); return returnValue; } 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(); 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 */ //Variant for the polhemus measurements in August 2016 //(.csv files from the polhemus software) //Important: due to the documentation, Polhemus uses //a left handed coordinate system while MITK uses a //right handed. A conversion is not included in this //read in method yet, because this is not required //for this special rotation evaliation (no matter //if it turns 11.25 degree to left or right). For //other usage this might be important to adapt! position[0] = myLineList.at(4).toDouble(); position[1] = myLineList.at(5).toDouble(); position[2] = myLineList.at(6).toDouble(); //Doesn't work... don't know how to interpret the //Polhemus quaternions. They are seem to different //different to other quaternions (NDI, Claron, etc.) //http://www.mathepedia.de/Quaternionen.aspx /* double qr = myLineList.at(7).toDouble(); double qx = myLineList.at(8).toDouble(); double qy = myLineList.at(9).toDouble(); double qz = myLineList.at(10).toDouble(); vnl_quaternion newQuat(qx, qy, qz, qr); orientation = newQuat; orientation.normalize();*/ /* orientation[3] = qr; //qr orientation[0] = qx; //qx orientation[1] = qy; //qy orientation[2] = qz; //qz orientation.normalize(); */ //Using Euler angles instead does work //azimuth: rotation about Z axis of reference frame double azimuthAngle = (myLineList.at(11).toDouble() / 180 * M_PI); //elevation: rotation about Y' axis (transformed Y axis of sonsor frame) double elevationAngle = (myLineList.at(12).toDouble() / 180 * M_PI); //roll: rotation about X axis of sensor frame double rollAngle = (myLineList.at(13).toDouble() / 180 * M_PI); vnl_quaternion eulerQuat(rollAngle, elevationAngle, azimuthAngle); orientation = eulerQuat; /* //code block for conversion from axis-angular representation double rotationAngle = myLineList.at(7).toDouble(); double rotationAxis[3]; rotationAxis[0] = myLineList.at(8).toDouble(); rotationAxis[1] = myLineList.at(9).toDouble(); rotationAxis[2] = myLineList.at(10).toDouble(); double betragRotationAxis = sqrt(pow(rotationAxis[0], 2) + pow(rotationAxis[1], 2) + pow(rotationAxis[2], 2)); rotationAngle /= betragRotationAxis; rotationAxis[0] /= betragRotationAxis; rotationAxis[1] /= betragRotationAxis; rotationAxis[2] /= betragRotationAxis; double qr = cos(rotationAngle/2); double qx = rotationAxis[0] * sin(rotationAngle/2); double qy = rotationAxis[1] * sin(rotationAngle/2); double qz = rotationAxis[1] * sin(rotationAngle/2); */ /* //code block for conversion from left-handed to right-handed mitk::Quaternion linksZuRechtsdrehend; double rotationAngle = -M_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; } time = myLineList.at(2).toDouble(); 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->SetTimeStamp(time); //DOES NOT WORK ANY MORE... CANNOT SET TIME TO itk::timestamp CLASS returnValue->SetDataValid(valid); returnValue->SetPosition(position); returnValue->SetOrientation(orientation); return returnValue; } +void mitk::NavigationDataCSVSequentialPlayer::SetOptions(bool rightHanded, std::string separatorSign, 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) +{ + 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; +} 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 11ba570b96..7e69b3d74a 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,114 +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 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); + NavigationDataCSVSequentialPlayer(); /** * \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 + * @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) + * @param elevatino number of the colum in the .csv file for Elevation (Euler Angles) + * @param roll number of the colum in the .csv file for Roll (Euler Angles) + * @param eulerInRadiants true if the Euler Angles in the .csv file are in radiants, false if they are in degrees + */ + void SetOptions(bool rightHanded, std::string 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); + /** * \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); 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 + std::string 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 }; } // namespace mitk #endif /* MITKNavigationDataCSVSequentialPlayer_H_HEADER_INCLUDED_ */