diff --git a/Examples/Plugins/org.mitk.example.gui.pcaexample/src/internal/PCAExample.cpp b/Examples/Plugins/org.mitk.example.gui.pcaexample/src/internal/PCAExample.cpp index de72b6f722..f1f35e83a3 100644 --- a/Examples/Plugins/org.mitk.example.gui.pcaexample/src/internal/PCAExample.cpp +++ b/Examples/Plugins/org.mitk.example.gui.pcaexample/src/internal/PCAExample.cpp @@ -1,167 +1,167 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include // Qmitk #include "PCAExample.h" // Qt #include // mitk image #include const std::string PCAExample::VIEW_ID = "org.mitk.views.pcaexample"; void PCAExample::SetFocus() { m_Controls.buttonPerformImageProcessing->setFocus(); } void PCAExample::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect(m_Controls.buttonPerformImageProcessing, SIGNAL(clicked()), this, SLOT(BtnPerfomPCAClicked())); //initialize point set widget and point set node mitk::DataNode::Pointer PointSetNode = mitk::DataNode::New(); PointSetNode->SetName("PCA Example Pointset"); mitk::PointSet::Pointer newPtSet = mitk::PointSet::New(); PointSetNode->SetData(newPtSet); m_Controls.m_pointSetWidget->SetPointSetNode(PointSetNode); this->GetDataStorage()->Add(PointSetNode); } PCAExample::PCAExample() { } PCAExample::~PCAExample() { //clean up mitk::DataNode::Pointer ptSetNode = m_Controls.m_pointSetWidget->GetPointSetNode(); m_Controls.m_pointSetWidget->SetPointSetNode(nullptr); this->GetDataStorage()->Remove(ptSetNode); this->GetDataStorage()->Remove(m_Axis1Node); this->GetDataStorage()->Remove(m_Axis2Node); this->GetDataStorage()->Remove(m_Axis3Node); } void PCAExample::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList &nodes) { // iterate all selected objects, adjust warning visibility foreach (mitk::DataNode::Pointer node, nodes) { if (node.IsNotNull() && dynamic_cast(node->GetData())) { m_Controls.buttonPerformImageProcessing->setEnabled(true); return; } } } void PCAExample::BtnPerfomPCAClicked() { std::vector eigenVectors; std::vector eigenValues; mitk::Vector3D mean; bool success = comutePCA(m_Controls.m_pointSetWidget->GetPointSet(), eigenVectors, eigenValues, mean); this->showEigenvectors(eigenVectors, eigenValues, mean); MITK_INFO << "PCA: " << success; } bool PCAExample::comutePCA(mitk::PointSet::Pointer input, std::vector &eigenVectors, std::vector &eigenValues, mitk::Vector3D &pointsMean) { //Step 1: Construct data matrix vnl_matrix dataMatrix(3, input->GetSize(), 0.0); int size = input->GetSize(); for (int i=0; iGetPoint(i)[0]; dataMatrix[1][i] = input->GetPoint(i)[1]; dataMatrix[2][i] = input->GetPoint(i)[2]; } //Step 2: Remove average for each row (Mittelwertbefreiung) mitk::Vector3D mean; for (int i = 0; i < size; i++) { mean += mitk::Vector3D(dataMatrix.get_column(i)); } mean /= size; for (int i = 0; i covMatrix = (1.0 / (size - 1.0)) * dataMatrix * dataMatrix.transpose(); //Step 4: Singular value composition vnl_svd svd(covMatrix); //Store results and print them to the console MITK_INFO << "DataMatrix: " << "\n" << dataMatrix; MITK_INFO << "CovMatrix: " << "\n" << covMatrix; for (int i = 0; i < 3; i++) { eigenVectors.push_back(svd.U().get_column(i)); eigenValues.push_back(sqrt(svd.W(i))); MITK_INFO << "Eigenvector " << i << ": " << eigenVectors.at(i); MITK_INFO << "Eigenvalue " << i << ": " << eigenValues.at(i); } //Compute center of points for (int i = 0; i < size; i++) { pointsMean += input->GetPoint(i).GetVectorFromOrigin(); } pointsMean /= size; return true; } void PCAExample::showEigenvectors(std::vector eigenVectors, std::vector eigenValues, mitk::Vector3D center) { m_Axis1Node = mitk::DataNode::New(); m_Axis1Node->SetName("Eigenvector 1"); mitk::PointSet::Pointer axis1 = mitk::PointSet::New(); - axis1->InsertPoint(0, center); - axis1->InsertPoint(1, (center + eigenVectors.at(0)*eigenValues.at(0))); + axis1->InsertPoint(0, mitk::Point3D(center)); + axis1->InsertPoint(1, mitk::Point3D(center + eigenVectors.at(0)*eigenValues.at(0))); m_Axis1Node->SetData(axis1); m_Axis1Node->SetBoolProperty("show contour", true); m_Axis1Node->SetColor(1, 0, 0); this->GetDataStorage()->Add(m_Axis1Node); m_Axis2Node = mitk::DataNode::New(); m_Axis2Node->SetName("Eigenvector 2"); mitk::PointSet::Pointer axis2 = mitk::PointSet::New(); - axis2->InsertPoint(0, center); - axis2->InsertPoint(1, (center + eigenVectors.at(1)*eigenValues.at(1))); + axis2->InsertPoint(0, mitk::Point3D(center)); + axis2->InsertPoint(1, mitk::Point3D(center + eigenVectors.at(1)*eigenValues.at(1))); m_Axis2Node->SetData(axis2); m_Axis2Node->SetBoolProperty("show contour", true); m_Axis2Node->SetColor(1, 0, 0); this->GetDataStorage()->Add(m_Axis2Node); m_Axis3Node = mitk::DataNode::New(); m_Axis3Node->SetName("Eigenvector 3"); mitk::PointSet::Pointer axis3 = mitk::PointSet::New(); - axis3->InsertPoint(0, center); - axis3->InsertPoint(1, (center + eigenVectors.at(2)*eigenValues.at(2))); + axis3->InsertPoint(0, mitk::Point3D(center)); + axis3->InsertPoint(1, mitk::Point3D(center + eigenVectors.at(2)*eigenValues.at(2))); m_Axis3Node->SetData(axis3); m_Axis3Node->SetBoolProperty("show contour", true); m_Axis3Node->SetColor(1, 0, 0); this->GetDataStorage()->Add(m_Axis3Node); } diff --git a/Modules/IGT/Testing/mitkNavigationDataReferenceTransformFilterTest.cpp b/Modules/IGT/Testing/mitkNavigationDataReferenceTransformFilterTest.cpp index f76ed9bae0..3c557e6186 100644 --- a/Modules/IGT/Testing/mitkNavigationDataReferenceTransformFilterTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataReferenceTransformFilterTest.cpp @@ -1,223 +1,223 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkNavigationDataReferenceTransformFilter.h" #include "mitkNavigationData.h" #include "mitkTestingMacros.h" #include #include /**Documentation * test for the class "NavigationDataReferenceTransformFilter". */ int mitkNavigationDataReferenceTransformFilterTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationDataReferenceTransformFilter") // let's create an object of our class mitk::NavigationDataReferenceTransformFilter::Pointer myFilter = mitk::NavigationDataReferenceTransformFilter::New(); // first test: did this work? // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since // it makes no sense to continue without an object. MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(),"Testing instantiation"); /*create helper objects: positions of the ND sources*/ mitk::Point3D sourcePos1,sourcePos2, sourcePos3, targetPos1, targetPos2, targetPos3; mitk::FillVector3D(sourcePos1, 11.1, 11.1, 11.1); mitk::FillVector3D(sourcePos2, 22.2, 22.2, 22.2); mitk::FillVector3D(sourcePos3, 33.3, 33.3, 33.3); mitk::FillVector3D(targetPos1, -1.1, -2.2, -3.3); mitk::FillVector3D(targetPos2, -4.4, -5.5, -6.6); mitk::FillVector3D(targetPos3, -7.7, -8.8, -9.9); /*create helper objects: orientations of the ND sources*/ mitk::NavigationData::OrientationType sourceOri1(0.1, 0.1, 0.1, 0.1); mitk::NavigationData::OrientationType sourceOri2(0.2, 0.2, 0.2, 0.2); mitk::NavigationData::OrientationType sourceOri3(0.3, 0.3, 0.3, 0.3); mitk::NavigationData::OrientationType targetOri1(0.4, 0.4, 0.4, 0.4); mitk::NavigationData::OrientationType targetOri2(0.5, 0.5, 0.5, 0.5); mitk::NavigationData::OrientationType targetOri3(0.6, 0.6, 0.6, 0.6); /*create helper objects: ND position accurancy and validity bool*/ mitk::ScalarType initialError(0.0); bool initialValid(true); /*create helper objects: NDs for the source and target NDs*/ mitk::NavigationData::Pointer snd1 = mitk::NavigationData::New(); snd1->SetPosition(sourcePos1); snd1->SetOrientation(sourceOri1); snd1->SetPositionAccuracy(initialError); snd1->SetDataValid(initialValid); mitk::NavigationData::Pointer snd2 = mitk::NavigationData::New(); snd2->SetPosition(sourcePos2); snd2->SetOrientation(sourceOri2); snd2->SetPositionAccuracy(initialError); snd2->SetDataValid(initialValid); mitk::NavigationData::Pointer snd3 = mitk::NavigationData::New(); snd3->SetPosition(sourcePos3); snd3->SetOrientation(sourceOri3); snd3->SetPositionAccuracy(initialError); snd3->SetDataValid(initialValid); mitk::NavigationData::Pointer tnd1 = mitk::NavigationData::New(); tnd1->SetPosition(targetPos1); tnd1->SetOrientation(targetOri1); tnd1->SetPositionAccuracy(initialError); tnd1->SetDataValid(initialValid); mitk::NavigationData::Pointer tnd2 = mitk::NavigationData::New(); tnd2->SetPosition(targetPos2); tnd2->SetOrientation(targetOri2); tnd2->SetPositionAccuracy(initialError); tnd2->SetDataValid(initialValid); mitk::NavigationData::Pointer tnd3 = mitk::NavigationData::New(); tnd3->SetPosition(targetPos3); tnd3->SetOrientation(targetOri3); tnd3->SetPositionAccuracy(initialError); tnd3->SetDataValid(initialValid); std::vector emptySourceNDs; std::vector oneSourceNDs; oneSourceNDs.push_back(snd1); std::vector twoSourceNDs; twoSourceNDs.push_back(snd1); twoSourceNDs.push_back(snd2); std::vector threeSourceNDs; threeSourceNDs.push_back(snd1); threeSourceNDs.push_back(snd2); threeSourceNDs.push_back(snd3); std::vector emptyTargetNDs; std::vector oneTargetNDs; oneTargetNDs.push_back(tnd1); std::vector twoTargetNDs; twoTargetNDs.push_back(tnd1); twoTargetNDs.push_back(tnd2); std::vector threeTargetNDs; threeTargetNDs.push_back(tnd1); threeTargetNDs.push_back(tnd2); threeTargetNDs.push_back(tnd3); // ------------------ setting no NDs ------------------ myFilter->SetSourceNavigationDatas(emptySourceNDs); MITK_TEST_CONDITION_REQUIRED(myFilter->GetSourceLandmarks()->IsEmpty() == true, "Testing behaviour if setting no source NDs"); myFilter->SetSourceNavigationDatas(emptyTargetNDs); MITK_TEST_CONDITION_REQUIRED(myFilter->GetTargetLandmarks()->IsEmpty() == true, "Testing behaviour if setting no target NDs"); // ------------------ setting one ND ------------------ myFilter->SetSourceNavigationDatas(oneSourceNDs); MITK_TEST_CONDITION_REQUIRED(myFilter->GetSourceLandmarks()->GetSize() == 3, "Testing if 3 source points are generated from one source ND"); myFilter->SetTargetNavigationDatas(oneTargetNDs); MITK_TEST_CONDITION_REQUIRED(myFilter->GetTargetLandmarks()->GetSize() == 3, "Testing if 3 target points are generated from one target ND"); // ------------------ setting two NDs ------------------ myFilter->SetSourceNavigationDatas(twoSourceNDs); MITK_TEST_CONDITION_REQUIRED(myFilter->GetSourceLandmarks()->GetSize() == 6, "Testing if 6 source points are generated from two source NDs"); myFilter->SetTargetNavigationDatas(twoTargetNDs); MITK_TEST_CONDITION_REQUIRED(myFilter->GetTargetLandmarks()->GetSize() == 6, "Testing if 6 target points are generated from two target NDs"); // ------------------ setting three NDs ------------------ myFilter->SetSourceNavigationDatas(threeSourceNDs); MITK_TEST_CONDITION_REQUIRED(myFilter->GetSourceLandmarks()->GetSize() == 3, "Testing if 3 source NDs are passed to 3 source points"); myFilter->SetTargetNavigationDatas(threeTargetNDs); MITK_TEST_CONDITION_REQUIRED(myFilter->GetTargetLandmarks()->GetSize() == 3, "Testing if 3 target NDs are passed to 3 target points"); // ------------------ setting different number of NDs for source and target ------------------ bool firstInitialize = myFilter->InitializeTransform(); myFilter->SetTargetNavigationDatas(twoTargetNDs); MITK_TEST_CONDITION_REQUIRED((firstInitialize == true && myFilter->InitializeTransform() == false), "Testing if initialization is denied, if different number of source and target NDs are set"); // ------------------ reinit of this filter ------------------ bool sourcePointsSet = myFilter->GetSourceLandmarks()->GetSize() > 0; bool targetPointsSet = myFilter->GetTargetLandmarks()->GetSize() > 0; MITK_TEST_CONDITION_REQUIRED(sourcePointsSet && targetPointsSet, "Testing if there are source and target landmarks set in the superclass"); myFilter->ReinitFilter(); bool sourcePointsCleared = myFilter->GetSourceLandmarks()->GetSize() == 0; bool targetPointsCleared = myFilter->GetTargetLandmarks()->GetSize() == 0; MITK_TEST_CONDITION_REQUIRED(sourcePointsCleared && targetPointsCleared, "Testing if reinit of filter was successful"); // ------------------ testing the point generation ------------------ myFilter->SetSourceNavigationDatas(oneSourceNDs); // set the ND with sourcePos1 and sourceOri1 for that the points will be generated itk::QuaternionRigidTransform::Pointer quaternionTransform = itk::QuaternionRigidTransform::New(); vnl_quaternion const vnlQuatIn(sourceOri1.x(), sourceOri1.y(), sourceOri1.z(), sourceOri1.r()); quaternionTransform->SetRotation(vnlQuatIn); mitk::Point3D pointA; mitk::Point3D pointB; mitk::Point3D pointC; //initializing three points with position(0|0|0) pointA.Fill(0); pointB.Fill(0); pointC.Fill(0); // changing position off all points in order to make them orthogonal pointA[0] = 1; pointB[1] = 1; pointC[2] = 1; // quaternion transform the points pointA = quaternionTransform->GetMatrix() * pointA; pointB = quaternionTransform->GetMatrix() * pointB; pointC = quaternionTransform->GetMatrix() * pointC; // now subtract them from the filter landmarks and compare them to the source pos - pointA = myFilter->GetSourceLandmarks()->GetPoint(0)-pointA; - pointB = myFilter->GetSourceLandmarks()->GetPoint(1)-pointB; - pointC = myFilter->GetSourceLandmarks()->GetPoint(2)-pointC; + pointA = mitk::Point3D(myFilter->GetSourceLandmarks()->GetPoint(0)-pointA); + pointB = mitk::Point3D(myFilter->GetSourceLandmarks()->GetPoint(1)-pointB); + pointC = mitk::Point3D(myFilter->GetSourceLandmarks()->GetPoint(2)-pointC); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(sourcePos1,pointA,mitk::eps,true), "Testing if point generation of first point is correct"); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(sourcePos1,pointB,mitk::eps,true), "Testing if point generation of second point is correct"); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(sourcePos1,pointC,mitk::eps,true), "Testing if point generation of third point is correct"); // deleting helper objects myFilter = nullptr; quaternionTransform = nullptr; snd1 = nullptr; snd2 = nullptr; snd3 = nullptr; tnd1 = nullptr; tnd2 = nullptr; tnd3 = nullptr; // always end with this! MITK_TEST_END(); } diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.cpp b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.cpp index 60cb9e101c..11fa90a23f 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.cpp @@ -1,393 +1,393 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkNavigationToolCreationWidget.h" //mitk headers #include #include #include #include #include "mitkTrackingDeviceTypeCollection.h" //qt headers #include #include #include #include #include //poco headers #include const std::string QmitkNavigationToolCreationWidget::VIEW_ID = "org.mitk.views.navigationtoolcreationwizardwidget"; QmitkNavigationToolCreationWidget::QmitkNavigationToolCreationWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Controls = nullptr; m_ToolToBeEdited = mitk::NavigationTool::New(); m_FinalTool = mitk::NavigationTool::New(); m_ToolTransformationWidget = new QmitkInteractiveTransformationWidget(); m_Controls = nullptr; CreateQtPartControl(this); CreateConnections(); this->InitializeUIToolLandmarkLists(); Initialize(nullptr, ""); //Default values, which are not stored in tool m_Controls->m_CalibrationFileName->setText("none"); m_Controls->m_Surface_Use_Sphere->setChecked(true); m_Controls->m_CalibrationLandmarksList->EnableEditButton(false); m_Controls->m_RegistrationLandmarksList->EnableEditButton(false); RefreshTrackingDeviceCollection(); OnSurfaceUseToggled(); } QmitkNavigationToolCreationWidget::~QmitkNavigationToolCreationWidget() { m_Controls->m_CalibrationLandmarksList->SetPointSetNode(nullptr); m_Controls->m_RegistrationLandmarksList->SetPointSetNode(nullptr); delete m_ToolTransformationWidget; } void QmitkNavigationToolCreationWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkNavigationToolCreationWidgetControls; m_Controls->setupUi(parent); } } void QmitkNavigationToolCreationWidget::CreateConnections() { if (m_Controls) { connect((QObject*)(m_Controls->m_TrackingDeviceTypeChooser), SIGNAL(currentIndexChanged(int)), this, SLOT(GetValuesFromGuiElements())); connect((QObject*)(m_Controls->m_ToolNameEdit), SIGNAL(textChanged(const QString)), this, SLOT(GetValuesFromGuiElements())); connect((QObject*)(m_Controls->m_ToolTypeChooser), SIGNAL(currentIndexChanged(int)), this, SLOT(GetValuesFromGuiElements())); connect((QObject*)(m_Controls->m_IdentifierEdit), SIGNAL(textChanged(const QString)), this, SLOT(GetValuesFromGuiElements())); connect((QObject*)(m_Controls->m_SerialNumberEdit), SIGNAL(textChanged(const QString)), this, SLOT(GetValuesFromGuiElements())); connect((QObject*)(m_Controls->m_ToolAxisX), SIGNAL(valueChanged(int)), this, SLOT(GetValuesFromGuiElements())); connect((QObject*)(m_Controls->m_ToolAxisY), SIGNAL(valueChanged(int)), this, SLOT(GetValuesFromGuiElements())); connect((QObject*)(m_Controls->m_ToolAxisZ), SIGNAL(valueChanged(int)), this, SLOT(GetValuesFromGuiElements())); //Buttons connect((QObject*)(m_Controls->m_LoadCalibrationFile), SIGNAL(clicked()), this, SLOT(OnLoadCalibrationFile())); connect(m_Controls->m_Surface_Use_Other, SIGNAL(toggled(bool)), this, SLOT(OnSurfaceUseToggled())); connect(m_Controls->m_Surface_Load_File, SIGNAL(toggled(bool)), this, SLOT(OnSurfaceUseToggled())); connect((QObject*)(m_Controls->m_LoadSurface), SIGNAL(clicked()), this, SLOT(OnLoadSurface())); connect((QObject*)(m_Controls->m_EditToolTip), SIGNAL(clicked()), this, SLOT(OnEditToolTip())); connect((QObject*)(m_ToolTransformationWidget), SIGNAL(EditToolTipFinished(mitk::AffineTransform3D::Pointer)), this, SLOT(OnEditToolTipFinished(mitk::AffineTransform3D::Pointer))); connect((QObject*)(m_Controls->m_cancel), SIGNAL(clicked()), this, SLOT(OnCancel())); connect((QObject*)(m_Controls->m_finished), SIGNAL(clicked()), this, SLOT(OnFinished())); } } void QmitkNavigationToolCreationWidget::Initialize(mitk::DataStorage* dataStorage, const std::string& supposedIdentifier, const std::string& supposedName) { m_DataStorage = dataStorage; //initialize UI components m_Controls->m_SurfaceChooser->SetDataStorage(m_DataStorage); m_Controls->m_SurfaceChooser->SetAutoSelectNewItems(true); m_Controls->m_SurfaceChooser->SetPredicate(mitk::NodePredicateDataType::New("Surface")); //Create new tool, which should be edited/created m_ToolToBeEdited = nullptr;//Reset m_ToolToBeEdited = mitk::NavigationTool::New();//Reinitialize m_ToolToBeEdited->SetIdentifier(supposedIdentifier); m_ToolToBeEdited->GetDataNode()->SetName(supposedName); this->SetDefaultData(m_ToolToBeEdited); } void QmitkNavigationToolCreationWidget::ShowToolPreview(std::string _name) { m_DataStorage->Add(m_ToolToBeEdited->GetDataNode()); m_ToolToBeEdited->GetDataNode()->SetName(_name); //change color to blue m_ToolToBeEdited->GetDataNode()->SetProperty("color", mitk::ColorProperty::New(0, 0, 1)); //Global Reinit to show new tool mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); } void QmitkNavigationToolCreationWidget::SetDefaultData(mitk::NavigationTool::Pointer DefaultTool) { //Set Members. This can either be the new initialized tool from call of Initialize() or a tool which already exists in the toolStorage m_ToolToBeEdited = DefaultTool->Clone(); //Set all gui variables SetGuiElements(); } void QmitkNavigationToolCreationWidget::SetGuiElements() { //Block signals, so that we don't call SetGuiElements again. This is undone at the end of this function! m_Controls->m_TrackingDeviceTypeChooser->blockSignals(true); m_Controls->m_ToolNameEdit->blockSignals(true); m_Controls->m_ToolTypeChooser->blockSignals(true); m_Controls->m_IdentifierEdit->blockSignals(true); m_Controls->m_SerialNumberEdit->blockSignals(true); m_Controls->m_ToolAxisX->blockSignals(true); m_Controls->m_ToolAxisY->blockSignals(true); m_Controls->m_ToolAxisZ->blockSignals(true); //DeviceType int index = m_Controls->m_TrackingDeviceTypeChooser->findText(QString::fromStdString(m_ToolToBeEdited->GetTrackingDeviceType())); if (index >= 0) { m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(index); } m_Controls->m_ToolNameEdit->setText(QString(m_ToolToBeEdited->GetToolName().c_str())); m_Controls->m_CalibrationFileName->setText(QString(m_ToolToBeEdited->GetCalibrationFile().c_str())); FillUIToolLandmarkLists(m_ToolToBeEdited->GetToolControlPoints(), m_ToolToBeEdited->GetToolLandmarks()); switch (m_ToolToBeEdited->GetType()) { case mitk::NavigationTool::Instrument: m_Controls->m_ToolTypeChooser->setCurrentIndex(0); break; case mitk::NavigationTool::Fiducial: m_Controls->m_ToolTypeChooser->setCurrentIndex(1); break; case mitk::NavigationTool::Skinmarker: m_Controls->m_ToolTypeChooser->setCurrentIndex(2); break; case mitk::NavigationTool::Unknown: m_Controls->m_ToolTypeChooser->setCurrentIndex(3); break; } m_Controls->m_IdentifierEdit->setText(QString(m_ToolToBeEdited->GetIdentifier().c_str())); m_Controls->m_SerialNumberEdit->setText(QString(m_ToolToBeEdited->GetSerialNumber().c_str())); QString _label = "(" + QString::number(m_ToolToBeEdited->GetToolTipPosition()[0], 'f', 1) + ", " + QString::number(m_ToolToBeEdited->GetToolTipPosition()[1], 'f', 1) + ", " + QString::number(m_ToolToBeEdited->GetToolTipPosition()[2], 'f', 1) + "), quat: [" + QString::number(m_ToolToBeEdited->GetToolAxisOrientation()[0], 'f', 2) + ", " + QString::number(m_ToolToBeEdited->GetToolAxisOrientation()[1], 'f', 2) + ", " + QString::number(m_ToolToBeEdited->GetToolAxisOrientation()[2], 'f', 2) + ", " + QString::number(m_ToolToBeEdited->GetToolAxisOrientation()[3], 'f', 2) + "]"; m_Controls->m_ToolTipLabel->setText(_label); //Undo block signals. Don't remove it, if signals are still blocked at the beginning of this function! m_Controls->m_TrackingDeviceTypeChooser->blockSignals(false); m_Controls->m_ToolNameEdit->blockSignals(false); m_Controls->m_ToolTypeChooser->blockSignals(false); m_Controls->m_IdentifierEdit->blockSignals(false); m_Controls->m_SerialNumberEdit->blockSignals(false); m_Controls->m_ToolAxisX->blockSignals(false); m_Controls->m_ToolAxisY->blockSignals(false); m_Controls->m_ToolAxisZ->blockSignals(false); } void QmitkNavigationToolCreationWidget::OnSurfaceUseToggled() { if (m_Controls->m_Surface_Use_Sphere->isChecked()) m_ToolToBeEdited->SetDefaultSurface(); m_Controls->m_SurfaceChooser->setEnabled(m_Controls->m_Surface_Use_Other->isChecked()); m_Controls->m_LoadSurface->setEnabled(m_Controls->m_Surface_Load_File->isChecked()); //Global Reinit to show tool surface preview mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); } void QmitkNavigationToolCreationWidget::OnLoadSurface() { std::string filename = QFileDialog::getOpenFileName(nullptr, tr("Open Surface"), QmitkIGTCommonHelper::GetLastFileLoadPath(), tr("STL (*.stl)")).toLatin1().data(); QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(QString::fromStdString(filename)); mitk::Surface::Pointer surface; try { surface = mitk::IOUtil::Load(filename.c_str()); } catch (mitk::Exception &e) { MITK_ERROR << "Exception occured: " << e.what(); return; } m_ToolToBeEdited->GetDataNode()->SetData(surface); //Global Reinit to show tool surface or preview mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); } void QmitkNavigationToolCreationWidget::OnLoadCalibrationFile() { QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open Calibration File"), QmitkIGTCommonHelper::GetLastFileLoadPath(), "*.*"); QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(fileName); m_Controls->m_CalibrationFileName->setText(fileName); m_ToolToBeEdited->SetCalibrationFile(fileName.toStdString()); } void QmitkNavigationToolCreationWidget::GetValuesFromGuiElements() { //Tracking Device m_ToolToBeEdited->SetTrackingDeviceType(m_Controls->m_TrackingDeviceTypeChooser->currentText().toStdString()); //m_ToolToBeEdited->GetDataNode()->SetName(m_Controls->m_ToolNameEdit->text().toStdString()); //Tool Landmarks mitk::PointSet::Pointer toolCalLandmarks, toolRegLandmarks; GetUIToolLandmarksLists(toolCalLandmarks, toolRegLandmarks); m_ToolToBeEdited->SetToolControlPoints(toolCalLandmarks); m_ToolToBeEdited->SetToolLandmarks(toolRegLandmarks); //Advanced if (m_Controls->m_ToolTypeChooser->currentText() == "Instrument") m_ToolToBeEdited->SetType(mitk::NavigationTool::Instrument); else if (m_Controls->m_ToolTypeChooser->currentText() == "Fiducial") m_ToolToBeEdited->SetType(mitk::NavigationTool::Fiducial); else if (m_Controls->m_ToolTypeChooser->currentText() == "Skinmarker") m_ToolToBeEdited->SetType(mitk::NavigationTool::Skinmarker); else m_FinalTool->SetType(mitk::NavigationTool::Unknown); m_ToolToBeEdited->SetIdentifier(m_Controls->m_IdentifierEdit->text().toLatin1().data()); m_ToolToBeEdited->SetSerialNumber(m_Controls->m_SerialNumberEdit->text().toLatin1().data()); ////Tool Axis //mitk::Point3D toolAxis; //toolAxis.SetElement(0, (m_Controls->m_ToolAxisX->value())); //toolAxis.SetElement(1, (m_Controls->m_ToolAxisY->value())); //toolAxis.SetElement(2, (m_Controls->m_ToolAxisZ->value())); //m_ToolToBeEdited->SetToolAxis(toolAxis); } mitk::NavigationTool::Pointer QmitkNavigationToolCreationWidget::GetCreatedTool() { return m_FinalTool; } void QmitkNavigationToolCreationWidget::OnFinished() { if (m_Controls->m_Surface_Use_Other->isChecked()) m_ToolToBeEdited->GetDataNode()->SetData(m_Controls->m_SurfaceChooser->GetSelectedNode()->GetData()); //here we create a new tool m_FinalTool = m_ToolToBeEdited->Clone(); //Set the correct name of data node, cause the m_ToolToBeEdited was called "Tool preview" m_FinalTool->GetDataNode()->SetName(m_Controls->m_ToolNameEdit->text().toStdString()); emit NavigationToolFinished(); } void QmitkNavigationToolCreationWidget::OnCancel() { Initialize(nullptr, "");//Reset everything to a fresh tool, like it was done in the constructor emit Canceled(); } void QmitkNavigationToolCreationWidget::SetTrackingDeviceType(mitk::TrackingDeviceType type, bool changeable /*= true*/) { //Adapt Gui int index = m_Controls->m_TrackingDeviceTypeChooser->findText(QString::fromStdString(type)); if (index >= 0) { m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(index); } m_Controls->m_TrackingDeviceTypeChooser->setEditable(changeable); //Set data to member m_ToolToBeEdited->SetTrackingDeviceType(type); } //################################################################################## //############################## internal help methods ############################# //################################################################################## void QmitkNavigationToolCreationWidget::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkNavigationToolCreationWidget::OnEditToolTip() { m_ToolTransformationWidget->SetToolToEdit(m_ToolToBeEdited); m_ToolTransformationWidget->SetDefaultRotation(m_ToolToBeEdited->GetToolAxisOrientation()); m_ToolTransformationWidget->SetDefaultOffset(m_ToolToBeEdited->GetToolTipPosition()); m_ToolTransformationWidget->open(); } void QmitkNavigationToolCreationWidget::OnEditToolTipFinished(mitk::AffineTransform3D::Pointer toolTip) { //if user pressed cancle, nullptr is returned. Do nothing. Else, set values. if (toolTip) { - m_ToolToBeEdited->SetToolTipPosition(toolTip->GetOffset()); + m_ToolToBeEdited->SetToolTipPosition(mitk::Point3D(toolTip->GetOffset())); mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(toolTip);//Convert to Navigation data for simple transversion to quaternion m_ToolToBeEdited->SetToolAxisOrientation(tempND->GetOrientation()); //Update Label QString _label = "(" + QString::number(m_ToolToBeEdited->GetToolTipPosition()[0], 'f', 1) + ", " + QString::number(m_ToolToBeEdited->GetToolTipPosition()[1], 'f', 1) + ", " + QString::number(m_ToolToBeEdited->GetToolTipPosition()[2], 'f', 1) + "), quat: [" + QString::number(m_ToolToBeEdited->GetToolAxisOrientation()[0], 'f', 2) + ", " + QString::number(m_ToolToBeEdited->GetToolAxisOrientation()[1], 'f', 2) + ", " + QString::number(m_ToolToBeEdited->GetToolAxisOrientation()[2], 'f', 2) + ", " + QString::number(m_ToolToBeEdited->GetToolAxisOrientation()[3], 'f', 2) + "]"; m_Controls->m_ToolTipLabel->setText(_label); } } void QmitkNavigationToolCreationWidget::FillUIToolLandmarkLists(mitk::PointSet::Pointer calLandmarks, mitk::PointSet::Pointer regLandmarks) { m_calLandmarkNode->SetData(calLandmarks); m_regLandmarkNode->SetData(regLandmarks); m_Controls->m_CalibrationLandmarksList->SetPointSetNode(m_calLandmarkNode); m_Controls->m_RegistrationLandmarksList->SetPointSetNode(m_regLandmarkNode); } void QmitkNavigationToolCreationWidget::GetUIToolLandmarksLists(mitk::PointSet::Pointer& calLandmarks, mitk::PointSet::Pointer& regLandmarks) { calLandmarks = dynamic_cast(m_calLandmarkNode->GetData()); regLandmarks = dynamic_cast(m_regLandmarkNode->GetData()); } void QmitkNavigationToolCreationWidget::InitializeUIToolLandmarkLists() { m_calLandmarkNode = mitk::DataNode::New(); m_regLandmarkNode = mitk::DataNode::New(); FillUIToolLandmarkLists(mitk::PointSet::New(), mitk::PointSet::New()); } void QmitkNavigationToolCreationWidget::RefreshTrackingDeviceCollection() { us::ModuleContext* context = us::GetModuleContext(); std::vector > refs = context->GetServiceReferences(); if (refs.empty()) { MITK_WARN << "No tracking device service found!"; return; } mitk::TrackingDeviceTypeCollection* _DeviceTypeCollection = context->GetService(refs.front()); for (auto name : _DeviceTypeCollection->GetTrackingDeviceTypeNames()) { //if the device is not included yet, add name to comboBox and widget to stackedWidget if (m_Controls->m_TrackingDeviceTypeChooser->findText(QString::fromStdString(name)) == -1) { m_Controls->m_TrackingDeviceTypeChooser->addItem(QString::fromStdString(name)); } } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCtUsRegistration.cpp b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCtUsRegistration.cpp index 456093d420..16b5a9a3b8 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCtUsRegistration.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/NavigationStepWidgets/QmitkUSNavigationStepCtUsRegistration.cpp @@ -1,2014 +1,2014 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkUSNavigationStepCtUsRegistration.h" #include "ui_QmitkUSNavigationStepCtUsRegistration.h" #include #include "mitkNodeDisplacementFilter.h" #include "../Filter/mitkFloatingImageToUltrasoundRegistrationFilter.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include #include #include #include "mitkProperties.h" #include #include #include #include #include #include #include #include #include #include #include #include static const int NUMBER_FIDUCIALS_NEEDED = 8; QmitkUSNavigationStepCtUsRegistration::QmitkUSNavigationStepCtUsRegistration(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), ui(new Ui::QmitkUSNavigationStepCtUsRegistration), m_PerformingGroundTruthProtocolEvaluation(false), m_FloatingImageToUltrasoundRegistrationFilter(nullptr), m_FreezeCombinedModality(false) { this->UnsetFloatingImageGeometry(); this->DefineDataStorageImageFilter(); this->CreateQtPartControl(this); } QmitkUSNavigationStepCtUsRegistration::~QmitkUSNavigationStepCtUsRegistration() { delete ui; } bool QmitkUSNavigationStepCtUsRegistration::OnStartStep() { MITK_INFO << "OnStartStep()"; return true; } bool QmitkUSNavigationStepCtUsRegistration::OnStopStep() { MITK_INFO << "OnStopStep()"; return true; } bool QmitkUSNavigationStepCtUsRegistration::OnFinishStep() { MITK_INFO << "OnFinishStep()"; return true; } bool QmitkUSNavigationStepCtUsRegistration::OnActivateStep() { MITK_INFO << "OnActivateStep()"; ui->floatingImageComboBox->SetDataStorage(this->GetDataStorage()); ui->ctImagesToChooseComboBox->SetDataStorage(this->GetDataStorage()); ui->segmentationComboBox->SetDataStorage(this->GetDataStorage()); ui->selectedSurfaceComboBox->SetDataStorage(this->GetDataStorage()); ui->pointSetComboBox->SetDataStorage(this->GetDataStorage()); m_FloatingImageToUltrasoundRegistrationFilter = mitk::FloatingImageToUltrasoundRegistrationFilter::New(); return true; } bool QmitkUSNavigationStepCtUsRegistration::OnDeactivateStep() { MITK_INFO << "OnDeactivateStep()"; return true; } void QmitkUSNavigationStepCtUsRegistration::OnUpdate() { if (m_NavigationDataSource.IsNull()) { return; } m_NavigationDataSource->Update(); m_FloatingImageToUltrasoundRegistrationFilter->Update(); } void QmitkUSNavigationStepCtUsRegistration::OnSettingsChanged(const itk::SmartPointer settingsNode) { Q_UNUSED(settingsNode); } QString QmitkUSNavigationStepCtUsRegistration::GetTitle() { return "CT-to-US registration"; } QmitkUSAbstractNavigationStep::FilterVector QmitkUSNavigationStepCtUsRegistration::GetFilter() { return FilterVector(); } void QmitkUSNavigationStepCtUsRegistration::OnSetCombinedModality() { mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNotNull()) { m_NavigationDataSource = combinedModality->GetNavigationDataSource(); } } void QmitkUSNavigationStepCtUsRegistration::UnsetFloatingImageGeometry() { m_ImageDimension[0] = 0; m_ImageDimension[1] = 0; m_ImageDimension[2] = 0; m_ImageSpacing[0] = 1; m_ImageSpacing[1] = 1; m_ImageSpacing[2] = 1; } void QmitkUSNavigationStepCtUsRegistration::SetFloatingImageGeometryInformation(mitk::Image * image) { m_ImageDimension[0] = image->GetDimension(0); m_ImageDimension[1] = image->GetDimension(1); m_ImageDimension[2] = image->GetDimension(2); m_ImageSpacing[0] = image->GetGeometry()->GetSpacing()[0]; m_ImageSpacing[1] = image->GetGeometry()->GetSpacing()[1]; m_ImageSpacing[2] = image->GetGeometry()->GetSpacing()[2]; } double QmitkUSNavigationStepCtUsRegistration::GetVoxelVolume() { if (m_FloatingImage.IsNull()) { return 0.0; } MITK_INFO << "ImageSpacing = " << m_ImageSpacing; return m_ImageSpacing[0] * m_ImageSpacing[1] * m_ImageSpacing[2]; } double QmitkUSNavigationStepCtUsRegistration::GetFiducialVolume(double radius) { return 1.333333333 * 3.141592 * (radius * radius * radius); } bool QmitkUSNavigationStepCtUsRegistration::FilterFloatingImage() { if (m_FloatingImage.IsNull()) { return false; } ImageType::Pointer itkImage1 = ImageType::New(); mitk::CastToItkImage(m_FloatingImage, itkImage1); this->InitializeImageFilters(); m_ThresholdFilter->SetInput(itkImage1); m_LaplacianFilter1->SetInput(m_ThresholdFilter->GetOutput()); m_LaplacianFilter2->SetInput(m_LaplacianFilter1->GetOutput()); m_BinaryThresholdFilter->SetInput(m_LaplacianFilter2->GetOutput()); m_HoleFillingFilter->SetInput(m_BinaryThresholdFilter->GetOutput()); m_BinaryImageToShapeLabelMapFilter->SetInput(m_HoleFillingFilter->GetOutput()); m_BinaryImageToShapeLabelMapFilter->Update(); ImageType::Pointer binaryImage = ImageType::New(); binaryImage = m_HoleFillingFilter->GetOutput(); this->EliminateTooSmallLabeledObjects(binaryImage); //mitk::CastToMitkImage(binaryImage, m_FloatingImage); return true; } void QmitkUSNavigationStepCtUsRegistration::InitializeImageFilters() { //Initialize threshold filters m_ThresholdFilter = itk::ThresholdImageFilter::New(); m_ThresholdFilter->SetOutsideValue(0); m_ThresholdFilter->SetLower(500); m_ThresholdFilter->SetUpper(3200); //Initialize binary threshold filter 1 m_BinaryThresholdFilter = BinaryThresholdImageFilterType::New(); m_BinaryThresholdFilter->SetOutsideValue(0); m_BinaryThresholdFilter->SetInsideValue(1); m_BinaryThresholdFilter->SetLowerThreshold(350); m_BinaryThresholdFilter->SetUpperThreshold(10000); //Initialize laplacian recursive gaussian image filter m_LaplacianFilter1 = LaplacianRecursiveGaussianImageFilterType::New(); m_LaplacianFilter2 = LaplacianRecursiveGaussianImageFilterType::New(); //Initialize binary hole filling filter m_HoleFillingFilter = VotingBinaryIterativeHoleFillingImageFilterType::New(); VotingBinaryIterativeHoleFillingImageFilterType::InputSizeType radius; radius.Fill(1); m_HoleFillingFilter->SetRadius(radius); m_HoleFillingFilter->SetBackgroundValue(0); m_HoleFillingFilter->SetForegroundValue(1); m_HoleFillingFilter->SetMaximumNumberOfIterations(5); //Initialize binary image to shape label map filter m_BinaryImageToShapeLabelMapFilter = BinaryImageToShapeLabelMapFilterType::New(); m_BinaryImageToShapeLabelMapFilter->SetInputForegroundValue(1); } double QmitkUSNavigationStepCtUsRegistration::GetCharacteristicDistanceAWithUpperMargin() { switch (ui->fiducialMarkerConfigurationComboBox->currentIndex()) { // case 0 is equal to fiducial marker configuration A (10mm distance) case 0: return 12.07; // case 1 is equal to fiducial marker configuration B (15mm distance) case 1: return 18.105; // case 2 is equal to fiducial marker configuration C (20mm distance) case 2: return 24.14; } return 0.0; } double QmitkUSNavigationStepCtUsRegistration::GetCharacteristicDistanceBWithLowerMargin() { switch (ui->fiducialMarkerConfigurationComboBox->currentIndex()) { // case 0 is equal to fiducial marker configuration A (10mm distance) case 0: return 12.07; // case 1 is equal to fiducial marker configuration B (15mm distance) case 1: return 18.105; // case 2 is equal to fiducial marker configuration C (20mm distance) case 2: return 24.14; } return 0.0; } double QmitkUSNavigationStepCtUsRegistration::GetCharacteristicDistanceBWithUpperMargin() { switch (ui->fiducialMarkerConfigurationComboBox->currentIndex()) { // case 0 is equal to fiducial marker configuration A (10mm distance) case 0: return 15.73; // case 1 is equal to fiducial marker configuration B (15mm distance) case 1: return 23.595; // case 2 is equal to fiducial marker configuration C (20mm distance) case 2: return 31.46; } return 0.0; } double QmitkUSNavigationStepCtUsRegistration::GetMinimalFiducialConfigurationDistance() { switch (ui->fiducialMarkerConfigurationComboBox->currentIndex()) { // case 0 is equal to fiducial marker configuration A (10mm distance) case 0: return 10.0; // case 1 is equal to fiducial marker configuration B (15mm distance) case 1: return 15.0; // case 2 is equal to fiducial marker configuration C (20mm distance) case 2: return 20.0; } return 0.0; } void QmitkUSNavigationStepCtUsRegistration::CreateMarkerModelCoordinateSystemPointSet() { if (m_MarkerModelCoordinateSystemPointSet.IsNull()) { m_MarkerModelCoordinateSystemPointSet = mitk::PointSet::New(); } else { m_MarkerModelCoordinateSystemPointSet->Clear(); } mitk::Point3D fiducial1; mitk::Point3D fiducial2; mitk::Point3D fiducial3; mitk::Point3D fiducial4; mitk::Point3D fiducial5; mitk::Point3D fiducial6; mitk::Point3D fiducial7; mitk::Point3D fiducial8; switch (ui->fiducialMarkerConfigurationComboBox->currentIndex()) { // case 0 is equal to fiducial marker configuration A (10mm distance) case 0: fiducial1[0] = 0; fiducial1[1] = 0; fiducial1[2] = 0; fiducial2[0] = 0; fiducial2[1] = 10; fiducial2[2] = 0; fiducial3[0] = 10; fiducial3[1] = 0; fiducial3[2] = 0; fiducial4[0] = 20; fiducial4[1] = 20; fiducial4[2] = 0; fiducial5[0] = 0; fiducial5[1] = 20; fiducial5[2] = 10; fiducial6[0] = 10; fiducial6[1] = 20; fiducial6[2] = 10; fiducial7[0] = 20; fiducial7[1] = 10; fiducial7[2] = 10; fiducial8[0] = 20; fiducial8[1] = 0; fiducial8[2] = 10; break; // case 1 is equal to fiducial marker configuration B (15mm distance) case 1: fiducial1[0] = 0; fiducial1[1] = 0; fiducial1[2] = 0; fiducial2[0] = 0; fiducial2[1] = 15; fiducial2[2] = 0; fiducial3[0] = 15; fiducial3[1] = 0; fiducial3[2] = 0; fiducial4[0] = 30; fiducial4[1] = 30; fiducial4[2] = 0; fiducial5[0] = 0; fiducial5[1] = 30; fiducial5[2] = 15; fiducial6[0] = 15; fiducial6[1] = 30; fiducial6[2] = 15; fiducial7[0] = 30; fiducial7[1] = 15; fiducial7[2] = 15; fiducial8[0] = 30; fiducial8[1] = 0; fiducial8[2] = 15; break; // case 2 is equal to fiducial marker configuration C (20mm distance) case 2: fiducial1[0] = 0; fiducial1[1] = 0; fiducial1[2] = 0; fiducial2[0] = 0; fiducial2[1] = 20; fiducial2[2] = 0; fiducial3[0] = 20; fiducial3[1] = 0; fiducial3[2] = 0; fiducial4[0] = 40; fiducial4[1] = 40; fiducial4[2] = 0; fiducial5[0] = 0; fiducial5[1] = 40; fiducial5[2] = 20; fiducial6[0] = 20; fiducial6[1] = 40; fiducial6[2] = 20; fiducial7[0] = 40; fiducial7[1] = 20; fiducial7[2] = 20; fiducial8[0] = 40; fiducial8[1] = 0; fiducial8[2] = 20; break; } m_MarkerModelCoordinateSystemPointSet->InsertPoint(0, fiducial1); m_MarkerModelCoordinateSystemPointSet->InsertPoint(1, fiducial2); m_MarkerModelCoordinateSystemPointSet->InsertPoint(2, fiducial3); m_MarkerModelCoordinateSystemPointSet->InsertPoint(3, fiducial4); m_MarkerModelCoordinateSystemPointSet->InsertPoint(4, fiducial5); m_MarkerModelCoordinateSystemPointSet->InsertPoint(5, fiducial6); m_MarkerModelCoordinateSystemPointSet->InsertPoint(6, fiducial7); m_MarkerModelCoordinateSystemPointSet->InsertPoint(7, fiducial8); /*mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Marker Model Coordinate System Point Set"); if (node == nullptr) { node = mitk::DataNode::New(); node->SetName("Marker Model Coordinate System Point Set"); node->SetData(m_MarkerModelCoordinateSystemPointSet); this->GetDataStorage()->Add(node); } else { node->SetData(m_MarkerModelCoordinateSystemPointSet); this->GetDataStorage()->Modified(); }*/ } void QmitkUSNavigationStepCtUsRegistration::InitializePointsToTransformForGroundTruthProtocol() { m_PointsToTransformGroundTruthProtocol.clear(); mitk::Point3D point0mm; mitk::Point3D point20mm; mitk::Point3D point40mm; mitk::Point3D point60mm; mitk::Point3D point80mm; mitk::Point3D point100mm; point0mm[0] = 0.0; point0mm[1] = 0.0; point0mm[2] = 0.0; point20mm[0] = 0.0; point20mm[1] = 0.0; point20mm[2] = 0.0; point40mm[0] = 0.0; point40mm[1] = 0.0; point40mm[2] = 0.0; point60mm[0] = 0.0; point60mm[1] = 0.0; point60mm[2] = 0.0; point80mm[0] = 0.0; point80mm[1] = 0.0; point80mm[2] = 0.0; point100mm[0] = 0.0; point100mm[1] = 0.0; point100mm[2] = 0.0; m_PointsToTransformGroundTruthProtocol.insert(std::pair(0, point0mm)); m_PointsToTransformGroundTruthProtocol.insert(std::pair(20, point20mm)); m_PointsToTransformGroundTruthProtocol.insert(std::pair(40, point40mm)); m_PointsToTransformGroundTruthProtocol.insert(std::pair(60, point60mm)); m_PointsToTransformGroundTruthProtocol.insert(std::pair(80, point80mm)); m_PointsToTransformGroundTruthProtocol.insert(std::pair(100, point100mm)); } void QmitkUSNavigationStepCtUsRegistration::CreatePointsToTransformForGroundTruthProtocol() { this->InitializePointsToTransformForGroundTruthProtocol(); switch (ui->fiducialMarkerConfigurationComboBox->currentIndex()) { // case 0 is equal to fiducial marker configuration A (10mm distance) case 0: MITK_WARN << "For this marker configuration (10mm) there does not exist a point to transform."; break; // case 1 is equal to fiducial marker configuration B (15mm distance) case 1: m_PointsToTransformGroundTruthProtocol.at(0)[0] = 130; // = 30mm to end of clipping plate + 100 mm to middle axis of measurement plate m_PointsToTransformGroundTruthProtocol.at(0)[1] = 15; m_PointsToTransformGroundTruthProtocol.at(0)[2] = -7; // = 5mm distance to clipping plate + 2mm to base m_PointsToTransformGroundTruthProtocol.at(20)[0] = 130; m_PointsToTransformGroundTruthProtocol.at(20)[1] = 15; m_PointsToTransformGroundTruthProtocol.at(20)[2] = -27; // = 5mm distance to clipping plate + 2mm to base + 20mm depth m_PointsToTransformGroundTruthProtocol.at(40)[0] = 130; m_PointsToTransformGroundTruthProtocol.at(40)[1] = 15; m_PointsToTransformGroundTruthProtocol.at(40)[2] = -47; // = 5mm distance to clipping plate + 2mm to base + 40mm depth m_PointsToTransformGroundTruthProtocol.at(60)[0] = 130; m_PointsToTransformGroundTruthProtocol.at(60)[1] = 15; m_PointsToTransformGroundTruthProtocol.at(60)[2] = -67; // = 5mm distance to clipping plate + 2mm to base + 60mm depth m_PointsToTransformGroundTruthProtocol.at(80)[0] = 130; m_PointsToTransformGroundTruthProtocol.at(80)[1] = 15; m_PointsToTransformGroundTruthProtocol.at(80)[2] = -87; // = 5mm distance to clipping plate + 2mm to base + 80mm depth m_PointsToTransformGroundTruthProtocol.at(100)[0] = 130; m_PointsToTransformGroundTruthProtocol.at(100)[1] = 15; m_PointsToTransformGroundTruthProtocol.at(100)[2] = -107; // = 5mm distance to clipping plate + 2mm to base + 100mm depth break; // case 2 is equal to fiducial marker configuration C (20mm distance) case 2: m_PointsToTransformGroundTruthProtocol.at(0)[0] = 135; // = 20 + 15mm to end of clipping plate + 100 mm to middle axis of measurement plate m_PointsToTransformGroundTruthProtocol.at(0)[1] = 20; m_PointsToTransformGroundTruthProtocol.at(0)[2] = -9; // = 7mm distance to clipping plate + 2mm to base m_PointsToTransformGroundTruthProtocol.at(20)[0] = 135; m_PointsToTransformGroundTruthProtocol.at(20)[1] = 20; m_PointsToTransformGroundTruthProtocol.at(20)[2] = -29; // = 7mm distance to clipping plate + 2mm to base + 20mm depth m_PointsToTransformGroundTruthProtocol.at(40)[0] = 135; m_PointsToTransformGroundTruthProtocol.at(40)[1] = 20; m_PointsToTransformGroundTruthProtocol.at(40)[2] = -49; // = 7mm distance to clipping plate + 2mm to base + 40mm depth m_PointsToTransformGroundTruthProtocol.at(60)[0] = 135; m_PointsToTransformGroundTruthProtocol.at(60)[1] = 20; m_PointsToTransformGroundTruthProtocol.at(60)[2] = -69; // = 7mm distance to clipping plate + 2mm to base + 60mm depth m_PointsToTransformGroundTruthProtocol.at(80)[0] = 135; m_PointsToTransformGroundTruthProtocol.at(80)[1] = 20; m_PointsToTransformGroundTruthProtocol.at(80)[2] = -89; // = 7mm distance to clipping plate + 2mm to base + 80mm depth m_PointsToTransformGroundTruthProtocol.at(100)[0] = 135; m_PointsToTransformGroundTruthProtocol.at(100)[1] = 20; m_PointsToTransformGroundTruthProtocol.at(100)[2] = -109; // = 7mm distance to clipping plate + 2mm to base + 100mm depth break; } } void QmitkUSNavigationStepCtUsRegistration::TransformPointsGroundTruthProtocol() { if (m_GroundTruthProtocolTransformedPoints.find(0) == m_GroundTruthProtocolTransformedPoints.end()) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); pointSet->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(0))); m_GroundTruthProtocolTransformedPoints.insert(std::pair(0, pointSet)); } else { m_GroundTruthProtocolTransformedPoints.at(0)->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(0))); } if (m_GroundTruthProtocolTransformedPoints.find(20) == m_GroundTruthProtocolTransformedPoints.end()) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); pointSet->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(20))); m_GroundTruthProtocolTransformedPoints.insert(std::pair(20, pointSet)); } else { m_GroundTruthProtocolTransformedPoints.at(20)->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(20))); } if (m_GroundTruthProtocolTransformedPoints.find(40) == m_GroundTruthProtocolTransformedPoints.end()) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); pointSet->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(40))); m_GroundTruthProtocolTransformedPoints.insert(std::pair(40, pointSet)); } else { m_GroundTruthProtocolTransformedPoints.at(40)->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(40))); } if (m_GroundTruthProtocolTransformedPoints.find(60) == m_GroundTruthProtocolTransformedPoints.end()) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); pointSet->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(60))); m_GroundTruthProtocolTransformedPoints.insert(std::pair(60, pointSet)); } else { m_GroundTruthProtocolTransformedPoints.at(60)->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(60))); } if (m_GroundTruthProtocolTransformedPoints.find(80) == m_GroundTruthProtocolTransformedPoints.end()) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); pointSet->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(80))); m_GroundTruthProtocolTransformedPoints.insert(std::pair(80, pointSet)); } else { m_GroundTruthProtocolTransformedPoints.at(80)->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(80))); } if (m_GroundTruthProtocolTransformedPoints.find(100) == m_GroundTruthProtocolTransformedPoints.end()) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); pointSet->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(100))); m_GroundTruthProtocolTransformedPoints.insert(std::pair(100, pointSet)); } else { m_GroundTruthProtocolTransformedPoints.at(100)->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(m_PointsToTransformGroundTruthProtocol.at(100))); } } void QmitkUSNavigationStepCtUsRegistration::AddTransformedPointsToDataStorage() { if (m_GroundTruthProtocolTransformedPoints.find(0) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(20) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(40) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(60) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(80) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(100) == m_GroundTruthProtocolTransformedPoints.end()) { QMessageBox msgBox; msgBox.setText("Cannot add transformed Points to DataStorage because they do not exist.\ Stopping evaluation the protocol."); msgBox.exec(); return; } std::string nameNode0mm = "GroundTruthProt-Depth0mm"; std::string nameNode20mm = "GroundTruthProt-Depth20mm"; std::string nameNode40mm = "GroundTruthProt-Depth40mm"; std::string nameNode60mm = "GroundTruthProt-Depth60mm"; std::string nameNode80mm = "GroundTruthProt-Depth80mm"; std::string nameNode100mm = "GroundTruthProt-Depth100mm"; //Add transformed points of depth 0mm to the data storage mitk::DataNode::Pointer node0mm = this->GetDataStorage()->GetNamedNode(nameNode0mm); if (node0mm.IsNull()) { node0mm = mitk::DataNode::New(); node0mm->SetName(nameNode0mm); node0mm->SetData(m_GroundTruthProtocolTransformedPoints.at(0)); this->GetDataStorage()->Add(node0mm); } else { node0mm->SetData(m_GroundTruthProtocolTransformedPoints.at(0)); this->GetDataStorage()->Modified(); } if(ui->protocolEvaluationTypeComboBox->currentText().compare("PLANE") == 0 ) { //Add transformed points of depth 20mm to the data storage mitk::DataNode::Pointer node20mm = this->GetDataStorage()->GetNamedNode(nameNode20mm); if (node20mm.IsNull()) { node20mm = mitk::DataNode::New(); node20mm->SetName(nameNode20mm); node20mm->SetData(m_GroundTruthProtocolTransformedPoints.at(20)); this->GetDataStorage()->Add(node20mm); } else { node20mm->SetData(m_GroundTruthProtocolTransformedPoints.at(20)); this->GetDataStorage()->Modified(); } //Add transformed points of depth 40mm to the data storage mitk::DataNode::Pointer node40mm = this->GetDataStorage()->GetNamedNode(nameNode40mm); if (node40mm.IsNull()) { node40mm = mitk::DataNode::New(); node40mm->SetName(nameNode40mm); node40mm->SetData(m_GroundTruthProtocolTransformedPoints.at(40)); this->GetDataStorage()->Add(node40mm); } else { node40mm->SetData(m_GroundTruthProtocolTransformedPoints.at(40)); this->GetDataStorage()->Modified(); } //Add transformed points of depth 60mm to the data storage mitk::DataNode::Pointer node60mm = this->GetDataStorage()->GetNamedNode(nameNode60mm); if (node60mm.IsNull()) { node60mm = mitk::DataNode::New(); node60mm->SetName(nameNode60mm); node60mm->SetData(m_GroundTruthProtocolTransformedPoints.at(60)); this->GetDataStorage()->Add(node60mm); } else { node60mm->SetData(m_GroundTruthProtocolTransformedPoints.at(60)); this->GetDataStorage()->Modified(); } //Add transformed points of depth 80mm to the data storage mitk::DataNode::Pointer node80mm = this->GetDataStorage()->GetNamedNode(nameNode80mm); if (node80mm.IsNull()) { node80mm = mitk::DataNode::New(); node80mm->SetName(nameNode80mm); node80mm->SetData(m_GroundTruthProtocolTransformedPoints.at(80)); this->GetDataStorage()->Add(node80mm); } else { node80mm->SetData(m_GroundTruthProtocolTransformedPoints.at(80)); this->GetDataStorage()->Modified(); } //Add transformed points of depth 100mm to the data storage mitk::DataNode::Pointer node100mm = this->GetDataStorage()->GetNamedNode(nameNode100mm); if (node100mm.IsNull()) { node100mm = mitk::DataNode::New(); node100mm->SetName(nameNode100mm); node100mm->SetData(m_GroundTruthProtocolTransformedPoints.at(100)); this->GetDataStorage()->Add(node100mm); } else { node100mm->SetData(m_GroundTruthProtocolTransformedPoints.at(100)); this->GetDataStorage()->Modified(); } } //Do a global reinit mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); } double QmitkUSNavigationStepCtUsRegistration::CalculateMeanFRE() { double meanFRE = 0.0; for (unsigned int counter = 0; counter < m_GroundTruthProtocolFRE.size(); ++counter) { meanFRE += m_GroundTruthProtocolFRE[counter]; } return meanFRE / m_GroundTruthProtocolFRE.size(); } double QmitkUSNavigationStepCtUsRegistration::CalculateStandardDeviationOfFRE(double meanFRE) { double variance = 0.0; for (unsigned int counter = 0; counter < m_GroundTruthProtocolFRE.size(); ++counter) { variance += ((meanFRE - m_GroundTruthProtocolFRE[counter]) * (meanFRE - m_GroundTruthProtocolFRE[counter])); } variance /= m_GroundTruthProtocolFRE.size(); // calculate the empirical variance (n) and not the sampling variance (n-1) return sqrt(variance); } void QmitkUSNavigationStepCtUsRegistration::CalculateGroundTruthProtocolTRE() { if (m_GroundTruthProtocolTransformedPoints.find(0) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(20) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(40) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(60) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(80) == m_GroundTruthProtocolTransformedPoints.end() || m_GroundTruthProtocolTransformedPoints.find(100) == m_GroundTruthProtocolTransformedPoints.end()) { QMessageBox msgBox; msgBox.setText("Cannot calculate TRE of Ground-Truth-Protocol because points were not transformed."); msgBox.exec(); return; } // clear the std::map containing possibly data of earlier TRE calculations m_GroundTruthProtocolTRE.clear(); // loop through all existing point sets containing the transformed points for (int counter = 0; m_GroundTruthProtocolTransformedPoints.find(counter) != m_GroundTruthProtocolTransformedPoints.end(); counter += 20) { //calculate the middle point of the point set mitk::PointSet::Pointer pointSet = m_GroundTruthProtocolTransformedPoints.at(counter); mitk::Point3D middlePoint; middlePoint[0] = 0.0; middlePoint[1] = 0.0; middlePoint[2] = 0.0; for (int position = 0; position < pointSet->GetSize(); ++position) { middlePoint[0] += pointSet->GetPoint(position)[0]; middlePoint[1] += pointSet->GetPoint(position)[1]; middlePoint[2] += pointSet->GetPoint(position)[2]; } middlePoint[0] /= pointSet->GetSize(); middlePoint[1] /= pointSet->GetSize(); middlePoint[2] /= pointSet->GetSize(); MITK_INFO << "Calculated MiddlePoint: " << middlePoint; //sum up the euclidean distances between the middle point and each transformed point double meanDistance = 0.0; for (int position = 0; position < pointSet->GetSize(); ++position) { meanDistance += middlePoint.SquaredEuclideanDistanceTo(pointSet->GetPoint(position)); MITK_INFO << "SquaredEuclideanDistance: " << middlePoint.SquaredEuclideanDistanceTo(pointSet->GetPoint(position)); } meanDistance /= pointSet->GetSize(); // this can be interpreted as empirical variance // the root of the empirical variance can be interpreted as the protocols registration TRE m_GroundTruthProtocolTRE.insert(std::pair(counter, sqrt(meanDistance))); MITK_INFO << "Ground-Truth-Protocol TRE: " << sqrt(meanDistance); } } void QmitkUSNavigationStepCtUsRegistration::EliminateTooSmallLabeledObjects( ImageType::Pointer binaryImage) { BinaryImageToShapeLabelMapFilterType::OutputImageType::Pointer labelMap = m_BinaryImageToShapeLabelMapFilter->GetOutput(); double voxelVolume = this->GetVoxelVolume(); double fiducialVolume; unsigned int numberOfPixels; if (ui->fiducialDiameter3mmRadioButton->isChecked()) { fiducialVolume = this->GetFiducialVolume(1.5); numberOfPixels = ceil(fiducialVolume / voxelVolume); } else { fiducialVolume = this->GetFiducialVolume(2.5); numberOfPixels = ceil(fiducialVolume / voxelVolume); } MITK_INFO << "Voxel Volume = " << voxelVolume << "; Fiducial Volume = " << fiducialVolume; MITK_INFO << "Number of pixels = " << numberOfPixels; labelMap = m_BinaryImageToShapeLabelMapFilter->GetOutput(); // The output of this filter is an itk::LabelMap, which contains itk::LabelObject's MITK_INFO << "There are " << labelMap->GetNumberOfLabelObjects() << " objects."; // Loop over each region for (int i = labelMap->GetNumberOfLabelObjects() - 1; i >= 0; --i) { // Get the ith region BinaryImageToShapeLabelMapFilterType::OutputImageType::LabelObjectType* labelObject = labelMap->GetNthLabelObject(i); MITK_INFO << "Object " << i << " contains " << labelObject->Size() << " pixel"; //TODO: Threshold-Wert evtl. experimentell besser abstimmen, // um zu verhindern, dass durch Threshold wahre Fiducial-Kandidaten elimiert werden. if (labelObject->Size() < numberOfPixels * 0.8) { for (unsigned int pixelId = 0; pixelId < labelObject->Size(); pixelId++) { binaryImage->SetPixel(labelObject->GetIndex(pixelId), 0); } labelMap->RemoveLabelObject(labelObject); } } } bool QmitkUSNavigationStepCtUsRegistration::EliminateFiducialCandidatesByEuclideanDistances() { if (m_CentroidsOfFiducialCandidates.size() < NUMBER_FIDUCIALS_NEEDED) { return false; } for (unsigned int counter = 0; counter < m_CentroidsOfFiducialCandidates.size(); ++counter) { int amountOfAcceptedFiducials = 0; mitk::Point3D fiducialCentroid(m_CentroidsOfFiducialCandidates.at(counter)); //Loop through all fiducial candidates and calculate the distance between the chosen fiducial // candidate and the other candidates. For each candidate with a right distance between // Configuration A: 7.93mm and 31.0mm (10 mm distance between fiducial centers) or // Configuration B: 11.895mm and 45.0mm (15 mm distance between fiducial centers) or // Configuration C: 15.86mm and 59.0mm (20 mm distance between fiducial centers) // // increase the amountOfAcceptedFiducials. for (unsigned int position = 0; position < m_CentroidsOfFiducialCandidates.size(); ++position) { if (position == counter) { continue; } mitk::Point3D otherCentroid(m_CentroidsOfFiducialCandidates.at(position)); double distance = fiducialCentroid.EuclideanDistanceTo(otherCentroid); switch (ui->fiducialMarkerConfigurationComboBox->currentIndex()) { // case 0 is equal to fiducial marker configuration A (10mm distance) case 0: if (distance > 7.93 && distance < 31.0) { ++amountOfAcceptedFiducials; } break; // case 1 is equal to fiducial marker configuration B (15mm distance) case 1: if (distance > 11.895 && distance < 45.0) { ++amountOfAcceptedFiducials; } break; // case 2 is equal to fiducial marker configuration C (20mm distance) case 2: if (distance > 15.86 && distance < 59.0) { ++amountOfAcceptedFiducials; } break; } } //The amountOfAcceptedFiducials must be at least 7. Otherwise delete the fiducial candidate // from the list of candidates. if (amountOfAcceptedFiducials < NUMBER_FIDUCIALS_NEEDED - 1) { MITK_INFO << "Deleting fiducial candidate at position: " << m_CentroidsOfFiducialCandidates.at(counter); m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + counter); if (m_CentroidsOfFiducialCandidates.size() < NUMBER_FIDUCIALS_NEEDED ) { return false; } counter = -1; } } //Classify the rested fiducial candidates by its characteristic Euclidean distances // between the canidates and remove all candidates with a false distance configuration: this->ClassifyFiducialCandidates(); return true; } void QmitkUSNavigationStepCtUsRegistration::ClassifyFiducialCandidates() { MITK_INFO << "ClassifyFiducialCandidates()"; std::vector fiducialCandidatesToBeRemoved; std::vector> distanceVectorsFiducials; this->CalculateDistancesBetweenFiducials(distanceVectorsFiducials); for (unsigned int counter = 0; counter < distanceVectorsFiducials.size(); ++counter) { int distanceA = 0; // => 10,00mm distance int distanceB = 0; // => 14,14mm distance int distanceC = 0; // => 17,32mm distance int distanceD = 0; // => 22,36mm distance int distanceE = 0; // => 24,49mm distance int distanceF = 0; // => 28,28mm distance std::vector &distances = distanceVectorsFiducials.at(counter); for (unsigned int number = 0; number < distances.size(); ++number) { double &distance = distances.at(number); switch (ui->fiducialMarkerConfigurationComboBox->currentIndex()) { // case 0 is equal to fiducial marker configuration A (10mm distance) case 0: if (distance > 7.93 && distance <= 12.07) { ++distanceA; } else if (distance > 12.07 && distance <= 15.73) { ++distanceB; } else if (distance > 15.73 && distance <= 19.84) { ++distanceC; } else if (distance > 19.84 && distance <= 23.425) { ++distanceD; } else if (distance > 23.425 && distance <= 26.385) { ++distanceE; } else if (distance > 26.385 && distance <= 31.00) { ++distanceF; } break; // case 1 is equal to fiducial marker configuration B (15mm distance) case 1: if (distance > 11.895 && distance <= 18.105) { ++distanceA; } else if (distance > 18.105 && distance <= 23.595) { ++distanceB; } else if (distance > 23.595 && distance <= 29.76) { ++distanceC; } else if (distance > 29.76 && distance <= 35.1375) { ++distanceD; if (distance > 33.54) { ++distanceE; } } else if (distance > 35.1375 && distance <= 39.5775) { ++distanceE; if (distance < 36.735) { ++distanceD; } } else if (distance > 39.5775 && distance <= 45.00) { ++distanceF; } break; // case 2 is equal to fiducial marker configuration C (20mm distance) case 2: if (distance > 15.86 && distance <= 24.14) { ++distanceA; } else if (distance > 24.14 && distance <= 31.46) { ++distanceB; } else if (distance > 31.46 && distance <= 39.68) { ++distanceC; } else if (distance > 39.68 && distance <= 46.85) { ++distanceD; } else if (distance > 46.85 && distance <= 52.77) { ++distanceE; } else if (distance > 52.77 && distance <= 59.00) { ++distanceF; } break; } }// End for-loop distances-vector //Now, having looped through all distances of one fiducial candidate, check // if the combination of different distances is known. The >= is due to the // possible occurrence of other fiducial candidates that have an distance equal to // one of the distances A - E. However, false fiducial candidates outside // the fiducial marker does not have the right distance configuration: if (((distanceA >= 2 && distanceD >= 2 && distanceE >= 2 && distanceF >= 1) || (distanceA >= 1 && distanceB >= 2 && distanceC >= 1 && distanceD >= 2 && distanceE >= 1) || (distanceB >= 2 && distanceD >= 4 && distanceF >= 1) || (distanceA >= 1 && distanceB >= 1 && distanceD >= 3 && distanceE >= 1 && distanceF >= 1)) == false) { MITK_INFO << "Detected fiducial candidate with unknown distance configuration."; fiducialCandidatesToBeRemoved.push_back(counter); } } for (int count = fiducialCandidatesToBeRemoved.size() - 1; count >= 0; --count) { MITK_INFO << "Removing fiducial candidate " << fiducialCandidatesToBeRemoved.at(count); m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + fiducialCandidatesToBeRemoved.at(count)); } } void QmitkUSNavigationStepCtUsRegistration::GetCentroidsOfLabeledObjects() { MITK_INFO << "GetCentroidsOfLabeledObjects()"; BinaryImageToShapeLabelMapFilterType::OutputImageType::Pointer labelMap = m_BinaryImageToShapeLabelMapFilter->GetOutput(); for (int i = labelMap->GetNumberOfLabelObjects() - 1; i >= 0; --i) { // Get the ith region BinaryImageToShapeLabelMapFilterType::OutputImageType::LabelObjectType* labelObject = labelMap->GetNthLabelObject(i); MITK_INFO << "Object " << i << " contains " << labelObject->Size() << " pixel"; mitk::Vector3D centroid; centroid[0] = labelObject->GetCentroid()[0]; centroid[1] = labelObject->GetCentroid()[1]; centroid[2] = labelObject->GetCentroid()[2]; m_CentroidsOfFiducialCandidates.push_back(centroid); } //evtl. for later: itk::LabelMapOverlayImageFilter } void QmitkUSNavigationStepCtUsRegistration::NumerateFiducialMarks() { MITK_INFO << "NumerateFiducialMarks()"; bool successFiducialNo1; bool successFiducialNo4; bool successFiducialNo2And3; bool successFiducialNo5; bool successFiducialNo8; bool successFiducialNo6; bool successFiducialNo7; std::vector> distanceVectorsFiducials; this->CalculateDistancesBetweenFiducials(distanceVectorsFiducials); successFiducialNo1 = this->FindFiducialNo1(distanceVectorsFiducials); successFiducialNo4 = this->FindFiducialNo4(distanceVectorsFiducials); successFiducialNo2And3 = this->FindFiducialNo2And3(); successFiducialNo5 = this->FindFiducialNo5(); successFiducialNo8 = this->FindFiducialNo8(); successFiducialNo6 = this->FindFiducialNo6(); successFiducialNo7 = this->FindFiducialNo7(); if (!successFiducialNo1 || !successFiducialNo4 || !successFiducialNo2And3 || !successFiducialNo5 || !successFiducialNo8 || !successFiducialNo6 || !successFiducialNo7) { QMessageBox msgBox; msgBox.setText("Cannot numerate/localize all fiducials successfully."); msgBox.exec(); return; } if (m_MarkerFloatingImageCoordinateSystemPointSet.IsNull()) { m_MarkerFloatingImageCoordinateSystemPointSet = mitk::PointSet::New(); } else if (m_MarkerFloatingImageCoordinateSystemPointSet->GetSize() != 0) { m_MarkerFloatingImageCoordinateSystemPointSet->Clear(); } for (unsigned int counter = 1; counter <= m_FiducialMarkerCentroids.size(); ++counter) { - m_MarkerFloatingImageCoordinateSystemPointSet->InsertPoint(counter - 1, m_FiducialMarkerCentroids.at(counter)); + m_MarkerFloatingImageCoordinateSystemPointSet->InsertPoint(counter - 1, mitk::Point3D(m_FiducialMarkerCentroids.at(counter))); } if( !m_PerformingGroundTruthProtocolEvaluation ) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(m_MarkerFloatingImageCoordinateSystemPointSet); node->SetName("MarkerFloatingImageCSPointSet"); //node->SetFloatProperty("pointsize", 5.0); this->GetDataStorage()->Add(node); } } void QmitkUSNavigationStepCtUsRegistration::CalculateDistancesBetweenFiducials(std::vector>& distanceVectorsFiducials) { std::vector distancesBetweenFiducials; for (unsigned int i = 0; i < m_CentroidsOfFiducialCandidates.size(); ++i) { distancesBetweenFiducials.clear(); mitk::Point3D fiducialCentroid(m_CentroidsOfFiducialCandidates.at(i)); for (unsigned int n = 0; n < m_CentroidsOfFiducialCandidates.size(); ++n) { mitk::Point3D otherCentroid(m_CentroidsOfFiducialCandidates.at(n)); distancesBetweenFiducials.push_back(fiducialCentroid.EuclideanDistanceTo(otherCentroid)); } //Sort the distances from low to big numbers std::sort(distancesBetweenFiducials.begin(), distancesBetweenFiducials.end()); //First entry of the distance vector must be 0, so erase it if (distancesBetweenFiducials.at(0) == 0.0) { distancesBetweenFiducials.erase(distancesBetweenFiducials.begin()); } //Add the distance vector to the collecting distances vector distanceVectorsFiducials.push_back(distancesBetweenFiducials); } for (unsigned int i = 0; i < distanceVectorsFiducials.size(); ++i) { MITK_INFO << "Vector " << i << ":"; for (unsigned int k = 0; k < distanceVectorsFiducials.at(i).size(); ++k) { MITK_INFO << distanceVectorsFiducials.at(i).at(k); } } } bool QmitkUSNavigationStepCtUsRegistration::FindFiducialNo1(std::vector>& distanceVectorsFiducials) { for (unsigned int i = 0; i < distanceVectorsFiducials.size(); ++i) { std::vector &distances = distanceVectorsFiducials.at(i); if (distances.size() < NUMBER_FIDUCIALS_NEEDED - 1 ) { MITK_WARN << "Cannot find fiducial 1, there aren't found enough fiducial candidates."; return false; } double characteristicDistanceAWithUpperMargin = this->GetCharacteristicDistanceAWithUpperMargin(); if (distances.at(0) <= characteristicDistanceAWithUpperMargin && distances.at(1) <= characteristicDistanceAWithUpperMargin) { MITK_INFO << "Found Fiducial 1 (PointSet number " << i << ")"; m_FiducialMarkerCentroids.insert( std::pair(1, m_CentroidsOfFiducialCandidates.at(i))); distanceVectorsFiducials.erase(distanceVectorsFiducials.begin() + i); m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + i); return true; } } return false; } bool QmitkUSNavigationStepCtUsRegistration::FindFiducialNo2And3() { if (m_FiducialMarkerCentroids.find(1) == m_FiducialMarkerCentroids.end() ) { MITK_WARN << "Cannot find fiducial No 2 and 3. Before must be found fiducial No 1."; return false; } mitk::Point3D fiducialNo1(m_FiducialMarkerCentroids.at(1)); mitk::Vector3D fiducialVectorA; mitk::Vector3D fiducialVectorB; mitk::Point3D fiducialPointA; mitk::Point3D fiducialPointB; bool foundFiducialA = false; bool foundFiducialB = false; mitk::Vector3D vectorFiducial1ToFiducialA; mitk::Vector3D vectorFiducial1ToFiducialB; for (unsigned int i = 0; i < m_CentroidsOfFiducialCandidates.size(); ++i) { mitk::Point3D fiducialCentroid(m_CentroidsOfFiducialCandidates.at(i)); double distance = fiducialNo1.EuclideanDistanceTo(fiducialCentroid); if (distance <= this->GetCharacteristicDistanceAWithUpperMargin()) { fiducialVectorA = m_CentroidsOfFiducialCandidates.at(i); fiducialPointA = fiducialCentroid; m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + i); foundFiducialA = true; break; } } for (unsigned int i = 0; i < m_CentroidsOfFiducialCandidates.size(); ++i) { mitk::Point3D fiducialCentroid(m_CentroidsOfFiducialCandidates.at(i)); double distance = fiducialNo1.EuclideanDistanceTo(fiducialCentroid); if (distance <= this->GetCharacteristicDistanceAWithUpperMargin()) { fiducialVectorB = m_CentroidsOfFiducialCandidates.at(i); fiducialPointB = fiducialCentroid; m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + i); foundFiducialB = true; break; } } if (!foundFiducialA || !foundFiducialB) { MITK_WARN << "Cannot identify fiducial candidates 2 and 3"; return false; } else if (m_CentroidsOfFiducialCandidates.size() == 0) { MITK_WARN << "Too less fiducials detected. Cannot identify fiducial candidates 2 and 3"; return false; } vectorFiducial1ToFiducialA = fiducialVectorA - m_FiducialMarkerCentroids.at(1); vectorFiducial1ToFiducialB = fiducialVectorB - m_FiducialMarkerCentroids.at(1); vnl_vector crossProductVnl = vnl_cross_3d(vectorFiducial1ToFiducialA.GetVnlVector(), vectorFiducial1ToFiducialB.GetVnlVector()); mitk::Vector3D crossProduct; crossProduct.SetVnlVector(crossProductVnl); mitk::Vector3D vectorFiducial1ToRandomLeftFiducial = m_CentroidsOfFiducialCandidates.at(0) - m_FiducialMarkerCentroids.at(1); double scalarProduct = (crossProduct * vectorFiducial1ToRandomLeftFiducial) / (crossProduct.GetNorm() * vectorFiducial1ToRandomLeftFiducial.GetNorm()); double alpha = acos(scalarProduct) * 57.29578; //Transform into degree MITK_INFO << "Scalar Product = " << alpha; if (alpha <= 90) { m_FiducialMarkerCentroids[3] = fiducialVectorA; m_FiducialMarkerCentroids[2] = fiducialVectorB; } else { m_FiducialMarkerCentroids[2] = fiducialVectorA; m_FiducialMarkerCentroids[3] = fiducialVectorB; } MITK_INFO << "Found Fiducial 2, PointSet: " << m_FiducialMarkerCentroids.at(2); MITK_INFO << "Found Fiducial 3, PointSet: " << m_FiducialMarkerCentroids.at(3); return true; } bool QmitkUSNavigationStepCtUsRegistration::FindFiducialNo4(std::vector>& distanceVectorsFiducials) { double characteristicDistanceBWithLowerMargin = this->GetCharacteristicDistanceBWithLowerMargin(); double characteristicDistanceBWithUpperMargin = this->GetCharacteristicDistanceBWithUpperMargin(); for (unsigned int i = 0; i < distanceVectorsFiducials.size(); ++i) { std::vector &distances = distanceVectorsFiducials.at(i); if (distances.size() < NUMBER_FIDUCIALS_NEEDED - 1) { MITK_WARN << "Cannot find fiducial 4, there aren't found enough fiducial candidates."; return false; } if (distances.at(0) > characteristicDistanceBWithLowerMargin && distances.at(0) <= characteristicDistanceBWithUpperMargin && distances.at(1) > characteristicDistanceBWithLowerMargin && distances.at(1) <= characteristicDistanceBWithUpperMargin) { MITK_INFO << "Found Fiducial 4 (PointSet number " << i << ")"; m_FiducialMarkerCentroids.insert(std::pair(4, m_CentroidsOfFiducialCandidates.at(i))); distanceVectorsFiducials.erase(distanceVectorsFiducials.begin() + i); m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + i); return true; } } return false; } bool QmitkUSNavigationStepCtUsRegistration::FindFiducialNo5() { if (m_FiducialMarkerCentroids.find(2) == m_FiducialMarkerCentroids.end()) { MITK_WARN << "To find fiducial No 5, fiducial No 2 has to be found before."; return false; } double characteristicDistanceBWithUpperMargin = this->GetCharacteristicDistanceBWithUpperMargin(); mitk::Point3D fiducialNo2(m_FiducialMarkerCentroids.at(2)); for (unsigned int counter = 0; counter < m_CentroidsOfFiducialCandidates.size(); ++counter) { mitk::Point3D fiducialCentroid(m_CentroidsOfFiducialCandidates.at(counter)); double distance = fiducialNo2.EuclideanDistanceTo(fiducialCentroid); if (distance <= characteristicDistanceBWithUpperMargin) { m_FiducialMarkerCentroids[5] = m_CentroidsOfFiducialCandidates.at(counter); m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + counter); MITK_INFO << "Found Fiducial No 5, PointSet: " << m_FiducialMarkerCentroids[5]; return true; } } MITK_WARN << "Cannot find fiducial No 5."; return false; } bool QmitkUSNavigationStepCtUsRegistration::FindFiducialNo6() { if (m_FiducialMarkerCentroids.find(5) == m_FiducialMarkerCentroids.end()) { MITK_WARN << "To find fiducial No 6, fiducial No 5 has to be found before."; return false; } double characteristicDistanceAWithUpperMargin = this->GetCharacteristicDistanceAWithUpperMargin(); mitk::Point3D fiducialNo5(m_FiducialMarkerCentroids.at(5)); for (unsigned int counter = 0; counter < m_CentroidsOfFiducialCandidates.size(); ++counter) { mitk::Point3D fiducialCentroid(m_CentroidsOfFiducialCandidates.at(counter)); double distance = fiducialNo5.EuclideanDistanceTo(fiducialCentroid); if (distance <= characteristicDistanceAWithUpperMargin) { m_FiducialMarkerCentroids[6] = m_CentroidsOfFiducialCandidates.at(counter); m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + counter); MITK_INFO << "Found Fiducial No 6, PointSet: " << m_FiducialMarkerCentroids[6]; return true; } } MITK_WARN << "Cannot find fiducial No 6."; return false; } bool QmitkUSNavigationStepCtUsRegistration::FindFiducialNo7() { if (m_FiducialMarkerCentroids.find(8) == m_FiducialMarkerCentroids.end()) { MITK_WARN << "To find fiducial No 7, fiducial No 8 has to be found before."; return false; } double characteristicDistanceAWithUpperMargin = this->GetCharacteristicDistanceAWithUpperMargin(); mitk::Point3D fiducialNo8(m_FiducialMarkerCentroids.at(8)); for (unsigned int counter = 0; counter < m_CentroidsOfFiducialCandidates.size(); ++counter) { mitk::Point3D fiducialCentroid(m_CentroidsOfFiducialCandidates.at(counter)); double distance = fiducialNo8.EuclideanDistanceTo(fiducialCentroid); if (distance <= characteristicDistanceAWithUpperMargin) { m_FiducialMarkerCentroids[7] = m_CentroidsOfFiducialCandidates.at(counter); m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + counter); MITK_INFO << "Found Fiducial No 7, PointSet: " << m_FiducialMarkerCentroids[7]; return true; } } MITK_WARN << "Cannot find fiducial No 7."; return false; } bool QmitkUSNavigationStepCtUsRegistration::FindFiducialNo8() { if (m_FiducialMarkerCentroids.find(3) == m_FiducialMarkerCentroids.end()) { MITK_WARN << "To find fiducial No 8, fiducial No 3 has to be found before."; return false; } double characteristicDistanceBWithUpperMargin = this->GetCharacteristicDistanceBWithUpperMargin(); mitk::Point3D fiducialNo3(m_FiducialMarkerCentroids.at(3)); for (unsigned int counter = 0; counter < m_CentroidsOfFiducialCandidates.size(); ++counter) { mitk::Point3D fiducialCentroid(m_CentroidsOfFiducialCandidates.at(counter)); double distance = fiducialNo3.EuclideanDistanceTo(fiducialCentroid); if (distance <= characteristicDistanceBWithUpperMargin) { m_FiducialMarkerCentroids[8] = m_CentroidsOfFiducialCandidates.at(counter); m_CentroidsOfFiducialCandidates.erase(m_CentroidsOfFiducialCandidates.begin() + counter); MITK_INFO << "Found Fiducial No 8, PointSet: " << m_FiducialMarkerCentroids[8]; return true; } } MITK_WARN << "Cannot find fiducial No 8."; return false; } void QmitkUSNavigationStepCtUsRegistration::DefineDataStorageImageFilter() { m_IsAPointSetPredicate = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); auto isSegmentation = mitk::NodePredicateDataType::New("Segment"); m_IsASurfacePredicate = mitk::NodePredicateDataType::New("Surface"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegmentation))); mitk::NodePredicateNot::Pointer isNotAHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); m_IsOfTypeImagePredicate = mitk::NodePredicateAnd::New(validImages, isNotAHelperObject); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New(isBinaryPredicate); mitk::NodePredicateAnd::Pointer isABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isBinaryPredicate); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isNotBinaryPredicate); m_IsASegmentationImagePredicate = mitk::NodePredicateOr::New(isABinaryImagePredicate, mitk::TNodePredicateDataType::New()); m_IsAPatientImagePredicate = mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, mitk::NodePredicateNot::New(mitk::TNodePredicateDataType::New())); } void QmitkUSNavigationStepCtUsRegistration::CreateQtPartControl(QWidget *parent) { ui->setupUi(parent); ui->floatingImageComboBox->SetPredicate(m_IsAPatientImagePredicate); ui->ctImagesToChooseComboBox->SetPredicate(m_IsAPatientImagePredicate); ui->segmentationComboBox->SetPredicate(m_IsASegmentationImagePredicate); ui->selectedSurfaceComboBox->SetPredicate(m_IsASurfacePredicate); ui->pointSetComboBox->SetPredicate(m_IsAPointSetPredicate); // create signal/slot connections connect(ui->floatingImageComboBox, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnFloatingImageComboBoxSelectionChanged(const mitk::DataNode*))); connect(ui->doRegistrationMarkerToImagePushButton, SIGNAL(clicked()), this, SLOT(OnRegisterMarkerToFloatingImageCS())); connect(ui->localizeFiducialMarkerPushButton, SIGNAL(clicked()), this, SLOT(OnLocalizeFiducials())); connect(ui->visualizeCTtoUSregistrationPushButton, SIGNAL(clicked()), this, SLOT(OnVisualizeCTtoUSregistration())); connect(ui->freezeUnfreezePushButton, SIGNAL(clicked()), this, SLOT(OnFreeze())); connect(ui->addCtImagePushButton, SIGNAL(clicked()), this, SLOT(OnAddCtImageClicked())); connect(ui->removeCtImagePushButton, SIGNAL(clicked()), this, SLOT(OnRemoveCtImageClicked())); connect(ui->evaluateProtocolPushButton, SIGNAL(clicked()), this, SLOT(OnEvaluateGroundTruthFiducialLocalizationProtocol())); connect(ui->actualizeSegmentationSurfacePSetDataPushButton, SIGNAL(clicked()), this, SLOT(OnActualizeSegmentationSurfacePointSetData())); connect(ui->calculateTREPushButton, SIGNAL(clicked()), this, SLOT(OnGetCursorPosition())); connect(ui->calculateCenterPushButton, SIGNAL(clicked()), this, SLOT(OnCalculateCenter())); } void QmitkUSNavigationStepCtUsRegistration::OnFloatingImageComboBoxSelectionChanged(const mitk::DataNode* node) { MITK_INFO << "OnFloatingImageComboBoxSelectionChanged()"; if (m_FloatingImage.IsNotNull()) { //TODO: Define, what will happen if the imageCT is not null... } if (node == nullptr) { this->UnsetFloatingImageGeometry(); m_FloatingImage = nullptr; return; } mitk::DataNode* selectedFloatingImage = ui->floatingImageComboBox->GetSelectedNode(); if (selectedFloatingImage == nullptr) { this->UnsetFloatingImageGeometry(); m_FloatingImage = nullptr; return; } mitk::Image::Pointer floatingImage = dynamic_cast(selectedFloatingImage->GetData()); if (floatingImage.IsNull()) { MITK_WARN << "Failed to cast selected segmentation node to mitk::Image*"; this->UnsetFloatingImageGeometry(); m_FloatingImage = nullptr; return; } m_FloatingImage = floatingImage; this->SetFloatingImageGeometryInformation(floatingImage.GetPointer()); } void QmitkUSNavigationStepCtUsRegistration::OnRegisterMarkerToFloatingImageCS() { this->CreateMarkerModelCoordinateSystemPointSet(); //Check for initialization if( m_MarkerModelCoordinateSystemPointSet.IsNull() || m_MarkerFloatingImageCoordinateSystemPointSet.IsNull() ) { MITK_WARN << "Fiducial Landmarks are not initialized yet, cannot register"; return; } //Retrieve fiducials if (m_MarkerFloatingImageCoordinateSystemPointSet->GetSize() != m_MarkerModelCoordinateSystemPointSet->GetSize()) { MITK_WARN << "Not the same number of fiducials, cannot register"; return; } else if (m_MarkerFloatingImageCoordinateSystemPointSet->GetSize() < 3) { MITK_WARN << "Need at least 3 fiducials, cannot register"; return; } //############### conversion to vtk data types (we will use the vtk landmark based transform) ########################## //convert point sets to vtk poly data vtkSmartPointer sourcePoints = vtkSmartPointer::New(); vtkSmartPointer targetPoints = vtkSmartPointer::New(); for (int i = 0; iGetSize(); i++) { double point[3] = { m_MarkerModelCoordinateSystemPointSet->GetPoint(i)[0], m_MarkerModelCoordinateSystemPointSet->GetPoint(i)[1], m_MarkerModelCoordinateSystemPointSet->GetPoint(i)[2] }; sourcePoints->InsertNextPoint(point); double point_targets[3] = { m_MarkerFloatingImageCoordinateSystemPointSet->GetPoint(i)[0], m_MarkerFloatingImageCoordinateSystemPointSet->GetPoint(i)[1], m_MarkerFloatingImageCoordinateSystemPointSet->GetPoint(i)[2] }; targetPoints->InsertNextPoint(point_targets); } //########################### here, the actual transform is computed ########################## //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(m_MarkerModelCoordinateSystemPointSet, m_MarkerFloatingImageCoordinateSystemPointSet, transform); MITK_INFO << "FRE: " << FRE << " mm"; if (m_PerformingGroundTruthProtocolEvaluation) { m_GroundTruthProtocolFRE.push_back(FRE); } //############################################################################################# //############### conversion back to itk/mitk data types ########################## //convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); itk::Matrix rotationDouble = itk::Matrix(); itk::Vector translationDouble = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); for (int k = 0; k<3; k++) for (int l = 0; l<3; l++) { rotationFloat[k][l] = m->GetElement(k, l); rotationDouble[k][l] = m->GetElement(k, l); } for (int k = 0; k<3; k++) { translationFloat[k] = m->GetElement(k, 3); translationDouble[k] = m->GetElement(k, 3); } //create mitk affine transform 3D and save it to the class member m_TransformMarkerCSToFloatingImageCS = mitk::AffineTransform3D::New(); m_TransformMarkerCSToFloatingImageCS->SetMatrix(rotationDouble); m_TransformMarkerCSToFloatingImageCS->SetOffset(translationDouble); MITK_INFO << m_TransformMarkerCSToFloatingImageCS; //################################################################ //############### object is transformed ########################## //transform surface/image //only move image if we have one. Sometimes, this widget is used just to register point sets without images. /*if (m_ImageNode.IsNotNull()) { //first we have to store the original ct image transform to compose it with the new transform later mitk::AffineTransform3D::Pointer imageTransform = m_ImageNode->GetData()->GetGeometry()->GetIndexToWorldTransform(); imageTransform->Compose(mitkTransform); mitk::AffineTransform3D::Pointer newImageTransform = mitk::AffineTransform3D::New(); //create new image transform... setting the composed directly leads to an error itk::Matrix rotationFloatNew = imageTransform->GetMatrix(); itk::Vector translationFloatNew = imageTransform->GetOffset(); newImageTransform->SetMatrix(rotationFloatNew); newImageTransform->SetOffset(translationFloatNew); m_ImageNode->GetData()->GetGeometry()->SetIndexToWorldTransform(newImageTransform); }*/ //If this option is set, each point will be transformed and the acutal coordinates of the points change. if( !m_PerformingGroundTruthProtocolEvaluation ) { mitk::PointSet* pointSet_orig = m_MarkerModelCoordinateSystemPointSet; mitk::PointSet::Pointer pointSet_moved = mitk::PointSet::New(); for (int i = 0; i < pointSet_orig->GetSize(); i++) { pointSet_moved->InsertPoint(m_TransformMarkerCSToFloatingImageCS->TransformPoint(pointSet_orig->GetPoint(i))); } pointSet_orig->Clear(); for (int i = 0; i < pointSet_moved->GetSize(); i++) pointSet_orig->InsertPoint(pointSet_moved->GetPoint(i)); //Do a global reinit mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); } } void QmitkUSNavigationStepCtUsRegistration::OnLocalizeFiducials() { m_FiducialMarkerCentroids.clear(); m_CentroidsOfFiducialCandidates.clear(); if (m_MarkerFloatingImageCoordinateSystemPointSet.IsNotNull()) { m_MarkerFloatingImageCoordinateSystemPointSet->Clear(); } if (!this->FilterFloatingImage()) { QMessageBox msgBox; msgBox.setText("Cannot perform filtering of the image. The floating image = nullptr."); msgBox.exec(); return; } mitk::AffineTransform3D::Pointer transform = m_FloatingImage->GetGeometry()->GetIndexToWorldTransform(); MITK_WARN << "IndexToWorldTransform_CTimage = " << transform; this->GetCentroidsOfLabeledObjects(); if (!this->EliminateFiducialCandidatesByEuclideanDistances() || m_CentroidsOfFiducialCandidates.size() != NUMBER_FIDUCIALS_NEEDED) { QMessageBox msgBox; QString text = QString("Have found %1 instead of 8 fiducial candidates.\ Cannot perform fiducial localization procedure.").arg(m_CentroidsOfFiducialCandidates.size()); msgBox.setText(text); msgBox.exec(); return; } //Before calling NumerateFiducialMarks it must be sure, // that there rested only 8 fiducial candidates. this->NumerateFiducialMarks(); } void QmitkUSNavigationStepCtUsRegistration::OnVisualizeCTtoUSregistration() { emit this->ActualizeCtToUsRegistrationWidget(); mitk::DataNode* segmentationNode = ui->segmentationComboBox->GetSelectedNode(); if (segmentationNode == nullptr) { QMessageBox msgBox; msgBox.setText("Cannot visualize CT-to-US registration. There is no segmentation selected."); msgBox.exec(); return; } mitk::AffineTransform3D::Pointer transform = segmentationNode->GetData()->GetGeometry()->GetIndexToWorldTransform(); MITK_WARN << "IndexToWorldTransform_segmentation = " << transform; mitk::DataNode* surfaceNode = ui->selectedSurfaceComboBox->GetSelectedNode(); if (surfaceNode == nullptr) { QMessageBox msgBox; msgBox.setText("Cannot visualize CT-to-US registration. There is no surface selected."); msgBox.exec(); return; } mitk::DataNode* pointSetNode = ui->pointSetComboBox->GetSelectedNode(); if (pointSetNode == nullptr) { QMessageBox msgBox; msgBox.setText("Cannot visualize CT-to-US registration. There is no pointSet selected."); msgBox.exec(); return; } if (this->GetCombinedModality(false).IsNull()) { QMessageBox msgBox; msgBox.setText("CombinedModality not yet set.\nPlease try again and click on the button."); msgBox.exec(); return; } if (m_FloatingImageToUltrasoundRegistrationFilter.IsNull()) { QMessageBox msgBox; msgBox.setText("Cannot visualize CT-to-US registration.\ The FloatingImageToUltrasoundRegistrationFilter is not initialized."); msgBox.exec(); return; } //Set the transformation from marker-CS to the sensor-CS accordingly to the chosen user-option m_FloatingImageToUltrasoundRegistrationFilter ->InitializeTransformationMarkerCSToSensorCS(ui->useNdiTrackerCheckBox->isChecked()); m_FloatingImageToUltrasoundRegistrationFilter->SetPointSet(pointSetNode); m_FloatingImageToUltrasoundRegistrationFilter->SetSegmentation(segmentationNode, m_FloatingImage); m_FloatingImageToUltrasoundRegistrationFilter->SetSurface(surfaceNode); m_FloatingImageToUltrasoundRegistrationFilter ->SetTransformMarkerCSToFloatingImageCS(m_TransformMarkerCSToFloatingImageCS); m_FloatingImageToUltrasoundRegistrationFilter ->SetTransformUSimageCSToTrackingCS(this->GetCombinedModality()->GetCalibration()); m_FloatingImageToUltrasoundRegistrationFilter ->ConnectTo(this->GetCombinedModality()->GetNavigationDataSource()); } void QmitkUSNavigationStepCtUsRegistration::OnFreeze() { if (this->GetCombinedModality(false).IsNull()) { return; } if (!m_FreezeCombinedModality) { m_FreezeCombinedModality = true; ui->freezeUnfreezePushButton->setText("Unfreeze"); this->GetCombinedModality()->SetIsFreezed(true); } else { m_FreezeCombinedModality = false; ui->freezeUnfreezePushButton->setText("Freeze"); this->GetCombinedModality()->SetIsFreezed(false); } } void QmitkUSNavigationStepCtUsRegistration::OnActualizeSegmentationSurfacePointSetData() { mitk::DataNode* segmentationNode = ui->segmentationComboBox->GetSelectedNode(); if (segmentationNode == nullptr) { QMessageBox msgBox; msgBox.setText("Cannot actualize segmentation + surface + pointset data. There is no segmentation selected."); msgBox.exec(); return; } mitk::DataNode* surfaceNode = ui->selectedSurfaceComboBox->GetSelectedNode(); if (surfaceNode == nullptr) { QMessageBox msgBox; msgBox.setText("Cannot actualize segmentation + surface + pointset data. There is no surface selected."); msgBox.exec(); return; } mitk::DataNode* pointSetNode = ui->pointSetComboBox->GetSelectedNode(); if (pointSetNode == nullptr) { QMessageBox msgBox; msgBox.setText("Cannot actualize segmentation + surface + pointset data. There is no pointSet selected."); msgBox.exec(); return; } m_FloatingImageToUltrasoundRegistrationFilter->SetPointSet(pointSetNode); m_FloatingImageToUltrasoundRegistrationFilter->SetSegmentation(segmentationNode, m_FloatingImage); m_FloatingImageToUltrasoundRegistrationFilter->SetSurface(surfaceNode); } void QmitkUSNavigationStepCtUsRegistration::OnGetCursorPosition() { emit GetCursorPosition(); } void QmitkUSNavigationStepCtUsRegistration::OnCalculateTRE(mitk::Point3D centroidOfTargetInUSImage) { mitk::DataNode::Pointer pointSetNode = ui->pointSetComboBox->GetSelectedNode(); if (pointSetNode.IsNull()) { QMessageBox msgBox; msgBox.setText("Cannot calculate TRE. The pointSetComboBox node returned a nullptr."); msgBox.exec(); return; } mitk::PointSet::Pointer pointSet = dynamic_cast(pointSetNode->GetData()); if (pointSet.IsNull()) { ui->distanceTREValue->setText(QString("Unknown")); return; } double distance = pointSet->GetPoint(0).EuclideanDistanceTo(centroidOfTargetInUSImage); ui->distanceTREValue->setText(QString("%1").arg(distance)); } void QmitkUSNavigationStepCtUsRegistration::OnCalculateCenter() { mitk::DataNode::Pointer node = ui->segmentationComboBox->GetSelectedNode(); if (node.IsNull()) { QMessageBox msgBox; msgBox.setText("Cannot calculate the centroid of the segmentation."\ "The segmentationComboBox node returned a nullptr."); msgBox.exec(); return; } mitk::LabelSetImage::Pointer image = dynamic_cast(node->GetData()); if (image.IsNull()) { MITK_WARN << "Cannot CalculateCenter - the segmentation cannot be converted to mitk::Image"; return; } ImageType::Pointer itkImage = ImageType::New(); mitk::CastToItkImage(image, itkImage); //Initialize binary image to shape label map filter BinaryImageToShapeLabelMapFilterType::Pointer shapeLabelMapFilter = BinaryImageToShapeLabelMapFilterType::New(); shapeLabelMapFilter->SetInputForegroundValue(1); shapeLabelMapFilter->SetInput(itkImage); shapeLabelMapFilter->Update(); BinaryImageToShapeLabelMapFilterType::OutputImageType::Pointer labelMap = shapeLabelMapFilter->GetOutput(); for (int i = labelMap->GetNumberOfLabelObjects() - 1; i >= 0; --i) { // Get the ith region BinaryImageToShapeLabelMapFilterType::OutputImageType::LabelObjectType* labelObject = labelMap->GetNthLabelObject(i); mitk::Vector3D centroid; centroid[0] = labelObject->GetCentroid()[0]; centroid[1] = labelObject->GetCentroid()[1]; centroid[2] = labelObject->GetCentroid()[2]; MITK_INFO << "Centroid of segmentation = " << centroid; } } void QmitkUSNavigationStepCtUsRegistration::OnAddCtImageClicked() { mitk::DataNode* selectedCtImage = ui->ctImagesToChooseComboBox->GetSelectedNode(); if (selectedCtImage == nullptr) { return; } mitk::Image::Pointer ctImage = dynamic_cast(selectedCtImage->GetData()); if (ctImage.IsNull()) { MITK_WARN << "Failed to cast selected segmentation node to mitk::Image*"; return; } QString name = QString::fromStdString(selectedCtImage->GetName()); for( int counter = 0; counter < ui->chosenCtImagesListWidget->count(); ++counter) { MITK_INFO << ui->chosenCtImagesListWidget->item(counter)->text() << " - " << counter; MITK_INFO << m_ImagesGroundTruthProtocol.at(counter).GetPointer(); if (ui->chosenCtImagesListWidget->item(counter)->text().compare(name) == 0) { MITK_INFO << "CT image already exist in list of chosen CT images. Do not add the image."; return; } } ui->chosenCtImagesListWidget->addItem(name); m_ImagesGroundTruthProtocol.push_back(ctImage); } void QmitkUSNavigationStepCtUsRegistration::OnRemoveCtImageClicked() { int position = ui->chosenCtImagesListWidget->currentRow(); if (ui->chosenCtImagesListWidget->count() == 0 || position < 0) { return; } m_ImagesGroundTruthProtocol.erase(m_ImagesGroundTruthProtocol.begin() + position); QListWidgetItem *item = ui->chosenCtImagesListWidget->currentItem(); ui->chosenCtImagesListWidget->removeItemWidget(item); delete item; } void QmitkUSNavigationStepCtUsRegistration::OnEvaluateGroundTruthFiducialLocalizationProtocol() { m_GroundTruthProtocolFRE.clear(); if (m_ImagesGroundTruthProtocol.size() != 6) { QMessageBox msgBox; msgBox.setText("For evaluating the Ground-Truth-Fiducial-Localization-Protocol there must be loaded 6 different CT images."); msgBox.exec(); return; } m_PerformingGroundTruthProtocolEvaluation = true; this->CreatePointsToTransformForGroundTruthProtocol(); m_GroundTruthProtocolTransformedPoints.clear(); for (unsigned int cycleNo = 0; cycleNo < m_ImagesGroundTruthProtocol.size(); ++cycleNo) { m_FloatingImage = m_ImagesGroundTruthProtocol.at(cycleNo); this->SetFloatingImageGeometryInformation(m_FloatingImage.GetPointer()); this->OnLocalizeFiducials(); this->OnRegisterMarkerToFloatingImageCS(); this->TransformPointsGroundTruthProtocol(); } this->AddTransformedPointsToDataStorage(); double meanFRE = this->CalculateMeanFRE(); double sdOfFRE = this->CalculateStandardDeviationOfFRE(meanFRE); this->CalculateGroundTruthProtocolTRE(); ui->meanFREValue->setText(QString("%1").arg(meanFRE)); ui->sdFREValue->setText(QString("%1").arg(sdOfFRE)); if (ui->protocolEvaluationTypeComboBox->currentText().compare("ANGLE") == 0) { if (m_GroundTruthProtocolTRE.find(0) != m_GroundTruthProtocolTRE.end()) { ui->TREValue->setText(QString("%1").arg(m_GroundTruthProtocolTRE.at(0))); } } else if (ui->protocolEvaluationTypeComboBox->currentText().compare("PLANE") == 0) { if (m_GroundTruthProtocolTRE.find(0) != m_GroundTruthProtocolTRE.end() && m_GroundTruthProtocolTRE.find(20) != m_GroundTruthProtocolTRE.end() && m_GroundTruthProtocolTRE.find(40) != m_GroundTruthProtocolTRE.end() && m_GroundTruthProtocolTRE.find(60) != m_GroundTruthProtocolTRE.end() && m_GroundTruthProtocolTRE.find(80) != m_GroundTruthProtocolTRE.end() && m_GroundTruthProtocolTRE.find(100) != m_GroundTruthProtocolTRE.end()) { ui->TREValue->setText(QString("Depth 0mm: %1\nDepth 20mm: %2\nDepth 40mm: %3\ \nDepth 60mm: %4\nDepth 80mm: %5\nDepth 100mm: %6") .arg(m_GroundTruthProtocolTRE.at(0)) .arg(m_GroundTruthProtocolTRE.at(20)) .arg(m_GroundTruthProtocolTRE.at(40)) .arg(m_GroundTruthProtocolTRE.at(60)) .arg(m_GroundTruthProtocolTRE.at(80)) .arg(m_GroundTruthProtocolTRE.at(100))); } } m_PerformingGroundTruthProtocolEvaluation = false; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp index 14450e93af..7fd7430f85 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp @@ -1,290 +1,290 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkUSNavigationStepPunctuationIntervention.h" #include "ui_QmitkUSNavigationStepPunctuationIntervention.h" #include "mitkNeedleProjectionFilter.h" #include "../Widgets/QmitkZoneProgressBar.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include "usModuleRegistry.h" #include QmitkUSNavigationStepPunctuationIntervention::QmitkUSNavigationStepPunctuationIntervention(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), m_Ui(new Ui::QmitkUSNavigationStepPunctuationIntervention), m_ZoneNodes(nullptr), m_NeedleProjectionFilter(mitk::NeedleProjectionFilter::New()), m_NeedleNavigationTool(mitk::NavigationTool::New()), m_OldColors(), m_SphereSource(vtkSmartPointer::New()), m_OBBTree(vtkSmartPointer::New()), m_IntersectPoints(vtkSmartPointer::New()) { m_Ui->setupUi(this); connect(m_Ui->m_AddNewAblationZone, SIGNAL(clicked()), this, SLOT(OnAddAblationZoneClicked())); connect(m_Ui->m_ShowToolAxisN, SIGNAL(stateChanged(int)), this, SLOT(OnShowToolAxisEnabled(int))); connect(m_Ui->m_EnableAblationMarking, SIGNAL(clicked()), this, SLOT(OnEnableAblationZoneMarkingClicked())); connect(m_Ui->m_AblationZoneSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnAblationZoneSizeSliderChanged(int))); m_Ui->m_AblationZonesBox->setVisible(false); } void QmitkUSNavigationStepPunctuationIntervention::SetNeedleMetaData(mitk::NavigationTool::Pointer needleNavigationTool) { this->m_NeedleNavigationTool = needleNavigationTool; } void QmitkUSNavigationStepPunctuationIntervention::OnEnableAblationZoneMarkingClicked() { if(m_Ui->m_EnableAblationMarking->isChecked()) m_Ui->m_AblationZonesBox->setVisible(true); else m_Ui->m_AblationZonesBox->setVisible(false); } void QmitkUSNavigationStepPunctuationIntervention::OnAblationZoneSizeSliderChanged(int size) { int id = m_Ui->m_AblationZonesList->currentRow(); if (id!=-1) {emit AblationZoneChanged(id,size);} }// void QmitkUSNavigationStepPunctuationIntervention::OnAddAblationZoneClicked() { QListWidgetItem* newItem = new QListWidgetItem("Ablation Zone (initial size: " + QString::number(m_Ui->m_AblationZoneSizeSlider->value()) + " mm)", m_Ui->m_AblationZonesList); newItem->setSelected(true); emit AddAblationZoneClicked(m_Ui->m_AblationZoneSizeSlider->value()); } QmitkUSNavigationStepPunctuationIntervention::~QmitkUSNavigationStepPunctuationIntervention() { mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(false); if ( dataStorage.IsNotNull() ) { // remove needle path from data storage if it is there mitk::DataNode::Pointer node = this->GetNamedDerivedNode ("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if ( node.IsNotNull() ) { dataStorage->Remove(node); } } delete m_Ui; } bool QmitkUSNavigationStepPunctuationIntervention::OnStartStep() { // create node for Needle Projection mitk::DataNode::Pointer node = this->GetNamedDerivedNodeAndCreate ("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); //m_NeedleProjectionFilter->SetToolAxisForFilter(m_NeedleNavigationTool->GetToolAxis()); return true; } bool QmitkUSNavigationStepPunctuationIntervention::OnRestartStep() { return this->OnActivateStep(); } bool QmitkUSNavigationStepPunctuationIntervention::OnFinishStep() { mitk::DataNode::Pointer finishPunctionResult = mitk::DataNode::New(); finishPunctionResult->SetName("PunctionResult"); mitk::Point3D needlePos = m_NeedleProjectionFilter->GetOutput(0)->GetPosition(); mitk::Quaternion needleRot = m_NeedleProjectionFilter->GetOutput(0)->GetOrientation(); finishPunctionResult->SetProperty("USNavigation::TipPositionEnd", mitk::Point3dProperty::New(needlePos)); MITK_INFO("USNavigationLogging") << "Instrument tip at end: " <ClearZones(); mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); // add progress bars for risk zone nodes m_ZoneNodes = dataStorage->GetDerivations(dataStorage->GetNamedNode(QmitkUSNavigationMarkerPlacement::DATANAME_ZONES)); // add zones to the widgets for risk structures for (mitk::DataStorage::SetOfObjects::ConstIterator it = m_ZoneNodes->Begin(); it != m_ZoneNodes->End(); ++it) { m_Ui->riskStructuresRangeWidget->AddZone(it->Value()); float rgb[3]; it->Value()->GetColor(rgb); mitk::Color color; color.SetRed(rgb[0]); color.SetGreen(rgb[1]); color.SetBlue(rgb[2]); m_OldColors[it->Value()] = color; } m_NeedleProjectionFilter->SelectInput(0); return true; } void QmitkUSNavigationStepPunctuationIntervention::OnShowToolAxisEnabled(int enabled) { if (enabled == 0) { m_NeedleProjectionFilter->ShowToolAxis(false); } else { m_NeedleProjectionFilter->ShowToolAxis(true); } } void QmitkUSNavigationStepPunctuationIntervention::OnUpdate() { if (this->GetCombinedModality(false).IsNull()) return; // get navigation data source and make sure that it is not null mitk::NavigationDataSource::Pointer navigationDataSource = this->GetCombinedModality()->GetNavigationDataSource(); if ( navigationDataSource.IsNull() ) { MITK_ERROR("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepPunctuationIntervention") << "Navigation Data Source of Combined Modality must not be null."; mitkThrow() << "Navigation Data Source of Combined Modality must not be null."; } // update body marker this->UpdateBodyMarkerStatus(navigationDataSource->GetOutput(1)); // update critical structures this->UpdateCriticalStructures(navigationDataSource->GetOutput(0),m_NeedleProjectionFilter->GetProjection()); m_NeedleProjectionFilter->Update(); //Update Distance to US image mitk::Point3D point1 = m_NeedleProjectionFilter->GetProjection()->GetPoint(0); mitk::Point3D point2 = m_NeedleProjectionFilter->GetProjection()->GetPoint(1); double distance = point1.EuclideanDistanceTo(point2); m_Ui->m_DistanceToUSPlane->setText(QString::number(distance) + " mm"); } void QmitkUSNavigationStepPunctuationIntervention::OnSettingsChanged(const itk::SmartPointer settingsNode) { if ( settingsNode.IsNull() ) { return; } } QString QmitkUSNavigationStepPunctuationIntervention::GetTitle() { return "Computer-assisted Intervention"; } bool QmitkUSNavigationStepPunctuationIntervention::GetIsRestartable() { return false; } QmitkUSNavigationStepPunctuationIntervention::FilterVector QmitkUSNavigationStepPunctuationIntervention::GetFilter() { return FilterVector(1, m_NeedleProjectionFilter.GetPointer()); } void QmitkUSNavigationStepPunctuationIntervention::OnSetCombinedModality() { mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if ( combinedModality.IsNotNull() ) { m_NeedleProjectionFilter->ConnectTo(combinedModality->GetNavigationDataSource()); // set calibration of the combined modality to the needle projection filter mitk::AffineTransform3D::Pointer usPlaneTransform = combinedModality->GetUSPlaneTransform(); if (usPlaneTransform.IsNotNull()) { m_NeedleProjectionFilter->SetTargetPlane(usPlaneTransform); } } else { MITK_WARN << "CombinedModality is null!"; } } void QmitkUSNavigationStepPunctuationIntervention::ClearZones() { m_Ui->riskStructuresRangeWidget->ClearZones(); } void QmitkUSNavigationStepPunctuationIntervention::UpdateBodyMarkerStatus(mitk::NavigationData::Pointer bodyMarker) { if ( bodyMarker.IsNull() ) { MITK_ERROR("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepPunctuationIntervention") << "Current Navigation Data for body marker of Combined Modality must not be null."; mitkThrow() << "Current Navigation Data for body marker of Combined Modality must not be null."; } bool valid = bodyMarker->IsDataValid(); // update body marker status label if (valid) { m_Ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); m_Ui->bodyMarkerTrackingStatusLabel->setText("Body marker is inside the tracking volume."); } else { m_Ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); m_Ui->bodyMarkerTrackingStatusLabel->setText("Body marker is not inside the tracking volume."); } m_Ui->riskStructuresRangeGroupBox->setEnabled(valid); } void QmitkUSNavigationStepPunctuationIntervention::UpdateCriticalStructures(mitk::NavigationData::Pointer needle, mitk::PointSet::Pointer path) { // update the distances for the risk structures widget m_Ui->riskStructuresRangeWidget->UpdateDistancesToNeedlePosition(needle); //iterate through all zones for (mitk::DataStorage::SetOfObjects::ConstIterator it = m_ZoneNodes->Begin(); it != m_ZoneNodes->End(); ++it) { mitk::DataNode::Pointer currentNode = it->Value(); //get center point and radius float radius = -1; mitk::Point3D center; currentNode->GetFloatProperty("zone.size", radius); - center = currentNode->GetData()->GetGeometry()->GetIndexToWorldTransform()->GetTranslation(); + center = mitk::Point3D(currentNode->GetData()->GetGeometry()->GetIndexToWorldTransform()->GetTranslation()); mitk::Point3D point0 = path->GetPoint(0); mitk::Point3D point1 = path->GetPoint(1); if (CheckSphereLineIntersection(center,radius,point0,point1)) {currentNode->SetColor(mitk::IGTColor_WARNING);} else {currentNode->SetColor(m_OldColors[currentNode]);} } } bool QmitkUSNavigationStepPunctuationIntervention::CheckSphereLineIntersection(mitk::Point3D& sphereOrigin, float& sphereRadius, mitk::Point3D& lineStart, mitk::Point3D& lineEnd) { double center[3] = {sphereOrigin[0],sphereOrigin[1],sphereOrigin[2]}; m_SphereSource->SetCenter(center); m_SphereSource->SetRadius(sphereRadius); m_SphereSource->Update(); m_OBBTree->SetDataSet(m_SphereSource->GetOutput()); m_OBBTree->BuildLocator(); double lineP0[3] = {lineStart[0], lineStart[1], lineStart[2]}; double lineP1[3] = {lineEnd[0], lineEnd[1], lineEnd[2]}; m_OBBTree->IntersectWithLine(lineP0, lineP1, m_IntersectPoints, nullptr); if (m_IntersectPoints->GetNumberOfPoints() > 0) {return true;} else {return false;} } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTNavigationToolCalibration.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTNavigationToolCalibration.cpp index 9b73b74a67..74ac043b7c 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTNavigationToolCalibration.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTNavigationToolCalibration.cpp @@ -1,756 +1,756 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // Blueberry #include #include // Qmitk #include "QmitkIGTNavigationToolCalibration.h" // mitk #include #include #include #include #include #include #include // Qt #include #include #include // vtk #include const std::string QmitkIGTNavigationToolCalibration::VIEW_ID = "org.mitk.views.igtnavigationtoolcalibration"; QmitkIGTNavigationToolCalibration::QmitkIGTNavigationToolCalibration() { m_ToolTransformationWidget = new QmitkInteractiveTransformationWidget(); } QmitkIGTNavigationToolCalibration::~QmitkIGTNavigationToolCalibration() { //The following code is required due to a bug in the point list widget. //If this is removed, MITK crashes when closing the view: m_Controls.m_RegistrationLandmarkWidget->SetPointSetNode(nullptr); m_Controls.m_CalibrationLandmarkWidget->SetPointSetNode(nullptr); //clean up data storage this->GetDataStorage()->Remove(m_ToolTipPointPreview); delete m_ToolTransformationWidget; } void QmitkIGTNavigationToolCalibration::SetFocus() { } void QmitkIGTNavigationToolCalibration::OnToolCalibrationMethodChanged(int index) { //if pivot calibration (3) or manual(0) is chosen only calibration pointer is needed if (index == 0 || index == 3) { if (!CheckInitialization(false)) { return; } } else{ if (!CheckInitialization()) { return; } } UpdateManualToolTipCalibrationView(); m_Controls.m_CalibrationMethodsWidget->setCurrentIndex(index); m_IndexCurrentCalibrationMethod = index; } void QmitkIGTNavigationToolCalibration::CreateQtPartControl(QWidget *parent) { m_TrackingTimer = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect(m_Controls.m_SetToolToCalibrate, SIGNAL(clicked()), this, SLOT(SetToolToCalibrate())); connect(m_Controls.m_SetPointer, SIGNAL(clicked()), this, SLOT(SetCalibrationPointer())); connect(m_TrackingTimer, SIGNAL(timeout()), this, SLOT(UpdateTrackingTimer())); connect(m_Controls.m_AddLandmark, SIGNAL(clicked()), this, SLOT(AddLandmark())); connect(m_Controls.m_SaveCalibratedTool, SIGNAL(clicked()), this, SLOT(SaveCalibratedTool())); connect(m_Controls.m_AddPivotPose, SIGNAL(clicked()), this, SLOT(OnAddPivotPose())); connect(m_Controls.m_ComputePivot, SIGNAL(clicked()), this, SLOT(OnComputePivot())); connect(m_Controls.m_UseComputedPivotPoint, SIGNAL(clicked()), this, SLOT(OnUseComputedPivotPoint())); connect(m_Controls.m_StartEditTooltipManually, SIGNAL(clicked()), this, SLOT(OnStartManualToolTipCalibration())); connect(m_Controls.m_GetPositions, SIGNAL(clicked()), this, SLOT(OnGetPositions())); connect(m_Controls.m_ToolAxis_X, SIGNAL(valueChanged(double)), this, SLOT(OnToolAxisSpinboxChanged())); connect(m_Controls.m_ToolAxis_Y, SIGNAL(valueChanged(double)), this, SLOT(OnToolAxisSpinboxChanged())); connect(m_Controls.m_ToolAxis_Z, SIGNAL(valueChanged(double)), this, SLOT(OnToolAxisSpinboxChanged())); connect(m_Controls.m_CalibrateToolAxis, SIGNAL(clicked()), this, SLOT(OnCalibrateToolAxis())); connect((QObject*)(m_ToolTransformationWidget), SIGNAL(EditToolTipFinished(mitk::AffineTransform3D::Pointer)), this, SLOT(OnManualEditToolTipFinished(mitk::AffineTransform3D::Pointer))); connect(m_Controls.m_CalibrationMethodComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnToolCalibrationMethodChanged(int))); connect((QObject*)(m_Controls.m_RunCalibrationButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnRunSingleRefToolCalibrationClicked())); connect((QObject*)(m_Controls.m_CollectNavigationDataButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnLoginSingleRefToolNavigationDataClicked())); connect((QObject*)(m_Controls.m_SetNewToolTipPosButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnSetNewToolTipPosButtonClicked())); m_IDToolToCalibrate = -1; m_IDCalibrationPointer = -1; m_IndexCurrentCalibrationMethod = -1; m_OnLoginSingleRefToolNavigationDataClicked = false; m_NumberOfNavigationDataCounter = 0; m_NumberOfNavigationData = -1; //for pivot calibration m_OnAddPivotPoseClicked = false; PivotCount = 0; m_PivotPoses = std::vector(); m_CalibrationLandmarks = mitk::PointSet::New(); m_CalibrationLandmarksNode = mitk::DataNode::New(); m_CalibrationLandmarksNode->SetData(m_CalibrationLandmarks); m_Controls.m_CalibrationLandmarkWidget->SetPointSetNode(m_CalibrationLandmarksNode); m_RegistrationLandmarks = mitk::PointSet::New(); m_RegistrationLandmarksNode = mitk::DataNode::New(); m_RegistrationLandmarksNode->SetData(m_RegistrationLandmarks); m_Controls.m_RegistrationLandmarkWidget->SetPointSetNode(m_RegistrationLandmarksNode); m_ToolSurfaceInToolCoordinatesDataNode = mitk::DataNode::New(); m_ToolSurfaceInToolCoordinatesDataNode->SetName("ToolSurface(ToolCoordinates)"); m_LoggedNavigationDataDifferences = std::vector< mitk::NavigationData::Pointer >(); } void QmitkIGTNavigationToolCalibration::OnRunSingleRefToolCalibrationClicked() { if (!CheckInitialization()) { return; } mitk::NavigationData::Pointer ToolTipTransform = mitk::NavigationData::New(); if (m_Controls.m_CalibratePosition->isChecked()) { //1: Compute mean translational offset vector m_ResultOffsetVector.Fill(0); for (std::vector::iterator vecIter = m_LoggedNavigationDataOffsets.begin(); vecIter != m_LoggedNavigationDataOffsets.end(); vecIter++) { m_ResultOffsetVector[0] = m_ResultOffsetVector[0] + (*vecIter)[0]; m_ResultOffsetVector[1] = m_ResultOffsetVector[1] + (*vecIter)[1]; m_ResultOffsetVector[2] = m_ResultOffsetVector[2] + (*vecIter)[2]; } m_ResultOffsetVector[0] = m_ResultOffsetVector[0] / m_LoggedNavigationDataOffsets.size(); m_ResultOffsetVector[1] = m_ResultOffsetVector[1] / m_LoggedNavigationDataOffsets.size(); m_ResultOffsetVector[2] = m_ResultOffsetVector[2] / m_LoggedNavigationDataOffsets.size(); this->m_Controls.m_ResultOfCalibration->setText( QString("x: ") + QString(QString::number(m_ResultOffsetVector[0], 103, 3)) + QString("; y: ") + (QString::number(m_ResultOffsetVector[1], 103, 3)) + QString("; z: ") + (QString::number(m_ResultOffsetVector[2], 103, 3))); ToolTipTransform->SetPosition(m_ResultOffsetVector); } if (m_Controls.m_CalibrateOrientation->isChecked()) { //2: Compute mean orientation mitk::Quaternion meanOrientation; std::vector allOrientations = std::vector (); for (std::size_t i = 0; i < m_LoggedNavigationDataDifferences.size(); i++) { allOrientations.push_back(m_LoggedNavigationDataDifferences.at(i)->GetOrientation()); } meanOrientation = mitk::QuaternionAveraging::CalcAverage(allOrientations); this->m_Controls.m_ResultOfCalibrationOrientation->setText( QString("qx: ") + QString(QString::number(meanOrientation.x(), 103, 3)) + QString("; qy: ") + (QString::number(meanOrientation.y(), 103, 3)) + QString("; qz: ") + (QString::number(meanOrientation.z(), 103, 3)) + QString("; qr: ") + (QString::number(meanOrientation.r(), 103, 3))); ToolTipTransform->SetOrientation(meanOrientation); } MITK_INFO << "Computed calibration: "; MITK_INFO << "Translation Vector: " << ToolTipTransform->GetPosition(); MITK_INFO << "Quaternion: (" << ToolTipTransform->GetOrientation() << ")"; MITK_INFO << "Euler Angles [rad]: (" << ToolTipTransform->GetOrientation().rotation_euler_angles() << ")"; MITK_INFO << "Matrix:"; vnl_matrix_fixed rotMatrix = ToolTipTransform->GetOrientation().rotation_matrix_transpose(); MITK_INFO << rotMatrix[0][0] << " " << rotMatrix[0][1] << " " << rotMatrix[0][2] << std::endl; MITK_INFO << rotMatrix[1][0] << " " << rotMatrix[1][1] << " " << rotMatrix[1][2] << std::endl; MITK_INFO << rotMatrix[2][0] << " " << rotMatrix[2][1] << " " << rotMatrix[2][2] << std::endl; //3: write everything into the final tool tip transform and save it as member (it will be written to the tool later on) mitk::NavigationData::Pointer ToolTipInTrackingCoordinates = mitk::NavigationData::New(); ToolTipInTrackingCoordinates->Compose(ToolTipTransform); ToolTipInTrackingCoordinates->Compose(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)); ShowToolTipPreview(ToolTipInTrackingCoordinates); m_Controls.m_SetNewToolTipPosButton->setEnabled(true); m_ComputedToolTipTransformation = ToolTipTransform; } void QmitkIGTNavigationToolCalibration::OnLoginSingleRefToolNavigationDataClicked() { if (!CheckInitialization()) { return; } //reset old data m_LoggedNavigationDataOffsets.clear(); m_LoggedNavigationDataDifferences.clear(); m_OnLoginSingleRefToolNavigationDataClicked = true; m_Controls.m_CollectNavigationDataButton->setEnabled(false); m_NumberOfNavigationData = m_Controls.m_NumberOfNavigationDataToCollect->value(); MITK_INFO << "Collecting " << m_NumberOfNavigationData << " NavigationData ... " << endl; } void QmitkIGTNavigationToolCalibration::LoginSingleRefToolNavigationData() { if (!CheckInitialization()) { return; } if (m_NumberOfNavigationDataCounter < m_NumberOfNavigationData) { //update label text QString labelText = "Collecting Data: " + QString::number(m_NumberOfNavigationDataCounter); m_Controls.m_CollectionStatus->setText(labelText); mitk::NavigationData::Pointer referenceTool = m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer); mitk::NavigationData::Pointer toolToCalibrate = m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate); //compute difference: // differenceND = toolToCalibrate^-1 * referenceTool mitk::NavigationData::Pointer differenceND = mitk::NavigationData::New(); differenceND->Compose(referenceTool); differenceND->Compose(toolToCalibrate->GetInverse()); //inverse mode... if (m_Controls.m_InvertQuaternions->isChecked()) { // negate identity matrix to directly show parameters that will set up in NDI 6D Software Architect differenceND = differenceND->GetInverse(); } //save difference in member m_LoggedNavigationDataOffsets.push_back(differenceND->GetPosition()); m_LoggedNavigationDataDifferences.push_back(differenceND); m_NumberOfNavigationDataCounter++; } if (m_NumberOfNavigationDataCounter == m_NumberOfNavigationData) { m_NumberOfNavigationDataCounter = 0; m_OnLoginSingleRefToolNavigationDataClicked = false; m_Controls.m_CollectNavigationDataButton->setEnabled(true); m_Controls.m_RunCalibrationButton->setEnabled(true); MITK_INFO << "Collecting " << m_NumberOfNavigationData << " NavigationData ... Finished" << endl; QString labelText = "Collected " + QString::number(m_NumberOfNavigationData) + " data samples!"; m_Controls.m_CollectionStatus->setText(labelText); } } void QmitkIGTNavigationToolCalibration::OnSetNewToolTipPosButtonClicked() { ApplyToolTipTransform(m_ComputedToolTipTransformation); RemoveToolTipPreview(); } void QmitkIGTNavigationToolCalibration::ClearOldPivot() { mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(); this->ApplyToolTipTransform(tempND); UpdateManualToolTipCalibrationView(); //m_ManualToolTipEditWidget->hide(); //TODO this->GetDataStorage()->Remove(m_ToolSurfaceInToolCoordinatesDataNode); } void QmitkIGTNavigationToolCalibration::OnAddPivotPose() { ClearOldPivot(); //When the collect Poses Button is Clicked m_OnAddPivotPoseClicked = true; m_NumberOfNavigationData = m_Controls.m_PosesToCollect->value(); } void QmitkIGTNavigationToolCalibration::AddPivotPose() { //Save the poses to be used in computation if (PivotCount < m_NumberOfNavigationData) { mitk::NavigationData::Pointer currentPose = mitk::NavigationData::New(); currentPose->Graft(m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_IDToolToCalibrate)); m_PivotPoses.push_back(currentPose); m_Controls.m_PoseNumber->setText(QString::number(m_PivotPoses.size())); PivotCount++; } if (PivotCount == m_NumberOfNavigationData) { m_OnAddPivotPoseClicked = false; } } void QmitkIGTNavigationToolCalibration::OnComputePivot() { mitk::PivotCalibration::Pointer myPivotCalibration = mitk::PivotCalibration::New(); for (std::size_t i = 0; i < this->m_PivotPoses.size(); i++) { myPivotCalibration->AddNavigationData(m_PivotPoses.at(i)); } QString resultString; if (myPivotCalibration->ComputePivotResult()) { mitk::NavigationData::Pointer markerTransformationTrackingCoordinates = m_PivotPoses.at(0); //Get computed pivot transfromation in tool coordinates mitk::NavigationData::Pointer ToolTipToTool = mitk::NavigationData::New(); ToolTipToTool->SetPosition(myPivotCalibration->GetResultPivotPoint()); ToolTipToTool->SetOrientation(mitk::Quaternion(0,0,0,1)); mitk::NavigationData::Pointer TrackerToTool = mitk::NavigationData::New(); TrackerToTool->SetOrientation(markerTransformationTrackingCoordinates->GetOrientation()); TrackerToTool->SetPosition(markerTransformationTrackingCoordinates->GetPosition()); TrackerToTool->Compose(ToolTipToTool); // Compute pivot point in relation to marker transformation for preview mitk::NavigationData::Pointer ToolTipToTracker = mitk::NavigationData::New(); ToolTipToTracker->Compose(ToolTipToTool); ToolTipToTracker->Compose(markerTransformationTrackingCoordinates); //add the preview node to the data storage ShowToolTipPreview(ToolTipToTracker); //parse result string resultString = QString("Pivot computation succeeded!\n") + QString("RMS Error: ") + QString::number(myPivotCalibration->GetResultRMSError()) + QString("\n") + QString("Pivot Point: ") + QString::number(myPivotCalibration->GetResultPivotPoint()[0]) + ";" + QString::number(myPivotCalibration->GetResultPivotPoint()[1]) + ";" + QString::number(myPivotCalibration->GetResultPivotPoint()[2]) + QString("\n"); //finally: save results to member variable m_ComputedToolTipTransformation = ToolTipToTool; //enable button to use the computed point with the tool m_Controls.m_UseComputedPivotPoint->setEnabled(true); } else { resultString = "Pivot computation failed!"; } MITK_INFO << resultString.toStdString().c_str(); m_Controls.m_ResultText->setText(resultString); } void QmitkIGTNavigationToolCalibration::UpdatePivotCount() { PivotCount = 0; while (!m_PivotPoses.empty()) { m_PivotPoses.pop_back(); } m_Controls.m_PoseNumber->setText(QString::number(PivotCount)); } void QmitkIGTNavigationToolCalibration::OnUseComputedPivotPoint() { RemoveToolTipPreview(); QString resultString = QString("Pivoted tool tip transformation was written to the tool ") + m_ToolToCalibrate->GetToolName().c_str(); ApplyToolTipTransform(m_ComputedToolTipTransformation, resultString.toStdString()); m_Controls.m_ResultText->setText(resultString); UpdatePivotCount(); } void QmitkIGTNavigationToolCalibration::ApplyToolTipTransform(mitk::NavigationData::Pointer ToolTipTransformInToolCoordinates, std::string message) { if (!CheckInitialization(false)) { return; } //Update tool in tool storage m_ToolToCalibrate->SetToolTipPosition(ToolTipTransformInToolCoordinates->GetPosition()); m_ToolToCalibrate->SetToolAxisOrientation(ToolTipTransformInToolCoordinates->GetOrientation()); //And also update tracking device, so the transform is directly used mitk::TrackingDeviceSource::Pointer trackingDeviceSource; try { trackingDeviceSource = dynamic_cast(m_NavigationDataSourceOfToolToCalibrate.GetPointer()); mitk::TrackingTool::Pointer TrackingToolToCalibrate = trackingDeviceSource->GetTrackingDevice()->GetTool(m_IDToolToCalibrate); TrackingToolToCalibrate->SetToolTipPosition(ToolTipTransformInToolCoordinates->GetPosition(), ToolTipTransformInToolCoordinates->GetOrientation()); } catch (std::exception& e) { MITK_ERROR << "Error while trying to set the tool tip to the running tracking device. Aborting! (" << e.what() << ")"; } MITK_INFO << message; } void QmitkIGTNavigationToolCalibration::ShowToolTipPreview(mitk::NavigationData::Pointer ToolTipInTrackingCoordinates) { if(m_ToolTipPointPreview.IsNull()) { m_ToolTipPointPreview = mitk::DataNode::New(); m_ToolTipPointPreview->SetName("Modified Tool Tip Preview"); mitk::Color blue; blue.SetBlue(1); m_ToolTipPointPreview->SetColor(blue); mitk::Surface::Pointer mySphere = mitk::Surface::New(); vtkSmartPointer vtkData = vtkSmartPointer::New(); vtkData->SetRadius(3.0f); vtkData->SetCenter(0.0, 0.0, 0.0); vtkData->Update(); mySphere->SetVtkPolyData(vtkData->GetOutput()); m_ToolTipPointPreview->SetData(mySphere); this->GetDataStorage()->Add(m_ToolTipPointPreview); } m_ToolTipPointPreview->GetData()->GetGeometry()->SetIndexToWorldTransform(ToolTipInTrackingCoordinates->GetAffineTransform3D()); } void QmitkIGTNavigationToolCalibration::RemoveToolTipPreview() { this->GetDataStorage()->Remove(m_ToolTipPointPreview.GetPointer()); } void QmitkIGTNavigationToolCalibration::UpdateManualToolTipCalibrationView() { if (m_ToolToCalibrate.IsNull()) { return; } //parse human readable transformation data and display it std::stringstream translation; std::stringstream orientation; translation << m_ToolToCalibrate->GetToolTipPosition(); orientation << "Quaternion: (" << m_ToolToCalibrate->GetToolAxisOrientation() << ")" << std::endl; orientation << std::endl; orientation << "Euler Angles [rad]: (" << m_ToolToCalibrate->GetToolAxisOrientation().rotation_euler_angles() << ")" << std::endl; orientation << std::endl; orientation << "Matrix:" << std::endl; vnl_matrix_fixed rotMatrix = m_ToolToCalibrate->GetToolAxisOrientation().rotation_matrix_transpose(); orientation << rotMatrix[0][0] << " " << rotMatrix[0][1] << " " << rotMatrix[0][2] << std::endl; orientation << rotMatrix[1][0] << " " << rotMatrix[1][1] << " " << rotMatrix[1][2] << std::endl; orientation << rotMatrix[2][0] << " " << rotMatrix[2][1] << " " << rotMatrix[2][2] << std::endl; m_Controls.m_ManualCurrentTranslation->setText(translation.str().c_str()); m_Controls.m_ManualCurrentOrientation->setPlainText(orientation.str().c_str()); } void QmitkIGTNavigationToolCalibration::OnStartManualToolTipCalibration() { if (!CheckInitialization(false)) { return; } m_ToolTransformationWidget->SetToolToEdit(m_ToolToCalibrate); m_ToolTransformationWidget->SetDefaultOffset(m_ToolToCalibrate->GetToolTipPosition()); m_ToolTransformationWidget->SetDefaultRotation(m_ToolToCalibrate->GetToolAxisOrientation()); m_ToolTransformationWidget->open(); } void QmitkIGTNavigationToolCalibration::OnManualEditToolTipFinished(mitk::AffineTransform3D::Pointer toolTip) { //This function is called, when the toolTipEdit view is closed. //if user pressed cancle, nullptr is returned. Do nothing. Else, set values. if (toolTip) { mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(toolTip);//Convert to Navigation data for simple transversion to quaternion QString resultString = QString("Manual edited values are written to ") + m_ToolToCalibrate->GetToolName().c_str(); ApplyToolTipTransform(tempND, resultString.toStdString()); m_Controls.m_ResultText->setText(resultString); m_ComputedToolTipTransformation = tempND; } UpdateManualToolTipCalibrationView(); } void QmitkIGTNavigationToolCalibration::OnGetPositions() { if (!CheckInitialization(true)) { return; } //Navigation Data from Tool which should be calibrated if (!m_AxisCalibration_ToolToCalibrate) m_AxisCalibration_ToolToCalibrate = mitk::NavigationData::New(); m_AxisCalibration_ToolToCalibrate->Graft(m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_IDToolToCalibrate)); //Navigation Data from calibration pointer tool if (!m_AxisCalibration_NavDataCalibratingTool) m_AxisCalibration_NavDataCalibratingTool = mitk::NavigationData::New(); m_AxisCalibration_NavDataCalibratingTool->Graft(m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_IDCalibrationPointer)); MITK_DEBUG << "Positions for tool axis calibration:"; MITK_DEBUG << " ToolTip: " << m_AxisCalibration_ToolToCalibrate->GetPosition() << ","; MITK_DEBUG << " Rotation: \n" << m_AxisCalibration_ToolToCalibrate->GetRotationMatrix(); MITK_DEBUG << " End of the tool: " << m_AxisCalibration_NavDataCalibratingTool->GetPosition(); QString _label = "Position recorded: " + QString::number(m_AxisCalibration_NavDataCalibratingTool->GetPosition()[0], 'f', 1) + ", " + QString::number(m_AxisCalibration_NavDataCalibratingTool->GetPosition()[1], 'f', 1) + ", " + QString::number(m_AxisCalibration_NavDataCalibratingTool->GetPosition()[2], 'f', 1); m_Controls.m_ToolAxisPositionLabel->setText(_label); } void QmitkIGTNavigationToolCalibration::OnCalibrateToolAxis() { if (!m_ComputedToolTipTransformation) { MITK_ERROR << "Please compute tool tip first."; QMessageBox::information(nullptr, "Error", "Please compute / specifiy tool tip first"); return; } if (!m_AxisCalibration_ToolToCalibrate || !m_AxisCalibration_NavDataCalibratingTool) { MITK_ERROR << "Please record position first."; QMessageBox::information(nullptr, "Error", "Please record position first"); return; } //Calculate the tool tip //here is an explanation, what is happening here: /* The axis is equal to the (tool tip) minus the (end of the tool) in tool coordinates of the tool which should be calibrated. The tool tip is defined as the origin of the tool coordinate system. The end of the tool is recorded by the calibration pointer's position and is transformed into the coordinate system of the tool to be calibrated Normalize it. */ //m_CalibratedToolAxis = -m_AxisCalibration_ToolToCalibrate->TransformPoint(m_AxisCalibration_NavDataCalibratingTool->GetPosition()).GetVectorFromOrigin(); m_CalibratedToolAxis = -m_AxisCalibration_ToolToCalibrate->GetInverse()->TransformPoint(m_AxisCalibration_NavDataCalibratingTool->GetPosition()).GetVectorFromOrigin(); MITK_DEBUG << "Tool Endpoint in Tool coordinates: " << m_CalibratedToolAxis; m_CalibratedToolAxis.Normalize(); MITK_DEBUG << "Tool Axis: " << m_CalibratedToolAxis; - m_ToolToCalibrate->SetToolAxis(m_CalibratedToolAxis); + m_ToolToCalibrate->SetToolAxis(mitk::Point3D(m_CalibratedToolAxis)); // Update TrackingTool m_ComputedToolTipTransformation->SetPosition(m_ToolToCalibrate->GetToolTipPosition()); m_ComputedToolTipTransformation->SetOrientation(m_ToolToCalibrate->GetToolAxisOrientation()); ApplyToolTipTransform(m_ComputedToolTipTransformation); //Update GUI QString calibratedToolAxisString = "Tool Axis: " + QString::number(m_CalibratedToolAxis.GetElement(0), 'f', 3) + ", " + QString::number(m_CalibratedToolAxis.GetElement(1), 'f', 3) + ", " + QString::number(m_CalibratedToolAxis.GetElement(2), 'f', 3); m_Controls.m_ToolAxisCalibrationLabel->setText(calibratedToolAxisString); //Block QT signals, we don't want to emit SpinboxChanged on the first value to overwrite the next ones m_Controls.m_ToolAxis_X->blockSignals(true); m_Controls.m_ToolAxis_Y->blockSignals(true); m_Controls.m_ToolAxis_Z->blockSignals(true); m_Controls.m_ToolAxis_X->setValue(m_CalibratedToolAxis[0]); m_Controls.m_ToolAxis_Y->setValue(m_CalibratedToolAxis[1]); m_Controls.m_ToolAxis_Z->setValue(m_CalibratedToolAxis[2]); m_Controls.m_ToolAxis_X->blockSignals(false); m_Controls.m_ToolAxis_Y->blockSignals(false); m_Controls.m_ToolAxis_Z->blockSignals(false); } void QmitkIGTNavigationToolCalibration::OnToolAxisSpinboxChanged() { m_CalibratedToolAxis.SetElement(0, m_Controls.m_ToolAxis_X->value()); m_CalibratedToolAxis.SetElement(1, m_Controls.m_ToolAxis_Y->value()); m_CalibratedToolAxis.SetElement(2, m_Controls.m_ToolAxis_Z->value()); - m_ToolToCalibrate->SetToolAxis(m_CalibratedToolAxis); + m_ToolToCalibrate->SetToolAxis(mitk::Point3D(m_CalibratedToolAxis)); // Update TrackingTool if (m_ComputedToolTipTransformation.IsNull()) { m_ComputedToolTipTransformation = mitk::NavigationData::New(); } m_ComputedToolTipTransformation->SetPosition(m_ToolToCalibrate->GetToolTipPosition()); m_ComputedToolTipTransformation->SetOrientation(m_ToolToCalibrate->GetToolAxisOrientation()); ApplyToolTipTransform(m_ComputedToolTipTransformation); MITK_INFO << "Tool axis changed to " << m_CalibratedToolAxis; } void QmitkIGTNavigationToolCalibration::SetToolToCalibrate() { m_IDToolToCalibrate = m_Controls.m_SelectionWidget->GetSelectedToolID(); if (m_IDToolToCalibrate == -1) //no valid tool to calibrate { m_Controls.m_CalToolLabel->setText(""); m_Controls.m_StatusWidgetToolToCalibrate->RemoveStatusLabels(); m_TrackingTimer->stop(); } else { m_ToolToCalibrate = m_Controls.m_SelectionWidget->GetSelectedNavigationTool(); m_NavigationDataSourceOfToolToCalibrate = m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource(); m_Controls.m_CalToolLabel->setText(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)->GetName()); //initialize widget m_Controls.m_StatusWidgetToolToCalibrate->RemoveStatusLabels(); m_Controls.m_StatusWidgetToolToCalibrate->SetShowPositions(true); m_Controls.m_StatusWidgetToolToCalibrate->SetTextAlignment(Qt::AlignLeft); m_Controls.m_StatusWidgetToolToCalibrate->AddNavigationData(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)); m_Controls.m_StatusWidgetToolToCalibrate->ShowStatusLabels(); //initialize manual tool tip calibration view UpdateManualToolTipCalibrationView(); //save tool surface in tool coordinates for further editing mitk::Surface::Pointer ToolSurface = dynamic_cast(m_ToolToCalibrate->GetDataNode()->GetData())->Clone(); m_ToolSurfaceInToolCoordinatesDataNode->SetData(ToolSurface); m_ToolSurfaceInToolCoordinatesDataNode->GetData()->GetGeometry()->SetIdentity(); // update tool tip and rotation information for tool tip calibration tab UpdateManualToolTipCalibrationView(); // update tool axis information for tool axis calibration tab mitk::Point3D toolAxis = m_ToolToCalibrate->GetToolAxis(); m_CalibratedToolAxis[0] = toolAxis[0]; m_CalibratedToolAxis[1] = toolAxis[1]; m_CalibratedToolAxis[2] = toolAxis[2]; m_Controls.m_ToolAxis_X->blockSignals(true); m_Controls.m_ToolAxis_Y->blockSignals(true); m_Controls.m_ToolAxis_Z->blockSignals(true); m_Controls.m_ToolAxis_X->setValue(m_CalibratedToolAxis[0]); m_Controls.m_ToolAxis_Y->setValue(m_CalibratedToolAxis[1]); m_Controls.m_ToolAxis_Z->setValue(m_CalibratedToolAxis[2]); m_Controls.m_ToolAxis_X->blockSignals(false); m_Controls.m_ToolAxis_Y->blockSignals(false); m_Controls.m_ToolAxis_Z->blockSignals(false); //start updating timer for status widgets, etc. if (!m_TrackingTimer->isActive()) m_TrackingTimer->start(100); } } void QmitkIGTNavigationToolCalibration::SetCalibrationPointer() { m_IDCalibrationPointer = m_Controls.m_SelectionWidget->GetSelectedToolID(); if (m_IDCalibrationPointer == -1) { m_Controls.m_PointerLabel->setText(""); m_Controls.m_StatusWidgetCalibrationPointer->RemoveStatusLabels(); m_TrackingTimer->stop(); } else { m_NavigationDataSourceOfCalibrationPointer = m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource(); m_Controls.m_PointerLabel->setText(m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer)->GetName()); //initialize widget m_Controls.m_StatusWidgetCalibrationPointer->RemoveStatusLabels(); m_Controls.m_StatusWidgetCalibrationPointer->SetShowPositions(true); m_Controls.m_StatusWidgetCalibrationPointer->SetTextAlignment(Qt::AlignLeft); m_Controls.m_StatusWidgetCalibrationPointer->AddNavigationData(m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer)); m_Controls.m_StatusWidgetCalibrationPointer->ShowStatusLabels(); if (!m_TrackingTimer->isActive()) m_TrackingTimer->start(100); } } void QmitkIGTNavigationToolCalibration::UpdateOffsetCoordinates() { if (m_NavigationDataSourceOfCalibrationPointer.IsNull() || m_NavigationDataSourceOfToolToCalibrate.IsNull()) { return; } mitk::NavigationData::Pointer referenceToolND = m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer); mitk::NavigationData::Pointer toolToCalibrateND = m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate); if (referenceToolND->IsDataValid() && toolToCalibrateND->IsDataValid()) { //computation: difference between both tools (in tool coordinates) //differenceND = toolToCalibrateND^-1 * referenceToolND mitk::NavigationData::Pointer differenceND = mitk::NavigationData::New(); differenceND->Compose(referenceToolND); differenceND->Compose(toolToCalibrateND->GetInverse()); //display this orientation in the UI m_Controls.m_OffsetCoordinates->setText( QString("x: ") + QString(QString::number(differenceND->GetPosition()[0], 103, 3)) + QString("; y: ") + (QString::number(differenceND->GetPosition()[1], 103, 3)) + QString("; z: ") + (QString::number(differenceND->GetPosition()[2], 103, 3))); m_Controls.m_OrientationOffsetCoordinates->setText( QString("qx: ") + QString(QString::number(differenceND->GetOrientation().x(), 103, 3)) + QString("; qy: ") + (QString::number(differenceND->GetOrientation().y(), 103, 3)) + QString("; qz: ") + (QString::number(differenceND->GetOrientation().z(), 103, 3)) + QString("; qr: ") + (QString::number(differenceND->GetOrientation().r(), 103, 3))); //also update preview if active if (m_ToolTipPointPreview.IsNotNull()) //NOT WORKING! TODO: fix or remove! { mitk::NavigationData::Pointer ToolTipTransform = mitk::NavigationData::New(); ToolTipTransform->SetPosition(m_ResultOffsetVector); mitk::NavigationData::Pointer ToolTipInTrackingCoordinates = mitk::NavigationData::New(); //maybe store as for better peformance... ToolTipInTrackingCoordinates->Compose(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)); ToolTipInTrackingCoordinates->Compose(ToolTipTransform); m_ToolTipPointPreview->GetData()->GetGeometry()->SetIndexToWorldTransform(ToolTipInTrackingCoordinates->GetAffineTransform3D()); } } } void QmitkIGTNavigationToolCalibration::UpdateTrackingTimer() { m_Controls.m_StatusWidgetToolToCalibrate->Refresh(); m_Controls.m_StatusWidgetCalibrationPointer->Refresh(); if (m_OnLoginSingleRefToolNavigationDataClicked) LoginSingleRefToolNavigationData(); if (m_OnAddPivotPoseClicked) AddPivotPose(); // 1 == Single Reference Calibration Method if (m_IndexCurrentCalibrationMethod == 1) UpdateOffsetCoordinates(); } void QmitkIGTNavigationToolCalibration::AddLandmark() { if (!CheckInitialization()) { return; } mitk::NavigationData::Pointer navDataTool = m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate); mitk::Point3D landmark = m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer)->GetPosition(); //convert to itk transform itk::Vector translation; for (int k = 0; k < 3; k++) translation[k] = navDataTool->GetPosition()[k]; itk::Matrix rotation; for (int k = 0; k < 3; k++) for (int l = 0; l < 3; l++) rotation[k][l] = navDataTool->GetOrientation().rotation_matrix_transpose()[k][l]; rotation = rotation.GetTranspose(); itk::Vector landmarkItk; landmarkItk[0] = landmark[0]; landmarkItk[1] = landmark[1]; landmarkItk[2] = landmark[2]; //compute landmark in tool coordinates itk::Matrix rotationInverse; for (int k = 0; k < 3; k++) for (int l = 0; l < 3; l++) rotationInverse[k][l] = rotation.GetInverse()[k][l]; landmarkItk = rotationInverse * (landmarkItk - translation); //convert back and add landmark to pointset landmark[0] = landmarkItk[0]; landmark[1] = landmarkItk[1]; landmark[2] = landmarkItk[2]; m_RegistrationLandmarks->InsertPoint(m_RegistrationLandmarks->GetSize(), landmark); } void QmitkIGTNavigationToolCalibration::SaveCalibratedTool() { if (m_ToolToCalibrate.IsNotNull()) { mitk::NavigationTool::Pointer calibratedTool = m_ToolToCalibrate; calibratedTool->SetToolControlPoints(this->m_CalibrationLandmarks); calibratedTool->SetToolLandmarks(this->m_RegistrationLandmarks); mitk::NavigationToolWriter::Pointer myWriter = mitk::NavigationToolWriter::New(); QString filename = QFileDialog::getSaveFileName(nullptr,tr("Save Navigation Tool"), "/", "*.IGTTool"); if (filename.isEmpty()) return; // ensure that file suffix is set QFileInfo file(filename); if (file.suffix().isEmpty()) { filename += ".IGTTool"; } if (myWriter->DoWrite(filename.toStdString(), calibratedTool)) MITK_INFO << "Saved calibrated tool to file " << filename; else MITK_WARN << "Can't write tool to file " << filename; } else { MITK_ERROR << "Did not find navigation tool storage of calibrated tool, aborting!"; } } bool QmitkIGTNavigationToolCalibration::CheckInitialization(bool CalibrationPointerRequired) { if ((m_IDToolToCalibrate == -1) || ((CalibrationPointerRequired) && (m_IDCalibrationPointer == -1) ) ) { QMessageBox msgBox; msgBox.setText("Tool to calibrate and/or calibration pointer not initialized, cannot proceed!"); msgBox.exec(); return false; } else { return true; } }