diff --git a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/files.cmake b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/files.cmake index 24fb49620e..6ae8c9f888 100644 --- a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/files.cmake +++ b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/files.cmake @@ -1,37 +1,41 @@ SET(SRC_CPP_FILES ) SET(INTERNAL_CPP_FILES QmitkIGTTrackingSemiAutomaticMeasurementView.cpp + QmitkIGTTrackingDataEvaluationView.cpp mitkPluginActivator.cpp ) SET(UI_FILES src/internal/QmitkIGTTrackingSemiAutomaticMeasurementViewControls.ui + src/internal/QmitkIGTTrackingDataEvaluationViewControls.ui ) SET(MOC_H_FILES src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.h + src/internal/QmitkIGTTrackingDataEvaluationView.h src/internal/mitkPluginActivator.h ) SET(CACHED_RESOURCE_FILES resources/icon.xpm + resources/icon-eval.xpm plugin.xml ) SET(QRC_FILES resources/QmitkIGTTrackingSemiAutomaticMeasurementView.qrc ) SET(CPP_FILES) foreach(file ${SRC_CPP_FILES}) SET(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) SET(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/plugin.xml b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/plugin.xml index 7d39be1758..a322bed111 100644 --- a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/plugin.xml +++ b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/plugin.xml @@ -1,11 +1,18 @@ + + + + \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/resources/QmitkIGTTrackingSemiAutomaticMeasurementView.qrc b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/resources/QmitkIGTTrackingSemiAutomaticMeasurementView.qrc index a6ab359bf6..4222814e5c 100644 --- a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/resources/QmitkIGTTrackingSemiAutomaticMeasurementView.qrc +++ b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/resources/QmitkIGTTrackingSemiAutomaticMeasurementView.qrc @@ -1,5 +1,8 @@ icon.xpm + + icon-eval.xpm + diff --git a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/resources/icon-eval.xpm b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/resources/icon-eval.xpm new file mode 100644 index 0000000000..dd04f91df1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/resources/icon-eval.xpm @@ -0,0 +1,107 @@ +/* XPM */ +static char * icon_xpm[] = { +"100 100 4 1", +" c None", +". c #FFFFFF", +"+ c #000000", +"@ c #22B14C", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +".............................++++...................................................................", +"...........................++++++...................................................................", +"..........................+++++++...................................................................", +".........................+++.++++...................................................................", +".........................++..++++...................................................................", +".............................++++...................................................................", +".............................++++...........................+++++++.................................", +".............................++++.........................++++++++++................................", +".............................++++.........................+++++++++++...............................", +".............................++++.........................++....+++++...............................", +".............................++++................................++++...............................", +".............................++++................................++++...............................", +".............................++++...............................++++................................", +".............................++++...........................+++++++.................................", +".............................++++...........................+++++++.................................", +".........................++++++++++++.......................+++++++++...............................", +".........................++++++++++++............................+++++..............................", +".........................++++++++++++.............................++++..............................", +"..................................................................++++..............................", +"..................................................................++++..............................", +"..........................................................++.....+++++..............................", +"..........................................................+++++++++++...............................", +"..........................................................++++++++++................................", +"............................................................++++++..................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"..........................................++++++....................................................", +"........................................++++++++++..................................................", +"........................................++++++++++..................................................", +"........................................++....+++++.................................................", +"...............................................++++.................................................", +"...............................................++++.................................................", +"...............................................++++.................................................", +"..............................................++++..................................................", +"..............................................++++..................................................", +".............................................++++...................................................", +"............................................++++....................................................", +"...........................................++++.....................................................", +"..........................................++++......................................................", +".........................................++++.......................................................", +".........................................+++........................................................", +"........................................++++++++++++................................................", +"........................................++++++++++++................................................", +"........................................++++++++++++................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................+++.............................................", +"...................................................+++++++..........................................", +"...................................................++++++++++.......................................", +"...................................................++++++++++++.....................................", +"...................................................+++++++++++++++..................................", +"........................+++++++++++++++++++++++++++++++++++++++++++++...............................", +".......................+++++++++++++++++++++++++++++++++@++++++++++++++.............................", +".......................+++++++++++++++++++++++++++++++++@@@@++++++++++++++..........................", +".......................+++++++++++++++++++++++++++++++++@@@@@@+++++++++++++++.......................", +".......................++++++++++++++++++++++++++++++++@@@@@@@@@@++++++++++++++.....................", +".......................+++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++++++++++++++..................", +".......................+++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++++++++++.................", +".......................+++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++++++++................", +".......................+++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++++++++................", +".......................+++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++++++++++.................", +".......................+++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++++++++++++++..................", +".......................++++++++++++++++++++++++++++++++@@@@@@@@@@++++++++++++++.....................", +".......................+++++++++++++++++++++++++++++++++@@@@@@+++++++++++++++.......................", +".......................+++++++++++++++++++++++++++++++++@@@@++++++++++++++..........................", +".......................+++++++++++++++++++++++++++++++++@++++++++++++++.............................", +"........................+++++++++++++++++++++++++++++++++++++++++++++...............................", +"...................................................+++++++++++++++..................................", +"...................................................++++++++++++.....................................", +"...................................................++++++++++.......................................", +"...................................................+++++++..........................................", +"....................................................+++.............................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"....................................................................................................", +"...................................................................................................."}; diff --git a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/src/internal/QmitkIGTTrackingDataEvaluationView.cpp b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/src/internal/QmitkIGTTrackingDataEvaluationView.cpp new file mode 100644 index 0000000000..4ccbee7cc6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/src/internal/QmitkIGTTrackingDataEvaluationView.cpp @@ -0,0 +1,1107 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +// Blueberry +#include +#include + +// Qmitk +#include "QmitkIGTTrackingDataEvaluationView.h" +#include "QmitkStdMultiWidget.h" + +// Qt +#include +#include + +// MITK +#include "mitkNavigationDataCSVSequentialPlayer.h" +#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()) ); + } +} + +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; iSetFiletype(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; jGetNumberOfOutputs(); j++) {myEvaluationFilter->SetInput(j,myPlayer->GetOutput(j));} + + + //update pipline until number of samlples is reached + for (int j=0; jm_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; iSetFiletype(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 filename + QString filename = QFileDialog::getOpenFileName(NULL,tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); + if (filename.isNull()) return; + + /* + //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; im_FileList);} + +} + +void QmitkIGTTrackingDataEvaluationView::OnLoadFileList() + { + m_FilenameVector = std::vector(); + m_FilenameVector.clear(); + OnAddToCurrentList(); + } + +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; + } + +//write output file header +WriteHeader(); + +//start loop and iterate through all files of list +for(int i=0; iSetFiletype(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; jGetNumberOfOutputs(); j++) {myEvaluationFilter->SetInput(j,myPlayer->GetOutput(j));} + + + + //update pipline until number of samlples is reached + for (int j=0; jm_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"; + } + + //write result to output file + WriteDataSet(myEvaluationFilter,m_FilenameVector.at(i)); + + } + +//close output file +m_CurrentWriteFile.close(); + +//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; iSetFiletype(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; jm_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; iSetFiletype(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; jGetNumberOfOutputs(); j++) {myEvaluationFilter->SetInput(j,myPlayer->GetOutput(j));} + + //update pipline until number of samlples is reached + for (int j=0; jm_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); + this->GetDataStorage()->Add(newNode); + } + +void QmitkIGTTrackingDataEvaluationView::OnGenerateRotationLines() + { + m_scalingfactor = m_Controls->m_ScalingFactor->value(); + + //start loop and iterate through all files of list + for(int i=0; iSetFiletype(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; jGetNumberOfOutputs(); j++) {myEvaluationFilter->SetInput(j,myPlayer->GetOutput(j));} + + //update pipline until number of samlples is reached + for (int j=0; jm_NumberOfSamples->value(); j++) + { + myEvaluationFilter->Update(); + if (!myPlayer->GetStreamValid()) + { + MITK_ERROR << "Error in file " << m_FilenameVector.at(i) << ": " << myPlayer->GetErrorMessage() << " ; Skipping file!"; + continue; + } + } + + if (!myPlayer->GetStreamValid()) 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; im_PointNumber1->value(); i++) + { + for (int j=0; jm_PointNumber2->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); + 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::NavigationDataRecorder::Pointer myRecorder = mitk::NavigationDataRecorder::New(); + myRecorder->SetFileName(outputFilename.c_str()); + mitk::NavigationData::Pointer input = mitk::NavigationData::New(); + if(m_Controls->m_ConvertCSV->isChecked()) myRecorder->SetOutputFormat(mitk::NavigationDataRecorder::csv); + myRecorder->AddNavigationData(input); + myRecorder->StartRecording(); + for (int i=0; iGraft(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"; + + } + + + } + +void QmitkIGTTrackingDataEvaluationView::CalculateDifferenceAngles() + { + + std::vector EvaluationDataCollection; + + //start loop and iterate through all files of list: store the evaluation data + for(int i=0; iSetFiletype(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; jGetNumberOfOutputs(); j++) {myEvaluationFilter->SetInput(j,myPlayer->GetOutput(j));} + //update pipline until number of samlples is reached + for (int j=0; jm_NumberOfSamples->value(); j++) {myEvaluationFilter->Update();} + } + + myEvaluationFilter->SetInput(NULL); + myPlayer=NULL; + EvaluationDataCollection.push_back(myEvaluationFilter); + } + + //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; im_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); + } + + + double AngleBetweenTwoQuaternions = GetAngleBetweenTwoQuaterions(q1,q2); + + //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 [-PI..+PI]; 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 / PI) * 180; + m_CurrentAngleDifferencesWriteFile << "Angle between " << pos1 << " and " << pos2 << ";" << idx1 << ";" << idx2 << ";" << angle << ";" << angle_degree << "\n"; + } + +double QmitkIGTTrackingDataEvaluationView::GetAngleBetweenTwoQuaterions(mitk::Quaternion a, mitk::Quaternion b) + { + double returnValue; + + /* + //another variant + mitk::Quaternion combinedRotation = b * a; + + itk::Vector pt1; //caution 5D-Tools: Vector must lie in the YZ-plane for a correct result. + pt1[0] = 0.0; + pt1[1] = 0.0; + pt1[2] = 100000.0; + + itk::Matrix rotMatrixA; + for(int i=0; i<3; i++) for(int j=0; j<3; j++) rotMatrixA[i][j] = combinedRotation.rotation_matrix_transpose().transpose()[i][j]; + itk::Vector pt2 = rotMatrixA*pt1; + + //compute angle between the two vectors + returnValue = (pt1[0]*pt2[0]+pt1[1]*pt2[1]+pt1[2]*pt2[2]) / ( sqrt(pow(pt1[0],2)+pow(pt1[1],2)+pow(pt1[2],2)) * sqrt(pow(pt2[0],2)+pow(pt2[1],2)+pow(pt2[2],2))); + returnValue = acos(returnValue); + + */ + + //variant with double precision + + itk::Vector point; //caution 5D-Tools: Vector must lie in the YZ-plane for a correct result. + //TODO: welchen Vektor hier nehmen? + point[0] = 0; + point[1] = 100000.0; + point[2] = 100000.0; + + //OB DAS HILFT? + a.normalize(); + b.normalize(); + + itk::Matrix rotMatrixA; + for(int i=0; i<3; i++) for(int j=0; j<3; j++) rotMatrixA[i][j] = a.rotation_matrix_transpose().transpose()[i][j]; + + itk::Matrix rotMatrixB; + for(int i=0; i<3; i++) for(int j=0; j<3; j++) rotMatrixB[i][j] = b.rotation_matrix_transpose().transpose()[i][j]; + + itk::Vector pt1 = rotMatrixA * point; + itk::Vector pt2 = rotMatrixB * point; + + returnValue = (pt1[0]*pt2[0]+pt1[1]*pt2[1]+pt1[2]*pt2[2]) / ( sqrt(pow(pt1[0],2.0)+pow(pt1[1],2.0)+pow(pt1[2],2.0)) * sqrt(pow(pt2[0],2.0)+pow(pt2[1],2.0)+pow(pt2[2],2.0))); + returnValue = acos(returnValue); + + + /* same code with float precision: + mitk::Point3D point; + mitk::FillVector3D(point,0,0,100); //caution 5D-Tools: Vector must lie in the YZ-plane for a correct result. + vnl_vector pt1 = a.rotate(point.Get_vnl_vector()); + vnl_vector pt2 = b.rotate(point.Get_vnl_vector()); + + //compute angle between the two vectors + returnValue = (pt1[0]*pt2[0]+pt1[1]*pt2[1]+pt1[2]*pt2[2]) / ( sqrt(pow(pt1[0],2)+pow(pt1[1],2)+pow(pt1[2],2)) * sqrt(pow(pt2[0],2)+pow(pt2[1],2)+pow(pt2[2],2))); + returnValue = acos(returnValue); + //angle(pt1,pt2); + */ + + + return returnValue; + } + +std::vector QmitkIGTTrackingDataEvaluationView::GetNavigationDatasFromFile(std::string filename) +{ +std::vector returnValue = std::vector(); +std::vector fileContentLineByLine = GetFileContentLineByLine(filename); +for(int i=1; i 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; iGetNumberOfAnalysedNavigationData(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; + +} diff --git a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/src/internal/QmitkIGTTrackingDataEvaluationView.h b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/src/internal/QmitkIGTTrackingDataEvaluationView.h new file mode 100644 index 0000000000..a928c578b3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/src/internal/QmitkIGTTrackingDataEvaluationView.h @@ -0,0 +1,125 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef QmitkIGTTrackingDataEvaluationView_h +#define QmitkIGTTrackingDataEvaluationView_h + +#include + +#include + +#include "ui_QmitkIGTTrackingDataEvaluationViewControls.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. + + \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 OnGeneratePointSet(); + void OnGeneratePointSetsOfSinglePositions(); + void OnGenerateRotationLines(); + void OnGenerateGroundTruthPointSet(); + void OnConvertCSVtoXMLFile(); + void OnCSVtoXMLLoadInputList(); + void OnCSVtoXMLLoadOutputList(); + + /** 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); + + //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); + + //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); +}; + + + +#endif // _QMITKIGTTRACKINGDATAEVALUATIONVIEW_H_INCLUDED + diff --git a/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/src/internal/QmitkIGTTrackingDataEvaluationViewControls.ui b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/src/internal/QmitkIGTTrackingDataEvaluationViewControls.ui new file mode 100644 index 0000000000..9095e6a5af --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igttrackingsemiautomaticmeasurement/src/internal/QmitkIGTTrackingDataEvaluationViewControls.ui @@ -0,0 +1,941 @@ + + + QmitkIGTTrackingDataEvaluationViewControls + + + + 0 + 0 + 378 + 955 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + 0 + + + + Evaluation + + + + + + Input File List (recorded NavigationData / *.csv): + + + + + + + + + + + + Add Path: + + + + + + + D:/Experimente/ + + + + + + + + + <!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> + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 110 + 0 + + + + Load New List + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 110 + 0 + + + + Add To Current List + + + + + + + + + + + Number of samples to analyze: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 1000000 + + + 150 + + + + + + + + + + + Result CSV Filename: + + + + + + + D:/Experimente/output.csv + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + START EVALUATION + + + + + + + + + Qt::Horizontal + + + + + + + Visualization Tools: + + + + + + + Generate PointSet of Mean Positions + + + + + + + Generate PointSets of Single Positions + + + + + + + Generate Lines for Rotation + + + + + + + + + Prefix for Data Nodes: + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 220 + + + + + + + + + Settings + + + + + + Output Settings + + + + + + <!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; text-decoration: underline;">Position</span></p></body></html> + + + + + + + Mean (x,y,z) + + + + + + + Standard Deviation (x,y,z) + + + + + + + Sample Standard Deviation (x,y,z) + + + + + + + <!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; text-decoration: underline;">Orientation</span></p></body></html> + + + + + + + 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) + + + + + + + <!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; text-decoration: underline;">Position Error</span></p></body></html> + + + + + + + Mean + + + + + + + Standard Deviation + + + + + + + Sample Standard Deviation + + + + + + + RMS + + + + + + + Median + + + + + + + Min/Max + + + + + + + <!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; text-decoration: underline;">Orientation Error</span></p></body></html> + + + + + + + Euler RMS + + + + + + + + + + + + Scaling Factor for Visualization: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 1.000000000000000 + + + + + + + + + Qt::Vertical + + + + 20 + 344 + + + + + + + + + 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 + + + + + + + + + + + + + +