diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp index b8fdb96d8d..2f57b3f459 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp +++ b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp @@ -1,186 +1,195 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "SimpleRenderWindowView.h" #include #include "org_mitk_example_gui_customviewer_views_Activator.h" #include #include #include #include #include #include /** * \brief Helper class adapted from QmitkAbstractRenderEditor by defining the correct plugin context. * * This helper class adapted from QmitkAbstractRenderEditor provides the rendering manager interface. */ // //! [SimpleRenderWindowViewHelper] class AbstractRenderWindowViewPrivate { public: AbstractRenderWindowViewPrivate() : m_RenderingManagerInterface(mitk::MakeRenderingManagerInterface(mitk::RenderingManager::GetInstance())), m_PrefServiceTracker(org_mitk_example_gui_customviewer_views_Activator::GetPluginContext()) // //! [SimpleRenderWindowViewHelper] { m_PrefServiceTracker.open(); } ~AbstractRenderWindowViewPrivate() { delete m_RenderingManagerInterface; } mitk::IRenderingManager *m_RenderingManagerInterface; ctkServiceTracker m_PrefServiceTracker; berry::IBerryPreferences::Pointer m_Prefs; }; const std::string SimpleRenderWindowView::VIEW_ID = "org.mitk.customviewer.views.simplerenderwindowview"; SimpleRenderWindowView::SimpleRenderWindowView() : m_RenderWindow(0), d(new AbstractRenderWindowViewPrivate) { } SimpleRenderWindowView::~SimpleRenderWindowView() { } QmitkRenderWindow *SimpleRenderWindowView::GetActiveQmitkRenderWindow() const { return m_RenderWindow; } QHash SimpleRenderWindowView::GetRenderWindows() const { QHash wnds; wnds.insert("transversal", m_RenderWindow); return wnds; } QHash SimpleRenderWindowView::GetQmitkRenderWindows() const { QHash wnds; wnds.insert("transversal", m_RenderWindow); return wnds; } QmitkRenderWindow *SimpleRenderWindowView::GetRenderWindow(const QString &id) const { if (id == "transversal") { return m_RenderWindow; } return 0; } QmitkRenderWindow *SimpleRenderWindowView::GetQmitkRenderWindow(const QString &id) const { if (id == "transversal") { return m_RenderWindow; } return 0; } +QmitkRenderWindow *SimpleRenderWindowView::GetQmitkRenderWindow(const mitk::BaseRenderer::ViewDirection &viewDirection) const +{ + if (viewDirection == mitk::BaseRenderer::ViewDirection::AXIAL) + { + return m_RenderWindow; + } + return 0; +} + mitk::Point3D SimpleRenderWindowView::GetSelectedPosition(const QString & /*id*/) const { const mitk::PlaneGeometry *pg = m_RenderWindow->GetSliceNavigationController()->GetCurrentPlaneGeometry(); if (pg) { return pg->GetCenter(); } else { return mitk::Point3D(); } } void SimpleRenderWindowView::SetSelectedPosition(const mitk::Point3D &, const QString &) { } void SimpleRenderWindowView::EnableDecorations(bool enable, const QStringList &decorations) { if (decorations.isEmpty() || decorations.contains(DECORATION_MENU)) { m_RenderWindow->ActivateMenuWidget(enable); } } bool SimpleRenderWindowView::IsDecorationEnabled(const QString &decoration) const { if (decoration == DECORATION_MENU) { return m_RenderWindow->GetActivateMenuWidgetFlag(); } return false; } QStringList SimpleRenderWindowView::GetDecorations() const { QStringList decorations; decorations << DECORATION_MENU; return decorations; } void SimpleRenderWindowView::SetFocus() { m_RenderWindow->setFocus(); } // //! [SimpleRenderWindowViewCreatePartControl] void SimpleRenderWindowView::CreateQtPartControl(QWidget *parent) { QVBoxLayout *layout = new QVBoxLayout(parent); layout->setContentsMargins(0, 0, 0, 0); m_RenderWindow = new QmitkRenderWindow(parent); layout->addWidget(m_RenderWindow); mitk::DataStorage::Pointer ds = this->GetDataStorage(); m_RenderWindow->GetRenderer()->SetDataStorage(ds); this->RequestUpdate(); } // //! [SimpleRenderWindowViewCreatePartControl] mitk::IRenderingManager *SimpleRenderWindowView::GetRenderingManager() const { // we use the global rendering manager here. This should maybe replaced // by a local one, managing only the render windows specific for the view return d->m_RenderingManagerInterface; } void SimpleRenderWindowView::RequestUpdate(mitk::RenderingManager::RequestType requestType) { if (GetRenderingManager()) GetRenderingManager()->RequestUpdateAll(requestType); } void SimpleRenderWindowView::ForceImmediateUpdate(mitk::RenderingManager::RequestType requestType) { if (GetRenderingManager()) GetRenderingManager()->ForceImmediateUpdateAll(requestType); } mitk::SliceNavigationController *SimpleRenderWindowView::GetTimeNavigationController() const { if (GetRenderingManager()) return GetRenderingManager()->GetTimeNavigationController(); return 0; } diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h index 951561c53d..529daa7a2b 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h +++ b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h @@ -1,147 +1,146 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef SimpleRenderWindowView_H_ #define SimpleRenderWindowView_H_ #include #include #include class QmitkRenderWindow; class AbstractRenderWindowViewPrivate; /** * \brief A view class suited for the ViewerPerspective within the custom viewer plug-in. * * This view class contributes data node rendering functionality to the ViewerPerspective. * Being a subclass of QmitkAbstractView, this class yields access to the data storage and * thus is interconnected with the mitk::QmitkDataManagerView present in the same perspective. * As a subclass of mitk::IRenderWindowPart, this class provides an instance of QmitkRenderWindow. * A SimpleRenderWindowView instance is part of the ViewerPerspective for data visualization. */ // //! [SimpleRenderWindowViewDeclaration] class SimpleRenderWindowView : public QmitkAbstractView, public mitk::IRenderWindowPart // //! [SimpleRenderWindowViewDeclaration] { Q_OBJECT public: /** * Standard constructor. */ SimpleRenderWindowView(); ~SimpleRenderWindowView(); /** * String based view identifier. */ static const std::string VIEW_ID; berryObjectMacro(SimpleRenderWindowView); // ------------------- mitk::IRenderWindowPart ---------------------- /** * \see mitk::IRenderWindowPart::GetActiveQmitkRenderWindow() */ QmitkRenderWindow *GetActiveQmitkRenderWindow() const override; - /** - * \see mitk::IRenderWindowPart::GetRenderWindows() - */ QHash GetRenderWindows() const; /** * \see mitk::IRenderWindowPart::GetQmitkRenderWindows() */ QHash GetQmitkRenderWindows() const override; - /** - * \see mitk::IRenderWindowPart::GetRenderWindow(QString) - */ QmitkRenderWindow *GetRenderWindow(const QString &id) const; /** * \see mitk::IRenderWindowPart::GetQmitkRenderWindow(QString) */ QmitkRenderWindow *GetQmitkRenderWindow(const QString &id) const override; + /** + * \see mitk::IRenderWindowPart::GetQmitkRenderWindow(mitk::BaseRenderer::ViewDirection) + */ + QmitkRenderWindow *GetQmitkRenderWindow(const mitk::BaseRenderer::ViewDirection &viewDirection) const override; + /** * \see mitk::IRenderWindowPart::GetSelectionPosition() */ mitk::Point3D GetSelectedPosition(const QString &id = QString()) const override; /** * \see mitk::IRenderWindowPart::SetSelectedPosition() */ void SetSelectedPosition(const mitk::Point3D &pos, const QString &id = QString()) override; /** * \see mitk::IRenderWindowPart::EnableDecorations() */ void EnableDecorations(bool enable, const QStringList &decorations = QStringList()) override; /** * \see mitk::IRenderWindowPart::IsDecorationEnabled() */ bool IsDecorationEnabled(const QString &decoration) const override; /** * \see mitk::IRenderWindowPart::GetDecorations() */ QStringList GetDecorations() const override; /** * \see mitk::QmitkAbstractRenderEditor::GetRenderingManager() */ mitk::IRenderingManager *GetRenderingManager() const override; /** * \see mitk::QmitkAbstractRenderEditor::RequestUpdate() */ void RequestUpdate( mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL) override; /** * \see mitk::QmitkAbstractRenderEditor::ForceImmediateUpdate() */ void ForceImmediateUpdate(mitk::RenderingManager::RequestType) override; /** * \see mitk::QmitkAbstractRenderEditor::GetTimeNavigationController() */ mitk::SliceNavigationController *GetTimeNavigationController() const override; protected: void SetFocus() override; /** * Creates the QmitkRenderWindow whose renderer is being connected to the view's data storage. */ void CreateQtPartControl(QWidget *parent) override; private: /** * The view's render window. */ QmitkRenderWindow *m_RenderWindow; QScopedPointer d; }; #endif /*SimpleRenderWindowView_H_*/ diff --git a/Examples/Tutorial/Step8/Step8.cpp b/Examples/Tutorial/Step8/Step8.cpp index 75c6201ebd..e660294d2b 100644 --- a/Examples/Tutorial/Step8/Step8.cpp +++ b/Examples/Tutorial/Step8/Step8.cpp @@ -1,81 +1,79 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "Step8.h" +#include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "mitkRenderingManager.h" #include #include //##Documentation //## @brief As Step6, but with QmitkStdMultiWidget as widget Step8::Step8(int argc, char *argv[], QWidget *parent) : Step6(argc, argv, parent) { } void Step8::SetupWidgets() { //************************************************************************* // Part I: Create windows and pass the tree to it //************************************************************************* // Create toplevel widget with vertical layout QVBoxLayout *vlayout = new QVBoxLayout(this); vlayout->setMargin(0); vlayout->setSpacing(2); // Create viewParent widget with horizontal layout QWidget *viewParent = new QWidget(this); vlayout->addWidget(viewParent); QHBoxLayout *hlayout = new QHBoxLayout(viewParent); hlayout->setMargin(0); //************************************************************************* // Part Ia: create and initialize QmitkStdMultiWidget //************************************************************************* QmitkStdMultiWidget *multiWidget = new QmitkStdMultiWidget(viewParent); hlayout->addWidget(multiWidget); // Tell the multiWidget which DataStorage to render multiWidget->SetDataStorage(m_DataStorage); // Initialize views as axial, sagittal, coronar (from // top-left to bottom) auto geo = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); // Initialize bottom-right view as 3D view multiWidget->GetRenderWindow4()->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); - // Enable standard handler for levelwindow-slider - multiWidget->EnableStandardLevelWindow(); - // Add the displayed views to the DataStorage to see their positions in 2D and 3D multiWidget->AddDisplayPlaneSubTree(); multiWidget->AddPlanesToDataStorage(); multiWidget->SetWidgetPlanesVisibility(true); //************************************************************************* // Part II: Setup standard interaction with the mouse //************************************************************************* } /** \example Step8.cpp */ diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp index 3cc40c3395..2c87ee6386 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUSNavigationMarkerPlacement.cpp @@ -1,874 +1,879 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationMarkerPlacement.h" #include "ui_QmitkUSNavigationMarkerPlacement.h" #include "NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h" #include "NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.h" #include "NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.h" #include "SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h" #include "mitkIRenderingManager.h" #include "mitkNodeDisplacementFilter.h" #include "mitkUSCombinedModality.h" #include #include "IO/mitkUSNavigationExperimentLogging.h" #include "IO/mitkUSNavigationStepTimer.h" #include #include #include #include #include #include #include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "QmitkStdMultiWidgetEditor.h" #include "mitkLayoutAnnotationRenderer.h" #include "mitkCameraController.h" #include // scene serialization #include #include #include #include #include const std::string QmitkUSNavigationMarkerPlacement::VIEW_ID = "org.mitk.views.usmarkerplacement"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR = "Tumour"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE = "Target Surface"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_ZONES = "Zones"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS = "Targets"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS = "Target Paths"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS = "Reached Targets"; QmitkUSNavigationMarkerPlacement::QmitkUSNavigationMarkerPlacement() : m_Parent(nullptr), m_NavigationSteps(), m_UpdateTimer(new QTimer(this)), m_ImageAndNavigationDataLoggingTimer(new QTimer(this)), m_StdMultiWidget(nullptr), m_CombinedModality(nullptr), m_ReinitAlreadyDone(false), m_IsExperimentRunning(false), m_CurrentApplicationName(), m_NavigationStepTimer(mitk::USNavigationStepTimer::New()), m_ExperimentLogging(mitk::USNavigationExperimentLogging::New()), m_IconRunning(QPixmap(":/USNavigation/record.png")), m_IconNotRunning(QPixmap(":/USNavigation/record-gray.png")), m_ResultsDirectory(), m_ExperimentName(), m_ExperimentResultsSubDirectory(), m_NavigationStepNames(), m_LoggingBackend(), m_USImageLoggingFilter(mitk::USImageLoggingFilter::New()), m_NavigationDataRecorder(mitk::NavigationDataRecorder::New()), m_TargetNodeDisplacementFilter(nullptr), m_AblationZonesDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_AblationZonesVector(), m_NeedleIndex(0), m_MarkerIndex(1), m_SceneNumber(1), m_WarnOverlay(mitk::TextAnnotation2D::New()), m_NavigationDataSource(nullptr), m_CurrentStorage(nullptr), m_ListenerDeviceChanged(this, &QmitkUSNavigationMarkerPlacement::OnCombinedModalityPropertyChanged), ui(new Ui::QmitkUSNavigationMarkerPlacement ) { connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(OnTimeout())); connect( m_ImageAndNavigationDataLoggingTimer, SIGNAL(timeout()), this, SLOT(OnImageAndNavigationDataLoggingTimeout())); // scale running (and not running) icon the specific height m_IconRunning = m_IconRunning.scaledToHeight(20, Qt::SmoothTransformation); m_IconNotRunning = m_IconNotRunning.scaledToHeight(20, Qt::SmoothTransformation); // set prefix for experiment logging (only keys with this prefix are taken // into consideration m_ExperimentLogging->SetKeyPrefix("USNavigation::"); m_UpdateTimer->start(33); // every 33 Milliseconds = 30 Frames/Second } QmitkUSNavigationMarkerPlacement::~QmitkUSNavigationMarkerPlacement() { // remove listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } // remove listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } delete ui; } void QmitkUSNavigationMarkerPlacement::OnChangeAblationZone(int id, int newSize) { if ((static_cast(m_AblationZonesVector.size()) < id) || (id < 0)) { return; } MITK_INFO << "Ablation Zone " << id << " changed, new size: " << newSize; // create a vtk sphere with given radius vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(newSize / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); mitk::Surface::Pointer zoneSurface = dynamic_cast(m_AblationZonesVector.at(id)->GetData()); zoneSurface->SetVtkPolyData(vtkSphere->GetOutput()); } void QmitkUSNavigationMarkerPlacement::OnAddAblationZone(int size) { m_AblationZonesDisplacementFilter->SetInitialReferencePose( m_CombinedModality->GetNavigationDataSource()->GetOutput(m_MarkerIndex)); mitk::DataNode::Pointer NewAblationZone = mitk::DataNode::New(); mitk::Point3D origin = m_CombinedModality->GetNavigationDataSource()->GetOutput(m_NeedleIndex)->GetPosition(); MITK_INFO("USNavigationLogging") << "Ablation Zone Added, initial size: " << size << ", origin: " << origin; mitk::Surface::Pointer zone = mitk::Surface::New(); // create a vtk sphere with given radius vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(size / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); zone->SetVtkPolyData(vtkSphere->GetOutput()); // set vtk sphere and origin to data node (origin must be set // again, because of the new sphere set as data) NewAblationZone->SetData(zone); NewAblationZone->GetData()->GetGeometry()->SetOrigin(origin); mitk::Color SphereColor = mitk::Color(); // default color SphereColor[0] = 102; SphereColor[1] = 0; SphereColor[2] = 204; NewAblationZone->SetColor(SphereColor); NewAblationZone->SetOpacity(0.3); // set name of zone std::stringstream name; name << "Ablation Zone" << m_AblationZonesVector.size(); NewAblationZone->SetName(name.str()); // add zone to filter m_AblationZonesDisplacementFilter->AddNode(NewAblationZone); m_AblationZonesVector.push_back(NewAblationZone); this->GetDataStorage()->Add(NewAblationZone); } void QmitkUSNavigationMarkerPlacement::CreateQtPartControl(QWidget *parent) { m_Parent = parent; ui->setupUi(parent); connect(ui->navigationProcessWidget, SIGNAL(SignalCombinedModalityChanged(itk::SmartPointer)), this, SLOT(OnCombinedModalityChanged(itk::SmartPointer))); connect(ui->navigationProcessWidget, SIGNAL(SignalSettingsChanged(itk::SmartPointer)), this, SLOT(OnSettingsChanged(itk::SmartPointer))); connect(ui->navigationProcessWidget, SIGNAL(SignalActiveNavigationStepChanged(int)), this, SLOT(OnActiveNavigationStepChanged(int))); connect(ui->navigationProcessWidget, SIGNAL(SignalActiveNavigationStepChangeRequested(int)), this, SLOT(OnNextNavigationStepInitialization(int))); connect(ui->startExperimentButton, SIGNAL(clicked()), this, SLOT(OnStartExperiment())); connect(ui->finishExperimentButton, SIGNAL(clicked()), this, SLOT(OnFinishExperiment())); connect(ui->m_enableNavigationLayout, SIGNAL(clicked()), this, SLOT(OnChangeLayoutClicked())); connect(ui->m_RenderWindowSelection, SIGNAL(valueChanged(int)), this, SLOT(OnRenderWindowSelection())); connect(ui->m_RefreshView, SIGNAL(clicked()), this, SLOT(OnRefreshView())); connect(ui->navigationProcessWidget, SIGNAL(SignalIntermediateResult(const itk::SmartPointer)), this, SLOT(OnIntermediateResultProduced(const itk::SmartPointer))); ui->navigationProcessWidget->SetDataStorage(this->GetDataStorage()); // indicate that no experiment is running at start ui->runningLabel->setPixmap(m_IconNotRunning); ui->navigationProcessWidget->SetSettingsWidget(new QmitkUSNavigationCombinedSettingsWidget(m_Parent)); } void QmitkUSNavigationMarkerPlacement::OnCombinedModalityPropertyChanged(const std::string &key, const std::string &) { if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { m_ReinitAlreadyDone = false; this->ReinitOnImage(); if (m_CombinedModality.IsNotNull() && !m_CombinedModality->GetIsCalibratedForCurrentStatus()) { mitk::LayoutAnnotationRenderer::AddAnnotation( m_WarnOverlay.GetPointer(), "stdmulti.widget1", mitk::LayoutAnnotationRenderer::TopLeft); MITK_WARN << "No calibration available for the selected ultrasound image depth."; } } } void QmitkUSNavigationMarkerPlacement::SetFocus() { this->ReinitOnImage(); } void QmitkUSNavigationMarkerPlacement::OnTimeout() { if (!m_StdMultiWidget) { // try to get the standard multi widget if it couldn't be got before - mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); + mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); - QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); + QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindowPart); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { - m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); + m_StdMultiWidget = dynamic_cast(multiWidgetEditor->GetMultiWidget()); + multiWidgetEditor->ShowLevelWindowWidget(false); SetTwoWindowView(); } this->CreateOverlays(); } if (m_CombinedModality.IsNotNull() && !this->m_CombinedModality->GetIsFreezed()) // if the combined modality is freezed: do nothing { ui->navigationProcessWidget->UpdateNavigationProgress(); m_AblationZonesDisplacementFilter->Update(); // update the 3D window only every fourth time to speed up the rendering (at least in 2D) this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); // make sure that a reinit was performed on the image this->ReinitOnImage(); } } void QmitkUSNavigationMarkerPlacement::OnEnableNavigationLayout() { MITK_INFO << "Navigation Layout"; // try to get the standard multi widget if it couldn't be got before - mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); + mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); - QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); + QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindowPart); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { - m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); + m_StdMultiWidget = dynamic_cast(multiWidgetEditor->GetMultiWidget()); + multiWidgetEditor->ShowLevelWindowWidget(false); SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::OnRenderWindowSelection() { SetTwoWindowView(); } void QmitkUSNavigationMarkerPlacement::OnRefreshView() { if (!ui->m_enableNavigationLayout->isChecked()) OnResetStandardLayout(); else { //Reinit the US Image Stream (this might be broken if there was a global reinit somewhere...) try { mitk::RenderingManager::GetInstance()->InitializeViews(//Reinit this->GetDataStorage()//GetDataStorage ->GetNamedNode("US Support Viewing Stream")->GetData()->GetTimeGeometry());//GetNode } catch (...) { MITK_DEBUG << "No reinit possible"; } SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::SetTwoWindowView() { if (m_StdMultiWidget) { - m_StdMultiWidget->DisableStandardLevelWindow(); int i, j, k; switch (this->ui->m_RenderWindowSelection->value()) { case 1: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetCameraController()->SetViewToCaudal(); i = 2; j = 3; //other windows k = 1; break; case 2: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetCameraController()->SetViewToSinister(); i = 1; j = 3; k = 2; break; case 3: mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetCameraController()->SetViewToAnterior(); i = 2; j = 1; k = 3; break; default: return; } - m_StdMultiWidget->changeLayoutTo2DUpAnd3DDown(k); + + // get the render window which is defined by index "k" and set it as "current render window widget" + // chose the layout that will set the current 2D window as top render window and the 3D windows as bottom render window + auto renderWindowWidget = m_StdMultiWidget->GetRenderWindowWidget(m_StdMultiWidget->GetNameFromIndex(k)); + m_StdMultiWidget->GetMultiWidgetLayoutManager()->SetCurrentRenderWindowWidget(renderWindowWidget.get()); + m_StdMultiWidget->GetMultiWidgetLayoutManager()->SetOneTop3DBottomLayout(); + ////Crosshair invisible in 3D view this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane")-> SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane")-> SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(k) + ".plane")-> SetBoolProperty("visible", true, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane")-> SetIntProperty("Crosshair.Gap Size", 0); this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane")-> SetIntProperty("Crosshair.Gap Size", 0); } } void QmitkUSNavigationMarkerPlacement::OnResetStandardLayout() { - //reset render windows - mitk::DataNode::Pointer widget1 = this->GetDataStorage()->GetNamedNode("stdmulti.widget1.plane"); - if (widget1.IsNotNull()) { widget1->SetVisibility(true); } - mitk::DataNode::Pointer widget2 = this->GetDataStorage()->GetNamedNode("stdmulti.widget2.plane"); - if (widget2.IsNotNull()) { widget2->SetVisibility(true); } - mitk::DataNode::Pointer widget3 = this->GetDataStorage()->GetNamedNode("stdmulti.widget3.plane"); - if (widget3.IsNotNull()) { widget3->SetVisibility(true); } - m_StdMultiWidget->changeLayoutToDefault(); + if (m_StdMultiWidget) + { + //reset render windows + m_StdMultiWidget->SetCrosshairVisibility(true); + m_StdMultiWidget->GetMultiWidgetLayoutManager()->SetDefaultLayout(); + } } void QmitkUSNavigationMarkerPlacement::OnChangeLayoutClicked() { if (ui->m_enableNavigationLayout->isChecked()) OnEnableNavigationLayout(); else OnResetStandardLayout(); } void QmitkUSNavigationMarkerPlacement::OnImageAndNavigationDataLoggingTimeout() { // update filter for logging navigation data and ultrasound images if (m_CombinedModality.IsNotNull()) { m_NavigationDataRecorder->Update(); // get last messages for logging filer and store them std::vector messages = m_LoggingBackend.GetNavigationMessages(); std::string composedMessage = ""; for (std::size_t i = 0; i < messages.size(); i++) { composedMessage += messages.at(i); } m_USImageLoggingFilter->AddMessageToCurrentImage(composedMessage); m_LoggingBackend.ClearNavigationMessages(); // update logging filter m_USImageLoggingFilter->Update(); } } void QmitkUSNavigationMarkerPlacement::OnStartExperiment() { // get name for the experiment by a QInputDialog bool ok; if (m_ExperimentName.isEmpty()) { // default: current date m_ExperimentName = QString::number(QDateTime::currentDateTime().date().year()) + "_" + QString::number(QDateTime::currentDateTime().date().month()) + "_" + QString::number(QDateTime::currentDateTime().date().day()) + "_experiment_" + QString::number(QDateTime::currentDateTime().time().hour()) + "." + QString::number(QDateTime::currentDateTime().time().minute()); } m_ExperimentName = QInputDialog::getText( m_Parent, QString("Experiment Name"), QString("Name of the Experiment"), QLineEdit::Normal, m_ExperimentName, &ok); MITK_INFO("USNavigationLogging") << "Experiment started: " << m_ExperimentName.toStdString(); if (ok && !m_ExperimentName.isEmpty()) { - // display error message and call the function recursivly if a directory + // display error message and call the function recursively if a directory // with the given name already exists QDir experimentResultsDir(m_ResultsDirectory + QDir::separator() + m_ExperimentName); if (experimentResultsDir.exists()) { QMessageBox::critical( m_Parent, "Results Directory Exists", "The result directory already exists.\nPlease choose an other name."); this->OnStartExperiment(); } else { QDir(m_ResultsDirectory).mkdir(m_ExperimentName); m_ExperimentResultsSubDirectory = m_ResultsDirectory + QDir::separator() + m_ExperimentName; // experiment is running now ui->runningLabel->setPixmap(m_IconRunning); ui->navigationProcessWidget->EnableInteraction(true); // (re)start timer for navigation step durations m_NavigationStepTimer->Reset(); m_NavigationStepTimer->SetOutputFileName( QString(m_ExperimentResultsSubDirectory + QDir::separator() + QString("durations.cvs")).toStdString()); m_NavigationStepTimer->SetActiveIndex(0, m_NavigationSteps.at(0)->GetTitle().toStdString()); ui->finishExperimentButton->setEnabled(true); ui->startExperimentButton->setDisabled(true); // initialize and register logging backend QString loggingFilename = m_ExperimentResultsSubDirectory + QDir::separator() + "logging.txt"; m_LoggingBackend.SetOutputFileName(loggingFilename.toStdString()); mbilog::RegisterBackend(&m_LoggingBackend); // initialize and start navigation data recorder form xml recording m_NavigationDataRecorder->StartRecording(); m_IsExperimentRunning = true; m_ImageAndNavigationDataLoggingTimer->start(1000); // (re)start experiment logging and set output file name m_ExperimentLogging->Reset(); m_ExperimentLogging->SetFileName( QString(m_ExperimentResultsSubDirectory + QDir::separator() + "experiment-logging.xml").toStdString()); } } } void QmitkUSNavigationMarkerPlacement::OnFinishExperiment() { this->WaitCursorOn(); MITK_INFO("USNavigationLogging") << "Experiment finished!"; MITK_INFO("USNavigationLogging") << "Position/Orientation of needle tip: " << (dynamic_cast(m_CombinedModality->GetTrackingDevice()->GetOutput(0)))->GetPosition(); MITK_INFO("USNavigationLogging") << "Position of target: " << m_TargetNodeDisplacementFilter->GetRawDisplacementNavigationData(0)->GetPosition(); MITK_INFO("USNavigationLogging") << "Total duration: " << m_NavigationStepTimer->GetTotalDuration(); ui->navigationProcessWidget->FinishCurrentNavigationStep(); m_ImageAndNavigationDataLoggingTimer->stop(); ui->runningLabel->setPixmap(m_IconNotRunning); ui->navigationProcessWidget->EnableInteraction(false); m_NavigationStepTimer->Stop(); // make sure that the navigation process will be start from beginning at the // next experiment ui->navigationProcessWidget->ResetNavigationProcess(); ui->finishExperimentButton->setDisabled(true); ui->startExperimentButton->setEnabled(true); MITK_INFO("USNavigationLogging") << "Writing logging data to " << m_ExperimentResultsSubDirectory.toStdString(); // save ultrasound images to the file system QDir(m_ExperimentResultsSubDirectory).mkdir("ImageStream"); m_USImageLoggingFilter->Update(); m_USImageLoggingFilter->SetImageFilesExtension(".jpg"); m_USImageLoggingFilter->SaveImages( QString(m_ExperimentResultsSubDirectory + QDir::separator() + "ImageStream" + QDir::separator()).toStdString()); m_USImageLoggingFilter = mitk::USImageLoggingFilter::New(); m_NavigationDataRecorder->StopRecording(); // Write data to csv and xml file mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.xml").toStdString().c_str())); mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.csv").toStdString().c_str())); // write logged navigation data messages to separate file std::stringstream csvNavigationMessagesFilename; csvNavigationMessagesFilename << m_ExperimentResultsSubDirectory.toStdString() << QDir::separator().toLatin1() << "CSVNavigationMessagesLogFile.csv"; MITK_INFO("USNavigationLogging") << "Writing logged navigation messages to separate csv file: " << csvNavigationMessagesFilename.str(); m_LoggingBackend.WriteCSVFileWithNavigationMessages(csvNavigationMessagesFilename.str()); mbilog::UnregisterBackend(&m_LoggingBackend); m_IsExperimentRunning = false; m_ImageAndNavigationDataLoggingTimer->stop(); m_CombinedModality = nullptr; // reset scene number for next experiment m_SceneNumber = 1; this->WaitCursorOff(); MITK_INFO("USNavigationLogging") << "Finished!"; } void QmitkUSNavigationMarkerPlacement::OnCombinedModalityChanged( itk::SmartPointer combinedModality) { // remove old listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } m_CombinedModality = combinedModality; m_ReinitAlreadyDone = false; // add a listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->AddPropertyChangedListener(m_ListenerDeviceChanged); } // update navigation data recorder for using the new combined modality mitk::NavigationDataSource::Pointer navigationDataSource = combinedModality->GetNavigationDataSource(); m_NavigationDataRecorder->ConnectTo(navigationDataSource); m_NavigationDataRecorder->ResetRecording(); // update ultrasound image logging filter for using the new combined modality mitk::USDevice::Pointer ultrasoundImageSource = combinedModality->GetUltrasoundDevice(); for (unsigned int n = 0; n < ultrasoundImageSource->GetNumberOfIndexedOutputs(); ++n) { m_USImageLoggingFilter->SetInput(n, ultrasoundImageSource->GetOutput(n)); } // update ablation zone filter for using the new combined modality for (unsigned int n = 0; n < navigationDataSource->GetNumberOfIndexedOutputs(); ++n) { m_AblationZonesDisplacementFilter->SetInput(n, navigationDataSource->GetOutput(n)); } m_AblationZonesDisplacementFilter->SelectInput(m_MarkerIndex); // make sure that a reinit is done for the new images this->ReinitOnImage(); } void QmitkUSNavigationMarkerPlacement::OnSettingsChanged(itk::SmartPointer settings) { std::string applicationName; if (!settings->GetStringProperty("settings.application", applicationName)) { // set default application if the string property is not available applicationName = "Marker Placement"; } // create navigation step widgets according to the selected application if (applicationName != m_CurrentApplicationName) { m_CurrentApplicationName = applicationName; QmitkUSNavigationProcessWidget::NavigationStepVector navigationSteps; if (applicationName == "Puncture") { QmitkUSNavigationStepCombinedModality* stepCombinedModality = new QmitkUSNavigationStepCombinedModality(m_Parent); QmitkUSNavigationStepTumourSelection* stepTumourSelection = new QmitkUSNavigationStepTumourSelection(m_Parent); stepTumourSelection->SetTargetSelectionOptional(true); m_TargetNodeDisplacementFilter = stepTumourSelection->GetTumourNodeDisplacementFilter(); QmitkUSNavigationStepZoneMarking* stepZoneMarking = new QmitkUSNavigationStepZoneMarking(m_Parent); QmitkUSNavigationStepPunctuationIntervention* stepIntervention = new QmitkUSNavigationStepPunctuationIntervention(m_Parent); connect(stepIntervention, SIGNAL(AddAblationZoneClicked(int)), this, SLOT(OnAddAblationZone(int))); connect(stepIntervention, SIGNAL(AblationZoneChanged(int, int)), this, SLOT(OnChangeAblationZone(int, int))); m_NavigationStepNames = std::vector(); navigationSteps.push_back(stepCombinedModality); m_NavigationStepNames.push_back("Combined Modality Initialization"); navigationSteps.push_back(stepTumourSelection); m_NavigationStepNames.push_back("Target Selection"); navigationSteps.push_back(stepZoneMarking); m_NavigationStepNames.push_back("Critical Structure Marking"); navigationSteps.push_back(stepIntervention); m_NavigationStepNames.push_back("Intervention"); } else if (applicationName == "Marker Placement") { QmitkUSNavigationStepCombinedModality *stepCombinedModality = new QmitkUSNavigationStepCombinedModality(m_Parent); QmitkUSNavigationStepTumourSelection *stepTumourSelection = new QmitkUSNavigationStepTumourSelection(m_Parent); m_TargetNodeDisplacementFilter = stepTumourSelection->GetTumourNodeDisplacementFilter(); QmitkUSNavigationStepZoneMarking *stepZoneMarking = new QmitkUSNavigationStepZoneMarking(m_Parent); QmitkUSNavigationStepPlacementPlanning *stepPlacementPlanning = new QmitkUSNavigationStepPlacementPlanning(m_Parent); QmitkUSNavigationStepMarkerIntervention *stepMarkerIntervention = new QmitkUSNavigationStepMarkerIntervention(m_Parent); m_NavigationStepNames = std::vector(); navigationSteps.push_back(stepCombinedModality); m_NavigationStepNames.push_back("Combined Modality Initialization"); navigationSteps.push_back(stepTumourSelection); m_NavigationStepNames.push_back("Target Selection"); navigationSteps.push_back(stepZoneMarking); m_NavigationStepNames.push_back("Critical Structure Marking"); navigationSteps.push_back(stepPlacementPlanning); m_NavigationStepNames.push_back("Placement Planning"); navigationSteps.push_back(stepMarkerIntervention); m_NavigationStepNames.push_back("Marker Intervention"); } // set navigation step widgets to the process widget ui->navigationProcessWidget->SetNavigationSteps(navigationSteps); for (QmitkUSNavigationProcessWidget::NavigationStepIterator it = m_NavigationSteps.begin(); it != m_NavigationSteps.end(); ++it) { delete *it; } m_NavigationSteps.clear(); m_NavigationSteps = navigationSteps; } // initialize gui according to the experiment mode setting bool experimentMode = false; settings->GetBoolProperty("settings.experiment-mode", experimentMode); ui->startExperimentButton->setVisible(experimentMode); ui->finishExperimentButton->setVisible(experimentMode); ui->runningLabel->setVisible(experimentMode); if (experimentMode && !m_IsExperimentRunning) { ui->navigationProcessWidget->ResetNavigationProcess(); ui->navigationProcessWidget->EnableInteraction(false); ui->runningLabel->setPixmap(m_IconNotRunning); } else if (!experimentMode) { if (m_IsExperimentRunning) { this->OnFinishExperiment(); } ui->navigationProcessWidget->EnableInteraction(true); } // get the results directory from the settings and use home directory if // there is no results directory configured std::string resultsDirectory; if (settings->GetStringProperty("settings.experiment-results-directory", resultsDirectory)) { m_ResultsDirectory = QString::fromStdString(resultsDirectory); } else { m_ResultsDirectory = QDir::homePath(); } // make sure that the results directory exists QDir resultsDirectoryQDir = QDir(m_ResultsDirectory); if (!resultsDirectoryQDir.exists()) { resultsDirectoryQDir.mkpath(m_ResultsDirectory); } MITK_INFO("USNavigation") << "Results Directory: " << m_ResultsDirectory.toStdString(); } void QmitkUSNavigationMarkerPlacement::OnActiveNavigationStepChanged(int index) { // update navigation step timer each time the active navigation step changes m_NavigationStepTimer->SetActiveIndex(index, m_NavigationSteps.at(index)->GetTitle().toStdString()); if (static_cast(m_NavigationStepNames.size()) <= index) { MITK_INFO("USNavigationLogging") << "Someting went wrong: unknown navigation step!"; } else { MITK_INFO("USNavigationLogging") << "Navigation step finished/changed, next step: " << this->m_NavigationStepNames.at(index).toStdString() << "; duration until now: " << m_NavigationStepTimer->GetTotalDuration(); } } void QmitkUSNavigationMarkerPlacement::OnNextNavigationStepInitialization(int index) { MITK_DEBUG << "Next Step: " << m_NavigationSteps.at(index)->GetTitle().toStdString(); if (m_NavigationSteps.at(index)->GetTitle().toStdString() == "Computer-assisted Intervention") { QmitkUSNavigationStepPunctuationIntervention* navigationStepPunctuationIntervention = static_cast(m_NavigationSteps.at(index)); if (navigationStepPunctuationIntervention != nullptr) { if (m_CurrentStorage.IsNull()) { this->UpdateToolStorage(); } if (m_CurrentStorage.IsNull() || (m_CurrentStorage->GetTool(m_NeedleIndex).IsNull())) { MITK_WARN << "Found null pointer when setting the tool axis, aborting"; } else { navigationStepPunctuationIntervention->SetNeedleMetaData(m_CurrentStorage->GetTool(m_NeedleIndex)); MITK_DEBUG << "Needle axis vector: " << m_CurrentStorage->GetTool(m_NeedleIndex)->GetToolAxis(); } } } } void QmitkUSNavigationMarkerPlacement::OnIntermediateResultProduced(const itk::SmartPointer resultsNode) { // intermediate results only matter during an experiment if (!m_IsExperimentRunning) { return; } this->WaitCursorOn(); // set results node to the experiment logging (for saving contents to the // file system) m_ExperimentLogging->SetResult(resultsNode); std::string resultsName; if (!resultsNode->GetName(resultsName)) { MITK_WARN << "Could not get name of current results node."; return; } // save the mitk scene std::string scenefile = QString(m_ExperimentResultsSubDirectory + QDir::separator() + QString("Scene %1 - ").arg(m_SceneNumber++, 2, 10, QChar('0')) + QString::fromStdString(resultsName).replace(":", "_") + ".mitk") .toStdString(); MITK_INFO << "Saving Scene File: " << scenefile; mitk::SceneIO::Pointer sceneIO = mitk::SceneIO::New(); mitk::NodePredicateNot::Pointer isNotHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); mitk::DataStorage::SetOfObjects::ConstPointer nodesToBeSaved = this->GetDataStorage()->GetSubset(isNotHelperObject); this->Convert2DImagesTo3D(nodesToBeSaved); sceneIO->SaveScene(nodesToBeSaved, this->GetDataStorage(), scenefile); this->WaitCursorOff(); } void QmitkUSNavigationMarkerPlacement::ReinitOnImage() { if (!m_ReinitAlreadyDone && m_CombinedModality.IsNotNull()) { // make sure that the output is already calibrated correctly // (if the zoom level was changed recently) m_CombinedModality->Modified(); m_CombinedModality->Update(); mitk::Image::Pointer image = m_CombinedModality->GetOutput(); if (image.IsNotNull() && image->IsInitialized()) { // make a reinit on the ultrasound image mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); if (renderWindow != NULL && image->GetTimeGeometry()->IsValid()) { renderWindow->GetRenderingManager()->InitializeViews( image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); renderWindow->GetRenderingManager()->RequestUpdateAll(); } this->RequestRenderWindowUpdate(); m_ReinitAlreadyDone = true; } } } void QmitkUSNavigationMarkerPlacement::Convert2DImagesTo3D(mitk::DataStorage::SetOfObjects::ConstPointer nodes) { for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); ++it) { if (it->Value()->GetData() && strcmp(it->Value()->GetData()->GetNameOfClass(), "Image") == 0) { // convert image to 3d image if it is 2d at the moment mitk::Image::Pointer image = dynamic_cast(it->Value()->GetData()); if (image.IsNotNull() && image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable()) { mitk::Convert2Dto3DImageFilter::Pointer convert2DTo3DImageFilter = mitk::Convert2Dto3DImageFilter::New(); convert2DTo3DImageFilter->SetInput(image); convert2DTo3DImageFilter->Update(); it->Value()->SetData(convert2DTo3DImageFilter->GetOutput()); } } } } void QmitkUSNavigationMarkerPlacement::CreateOverlays() { // initialize warning overlay (and do not display it, yet) m_WarnOverlay->SetText("Warning: No calibration available for current depth."); // set position and font size for the text overlay // (nonesense postition as a layouter is used, but it ignored // the overlay without setting a position here) mitk::Point2D overlayPosition; overlayPosition.SetElement(0, -50.0f); overlayPosition.SetElement(1, -50.0f); m_WarnOverlay->SetPosition2D(overlayPosition); m_WarnOverlay->SetFontSize(22); m_WarnOverlay->SetColor(1, 0, 0); // overlay should be red } void QmitkUSNavigationMarkerPlacement::UpdateToolStorage() { if (m_NavigationDataSource.IsNull()) { m_NavigationDataSource = m_CombinedModality->GetNavigationDataSource(); } if (m_NavigationDataSource.IsNull()) { MITK_WARN << "Found an invalid navigation data source object!"; } us::ModuleContext* context = us::GetModuleContext(); std::string id = m_NavigationDataSource->US_PROPKEY_ID; std::string filter = "(" + mitk::NavigationToolStorage::US_PROPKEY_SOURCE_ID + "=" + id + ")"; // Get Storage std::vector > refs = context->GetServiceReferences(); m_CurrentStorage = context->GetService(refs.front()); if (m_CurrentStorage.IsNull()) { MITK_WARN << "Found an invalid storage object!"; } else if (m_CurrentStorage->GetToolCount() != m_NavigationDataSource->GetNumberOfOutputs()) //there is something wrong with the storage { MITK_WARN << "Found a tool storage, but it has not the same number of tools like the NavigationDataSource. This storage won't be used because it isn't the right one."; m_CurrentStorage = NULL; } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp index 12da728a93..c2e9e5a46f 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp @@ -1,1169 +1,1168 @@ /*========================================================================= The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. =========================================================================*/ #include // Blueberry #include #include // Qmitk #include "QmitkIGTTrackingDataEvaluationView.h" -#include "QmitkStdMultiWidget.h" // Qt #include #include #include // MITK #include "mitkNavigationDataCSVSequentialPlayer.h" #include #include #include #include #include //ITK #include //VNL #include //vtk headers #include #include #include const std::string QmitkIGTTrackingDataEvaluationView::VIEW_ID = "org.mitk.views.igttrackingdataevaluation"; QmitkIGTTrackingDataEvaluationView::QmitkIGTTrackingDataEvaluationView() : QmitkFunctionality() , m_Controls(0) , m_MultiWidget(nullptr) , m_scalingfactor(1) { m_CSVtoXMLInputFilenameVector = std::vector(); m_CSVtoXMLOutputFilenameVector = std::vector(); } QmitkIGTTrackingDataEvaluationView::~QmitkIGTTrackingDataEvaluationView() { } void QmitkIGTTrackingDataEvaluationView::CreateQtPartControl(QWidget *parent) { // build up qt view, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkIGTTrackingDataEvaluationViewControls; m_Controls->setupUi(parent); connect(m_Controls->m_LoadInputFileList, SIGNAL(clicked()), this, SLOT(OnLoadFileList())); connect(m_Controls->m_StartEvaluation, SIGNAL(clicked()), this, SLOT(OnEvaluateData())); connect(m_Controls->m_AddToCurrentList, SIGNAL(clicked()), this, SLOT(OnAddToCurrentList())); connect(m_Controls->m_GeneratePointSetOfMeanPositions, SIGNAL(clicked()), this, SLOT(OnGeneratePointSet())); connect(m_Controls->m_GenerateRotationLines, SIGNAL(clicked()), this, SLOT(OnGenerateRotationLines())); connect(m_Controls->m_GeneratePointSet, SIGNAL(clicked()), this, SLOT(OnGenerateGroundTruthPointSet())); connect(m_Controls->m_Convert, SIGNAL(clicked()), this, SLOT(OnConvertCSVtoXMLFile())); connect(m_Controls->m_loadCSVtoXMLInputList, SIGNAL(clicked()), this, SLOT(OnCSVtoXMLLoadInputList())); connect(m_Controls->m_loadCSVtoXMLOutputList, SIGNAL(clicked()), this, SLOT(OnCSVtoXMLLoadOutputList())); connect(m_Controls->m_OrientationCalculationGenerateReference, SIGNAL(clicked()), this, SLOT(OnOrientationCalculation_CalcRef())); connect(m_Controls->m_OrientationCalculationWriteOrientationsToFile, SIGNAL(clicked()), this, SLOT(OnOrientationCalculation_CalcOrientandWriteToFile())); connect(m_Controls->m_GeneratePointSetsOfSinglePositions, SIGNAL(clicked()), this, SLOT(OnGeneratePointSetsOfSinglePositions())); connect(m_Controls->m_StartEvaluationAll, SIGNAL(clicked()), this, SLOT(OnEvaluateDataAll())); connect(m_Controls->m_GridMatching, SIGNAL(clicked()), this, SLOT(OnPerfomGridMatching())); connect(m_Controls->m_ComputeRotation, SIGNAL(clicked()), this, SLOT(OnComputeRotation())); //initialize data storage combo boxes m_Controls->m_ReferencePointSetComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ReferencePointSetComboBox->SetAutoSelectNewItems(true); m_Controls->m_ReferencePointSetComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); m_Controls->m_MeasurementPointSetComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MeasurementPointSetComboBox->SetAutoSelectNewItems(true); m_Controls->m_MeasurementPointSetComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); } } void QmitkIGTTrackingDataEvaluationView::OnComputeRotation() { //Get all data from UI auto EvaluationDataCollection = GetAllDataFromUIList(); //Compute mean Quaternions auto OrientationVector = GetMeanOrientationsOfAllData(EvaluationDataCollection); //Compute Rotations itk::Vector rotationVec; //adapt for Aurora 5D tools: [0,0,1000] rotationVec[0] = m_Controls->m_rotVecX->value(); //X rotationVec[1] = m_Controls->m_rotVecY->value(); //Y rotationVec[2] = m_Controls->m_rotVecZ->value(); //Z std::vector allOrientationErrors; for (std::vector::size_type i = 0; i < OrientationVector.size() - 1; ++i) { double AngleBetweenTwoQuaternions = mitk::StaticIGTHelperFunctions::GetAngleBetweenTwoQuaterions(OrientationVector.at(i), OrientationVector.at(i+1), rotationVec); double AngularError = fabs(AngleBetweenTwoQuaternions - 11.25); std::stringstream description; description << "Rotation Error ROT" << (i + 1) << " / ROT" << (i + 2); allOrientationErrors.push_back({ AngularError, description.str() }); MITK_INFO << description.str() << ": " << AngularError; } //compute statistics std::vector orientationErrorStatistics; orientationErrorStatistics = mitk::HummelProtocolEvaluation::ComputeStatistics(allOrientationErrors); MITK_INFO << "## Rotation error statistics: ##"; for (auto stat : orientationErrorStatistics) { MITK_INFO << stat.description << ": " << stat.distanceError; } //write results to file allOrientationErrors.insert(allOrientationErrors.end(), orientationErrorStatistics.begin(), orientationErrorStatistics.end()); allOrientationErrors.push_back({rotationVec[0],"Rot Vector [x]"}); allOrientationErrors.push_back({rotationVec[1], "Rot Vector [y]"}); allOrientationErrors.push_back({rotationVec[2], "Rot Vector [z]"}); std::stringstream filenameOrientationStat; filenameOrientationStat << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".orientationStatistics.csv"; MITK_INFO << "Writing output to file " << filenameOrientationStat.str(); writeToFile(filenameOrientationStat.str(), allOrientationErrors); } void QmitkIGTTrackingDataEvaluationView::OnPerfomGridMatching() { mitk::PointSet::Pointer reference = dynamic_cast(m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()); mitk::PointSet::Pointer measurement = dynamic_cast(m_Controls->m_MeasurementPointSetComboBox->GetSelectedNode()->GetData()); //convert point sets to vtk poly data vtkSmartPointer sourcePoints = vtkSmartPointer::New(); vtkSmartPointer targetPoints = vtkSmartPointer::New(); for (int i = 0; iGetSize(); i++) { double point[3] = { reference->GetPoint(i)[0], reference->GetPoint(i)[1], reference->GetPoint(i)[2] }; sourcePoints->InsertNextPoint(point); double point_targets[3] = { measurement->GetPoint(i)[0], measurement->GetPoint(i)[1], measurement->GetPoint(i)[2] }; targetPoints->InsertNextPoint(point_targets); } //compute transform vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->SetModeToRigidBody(); transform->Modified(); transform->Update(); //compute FRE of transform double FRE = mitk::StaticIGTHelperFunctions::ComputeFRE(reference, measurement, transform); MITK_INFO << "FRE after grid matching: " + QString::number(FRE) + " mm"; //convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); itk::Matrix rotationDouble = itk::Matrix(); itk::Vector translationDouble = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); for (int k = 0; k<3; k++) for (int l = 0; l<3; l++) { rotationFloat[k][l] = m->GetElement(k, l); rotationDouble[k][l] = m->GetElement(k, l); } for (int k = 0; k<3; k++) { translationFloat[k] = m->GetElement(k, 3); translationDouble[k] = m->GetElement(k, 3); } //create affine transform 3D mitk::AffineTransform3D::Pointer mitkTransform = mitk::AffineTransform3D::New(); mitkTransform->SetMatrix(rotationDouble); mitkTransform->SetOffset(translationDouble); mitk::NavigationData::Pointer transformNavigationData = mitk::NavigationData::New(mitkTransform); m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(mitkTransform); m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()->GetGeometry()->Modified(); //write to file std::stringstream filename; filename << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".GridMatchingResult.csv"; MITK_INFO << "Writing output to file " << filename.str(); std::vector FRE_Error; FRE_Error.push_back({ FRE, "FRE after grid matching [mm]" }); writeToFile(filename.str(), FRE_Error); } void QmitkIGTTrackingDataEvaluationView::OnOrientationCalculation_CalcRef() { if (m_FilenameVector.size() != 3) { MessageBox("Need exactly three points as reference, aborting!"); return; } //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector[i]); //check if the stream is valid and skip file if not //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); //update pipline until number of samples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) myEvaluationFilter->Update(); //store mean position as reference switch (i) { case 0: m_RefPoint1 = myEvaluationFilter->GetPositionMean(0); break; case 1: m_RefPoint2 = myEvaluationFilter->GetPositionMean(0); break; case 2: m_RefPoint3 = myEvaluationFilter->GetPositionMean(0); break; } } MessageBox("Created Reference!"); } void QmitkIGTTrackingDataEvaluationView::OnOrientationCalculation_CalcOrientandWriteToFile() { //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //open file header QString outputname = QString(m_FilenameVector.at(i).c_str()) + "_orientationFile.csv"; m_CurrentWriteFile.open(outputname.toStdString().c_str(), std::ios::out); if (m_CurrentWriteFile.bad()) { MessageBox("Error: Can't open output file!"); return; } //write header to file m_CurrentWriteFile << "Nr;Calypso_Time;Valid_Reference;MeasureTool_Measurement-Tool[x];MeasureTool_Measurement-Tool[y];MeasureTool_Measurement-Tool[z];MeasureTool_Measurement-Tool[qx];MeasureTool_Measurement-Tool[qy];MeasureTool_Measurement-Tool[qz];MeasureTool_Measurement-Tool[qr]\n"; //update pipeline until number of samples is reached int step = 0; mitk::Point3D point1, point2, point3; mitk::Quaternion current_orientation; for (int j = 0; !myPlayer->IsAtEnd(); j++) { myPlayer->Update(); mitk::NavigationData::Pointer currentNavData = myPlayer->GetOutput(0); switch (step) { case 0: step++; point1 = currentNavData->GetPosition(); break; case 1: step++; point2 = currentNavData->GetPosition(); break; case 2: step = 0; point3 = currentNavData->GetPosition(); //compute transform from reference to current points if (point1[0] == 0 && point1[1] == 0 && point1[2] == 0 && point2[0] == 0 && point2[1] == 0 && point2[2] == 0 && point3[0] == 0 && point3[1] == 0 && point3[2] == 0 ) current_orientation.fill(0); else { vtkSmartPointer transform = vtkSmartPointer::New(); vtkSmartPointer sourcePoints = vtkSmartPointer::New(); double sourcepoint1[3] = { point1[0], point1[1], point1[2] }; double sourcepoint2[3] = { point2[0], point2[1], point2[2] }; double sourcepoint3[3] = { point3[0], point3[1], point3[2] }; sourcePoints->InsertNextPoint(sourcepoint1); sourcePoints->InsertNextPoint(sourcepoint2); sourcePoints->InsertNextPoint(sourcepoint3); vtkSmartPointer targetPoints = vtkSmartPointer::New(); double targetpoint1[3] = { m_RefPoint1[0], m_RefPoint1[1], m_RefPoint1[2] }; double targetpoint2[3] = { m_RefPoint2[0], m_RefPoint2[1], m_RefPoint2[2] }; double targetpoint3[3] = { m_RefPoint3[0], m_RefPoint3[1], m_RefPoint3[2] }; targetPoints->InsertNextPoint(targetpoint1); targetPoints->InsertNextPoint(targetpoint2); targetPoints->InsertNextPoint(targetpoint3); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->Modified(); transform->Update(); mitk::Transform::Pointer newTransform = mitk::Transform::New(); newTransform->SetMatrix(transform->GetMatrix()); current_orientation = newTransform->GetOrientation(); //add pointset with the three positions if ((j > 15) && (j < 18)) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); newPointSet->InsertPoint(0, point1); newPointSet->InsertPoint(1, point2); newPointSet->InsertPoint(2, point3); QString name = QString(m_FilenameVector.at(i).c_str()); newNode->SetName(name.toStdString().c_str()); newNode->SetData(newPointSet); newNode->SetFloatProperty("pointsize", 0.1); this->GetDataStorage()->Add(newNode); } } break; } m_CurrentWriteFile << i << ";"; m_CurrentWriteFile << currentNavData->GetTimeStamp() << ";"; //IMPORTANT: change to GetIGTTimeStamp in new version! m_CurrentWriteFile << "true;"; m_CurrentWriteFile << currentNavData->GetPosition()[0] << ";"; m_CurrentWriteFile << currentNavData->GetPosition()[1] << ";"; m_CurrentWriteFile << currentNavData->GetPosition()[2] << ";"; m_CurrentWriteFile << current_orientation.x() << ";"; m_CurrentWriteFile << current_orientation.y() << ";"; m_CurrentWriteFile << current_orientation.z() << ";"; m_CurrentWriteFile << current_orientation.r() << ";"; m_CurrentWriteFile << "\n"; } //close output file m_CurrentWriteFile.close(); } MessageBox("Finished!"); } -void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) +void QmitkIGTTrackingDataEvaluationView::MultiWidgetAvailable(QmitkAbstractMultiWidget &multiWidget) { - m_MultiWidget = &stdMultiWidget; + m_MultiWidget = dynamic_cast(&multiWidget); } -void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetNotAvailable() +void QmitkIGTTrackingDataEvaluationView::MultiWidgetNotAvailable() { m_MultiWidget = nullptr; } void QmitkIGTTrackingDataEvaluationView::OnAddToCurrentList() { //read in files QStringList files = QFileDialog::getOpenFileNames(nullptr, "Select one or more files to open", "/", "CSV (*.csv)"); if (files.isEmpty()) return; for (int i = 0; i < files.size(); i++) { std::string tmp = files.at(i).toStdString().c_str(); m_FilenameVector.push_back(tmp); } //fill list at GUI m_Controls->m_FileList->clear(); for (unsigned int i = 0; i < m_FilenameVector.size(); i++) { new QListWidgetItem(tr(m_FilenameVector.at(i).c_str()), m_Controls->m_FileList); } } void QmitkIGTTrackingDataEvaluationView::OnLoadFileList() { m_FilenameVector = std::vector(); m_FilenameVector.clear(); OnAddToCurrentList(); } void QmitkIGTTrackingDataEvaluationView::OnEvaluateDataAll() { std::vector results5cm, results15cm, results30cm, resultsAccum; mitk::HummelProtocolEvaluation::HummelProtocolMeasurementVolume volume; if (m_Controls->m_standardVolume->isChecked()) { volume = mitk::HummelProtocolEvaluation::standard; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); mitk::HummelProtocolEvaluation::Evaluate15cmDistances(m_PointSetMeanPositions, volume, results15cm); mitk::HummelProtocolEvaluation::Evaluate30cmDistances(m_PointSetMeanPositions, volume, results30cm); mitk::HummelProtocolEvaluation::EvaluateAccumulatedDistances(m_PointSetMeanPositions, volume, resultsAccum); } else if (m_Controls->m_smallVolume->isChecked()) { volume = mitk::HummelProtocolEvaluation::small; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); } else if (m_Controls->m_mediumVolume->isChecked()) { volume = mitk::HummelProtocolEvaluation::medium; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); } //write results to file std::stringstream filename5cm; filename5cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results5cm.csv"; MITK_INFO << "Writing output to file " << filename5cm.str(); writeToFile(filename5cm.str(), results5cm); std::stringstream filename15cm; filename15cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results15cm.csv"; MITK_INFO << "Writing output to file " << filename15cm.str(); writeToFile(filename15cm.str(), results15cm); std::stringstream filename30cm; filename30cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results30cm.csv"; MITK_INFO << "Writing output to file " << filename30cm.str(); writeToFile(filename30cm.str(), results30cm); std::stringstream filenameAccum; filenameAccum << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".resultsAccumDist.csv"; MITK_INFO << "Writing output to file " << filenameAccum.str(); writeToFile(filenameAccum.str(), resultsAccum); } void QmitkIGTTrackingDataEvaluationView::OnEvaluateData() { //open output file m_CurrentWriteFile.open(std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str(), std::ios::out); if (m_CurrentWriteFile.bad()) { MessageBox("Error: Can't open output file!"); return; } std::vector jitterValues; //write output file header WriteHeader(); //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++i) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } if (myPlayer->GetNumberOfSnapshots() < m_Controls->m_NumberOfSamples->value()) { MITK_WARN << "Number of snapshots (" << myPlayer->GetNumberOfSnapshots() << ") smaller than number of samples to evaluate (" << m_Controls->m_NumberOfSamples->value() << ") ! Cannot proceed!"; return; } //update pipline until number of samples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) myEvaluationFilter->Update(); //store all jitter values in separate vector for statistics jitterValues.push_back({ myEvaluationFilter->GetPositionErrorRMS(0), "RMS" }); //write result to output file WriteDataSet(myEvaluationFilter, m_FilenameVector.at(i)); } //close output file for single data m_CurrentWriteFile.close(); //compute statistics std::vector jitterStatistics = mitk::HummelProtocolEvaluation::ComputeStatistics(jitterValues); MITK_INFO << "## Jitter (RMS) statistics: ##"; for (auto jitterStat : jitterStatistics) {MITK_INFO << jitterStat.description << ": " << jitterStat.distanceError;} //write statistic results to separate file std::stringstream filenameJitterStat; filenameJitterStat << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".resultsJitterStatistics.csv"; MITK_INFO << "Writing output to file " << filenameJitterStat.str(); writeToFile(filenameJitterStat.str(), jitterStatistics); //calculate angles if option is on if (m_Controls->m_settingDifferenceAngles->isChecked() || m_Controls->m_DifferencesSLERP->isChecked()) CalculateDifferenceAngles(); MessageBox("Finished!"); } void QmitkIGTTrackingDataEvaluationView::OnGeneratePointSetsOfSinglePositions() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create point set for this file mitk::PointSet::Pointer thisPointSet = mitk::PointSet::New(); //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //update pipline until number of samlples is reached and store every single point for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) { myPlayer->Update(); mitk::Point3D thisPoint = myPlayer->GetOutput()->GetPosition(); thisPoint[0] *= m_scalingfactor; thisPoint[1] *= m_scalingfactor; thisPoint[2] *= m_scalingfactor; thisPointSet->InsertPoint(j, thisPoint); } //add point set to data storage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString name = this->m_Controls->m_prefix->text() + QString("PointSet_of_All_Positions_") + QString::number(i); newNode->SetName(name.toStdString()); newNode->SetData(thisPointSet); this->GetDataStorage()->Add(newNode); } } void QmitkIGTTrackingDataEvaluationView::OnGeneratePointSet() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); mitk::PointSet::Pointer generatedPointSet = mitk::PointSet::New(); //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } //update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) { myEvaluationFilter->Update(); } //add mean position to point set mitk::Point3D meanPos = myEvaluationFilter->GetPositionMean(0); if (m_scalingfactor != 1) { meanPos[0] *= m_scalingfactor; meanPos[1] *= m_scalingfactor; meanPos[2] *= m_scalingfactor; } generatedPointSet->InsertPoint(i, meanPos); } //add point set to data storage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString name = this->m_Controls->m_prefix->text() + "PointSet_of_Mean_Positions"; newNode->SetName(name.toStdString()); newNode->SetData(generatedPointSet); newNode->SetFloatProperty("pointsize", 5); this->GetDataStorage()->Add(newNode); m_PointSetMeanPositions = generatedPointSet; } void QmitkIGTTrackingDataEvaluationView::OnGenerateRotationLines() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } //update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) myEvaluationFilter->Update(); //create line from mean pos to a second point which lies along the sensor (1,0,0 in tool coordinates for aurora) mitk::Point3D meanPos = myEvaluationFilter->GetPositionMean(0); if (m_scalingfactor != 1) { meanPos[0] *= m_scalingfactor; meanPos[1] *= m_scalingfactor; meanPos[2] *= m_scalingfactor; } mitk::Point3D secondPoint; mitk::Point3D thirdPoint; mitk::Point3D fourthPoint; mitk::FillVector3D(secondPoint, 2, 0, 0); //X vnl_vector secondPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * secondPoint.GetVnlVector() + meanPos.GetVnlVector(); mitk::Point3D secondPointTransformedMITK; mitk::FillVector3D(secondPointTransformedMITK, secondPointTransformed[0], secondPointTransformed[1], secondPointTransformed[2]); mitk::FillVector3D(thirdPoint, 0, 4, 0); //Y vnl_vector thirdPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * thirdPoint.GetVnlVector() + meanPos.GetVnlVector(); mitk::Point3D thirdPointTransformedMITK; mitk::FillVector3D(thirdPointTransformedMITK, thirdPointTransformed[0], thirdPointTransformed[1], thirdPointTransformed[2]); mitk::FillVector3D(fourthPoint, 0, 0, 6); //Z vnl_vector fourthPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * fourthPoint.GetVnlVector() + meanPos.GetVnlVector(); mitk::Point3D fourthPointTransformedMITK; mitk::FillVector3D(fourthPointTransformedMITK, fourthPointTransformed[0], fourthPointTransformed[1], fourthPointTransformed[2]); mitk::PointSet::Pointer rotationLine = mitk::PointSet::New(); rotationLine->InsertPoint(0, secondPointTransformedMITK); rotationLine->InsertPoint(1, meanPos); rotationLine->InsertPoint(2, thirdPointTransformedMITK); rotationLine->InsertPoint(3, meanPos); rotationLine->InsertPoint(4, fourthPointTransformedMITK); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString nodeName = this->m_Controls->m_prefix->text() + "RotationLineNumber" + QString::number(i); newNode->SetName(nodeName.toStdString()); newNode->SetData(rotationLine); newNode->SetBoolProperty("show contour", true); newNode->SetFloatProperty("pointsize", 0.5); this->GetDataStorage()->Add(newNode); } } void QmitkIGTTrackingDataEvaluationView::OnGenerateGroundTruthPointSet() { mitk::PointSet::Pointer generatedPointSet = mitk::PointSet::New(); int currentPointID = 0; mitk::Point3D currentPoint; mitk::FillVector3D(currentPoint, 0, 0, 0); for (int i = 0; i < m_Controls->m_PointNumber2->value(); i++) { for (int j = 0; j < m_Controls->m_PointNumber1->value(); j++) { generatedPointSet->InsertPoint(currentPointID, currentPoint); currentPointID++; currentPoint[1] += m_Controls->m_PointDistance->value(); } currentPoint[1] = 0; currentPoint[2] += m_Controls->m_PointDistance->value(); } mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString nodeName = "GroundTruthPointSet_" + QString::number(m_Controls->m_PointNumber1->value()) + "x" + QString::number(m_Controls->m_PointNumber2->value()) + "_(" + QString::number(m_Controls->m_PointDistance->value()) + "mm)"; newNode->SetName(nodeName.toStdString()); newNode->SetData(generatedPointSet); newNode->SetFloatProperty("pointsize", 5); this->GetDataStorage()->Add(newNode); } void QmitkIGTTrackingDataEvaluationView::OnConvertCSVtoXMLFile() { if (m_Controls->m_ConvertSingleFile->isChecked()) { //convert one file int lines = ConvertOneFile(this->m_Controls->m_InputCSV->text().toStdString(), this->m_Controls->m_OutputXML->text().toStdString()); QString result = "Converted one file with" + QString::number(lines) + " data sets"; MessageBox(result.toStdString()); } else //converte file list { if (m_CSVtoXMLInputFilenameVector.empty() || m_CSVtoXMLOutputFilenameVector.empty()) { MessageBox("Error: one list is not loaded!"); return; } else if (m_CSVtoXMLInputFilenameVector.size() != m_CSVtoXMLOutputFilenameVector.size()) { MessageBox("Error: lists do not have the same number of files!"); return; } for (std::size_t i = 0; i < m_CSVtoXMLInputFilenameVector.size(); ++i) { ConvertOneFile(m_CSVtoXMLInputFilenameVector.at(i), m_CSVtoXMLOutputFilenameVector.at(i)); } QString result = "Converted " + QString::number(m_CSVtoXMLInputFilenameVector.size()) + " files from file list!"; MessageBox(result.toStdString()); } } int QmitkIGTTrackingDataEvaluationView::ConvertOneFile(std::string inputFilename, std::string outputFilename) { std::vector myNavigationDatas = GetNavigationDatasFromFile(inputFilename); mitk::NavigationDataRecorderDeprecated::Pointer myRecorder = mitk::NavigationDataRecorderDeprecated::New(); myRecorder->SetFileName(outputFilename.c_str()); mitk::NavigationData::Pointer input = mitk::NavigationData::New(); if (m_Controls->m_ConvertCSV->isChecked()) myRecorder->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); myRecorder->AddNavigationData(input); myRecorder->StartRecording(); for (std::size_t i = 0; i < myNavigationDatas.size(); ++i) { input->Graft(myNavigationDatas.at(i)); myRecorder->Update(); } myRecorder->StopRecording(); return myNavigationDatas.size(); } void QmitkIGTTrackingDataEvaluationView::OnCSVtoXMLLoadInputList() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_CSVtoXMLInputFilenameVector = this->GetFileContentLineByLine(filename.toStdString()); m_Controls->m_labelCSVtoXMLInputList->setText("READY"); } void QmitkIGTTrackingDataEvaluationView::OnCSVtoXMLLoadOutputList() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_CSVtoXMLOutputFilenameVector = this->GetFileContentLineByLine(filename.toStdString()); m_Controls->m_labelCSVtoXMLOutputList->setText("READY"); } void QmitkIGTTrackingDataEvaluationView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkIGTTrackingDataEvaluationView::WriteHeader() { m_CurrentWriteFile << "Filename;"; m_CurrentWriteFile << "N;"; m_CurrentWriteFile << "N_invalid;"; m_CurrentWriteFile << "Percentage_invalid;"; if (m_Controls->m_settingPosMean->isChecked()) { m_CurrentWriteFile << "Position_Mean[x];"; m_CurrentWriteFile << "Position_Mean[y];"; m_CurrentWriteFile << "Position_Mean[z];"; } if (m_Controls->m_settingPosStabw->isChecked()) { m_CurrentWriteFile << "Position_StandDev[x];"; m_CurrentWriteFile << "Position_StandDev[y];"; m_CurrentWriteFile << "Position_StandDev[z];"; } if (m_Controls->m_settingPosSampleStabw->isChecked()) { m_CurrentWriteFile << "Position_SampleStandDev[x];"; m_CurrentWriteFile << "Position_SampleStandDev[y];"; m_CurrentWriteFile << "Position_SampleStandDev[z];"; } if (m_Controls->m_settingQuaternionMean->isChecked()) { m_CurrentWriteFile << "Quaternion_Mean[qx];"; m_CurrentWriteFile << "Quaternion_Mean[qy];"; m_CurrentWriteFile << "Quaternion_Mean[qz];"; m_CurrentWriteFile << "Quaternion_Mean[qr];"; } if (m_Controls->m_settionQuaternionStabw->isChecked()) { m_CurrentWriteFile << "Quaternion_StandDev[qx];"; m_CurrentWriteFile << "Quaternion_StandDev[qy];"; m_CurrentWriteFile << "Quaternion_StandDev[qz];"; m_CurrentWriteFile << "Quaternion_StandDev[qr];"; } if (m_Controls->m_settingPosErrorMean->isChecked()) m_CurrentWriteFile << "PositionError_Mean;"; if (m_Controls->m_settingPosErrorStabw->isChecked()) m_CurrentWriteFile << "PositionError_StandDev;"; if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) m_CurrentWriteFile << "PositionError_SampleStandDev;"; if (m_Controls->m_settingPosErrorRMS->isChecked()) m_CurrentWriteFile << "PositionError_RMS;"; if (m_Controls->m_settingPosErrorMedian->isChecked()) m_CurrentWriteFile << "PositionError_Median;"; if (m_Controls->m_settingPosErrorMinMax->isChecked()) { m_CurrentWriteFile << "PositionError_Max;"; m_CurrentWriteFile << "PositionError_Min;"; } if (m_Controls->m_settingEulerMean->isChecked()) { m_CurrentWriteFile << "Euler_tx;"; m_CurrentWriteFile << "Euler_ty;"; m_CurrentWriteFile << "Euler_tz;"; } if (m_Controls->m_settingEulerRMS->isChecked()) { m_CurrentWriteFile << "EulerErrorRMS (rad);"; m_CurrentWriteFile << "EulerErrorRMS (grad);"; } m_CurrentWriteFile << "\n"; } void QmitkIGTTrackingDataEvaluationView::WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter, std::string dataSetName) { if (myEvaluationFilter->GetNumberOfOutputs() == 0) m_CurrentWriteFile << "Error: no input \n"; else { m_CurrentWriteFile << dataSetName << ";"; m_CurrentWriteFile << myEvaluationFilter->GetNumberOfAnalysedNavigationData(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetNumberOfInvalidSamples(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPercentageOfInvalidSamples(0) << ";"; if (m_Controls->m_settingPosMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[2] << ";"; } if (m_Controls->m_settingPosStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[2] << ";"; } if (m_Controls->m_settingPosSampleStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[2] << ";"; } if (m_Controls->m_settingQuaternionMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).x() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).y() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).z() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).r() << ";"; } if (m_Controls->m_settionQuaternionStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).x() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).y() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).z() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).r() << ";"; } if (m_Controls->m_settingPosErrorMean->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMean(0) << ";"; if (m_Controls->m_settingPosErrorStabw->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorStandardDeviation(0) << ";"; if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorSampleStandardDeviation(0) << ";"; if (m_Controls->m_settingPosErrorRMS->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorRMS(0) << ";"; if (m_Controls->m_settingPosErrorMedian->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMedian(0) << ";"; if (m_Controls->m_settingPosErrorMinMax->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMax(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMin(0) << ";"; } if (m_Controls->m_settingEulerMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[2] << ";"; } if (m_Controls->m_settingEulerRMS->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesRMS(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesRMSDegree(0) << ";"; } m_CurrentWriteFile << "\n"; } } std::vector QmitkIGTTrackingDataEvaluationView::GetMeanOrientationsOfAllData(std::vector allData, bool useSLERP) { std::vector returnValue; for (auto dataSet : allData) { if (useSLERP) returnValue.push_back(GetSLERPAverage(dataSet)); else returnValue.push_back(dataSet->GetQuaternionMean(0)); } return returnValue; } std::vector QmitkIGTTrackingDataEvaluationView::GetAllDataFromUIList() { std::vector EvaluationDataCollection; //start loop and iterate through all files of list: store the evaluation data for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); //update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) myEvaluationFilter->Update(); myEvaluationFilter->SetInput(nullptr); myPlayer = nullptr; EvaluationDataCollection.push_back(myEvaluationFilter); } return EvaluationDataCollection; } void QmitkIGTTrackingDataEvaluationView::CalculateDifferenceAngles() { //Get all data from UI std::vector EvaluationDataCollection = GetAllDataFromUIList(); //calculation and writing of output data //open output file m_CurrentAngleDifferencesWriteFile.open(std::string((m_Controls->m_OutputFilename->text() + ".angledifferences.csv").toUtf8()).c_str(), std::ios::out); if (m_CurrentAngleDifferencesWriteFile.bad()) { MessageBox("Error: Can't open output file for angle differences calculation!"); return; } //write header WriteDifferenceAnglesHeader(); //compute angle differences QString pos1 = "invalid"; QString pos2 = "invalid"; //now iterate through all evaluation data and calculate the angles for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { pos1 = QString::fromStdString(itksys::SystemTools::GetFilenameWithoutLastExtension(m_FilenameVector.at(i))); for (std::size_t j = 0; j < m_FilenameVector.size(); ++j) { pos2 = QString::fromStdString(itksys::SystemTools::GetFilenameWithoutLastExtension(m_FilenameVector.at(j))); mitk::Quaternion q1; mitk::Quaternion q2; if (m_Controls->m_DifferencesSLERP->isChecked()) { //compute slerp average q1 = GetSLERPAverage(EvaluationDataCollection.at(i)); q2 = GetSLERPAverage(EvaluationDataCollection.at(j)); } else { //compute arithmetic average q1 = EvaluationDataCollection.at(i)->GetQuaternionMean(0); q2 = EvaluationDataCollection.at(j)->GetQuaternionMean(0); } itk::Vector rotationVec; //adapt for Aurora 5D tools: [0,0,1000] rotationVec[0] = 10000; //X rotationVec[1] = 0; //Y rotationVec[2] = 0; //Z double AngleBetweenTwoQuaternions = mitk::StaticIGTHelperFunctions::GetAngleBetweenTwoQuaterions(q1, q2, rotationVec); //write data set WriteDifferenceAnglesDataSet(pos1.toStdString(), pos2.toStdString(), i, j, AngleBetweenTwoQuaternions); } } //close output file m_CurrentAngleDifferencesWriteFile.close(); } void QmitkIGTTrackingDataEvaluationView::WriteDifferenceAnglesHeader() { m_CurrentAngleDifferencesWriteFile << "Name;Idx1;Idx2;Angle [Degree]\n"; } void QmitkIGTTrackingDataEvaluationView::WriteDifferenceAnglesDataSet(std::string pos1, std::string pos2, int idx1, int idx2, double angle) { m_CurrentAngleDifferencesWriteFile << "Angle between " << pos1 << " and " << pos2 << ";" << idx1 << ";" << idx2 << ";" << angle << "\n"; MITK_INFO << "Angle: " << angle; } std::vector QmitkIGTTrackingDataEvaluationView::GetNavigationDatasFromFile(std::string filename) { std::vector returnValue = std::vector(); std::vector fileContentLineByLine = GetFileContentLineByLine(filename); for (std::size_t i = 1; i < fileContentLineByLine.size(); ++i) //skip header so start at 1 { returnValue.push_back(GetNavigationDataOutOfOneLine(fileContentLineByLine.at(i))); } return returnValue; } std::vector QmitkIGTTrackingDataEvaluationView::GetFileContentLineByLine(std::string filename) { std::vector readData = std::vector(); //save old locale char * oldLocale; oldLocale = setlocale(LC_ALL, 0); //define own locale std::locale C("C"); setlocale(LC_ALL, "C"); //read file std::ifstream file; file.open(filename.c_str(), std::ios::in); if (file.good()) { //read out file file.seekg(0L, std::ios::beg); // move to begin of file while (!file.eof()) { std::string buffer; std::getline(file, buffer); // read out file line by line if (buffer.size() > 0) readData.push_back(buffer); } } file.close(); //switch back to old locale setlocale(LC_ALL, oldLocale); return readData; } mitk::NavigationData::Pointer QmitkIGTTrackingDataEvaluationView::GetNavigationDataOutOfOneLine(std::string line) { mitk::NavigationData::Pointer returnValue = mitk::NavigationData::New(); QString myLine = QString(line.c_str()); QStringList myLineList = myLine.split(';'); mitk::Point3D position; mitk::Quaternion orientation; bool valid = false; if (myLineList.at(2).toStdString() == "1") valid = true; position[0] = myLineList.at(3).toDouble(); position[1] = myLineList.at(4).toDouble(); position[2] = myLineList.at(5).toDouble(); orientation[0] = myLineList.at(6).toDouble(); orientation[1] = myLineList.at(7).toDouble(); orientation[2] = myLineList.at(8).toDouble(); orientation[3] = myLineList.at(9).toDouble(); returnValue->SetDataValid(valid); returnValue->SetPosition(position); returnValue->SetOrientation(orientation); return returnValue; } mitk::Quaternion QmitkIGTTrackingDataEvaluationView::GetSLERPAverage(mitk::NavigationDataEvaluationFilter::Pointer evaluationFilter) { mitk::Quaternion average; //build a vector of quaternions from the evaulation filter (caution always takes the first (0) input of the filter std::vector quaternions = std::vector(); for (int i = 0; i < evaluationFilter->GetNumberOfAnalysedNavigationData(0); i++) { mitk::Quaternion currentq = evaluationFilter->GetLoggedOrientation(i, 0); quaternions.push_back(currentq); } //compute the slerp average using the quaternion averaging class mitk::QuaternionAveraging::Pointer myAverager = mitk::QuaternionAveraging::New(); average = myAverager->CalcAverage(quaternions); return average; } void QmitkIGTTrackingDataEvaluationView::writeToFile(std::string filename, std::vector values) { std::fstream currentFile; currentFile.open(filename.c_str(), std::ios::out); if (currentFile.bad()) { MITK_WARN << "Cannot open file, aborting!"; return; } currentFile << "Description" << ";" << "Error[mm]" << "\n"; for (auto currentError : values) { currentFile << currentError.description << ";" << currentError.distanceError << "\n"; } currentFile.close(); } mitk::NavigationDataCSVSequentialPlayer::Pointer QmitkIGTTrackingDataEvaluationView::ConstructNewNavigationDataPlayer() { bool rightHanded = m_Controls->m_RigthHanded->isChecked(); QString separator = m_Controls->m_SeparatorSign->text(); QChar sepaSign = separator.at(0); //char separatorSign; char separatorSign = sepaSign.toLatin1(); //std::string separatorSign = m_Controls->m_SeparatorSign->text().toStdString(); int sampleCount = m_Controls->m_SampleCount->value(); bool headerRow = m_Controls->m_HeaderRow->isChecked(); int xPos = m_Controls->m_XPos->value(); int yPos = m_Controls->m_YPos->value(); int zPos = m_Controls->m_ZPos->value(); bool useQuats = m_Controls->m_UseQuats->isChecked(); int qx = m_Controls->m_Qx->value(); int qy = m_Controls->m_Qy->value(); int qz = m_Controls->m_Qz->value(); int qr = m_Controls->m_Qr->value(); int azimuth = m_Controls->m_Azimuth->value(); int elevation = m_Controls->m_Elevation->value(); int roll = m_Controls->m_Roll->value(); bool eulersInRad = m_Controls->m_Radiants->isChecked(); //need to find the biggest column number to determine the minimal number of columns the .csv file has to have int allInts[] = {xPos, yPos, zPos, qx, qy, qr, azimuth, elevation, roll}; int minNumberOfColumns = (*std::max_element(allInts, allInts+9)+1); //size needs to be +1 because columns start at 0 but size at 1 mitk::NavigationDataCSVSequentialPlayer::Pointer navDataPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); navDataPlayer->SetOptions(rightHanded, separatorSign, sampleCount, headerRow, xPos, yPos, zPos, useQuats, qx, qy, qz, qr, azimuth, elevation, roll, eulersInRad, minNumberOfColumns); return navDataPlayer; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h index 28271da295..f73c5f142c 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h @@ -1,142 +1,143 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkIGTTrackingDataEvaluationView_h #define QmitkIGTTrackingDataEvaluationView_h #include #include +#include #include "ui_QmitkIGTTrackingDataEvaluationViewControls.h" #include "mitkHummelProtocolEvaluation.h" #include #include "mitkNavigationDataCSVSequentialPlayer.h" /*! \brief QmitkIGTTrackingDataEvaluationView \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkIGTTrackingDataEvaluationView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkIGTTrackingDataEvaluationView(); virtual ~QmitkIGTTrackingDataEvaluationView(); virtual void CreateQtPartControl(QWidget *parent); - virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); - virtual void StdMultiWidgetNotAvailable(); + virtual void MultiWidgetAvailable(QmitkAbstractMultiWidget &multiWidget) override; + virtual void MultiWidgetNotAvailable() override; protected slots: void OnLoadFileList(); void OnAddToCurrentList(); void OnEvaluateData(); void OnEvaluateDataAll(); void OnGeneratePointSet(); void OnGeneratePointSetsOfSinglePositions(); void OnGenerateRotationLines(); void OnGenerateGroundTruthPointSet(); void OnConvertCSVtoXMLFile(); void OnCSVtoXMLLoadInputList(); void OnCSVtoXMLLoadOutputList(); void OnPerfomGridMatching(); void OnComputeRotation(); /** Reads in exactly three position files als reference. */ void OnOrientationCalculation_CalcRef(); /** Uses always three positions (1,2,3: first orientation; 4,5,6: second orientation; and so on) in every file to calcualte a orientation. */ void OnOrientationCalculation_CalcOrientandWriteToFile(); protected: Ui::QmitkIGTTrackingDataEvaluationViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; std::vector m_FilenameVector; void MessageBox(std::string s); std::fstream m_CurrentWriteFile; void WriteHeader(); void WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer evaluationFilter, std::string dataSetName); //members for orientation calculation mitk::Point3D m_RefPoint1; mitk::Point3D m_RefPoint2; mitk::Point3D m_RefPoint3; double m_scalingfactor; //scaling factor for visualization, 1 by default //angle diffrences: seperated file std::fstream m_CurrentAngleDifferencesWriteFile; void CalculateDifferenceAngles(); void WriteDifferenceAnglesHeader(); void WriteDifferenceAnglesDataSet(std::string pos1, std::string pos2, int idx1, int idx2, double angle); void writeToFile(std::string filename, std::vector values); //different help methods to read a csv logging file std::vector GetNavigationDatasFromFile(std::string filename); std::vector GetFileContentLineByLine(std::string filename); mitk::NavigationData::Pointer GetNavigationDataOutOfOneLine(std::string line); //help method to sonstruct the NavigationDataCSVSequentialPlayer filled with all the options from the UI mitk::NavigationDataCSVSequentialPlayer::Pointer ConstructNewNavigationDataPlayer(); //CSV to XML members std::vector m_CSVtoXMLInputFilenameVector; std::vector m_CSVtoXMLOutputFilenameVector; //returns the number of converted lines int ConvertOneFile(std::string inputFilename, std::string outputFilename); /** @brief calculates the angle in the plane perpendicular to the rotation axis of the two quaterions. */ double GetAngleBetweenTwoQuaterions(mitk::Quaternion a, mitk::Quaternion b); /** @brief calculates the slerp average of a set of quaternions which is stored in the navigation data evaluation filter */ mitk::Quaternion GetSLERPAverage(mitk::NavigationDataEvaluationFilter::Pointer); /** @brief Stores the mean positions of all evaluated data */ mitk::PointSet::Pointer m_PointSetMeanPositions; /** @return returns the mean orientation of all given data */ std::vector GetMeanOrientationsOfAllData(std::vector allData, bool useSLERP = false); /** @return returns all data read from the data list as NavigationDataEvaluationFilters */ std::vector GetAllDataFromUIList(); }; #endif // _QMITKIGTTRACKINGDATAEVALUATIONVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp index d63b994090..96cffb41fa 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp @@ -1,623 +1,622 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkIGTTrackingSemiAutomaticMeasurementView.h" -#include "QmitkStdMultiWidget.h" // Qt #include #include #include #include // MITK #include #include #include #include "mitkHummelProtocolEvaluation.h" // POCO #include #include const std::string QmitkIGTTrackingSemiAutomaticMeasurementView::VIEW_ID = "org.mitk.views.igttrackingsemiautomaticmeasurement"; QmitkIGTTrackingSemiAutomaticMeasurementView::QmitkIGTTrackingSemiAutomaticMeasurementView() : QmitkFunctionality() , m_Controls(0) , m_MultiWidget(nullptr) { m_NextFile = 0; m_FilenameVector = std::vector(); m_Timer = new QTimer(this); m_logging = false; m_referenceValid = true; m_tracking = false; m_EvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); } QmitkIGTTrackingSemiAutomaticMeasurementView::~QmitkIGTTrackingSemiAutomaticMeasurementView() { } void QmitkIGTTrackingSemiAutomaticMeasurementView::CreateResults() { QString LogFileName = m_Controls->m_OutputPath->text() + "_results.log"; mitk::LoggingBackend::Unregister(); mitk::LoggingBackend::SetLogFile(LogFileName.toStdString().c_str()); mitk::LoggingBackend::Register(); double RMSmean = 0; for (std::size_t i = 0; i < m_RMSValues.size(); ++i) { MITK_INFO << "RMS at " << this->m_FilenameVector.at(i) << ": " << m_RMSValues.at(i); RMSmean += m_RMSValues.at(i); } RMSmean /= m_RMSValues.size(); MITK_INFO << "RMS mean over " << m_RMSValues.size() << " values: " << RMSmean; mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName("Tracking Results"); newNode->SetData(this->m_MeanPoints); this->GetDataStorage()->Add(newNode); std::vector results5cmDistances; if (m_Controls->m_mediumVolume->isChecked()) mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_MeanPoints, mitk::HummelProtocolEvaluation::medium, results5cmDistances); else if (m_Controls->m_smallVolume->isChecked()) mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_MeanPoints, mitk::HummelProtocolEvaluation::small, results5cmDistances); else if (m_Controls->m_standardVolume->isChecked()) mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_MeanPoints, mitk::HummelProtocolEvaluation::standard, results5cmDistances); } void QmitkIGTTrackingSemiAutomaticMeasurementView::CreateQtPartControl(QWidget *parent) { // build up qt view, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkIGTTrackingSemiAutomaticMeasurementViewControls; m_Controls->setupUi(parent); //buttons connect(m_Controls->m_LoadMeasurementToolStorage, SIGNAL(clicked()), this, SLOT(OnLoadMeasurementStorage())); connect(m_Controls->m_LoadReferenceToolStorage, SIGNAL(clicked()), this, SLOT(OnLoadReferenceStorage())); connect(m_Controls->m_StartTracking, SIGNAL(clicked()), this, SLOT(OnStartTracking())); connect(m_Controls->m_LoadList, SIGNAL(clicked()), this, SLOT(OnMeasurementLoadFile())); connect(m_Controls->m_StartNextMeasurement, SIGNAL(clicked()), this, SLOT(StartNextMeasurement())); connect(m_Controls->m_ReapeatLastMeasurement, SIGNAL(clicked()), this, SLOT(RepeatLastMeasurement())); connect(m_Controls->m_SetReference, SIGNAL(clicked()), this, SLOT(OnSetReference())); connect(m_Controls->m_UseReferenceTrackingSystem, SIGNAL(toggled(bool)), this, SLOT(OnUseReferenceToggled(bool))); connect(m_Controls->m_CreateResults, SIGNAL(clicked()), this, SLOT(CreateResults())); //event filter qApp->installEventFilter(this); //timers connect(m_Timer, SIGNAL(timeout()), this, SLOT(UpdateTimer())); } //initialize some view m_Controls->m_StopTracking->setEnabled(false); } -void QmitkIGTTrackingSemiAutomaticMeasurementView::StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) +void QmitkIGTTrackingSemiAutomaticMeasurementView::MultiWidgetAvailable(QmitkAbstractMultiWidget &multiWidget) { - m_MultiWidget = &stdMultiWidget; + m_MultiWidget = dynamic_cast(&multiWidget); +} + +void QmitkIGTTrackingSemiAutomaticMeasurementView::MultiWidgetNotAvailable() +{ + m_MultiWidget = nullptr; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnUseReferenceToggled(bool state) { if (state) { m_Controls->m_ReferenceBox->setEnabled(true); m_Controls->m_SetReference->setEnabled(true); } else { m_Controls->m_ReferenceBox->setEnabled(false); m_Controls->m_SetReference->setEnabled(false); } } -void QmitkIGTTrackingSemiAutomaticMeasurementView::StdMultiWidgetNotAvailable() -{ - m_MultiWidget = nullptr; -} - mitk::NavigationToolStorage::Pointer QmitkIGTTrackingSemiAutomaticMeasurementView::ReadStorage(std::string file) { mitk::NavigationToolStorage::Pointer returnValue; //initialize tool storage returnValue = mitk::NavigationToolStorage::New(); //read tool storage from disk mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(GetDataStorage()); returnValue = myDeserializer->Deserialize(file); if (returnValue.IsNull()) { QMessageBox msgBox; msgBox.setText(myDeserializer->GetErrorMessage().c_str()); msgBox.exec(); returnValue = nullptr; } return returnValue; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnSetReference() { //initialize reference m_ReferenceStartPositions = std::vector(); m_ReferenceTrackingDeviceSource->Update(); QString Label = "Positions At Start: "; for (unsigned int i = 0; i < m_ReferenceTrackingDeviceSource->GetNumberOfOutputs(); ++i) { mitk::Point3D position = m_ReferenceTrackingDeviceSource->GetOutput(i)->GetPosition(); Label = Label + "Tool" + QString::number(i) + ":[" + QString::number(position[0]) + ":" + QString::number(position[1]) + ":" + QString::number(position[1]) + "] "; m_ReferenceStartPositions.push_back(position); } m_Controls->m_ReferencePosAtStart->setText(Label); } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnLoadMeasurementStorage() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Toolfile"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_MeasurementStorage = ReadStorage(filename.toStdString()); //update label Poco::Path myPath = Poco::Path(filename.toStdString()); //use this to seperate filename from path QString toolLabel = QString("Tool Storage: ") + QString::number(m_MeasurementStorage->GetToolCount()) + " Tools from " + myPath.getFileName().c_str(); m_Controls->m_MeasurementToolStorageLabel->setText(toolLabel); //update status widget m_Controls->m_ToolStatusWidget->RemoveStatusLabels(); m_Controls->m_ToolStatusWidget->PreShowTools(m_MeasurementStorage); } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnLoadReferenceStorage() { //read in filename static QString oldFile; if (oldFile.isNull()) oldFile = "/"; QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Toolfile"), oldFile, tr("All Files (*.*)")); if (filename.isNull()) return; oldFile = filename; m_ReferenceStorage = ReadStorage(filename.toStdString()); //update label Poco::Path myPath = Poco::Path(filename.toStdString()); //use this to seperate filename from path QString toolLabel = QString("Tool Storage: ") + QString::number(m_ReferenceStorage->GetToolCount()) + " Tools from " + myPath.getFileName().c_str(); m_Controls->m_ReferenceToolStorageLabel->setText(toolLabel); } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnStartTracking() { //check if everything is ready to start tracking if (m_MeasurementStorage.IsNull()) { MessageBox("Error: No measurement tools loaded yet!"); return; } else if (m_ReferenceStorage.IsNull() && m_Controls->m_UseReferenceTrackingSystem->isChecked()) { MessageBox("Error: No refernce tools loaded yet!"); return; } else if (m_MeasurementStorage->GetToolCount() == 0) { MessageBox("Error: No way to track without tools!"); return; } else if (m_Controls->m_UseReferenceTrackingSystem->isChecked() && (m_ReferenceStorage->GetToolCount() == 0)) { MessageBox("Error: No way to track without tools!"); return; } //build the first IGT pipeline (MEASUREMENT) mitk::TrackingDeviceSourceConfigurator::Pointer myTrackingDeviceSourceFactory1 = mitk::TrackingDeviceSourceConfigurator::New(this->m_MeasurementStorage, this->m_Controls->m_MeasurementTrackingDeviceConfigurationWidget->GetTrackingDevice()); m_MeasurementTrackingDeviceSource = myTrackingDeviceSourceFactory1->CreateTrackingDeviceSource(this->m_MeasurementToolVisualizationFilter); if (m_MeasurementTrackingDeviceSource.IsNull()) { MessageBox(myTrackingDeviceSourceFactory1->GetErrorMessage()); return; } //connect the tool visualization widget for (unsigned int i = 0; i < m_MeasurementTrackingDeviceSource->GetNumberOfOutputs(); ++i) { m_Controls->m_ToolStatusWidget->AddNavigationData(m_MeasurementTrackingDeviceSource->GetOutput(i)); m_EvaluationFilter->SetInput(i, m_MeasurementTrackingDeviceSource->GetOutput(i)); } m_Controls->m_ToolStatusWidget->ShowStatusLabels(); m_Controls->m_ToolStatusWidget->SetShowPositions(true); m_Controls->m_ToolStatusWidget->SetShowQuaternions(true); //build the second IGT pipeline (REFERENCE) if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { mitk::TrackingDeviceSourceConfigurator::Pointer myTrackingDeviceSourceFactory2 = mitk::TrackingDeviceSourceConfigurator::New(this->m_ReferenceStorage, this->m_Controls->m_ReferenceDeviceConfigurationWidget->GetTrackingDevice()); m_ReferenceTrackingDeviceSource = myTrackingDeviceSourceFactory2->CreateTrackingDeviceSource(); if (m_ReferenceTrackingDeviceSource.IsNull()) { MessageBox(myTrackingDeviceSourceFactory2->GetErrorMessage()); return; } } //initialize tracking try { m_MeasurementTrackingDeviceSource->Connect(); m_MeasurementTrackingDeviceSource->StartTracking(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceTrackingDeviceSource->Connect(); m_ReferenceTrackingDeviceSource->StartTracking(); } } catch (...) { MessageBox("Error while starting the tracking device!"); return; } //set reference if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) OnSetReference(); //start timer m_Timer->start(1000 / (m_Controls->m_SamplingRate->value())); m_Controls->m_StartTracking->setEnabled(false); m_Controls->m_StartTracking->setEnabled(true); m_tracking = true; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnStopTracking() { if (this->m_logging) FinishMeasurement(); m_MeasurementTrackingDeviceSource->Disconnect(); m_MeasurementTrackingDeviceSource->StopTracking(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceTrackingDeviceSource->Disconnect(); m_ReferenceTrackingDeviceSource->StopTracking(); } m_Timer->stop(); m_Controls->m_StartTracking->setEnabled(true); m_Controls->m_StartTracking->setEnabled(false); m_tracking = false; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnMeasurementLoadFile() { m_FilenameVector = std::vector(); m_FilenameVector.clear(); m_NextFile = 0; //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; //define own locale std::locale C("C"); setlocale(LC_ALL, "C"); //read file std::ifstream file; file.open(filename.toStdString().c_str(), std::ios::in); if (file.good()) { //read out file file.seekg(0L, std::ios::beg); // move to begin of file while (!file.eof()) { std::string buffer; std::getline(file, buffer); // read out file line by line if (buffer.size() > 0) m_FilenameVector.push_back(buffer); } } //fill list at GUI m_Controls->m_MeasurementList->clear(); for (unsigned int i = 0; i < m_FilenameVector.size(); i++) { new QListWidgetItem(tr(m_FilenameVector.at(i).c_str()), m_Controls->m_MeasurementList); } //update label next measurement std::stringstream label; label << "Next Measurement: " << m_FilenameVector.at(0); m_Controls->m_NextMeasurement->setText(label.str().c_str()); //reset results files m_MeanPoints = mitk::PointSet::New(); m_RMSValues = std::vector(); m_EvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); if (m_MeasurementToolVisualizationFilter.IsNotNull()) m_EvaluationFilter->SetInput(0, m_MeasurementToolVisualizationFilter->GetOutput(0)); } void QmitkIGTTrackingSemiAutomaticMeasurementView::UpdateTimer() { if (m_EvaluationFilter.IsNotNull() && m_logging) m_EvaluationFilter->Update(); else m_MeasurementToolVisualizationFilter->Update(); m_Controls->m_ToolStatusWidget->Refresh(); //update reference if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceTrackingDeviceSource->Update(); QString Label = "Current Positions: "; bool distanceThresholdExceeded = false; for (unsigned int i = 0; i < m_ReferenceTrackingDeviceSource->GetNumberOfOutputs(); ++i) { mitk::Point3D position = m_ReferenceTrackingDeviceSource->GetOutput(i)->GetPosition(); Label = Label + "Tool" + QString::number(i) + ":[" + QString::number(position[0]) + ":" + QString::number(position[1]) + ":" + QString::number(position[1]) + "] "; if (position.EuclideanDistanceTo(m_ReferenceStartPositions.at(i)) > m_Controls->m_ReferenceThreshold->value()) distanceThresholdExceeded = true; } m_Controls->m_ReferenceCurrentPos->setText(Label); if (distanceThresholdExceeded) { m_Controls->m_ReferenceOK->setText("NOT OK!"); m_referenceValid = false; } else { m_Controls->m_ReferenceOK->setText("OK"); m_referenceValid = true; } } //update logging if (m_logging) { //check for missing objects if (m_MeasurementLoggingFilterXML.IsNull() || m_MeasurementLoggingFilterCSV.IsNull() ) { return; } //log/measure m_MeasurementLoggingFilterXML->Update(); m_MeasurementLoggingFilterCSV->Update(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked() && m_ReferenceLoggingFilterXML.IsNotNull() && m_ReferenceLoggingFilterCSV.IsNotNull()) { m_ReferenceLoggingFilterXML->Update(); m_ReferenceLoggingFilterCSV->Update(); } m_loggedFrames++; LogAdditionalCSVFile(); //check if all frames are logged ... if yes finish the measurement if (m_loggedFrames > m_Controls->m_SamplesPerMeasurement->value()) { FinishMeasurement(); } //update logging label QString loggingLabel = "Collected Samples: " + QString::number(m_loggedFrames); m_Controls->m_CollectedSamples->setText(loggingLabel); } } void QmitkIGTTrackingSemiAutomaticMeasurementView::StartNextMeasurement() { if (this->m_NextFile >= static_cast(m_FilenameVector.size())) { MessageBox("Last Measurement reached!"); return; } m_loggedFrames = 0; m_logging = true; //check if directory exists, if not create one Poco::File myPath(std::string(m_Controls->m_OutputPath->text().toUtf8()).c_str()); if (!myPath.exists()) myPath.createDirectory(); QString LogFileName = m_Controls->m_OutputPath->text() + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".log"; mitk::LoggingBackend::Unregister(); mitk::LoggingBackend::SetLogFile(LogFileName.toStdString().c_str()); mitk::LoggingBackend::Register(); //initialize logging filters m_MeasurementLoggingFilterXML = mitk::NavigationDataRecorderDeprecated::New(); m_MeasurementLoggingFilterXML->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_MeasurementLoggingFilterCSV = mitk::NavigationDataRecorderDeprecated::New(); m_MeasurementLoggingFilterCSV->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_MeasurementLoggingFilterXML->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::xml); m_MeasurementLoggingFilterCSV->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); QString MeasurementFilenameXML = m_Controls->m_OutputPath->text() + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".xml"; QString MeasurementFilenameCSV = m_Controls->m_OutputPath->text() + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".csv"; m_MeasurementLoggingFilterXML->SetFileName(MeasurementFilenameXML.toStdString()); m_MeasurementLoggingFilterCSV->SetFileName(MeasurementFilenameCSV.toStdString()); m_MeasurementLoggingFilterXML->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); m_MeasurementLoggingFilterCSV->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceLoggingFilterXML = mitk::NavigationDataRecorderDeprecated::New(); m_ReferenceLoggingFilterXML->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_ReferenceLoggingFilterCSV = mitk::NavigationDataRecorderDeprecated::New(); m_ReferenceLoggingFilterCSV->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_ReferenceLoggingFilterXML->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::xml); m_ReferenceLoggingFilterCSV->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); QString ReferenceFilenameXML = m_Controls->m_OutputPath->text() + "Reference_" + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".xml"; QString ReferenceFilenameCSV = m_Controls->m_OutputPath->text() + "Reference_" + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".csv"; m_ReferenceLoggingFilterXML->SetFileName(ReferenceFilenameXML.toStdString()); m_ReferenceLoggingFilterCSV->SetFileName(ReferenceFilenameCSV.toStdString()); m_ReferenceLoggingFilterXML->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); m_ReferenceLoggingFilterCSV->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); } //start additional csv logging StartLoggingAdditionalCSVFile(m_FilenameVector.at(m_NextFile)); //connect filter for (unsigned int i = 0; i < m_MeasurementToolVisualizationFilter->GetNumberOfOutputs(); ++i) { m_MeasurementLoggingFilterXML->AddNavigationData(m_MeasurementToolVisualizationFilter->GetOutput(i)); m_MeasurementLoggingFilterCSV->AddNavigationData(m_MeasurementToolVisualizationFilter->GetOutput(i)); } if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) for (unsigned int i = 0; i < m_ReferenceTrackingDeviceSource->GetNumberOfOutputs(); ++i) { m_ReferenceLoggingFilterXML->AddNavigationData(m_ReferenceTrackingDeviceSource->GetOutput(i)); m_ReferenceLoggingFilterCSV->AddNavigationData(m_ReferenceTrackingDeviceSource->GetOutput(i)); } //start filter m_MeasurementLoggingFilterXML->StartRecording(); m_MeasurementLoggingFilterCSV->StartRecording(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceLoggingFilterXML->StartRecording(); m_ReferenceLoggingFilterCSV->StartRecording(); } //disable all buttons DisableAllButtons(); //update label next measurement std::stringstream label; if ((m_NextFile + 1) >= static_cast(m_FilenameVector.size())) label << "Next Measurement: "; else label << "Next Measurement: " << m_FilenameVector.at(m_NextFile + 1); m_Controls->m_NextMeasurement->setText(label.str().c_str()); //update label last measurement std::stringstream label2; label2 << "Last Measurement: " << m_FilenameVector.at(m_NextFile); m_Controls->m_LastMeasurement->setText(label2.str().c_str()); m_NextFile++; } void QmitkIGTTrackingSemiAutomaticMeasurementView::RepeatLastMeasurement() { m_NextFile--; StartNextMeasurement(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::DisableAllButtons() { m_Controls->m_LoadList->setEnabled(false); m_Controls->m_StartNextMeasurement->setEnabled(false); m_Controls->m_ReapeatLastMeasurement->setEnabled(false); m_Controls->m_SamplingRate->setEnabled(false); m_Controls->m_SamplesPerMeasurement->setEnabled(false); m_Controls->m_ReferenceThreshold->setEnabled(false); } void QmitkIGTTrackingSemiAutomaticMeasurementView::EnableAllButtons() { m_Controls->m_LoadList->setEnabled(true); m_Controls->m_StartNextMeasurement->setEnabled(true); m_Controls->m_ReapeatLastMeasurement->setEnabled(true); m_Controls->m_SamplingRate->setEnabled(true); m_Controls->m_SamplesPerMeasurement->setEnabled(true); m_Controls->m_ReferenceThreshold->setEnabled(true); } void QmitkIGTTrackingSemiAutomaticMeasurementView::FinishMeasurement() { m_logging = false; m_MeasurementLoggingFilterXML->StopRecording(); m_MeasurementLoggingFilterCSV->StopRecording(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceLoggingFilterXML->StopRecording(); m_ReferenceLoggingFilterCSV->StopRecording(); } StopLoggingAdditionalCSVFile(); int id = m_NextFile - 1; mitk::Point3D positionMean = m_EvaluationFilter->GetPositionMean(0); MITK_INFO << "Evaluated " << m_EvaluationFilter->GetNumberOfAnalysedNavigationData(0) << " samples."; double rms = m_EvaluationFilter->GetPositionErrorRMS(0); MITK_INFO << "RMS: " << rms; MITK_INFO << "Position Mean: " << positionMean; m_MeanPoints->SetPoint(id, positionMean); if (static_cast(m_RMSValues.size()) <= id) m_RMSValues.push_back(rms); else m_RMSValues[id] = rms; m_EvaluationFilter->ResetStatistic(); EnableAllButtons(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::StartLoggingAdditionalCSVFile(std::string filePostfix) { //write logfile header QString header = "Nr;MITK_Time;Valid_Reference;"; QString tool = QString("MeasureTool_") + QString(m_MeasurementTrackingDeviceSource->GetOutput(0)->GetName()); header = header + tool + "[x];" + tool + "[y];" + tool + "[z];" + tool + "[qx];" + tool + "[qy];" + tool + "[qz];" + tool + "[qr]\n"; //open logfile and write header m_logFileCSV.open(std::string(m_Controls->m_OutputPath->text().toUtf8()).append("/LogFileCombined").append(filePostfix.c_str()).append(".csv").c_str(), std::ios::out); m_logFileCSV << header.toStdString().c_str(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::LogAdditionalCSVFile() { mitk::Point3D pos = m_MeasurementTrackingDeviceSource->GetOutput(0)->GetPosition(); mitk::Quaternion rot = m_MeasurementTrackingDeviceSource->GetOutput(0)->GetOrientation(); std::string valid = ""; if (m_referenceValid) valid = "true"; else valid = "false"; std::stringstream timestamp; timestamp << m_MeasurementTrackingDeviceSource->GetOutput(0)->GetTimeStamp(); QString dataSet = QString::number(m_loggedFrames) + ";" + QString(timestamp.str().c_str()) + ";" + QString(valid.c_str()) + ";" + QString::number(pos[0]) + ";" + QString::number(pos[1]) + ";" + QString::number(pos[2]) + ";" + QString::number(rot.x()) + ";" + QString::number(rot.y()) + ";" + QString::number(rot.z()) + ";" + QString::number(rot.r()) + "\n"; m_logFileCSV << dataSet.toStdString(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::StopLoggingAdditionalCSVFile() { m_logFileCSV.close(); } bool QmitkIGTTrackingSemiAutomaticMeasurementView::eventFilter(QObject *, QEvent *ev) { if (ev->type() == QEvent::KeyPress) { QKeyEvent *k = (QKeyEvent *)ev; bool down = k->key() == 16777239; if (down && m_tracking && !m_logging) StartNextMeasurement(); } return false; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.h b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.h index 3ec59713ba..5b09a0aff7 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.h +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.h @@ -1,132 +1,133 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkIGTTrackingSemiAutomaticMeasurementView_h #define QmitkIGTTrackingSemiAutomaticMeasurementView_h #include #include +#include //QT #include //MITK #include #include #include #include #include #include "ui_QmitkIGTTrackingSemiAutomaticMeasurementViewControls.h" /*! \brief QmitkIGTTrackingSemiAutomaticMeasurementView \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkIGTTrackingSemiAutomaticMeasurementView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkIGTTrackingSemiAutomaticMeasurementView(); virtual ~QmitkIGTTrackingSemiAutomaticMeasurementView(); virtual void CreateQtPartControl(QWidget *parent); - virtual void StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget); - virtual void StdMultiWidgetNotAvailable(); + virtual void MultiWidgetAvailable(QmitkAbstractMultiWidget &multiWidget) override; + virtual void MultiWidgetNotAvailable() override; protected slots: void OnLoadMeasurementStorage(); void OnLoadReferenceStorage(); void OnStartTracking(); void OnStopTracking(); void OnMeasurementLoadFile(); void OnSetReference(); void StartNextMeasurement(); void RepeatLastMeasurement(); void UpdateTimer(); void CreateResults(); void OnUseReferenceToggled(bool state); protected: Ui::QmitkIGTTrackingSemiAutomaticMeasurementViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; //the tool storages mitk::NavigationToolStorage::Pointer m_MeasurementStorage; mitk::NavigationToolStorage::Pointer m_ReferenceStorage; //members for the filter pipeline mitk::TrackingDeviceSource::Pointer m_MeasurementTrackingDeviceSource; mitk::NavigationDataObjectVisualizationFilter::Pointer m_MeasurementToolVisualizationFilter; mitk::NavigationDataRecorderDeprecated::Pointer m_MeasurementLoggingFilterXML; mitk::NavigationDataRecorderDeprecated::Pointer m_MeasurementLoggingFilterCSV; mitk::TrackingDeviceSource::Pointer m_ReferenceTrackingDeviceSource; mitk::NavigationDataRecorderDeprecated::Pointer m_ReferenceLoggingFilterXML; mitk::NavigationDataRecorderDeprecated::Pointer m_ReferenceLoggingFilterCSV; //members for file name list std::vector m_FilenameVector; int m_NextFile; //help methods mitk::NavigationToolStorage::Pointer ReadStorage(std::string file); void MessageBox(std::string s); void DisableAllButtons(); void EnableAllButtons(); void FinishMeasurement(); void StartLoggingAdditionalCSVFile(std::string filePostfix); void LogAdditionalCSVFile(); void StopLoggingAdditionalCSVFile(); //timer QTimer* m_Timer; //memebers for reference checking std::vector m_ReferenceStartPositions; bool m_referenceValid; //logging members int m_loggedFrames; bool m_logging; std::fstream m_logFileCSV; //event filter for key presses bool eventFilter(QObject *obj, QEvent *ev); //results members mitk::PointSet::Pointer m_MeanPoints; std::vector m_RMSValues; mitk::NavigationDataEvaluationFilter::Pointer m_EvaluationFilter; bool m_tracking; }; #endif // _QMITKIGTTRACKINGSEMIAUTOMATICMEASUREMENTVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp index 0c651095d4..1569a73d8e 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp +++ b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp @@ -1,731 +1,732 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkIGTTrackingLabView.h" +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt #include #include #include // vtk #include const std::string QmitkIGTTrackingLabView::VIEW_ID = "org.mitk.views.igttrackinglab"; QmitkIGTTrackingLabView::QmitkIGTTrackingLabView() : QmitkAbstractView() ,m_Source(nullptr) ,m_PermanentRegistrationFilter(nullptr) ,m_Visualizer(nullptr) ,m_VirtualView(nullptr) ,m_PSRecordingPointSet(nullptr) ,m_PointSetRecording(false) ,m_PermanentRegistration(false) ,m_CameraView(false) ,m_ImageFiducialsDataNode(nullptr) ,m_TrackerFiducialsDataNode(nullptr) ,m_PermanentRegistrationSourcePoints(nullptr) { } //############################################################################################### //############################################################################################### //############################## Timer method for IGT pipeline updating ######################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::UpdateTimer() { if (m_PermanentRegistration && m_PermanentRegistrationFilter.IsNotNull()) { if(IsTransformDifferenceHigh(m_ObjectmarkerNavigationData, m_ObjectmarkerNavigationDataLastUpdate)) { m_ObjectmarkerNavigationDataLastUpdate->Graft(m_ObjectmarkerNavigationData); m_PermanentRegistrationFilter->Update(); } } if (m_CameraView && m_VirtualView.IsNotNull()) {m_VirtualView->Update();} if(m_PointSetRecording && m_PSRecordingPointSet.IsNotNull()) { int size = m_PSRecordingPointSet->GetSize(); mitk::NavigationData::Pointer nd = m_PointSetRecordingNavigationData; if(size > 0) { mitk::Point3D p = m_PSRecordingPointSet->GetPoint(size-1); if(p.EuclideanDistanceTo(nd->GetPosition()) > (double) m_Controls.m_PSRecordingSpinBox->value()) m_PSRecordingPointSet->InsertPoint(size, nd->GetPosition()); } else m_PSRecordingPointSet->InsertPoint(size, nd->GetPosition()); } } //############################################################################################### //############################################################################################### //############################## Slots of CONFIGURATION step #################################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnSetupNavigation() { if(m_Source.IsNotNull()) if(m_Source->IsTracking()) return; mitk::DataStorage* ds = this->GetDataStorage(); if(ds == nullptr) { MITK_WARN << "IGTSurfaceTracker: Error. Cannot access DataStorage. Navigation not possible"; return; } //Building up the filter pipeline try { this->InitializeRegistration(); } catch(mitk::IGTException& e) { MITK_WARN << "Error while building the IGT-Pipeline: " << e.GetDescription(); this->DestroyIGTPipeline(); // destroy the pipeline if building is incomplete return; } catch(...) { MITK_WARN << "Unexpected error while building the IGT-Pipeline"; this->DestroyIGTPipeline(); return; } } void QmitkIGTTrackingLabView::OnInstrumentSelected() { if (m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource().IsNotNull()) { m_InstrumentNavigationData = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedToolID()); } else { m_Controls.m_PointerNameLabel->setText(""); return; } if (m_InstrumentNavigationData.IsNotNull()) { m_Controls.m_PointerNameLabel->setText(m_InstrumentNavigationData->GetName()); } else { m_Controls.m_PointerNameLabel->setText(""); } } void QmitkIGTTrackingLabView::OnObjectmarkerSelected() { if (m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource().IsNotNull()) { m_ObjectmarkerNavigationData = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedToolID()); MITK_INFO << "Objectmarker rotation: " << m_ObjectmarkerNavigationData->GetOrientation(); } else { m_Controls.m_ObjectmarkerNameLabel->setText(""); return; } if (m_ObjectmarkerNavigationData.IsNotNull()) { m_Controls.m_ObjectmarkerNameLabel->setText(m_ObjectmarkerNavigationData->GetName()); } else { m_Controls.m_ObjectmarkerNameLabel->setText(""); } } //############################################################################################### //############################################################################################### //####################### Slots of INITIAL REGISTRATION step #################################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnInitialRegistration() { //Check for initialization if (!CheckRegistrationInitialization()) return; mitk::PointSet::Pointer imageFiducials = dynamic_cast(m_ImageFiducialsDataNode->GetData()); mitk::PointSet::Pointer trackerFiducials = dynamic_cast(m_TrackerFiducialsDataNode->GetData()); //############### 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] = {imageFiducials->GetPoint(i)[0],imageFiducials->GetPoint(i)[1],imageFiducials->GetPoint(i)[2]}; sourcePoints->InsertNextPoint(point); double point_targets[3] = {trackerFiducials->GetPoint(i)[0],trackerFiducials->GetPoint(i)[1],trackerFiducials->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(imageFiducials, trackerFiducials, transform); m_Controls.m_RegistrationWidget->SetQualityDisplayText("FRE: " + QString::number(FRE) + " mm"); //############################################################################################# //############### 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 affine transform 3D surface mitk::AffineTransform3D::Pointer mitkTransform = mitk::AffineTransform3D::New(); mitkTransform->SetMatrix(rotationDouble); mitkTransform->SetOffset(translationDouble); //############################################################################################# //############### object is transformed ########################## //save transform m_T_ObjectReg = mitk::NavigationData::New(mitkTransform); // this is stored in a member because it is needed for permanent registration later on //transform surface if(m_Controls.m_SurfaceActive->isChecked() && m_Controls.m_ObjectComboBox->GetSelectedNode().IsNotNull()) { m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(mitkTransform); } //################################################################ //############### if activated: ct image is also transformed ########################## //transform ct image //todo: Erklären, dass hier AffineTransform3D verwendet wird, weil NavigationData kein Spacing unterstützt! if(m_Controls.m_ImageActive->isChecked() && m_Controls.m_ImageComboBox->GetSelectedNode().IsNotNull()) { //first we have to store the original ct image transform to compose it with the new transform later mitk::AffineTransform3D::Pointer imageTransform = m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->GetIndexToWorldTransform(); m_T_ImageGeo = mitk::AffineTransform3D::New(); // this is also stored in a member because it is needed for permanent registration later on //now the new transform of the ct image is computed m_T_ImageGeo->Compose(imageTransform); 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_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(newImageTransform); m_T_ImageReg = m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->GetIndexToWorldTransform(); } //################################################################ } void QmitkIGTTrackingLabView::OnAddRegistrationTrackingFiducial() { mitk::NavigationData::Pointer nd = m_InstrumentNavigationData; if( nd.IsNull() || !nd->IsDataValid()) { QMessageBox::warning( 0, "Invalid tracking data", "Navigation data is not available or invalid!", QMessageBox::Ok ); return; } if(m_TrackerFiducialsDataNode.IsNotNull() && m_TrackerFiducialsDataNode->GetData() != nullptr) { mitk::PointSet::Pointer ps = dynamic_cast(m_TrackerFiducialsDataNode->GetData()); ps->InsertPoint(ps->GetSize(), nd->GetPosition()); } else QMessageBox::warning(nullptr, "IGTSurfaceTracker: Error", "Can not access Tracker Fiducials. Adding fiducial not possible!"); } void QmitkIGTTrackingLabView::InitializeRegistration() { mitk::DataStorage* ds = this->GetDataStorage(); if( ds == nullptr ) return; // let the registration widget know about the slice navigation controllers // in the active render window part (crosshair updates) foreach(QmitkRenderWindow* renderWindow, this->GetRenderWindowPart()->GetQmitkRenderWindows().values()) { m_Controls.m_RegistrationWidget->AddSliceNavigationController(renderWindow->GetSliceNavigationController()); } if(m_ImageFiducialsDataNode.IsNull()) { m_ImageFiducialsDataNode = mitk::DataNode::New(); mitk::PointSet::Pointer ifPS = mitk::PointSet::New(); m_ImageFiducialsDataNode->SetData(ifPS); mitk::Color color; color.Set(1.0f, 0.0f, 0.0f); m_ImageFiducialsDataNode->SetName("Image Fiducials"); m_ImageFiducialsDataNode->SetColor(color); m_ImageFiducialsDataNode->SetBoolProperty( "updateDataOnRender", false ); ds->Add(m_ImageFiducialsDataNode); } m_Controls.m_RegistrationWidget->SetImageFiducialsNode(m_ImageFiducialsDataNode); if(m_TrackerFiducialsDataNode.IsNull()) { m_TrackerFiducialsDataNode = mitk::DataNode::New(); mitk::PointSet::Pointer tfPS = mitk::PointSet::New(); m_TrackerFiducialsDataNode->SetData(tfPS); mitk::Color color; color.Set(0.0f, 1.0f, 0.0f); m_TrackerFiducialsDataNode->SetName("Tracking Fiducials"); m_TrackerFiducialsDataNode->SetColor(color); m_TrackerFiducialsDataNode->SetBoolProperty( "updateDataOnRender", false ); ds->Add(m_TrackerFiducialsDataNode); } m_Controls.m_RegistrationWidget->SetTrackerFiducialsNode(m_TrackerFiducialsDataNode); } //############################################################################################### //############################################################################################### //####################### Slots of PERMANENT REGISTRATION step ################################## //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnPermanentRegistration(bool on) { if(on) { //###################################################################### //######################## inititalization ############################# //###################################################################### //some initial checks if(!CheckRegistrationInitialization()) { m_Controls.m_UsePermanentRegistrationToggle->setChecked(false); return; } //remember initial object transform to calculate the object to marker transform later on and convert it to navigation data mitk::AffineTransform3D::Pointer transform = this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->GetIndexToWorldTransform(); mitk::NavigationData::Pointer T_Object = mitk::NavigationData::New(transform,false); //TODO: catch exception during conversion? //then reset the transform because we will now start to calculate the permanent registration this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIdentity(); if(m_Controls.m_ImageActive->isChecked()) {this->m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(m_T_ImageGeo);} //create the permanent registration filter m_PermanentRegistrationFilter = mitk::NavigationDataObjectVisualizationFilter::New(); //###################################################################### //first: initialize permanent registration of surface (always activated) //###################################################################### //connect filter to source m_PermanentRegistrationFilter->SetInput(0,this->m_ObjectmarkerNavigationData); //set representation object m_PermanentRegistrationFilter->SetRepresentationObject(0,this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()); //get the marker transform out of the navigation data mitk::NavigationData::Pointer T_Marker = m_ObjectmarkerNavigationData; //compute transform from object to marker (T_MarkerRel = T_Object * T_Marker^-1) mitk::NavigationData::Pointer T_MarkerRel = mitk::NavigationData::New(); T_MarkerRel->Compose(T_Object); T_MarkerRel->Compose(T_Marker->GetInverse()); m_T_MarkerRel = T_MarkerRel; m_PermanentRegistrationFilter->SetOffset(0,m_T_MarkerRel->GetAffineTransform3D()); //###################################################################### //second: initialize permanent registration of image (if activated) //###################################################################### if (m_Controls.m_ImageActive->isChecked() && (m_Controls.m_ImageComboBox->GetSelectedNode().IsNotNull())) { mitk::DataNode::Pointer imageNode = this->m_Controls.m_ImageComboBox->GetSelectedNode(); imageNode->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_LINEAR) ); m_PermanentRegistrationFilter->SetInput(1,this->m_ObjectmarkerNavigationData); m_PermanentRegistrationFilter->SetRepresentationObject(1,imageNode->GetData()); //for the image we can't use NavigationData objects as transforms because an image needs additional geometry information, e.g., spacing //thus we use mitk::AffineTransform3D objects //computer transform from image to marker (T_ImageRel = T_ImageGeo * T_MarkerRel) mitk::AffineTransform3D::Pointer T_ImageRel = mitk::AffineTransform3D::New(); T_ImageRel->SetIdentity(); T_ImageRel->Compose(m_T_ImageGeo); T_ImageRel->Compose(m_T_MarkerRel->GetAffineTransform3D()); m_PermanentRegistrationFilter->SetOffset(1,T_ImageRel); } //some general stuff m_PermanentRegistration = true; m_ObjectmarkerNavigationDataLastUpdate = mitk::NavigationData::New(); } else //if off = disable the permanent registration { //stop permanent registration m_PermanentRegistration = false; //restore old registration if(m_T_ObjectReg.IsNotNull()) {this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(m_T_ObjectReg->GetAffineTransform3D());} if(m_T_ImageReg.IsNotNull()) {this->m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(m_T_ImageReg);} //delete filter m_PermanentRegistrationFilter = nullptr; } } //############################################################################################### //############################################################################################### //####################### Slots of POINT SET RECORDING step ##################################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnPointSetRecording(bool record) { mitk::DataStorage* ds = this->GetDataStorage(); if(record) { if (m_Controls.m_PointSetRecordingToolSelectionWidget->GetSelectedToolID() == -1) { QMessageBox::warning(nullptr, "Error", "No tool selected for point set recording!"); m_Controls.m_PointSetRecordCheckBox->setChecked(false); return; } m_PointSetRecordingNavigationData = m_Controls.m_PointSetRecordingToolSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_PointSetRecordingToolSelectionWidget->GetSelectedToolID()); //initialize point set mitk::DataNode::Pointer psRecND = ds->GetNamedNode("Recorded Points"); if(m_PSRecordingPointSet.IsNull() || psRecND.IsNull()) { m_PSRecordingPointSet = nullptr; m_PSRecordingPointSet = mitk::PointSet::New(); mitk::DataNode::Pointer dn = mitk::DataNode::New(); dn->SetName("Recorded Points"); dn->SetColor(0.,1.,0.); dn->SetData(m_PSRecordingPointSet); ds->Add(dn); } else { m_PSRecordingPointSet->Clear(); } m_PointSetRecording = true; } else { m_PointSetRecording = false; } } //############################################################################################### //############################################################################################### //####################### Slots of VIRTUAL CAMERA VIEW step ##################################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnVirtualCamera(bool on) { if (m_Controls.m_CameraViewSelection->GetSelectedToolID() == -1) { m_Controls.m_ActivateNeedleView->setChecked(false); QMessageBox::warning(nullptr, "Error", "No tool selected for camera view!"); return; } if(on) { m_VirtualView = mitk::CameraVisualization::New(); m_VirtualView->SetInput(m_Controls.m_CameraViewSelection->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_CameraViewSelection->GetSelectedToolID())); mitk::Vector3D viewDirection; viewDirection[0] = (int)(m_Controls.m_NeedleViewX->isChecked()); viewDirection[1] = (int)(m_Controls.m_NeedleViewY->isChecked()); viewDirection[2] = (int)(m_Controls.m_NeedleViewZ->isChecked()); if (m_Controls.m_NeedleViewInvert->isChecked()) viewDirection *= -1; m_VirtualView->SetDirectionOfProjectionInToolCoordinates(viewDirection); mitk::Vector3D viewUpVector; viewUpVector[0] = (int)(m_Controls.m_NeedleUpX->isChecked()); viewUpVector[1] = (int)(m_Controls.m_NeedleUpY->isChecked()); viewUpVector[2] = (int)(m_Controls.m_NeedleUpZ->isChecked()); if (m_Controls.m_NeedleUpInvert->isChecked()) viewUpVector *= -1; m_VirtualView->SetViewUpInToolCoordinates(viewUpVector); m_VirtualView->SetRenderer(this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderer()); //next line: better code when this plugin is migrated to mitk::abstractview //m_VirtualView->SetRenderer(mitk::BaseRenderer::GetInstance(this->GetRenderWindowPart()->GetRenderWindow("3d")->GetRenderWindow())); m_CameraView = true; //make pointer itself invisible m_Controls.m_CameraViewSelection->GetSelectedNavigationTool()->GetDataNode()->SetBoolProperty("visible",false); //disable UI elements m_Controls.m_ViewDirectionBox->setEnabled(false); m_Controls.m_ViewUpBox->setEnabled(false); } else { m_VirtualView = nullptr; m_CameraView = false; m_Controls.m_CameraViewSelection->GetSelectedNavigationTool()->GetDataNode()->SetBoolProperty("visible",true); m_Controls.m_ViewDirectionBox->setEnabled(true); m_Controls.m_ViewUpBox->setEnabled(true); } } //############################################################################################### //############################################################################################### //############################## some general UI methods, always needed ######################### //############################################################################################### //############################################################################################### QmitkIGTTrackingLabView::~QmitkIGTTrackingLabView() { if (m_Timer->isActive()) m_Timer->stop(); } void QmitkIGTTrackingLabView::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); this->CreateBundleWidgets(); this->CreateConnections(); } void QmitkIGTTrackingLabView::CreateBundleWidgets() { //initialize registration widget m_Controls.m_RegistrationWidget->HideStaticRegistrationRadioButton(true); m_Controls.m_RegistrationWidget->HideContinousRegistrationRadioButton(true); m_Controls.m_RegistrationWidget->HideUseICPRegistrationCheckbox(true); } void QmitkIGTTrackingLabView::CreateConnections() { //initialize timer m_Timer = new QTimer(this); //create connections connect(m_Timer, SIGNAL(timeout()), this, SLOT(UpdateTimer())); connect( m_Controls.m_UsePermanentRegistrationToggle, SIGNAL(toggled(bool)), this, SLOT(OnPermanentRegistration(bool)) ); connect( m_Controls.m_TrackingDeviceSelectionWidget, SIGNAL(NavigationDataSourceSelected(mitk::NavigationDataSource::Pointer)), this, SLOT(OnSetupNavigation()) ); connect( m_Controls.m_UseAsPointerButton, SIGNAL(clicked()), this, SLOT(OnInstrumentSelected()) ); connect( m_Controls.m_UseAsObjectmarkerButton, SIGNAL(clicked()), this, SLOT(OnObjectmarkerSelected()) ); connect( m_Controls.m_RegistrationWidget, SIGNAL(AddedTrackingFiducial()), this, SLOT(OnAddRegistrationTrackingFiducial()) ); connect( m_Controls.m_RegistrationWidget, SIGNAL(PerformFiducialRegistration()), this, SLOT(OnInitialRegistration()) ); connect( m_Controls.m_PointSetRecordCheckBox, SIGNAL(toggled(bool)), this, SLOT(OnPointSetRecording(bool)) ); connect( m_Controls.m_ActivateNeedleView, SIGNAL(toggled(bool)), this, SLOT(OnVirtualCamera(bool)) ); //start timer m_Timer->start(30); //initialize Combo Boxes m_Controls.m_ObjectComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_ObjectComboBox->SetAutoSelectNewItems(false); m_Controls.m_ObjectComboBox->SetPredicate(mitk::NodePredicateDataType::New("Surface")); m_Controls.m_ImageComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_ImageComboBox->SetAutoSelectNewItems(false); m_Controls.m_ImageComboBox->SetPredicate(mitk::NodePredicateDataType::New("Image")); } void QmitkIGTTrackingLabView::SetFocus() { m_Controls.m_UseAsPointerButton->setFocus(); } //############################################################################################### //############################################################################################### //####################### some additional slots and help methods ################################ //####################### for cleaner code - not that important ################################ //####################### to understand the basic functions ################################ //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::DestroyIGTPipeline() { if(m_Source.IsNotNull()) { m_Source->StopTracking(); m_Source->Disconnect(); m_Source = nullptr; } m_PermanentRegistrationFilter = nullptr; m_Visualizer = nullptr; m_VirtualView = nullptr; } bool QmitkIGTTrackingLabView::CheckRegistrationInitialization() { // a couple of variables which we need in this method std::string warningMessage = ""; bool initializationErrorDetected = false; mitk::PointSet::Pointer imageFiducials,trackerFiducials; // check some initialization stuff if (m_ImageFiducialsDataNode.IsNull() || m_TrackerFiducialsDataNode.IsNull()) { warningMessage = "Initialization not finished!"; MITK_WARN << warningMessage; QMessageBox::warning(nullptr, "Registration not possible", warningMessage.c_str()); return false; } else { imageFiducials = dynamic_cast(m_ImageFiducialsDataNode->GetData()); trackerFiducials = dynamic_cast(m_TrackerFiducialsDataNode->GetData()); } // now, do a lot of other checks... if (m_Controls.m_SurfaceActive->isChecked() && m_Controls.m_ObjectComboBox->GetSelectedNode().IsNull()) { warningMessage = "No surface selected for registration.\nRegistration is not possible"; initializationErrorDetected = true; } else if (m_Controls.m_ImageActive->isChecked() && m_Controls.m_ImageComboBox->GetSelectedNode().IsNull()) { warningMessage = "No image selected for registration.\nRegistration is not possible"; initializationErrorDetected = true; } else if (imageFiducials.IsNull() || trackerFiducials.IsNull()) { warningMessage = "Fiducial data objects not found. \n" "Please set 3 or more fiducials in the image and with the tracking system.\n\n" "Registration is not possible"; initializationErrorDetected = true; } else if ((imageFiducials->GetSize() < 3) || (trackerFiducials->GetSize() < 3) || (imageFiducials->GetSize() != trackerFiducials->GetSize())) { warningMessage = "Not enough fiducial pairs found. At least 3 fiducial must exist for the image and the tracking system respectively."; initializationErrorDetected = true; } // finaly: if an err was detected, give a warning and an error popup, then return false if(initializationErrorDetected) { MITK_WARN << warningMessage; QMessageBox::warning(nullptr, "Registration not possible", warningMessage.c_str()); return false; } //if no error was detected simply return true else {return true;} } bool QmitkIGTTrackingLabView::IsTransformDifferenceHigh(mitk::NavigationData::Pointer transformA, mitk::NavigationData::Pointer transformB, double euclideanDistanceThreshold, double angularDifferenceThreshold) { if(transformA.IsNull() || transformA.IsNull()) {return false;} mitk::Point3D posA,posB; posA = transformA->GetPosition(); posB = transformB->GetPosition(); if(posA.EuclideanDistanceTo(posB) > euclideanDistanceThreshold) {return true;} double returnValue; mitk::Quaternion rotA,rotB; rotA = transformA->GetOrientation(); rotB = transformB->GetOrientation(); itk::Vector point; //caution 5D-Tools: Vector must lie in the YZ-plane for a correct result. point[0] = 0.0; point[1] = 0.0; point[2] = 100000.0; rotA.normalize(); rotB.normalize(); itk::Matrix rotMatrixA; for(int i=0; i<3; i++) for(int j=0; j<3; j++) rotMatrixA[i][j] = rotA.rotation_matrix_transpose().transpose()[i][j]; itk::Matrix rotMatrixB; for(int i=0; i<3; i++) for(int j=0; j<3; j++) rotMatrixB[i][j] = rotB.rotation_matrix_transpose().transpose()[i][j]; itk::Vector pt1 = rotMatrixA * point; itk::Vector pt2 = rotMatrixB * point; returnValue = (pt1[0]*pt2[0]+pt1[1]*pt2[1]+pt1[2]*pt2[2]) / ( sqrt(pow(pt1[0],2.0)+pow(pt1[1],2.0)+pow(pt1[2],2.0)) * sqrt(pow(pt2[0],2.0)+pow(pt2[1],2.0)+pow(pt2[2],2.0))); returnValue = acos(returnValue); if(returnValue*57.3 > angularDifferenceThreshold){return true;} return false; } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp index d32826c240..62c5c49005 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp @@ -1,104 +1,105 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include //Mitk #include #include #include #include #include #include #include // Qmitk #include "QmitkIGTFiducialRegistration.h" +#include // Qt #include #include #include // MicroServices #include #include #include "usServiceReference.h" const std::string QmitkIGTFiducialRegistration::VIEW_ID = "org.mitk.views.IGTFiducialRegistration"; void QmitkIGTFiducialRegistration::SetFocus() { } void QmitkIGTFiducialRegistration::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); //Connect signals and slots connect(m_Controls.m_ChooseSelectedPointer, SIGNAL(clicked()), this, SLOT(PointerSelectionChanged())); connect(m_Controls.m_ChooseSelectedImage, SIGNAL(clicked()), this, SLOT(ImageSelectionChanged())); //Initialize Combobox m_Controls.m_DataStorageComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_DataStorageComboBox->SetAutoSelectNewItems(false); m_Controls.m_DataStorageComboBox->SetPredicate(mitk::NodePredicateOr::New(mitk::NodePredicateDataType::New("Surface"), mitk::NodePredicateDataType::New("Image"))); //Initialize Fiducial Registration Widget m_Controls.m_FiducialRegistrationWidget->setDataStorage(this->GetDataStorage()); m_Controls.m_FiducialRegistrationWidget->HideStaticRegistrationRadioButton(true); m_Controls.m_FiducialRegistrationWidget->HideContinousRegistrationRadioButton(true); m_Controls.m_FiducialRegistrationWidget->HideUseICPRegistrationCheckbox(true); } void QmitkIGTFiducialRegistration::InitializeRegistration() { foreach(QmitkRenderWindow* renderWindow, this->GetRenderWindowPart()->GetQmitkRenderWindows().values()) { this->m_Controls.m_FiducialRegistrationWidget->AddSliceNavigationController(renderWindow->GetSliceNavigationController()); } } void QmitkIGTFiducialRegistration::PointerSelectionChanged() { InitializeRegistration(); int toolID = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedToolID(); m_TrackingPointer = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(toolID); m_Controls.m_FiducialRegistrationWidget->setTrackerNavigationData(m_TrackingPointer); m_Controls.m_PointerLabel->setText(m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationTool()->GetToolName().c_str()); } void QmitkIGTFiducialRegistration::ImageSelectionChanged() { InitializeRegistration(); m_Controls.m_ImageLabel->setText(m_Controls.m_DataStorageComboBox->GetSelectedNode()->GetName().c_str()); m_Controls.m_FiducialRegistrationWidget->setImageNode(m_Controls.m_DataStorageComboBox->GetSelectedNode()); } QmitkIGTFiducialRegistration::QmitkIGTFiducialRegistration() { } QmitkIGTFiducialRegistration::~QmitkIGTFiducialRegistration() { } diff --git a/Plugins/org.mitk.gui.qt.pointsetinteraction/src/internal/QmitkPointSetInteractionView.cpp b/Plugins/org.mitk.gui.qt.pointsetinteraction/src/internal/QmitkPointSetInteractionView.cpp index 85a41651a3..43759a7647 100755 --- a/Plugins/org.mitk.gui.qt.pointsetinteraction/src/internal/QmitkPointSetInteractionView.cpp +++ b/Plugins/org.mitk.gui.qt.pointsetinteraction/src/internal/QmitkPointSetInteractionView.cpp @@ -1,148 +1,151 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Qmitk related includes #include "QmitkPointSetInteractionView.h" #include "ui_QmitkPointSetInteractionViewControls.h" #include #include #include #include -#include -#include + #include #include +#include + +#include +#include const std::string QmitkPointSetInteractionView::VIEW_ID = "org.mitk.views.pointsetinteraction"; QmitkPointSetInteractionView::QmitkPointSetInteractionView( QObject* /*parent*/ ) : m_Controls(0) { } QmitkPointSetInteractionView::~QmitkPointSetInteractionView() { } void QmitkPointSetInteractionView::CreateQtPartControl( QWidget *parent ) { m_Controls = new Ui::QmitkPointSetInteractionControls; m_Controls->setupUi(parent); m_Controls->m_PbAddPointSet->connect( m_Controls->m_PbAddPointSet, SIGNAL( clicked() ) , this, SLOT( OnAddPointSetClicked() ) ); if (mitk::IRenderWindowPart *renderWindowPart = GetRenderWindowPart()) { // let the point set widget know about the render window part (crosshair updates) RenderWindowPartActivated(renderWindowPart); } } void QmitkPointSetInteractionView::SetFocus() { m_Controls->m_PbAddPointSet->setFocus(); } void QmitkPointSetInteractionView::OnAddPointSetClicked() { //Ask for the name of the point set bool ok = false; QString name = QInputDialog::getText( QApplication::activeWindow() , tr("Add point set..."), tr("Enter name for the new point set"), QLineEdit::Normal, tr("PointSet"), &ok ); if ( ! ok || name.isEmpty() ) return; // //Create a new empty pointset // mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); // // Create a new data tree node // mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); // // fill the data tree node with the appropriate information // pointSetNode->SetData( pointSet ); pointSetNode->SetProperty( "name", mitk::StringProperty::New( name.toStdString() ) ); pointSetNode->SetProperty( "opacity", mitk::FloatProperty::New( 1 ) ); pointSetNode->SetColor( 1.0, 1.0, 0.0 ); // // add the node to the ds // this->GetDataStorage()->Add(pointSetNode); // make new selection and emulate selection for this berry::IWorkbenchPart::Pointer nullPart; QList selection; selection.push_back(pointSetNode); this->OnSelectionChanged(nullPart, selection); } void QmitkPointSetInteractionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { mitk::DataNode::Pointer selectedNode; if(!nodes.empty()) selectedNode = nodes.front(); mitk::PointSet::Pointer pointSet; if(selectedNode.IsNotNull()) pointSet = dynamic_cast(selectedNode->GetData()); if (pointSet.IsNotNull()) { m_SelectedPointSetNode = selectedNode; m_Controls->m_CurrentPointSetLabel->setText(QString::fromStdString(selectedNode->GetName())); m_Controls->m_PointListWidget->SetPointSetNode(selectedNode); } else { m_Controls->m_CurrentPointSetLabel->setText(tr("None")); m_Controls->m_PointListWidget->SetPointSetNode(nullptr); } } void QmitkPointSetInteractionView::NodeChanged( const mitk::DataNode* node ) { if(node == m_SelectedPointSetNode && m_Controls->m_CurrentPointSetLabel->text().toStdString() != node->GetName()) { m_Controls->m_CurrentPointSetLabel->setText(QString::fromStdString(node->GetName())); } } void QmitkPointSetInteractionView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if(m_Controls) { m_Controls->m_PointListWidget->AddSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); m_Controls->m_PointListWidget->AddSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); m_Controls->m_PointListWidget->AddSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); } } void QmitkPointSetInteractionView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { if(m_Controls) { m_Controls->m_PointListWidget->RemoveSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); m_Controls->m_PointListWidget->RemoveSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); m_Controls->m_PointListWidget->RemoveSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); } } diff --git a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp index 47556da11c..ccbdba7f46 100644 --- a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp +++ b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp @@ -1,460 +1,461 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPreprocessingResamplingView.h" // QT includes (GUI) #include #include #include #include #include #include #include // Berry includes (selection service) #include #include // MITK includes (GUI) #include "QmitkStdMultiWidget.h" #include "QmitkDataNodeSelectionProvider.h" #include "mitkDataNodeObject.h" // MITK includes (general) #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateAnd.h" #include "mitkImageTimeSelector.h" #include "mitkVectorImageMapper2D.h" #include "mitkProperties.h" +#include "mitkLevelWindowProperty.h" // Includes for image casting between ITK and MITK #include "mitkImageCast.h" #include "mitkITKImageImport.h" // ITK includes (general) #include #include // Resampling #include #include #include #include #include #include #include // STD #include // Convenient Definitions typedef itk::Image ImageType; typedef itk::Image SegmentationImageType; typedef itk::Image DoubleImageType; typedef itk::Image, 3> VectorImageType; typedef itk::ResampleImageFilter< ImageType, ImageType > ResampleImageFilterType; typedef itk::ResampleImageFilter< ImageType, ImageType > ResampleImageFilterType2; typedef itk::CastImageFilter< ImageType, DoubleImageType > ImagePTypeToFloatPTypeCasterType; typedef itk::LinearInterpolateImageFunction< ImageType, double > LinearInterpolatorType; typedef itk::NearestNeighborInterpolateImageFunction< ImageType, double > NearestInterpolatorType; typedef itk::BSplineInterpolateImageFunction BSplineInterpolatorType; QmitkPreprocessingResampling::QmitkPreprocessingResampling() : QmitkAbstractView(), m_Controls(NULL), m_SelectedImageNode(NULL), m_TimeStepperAdapter(NULL) { } QmitkPreprocessingResampling::~QmitkPreprocessingResampling() { } void QmitkPreprocessingResampling::CreateQtPartControl(QWidget *parent) { if (m_Controls == NULL) { m_Controls = new Ui::QmitkPreprocessingResamplingViewControls; m_Controls->setupUi(parent); this->CreateConnections(); mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); mitk::NodePredicateDataType::Pointer imagePredicate = mitk::NodePredicateDataType::New("Image"); } m_SelectedImageNode = mitk::DataStorageSelection::New(this->GetDataStorage(), false); // Setup Controls this->m_Controls->cbParam4->clear(); this->m_Controls->cbParam4->insertItem(LINEAR, "Linear"); this->m_Controls->cbParam4->insertItem(NEAREST, "Nearest neighbor"); this->m_Controls->cbParam4->insertItem(SPLINE, "B-Spline"); } void QmitkPreprocessingResampling::CreateConnections() { if ( m_Controls ) { connect((QObject*)(m_Controls->btnDoIt), SIGNAL(clicked()), (QObject*) this, SLOT(StartButtonClicked())); connect((QObject*)(m_Controls->buttonExecuteOnMultipleImages), SIGNAL(clicked()), (QObject*) this, SLOT(StartMultipleImagesButtonClicked())); connect( (QObject*)(m_Controls->cbParam4), SIGNAL( activated(int) ), this, SLOT( SelectInterpolator(int) ) ); } } void QmitkPreprocessingResampling::InternalGetTimeNavigationController() { auto renwin_part = GetRenderWindowPart(); if( renwin_part != nullptr ) { auto tnc = renwin_part->GetTimeNavigationController(); if( tnc != nullptr ) { m_TimeStepperAdapter = new QmitkStepperAdapter((QObject*) m_Controls->sliceNavigatorTime, tnc->GetTime(), "sliceNavigatorTimeFromBIP"); } } } void QmitkPreprocessingResampling::SetFocus() { } //datamanager selection changed void QmitkPreprocessingResampling::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { ResetOneImageOpPanel(); //any nodes there? if (!nodes.empty()) { // reset GUI m_Controls->sliceNavigatorTime->setEnabled(false); m_Controls->leImage1->setText(tr("Select an Image in Data Manager")); m_SelectedNodes.clear(); for (mitk::DataNode* _DataNode : nodes) { m_SelectedImageNode->RemoveAllNodes(); *m_SelectedImageNode = _DataNode; mitk::Image::Pointer tempImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); //no image if (tempImage.IsNull() || (tempImage->IsInitialized() == false)) { if (m_SelectedNodes.size() < 1) { m_Controls->leImage1->setText(tr("Not an image.")); } continue; } //2D image if (tempImage->GetDimension() < 3) { if (m_SelectedNodes.size() < 1) { m_Controls->leImage1->setText(tr("2D images are not supported.")); } continue; } if (m_SelectedNodes.size() < 1) { m_Controls->leImage1->setText(QString(m_SelectedImageNode->GetNode()->GetName().c_str())); mitk::Vector3D aSpacing = tempImage->GetGeometry()->GetSpacing(); std::string text("x-spacing (" + std::to_string(aSpacing[0]) + ")"); m_Controls->tlParam1->setText(text.c_str()); text = "y-spacing (" + std::to_string(aSpacing[1]) + ")"; m_Controls->tlParam2->setText(text.c_str()); text = "z-spacing (" + std::to_string(aSpacing[2]) + ")"; m_Controls->tlParam3->setText(text.c_str()); if (tempImage->GetDimension() > 3) { // try to retrieve the TNC (for 4-D Processing ) this->InternalGetTimeNavigationController(); m_Controls->sliceNavigatorTime->setEnabled(true); m_Controls->tlTime->setEnabled(true); } } m_SelectedNodes.push_back(_DataNode); } if (m_SelectedNodes.size() > 0) { *m_SelectedImageNode = m_SelectedNodes[0]; } ResetParameterPanel(); } } void QmitkPreprocessingResampling::ResetOneImageOpPanel() { m_Controls->tlTime->setEnabled(false); m_Controls->btnDoIt->setEnabled(false); m_Controls->buttonExecuteOnMultipleImages->setEnabled(false); m_Controls->cbHideOrig->setEnabled(false); m_Controls->leImage1->setText(tr("Select an Image in Data Manager")); m_Controls->tlParam1->setText("x-spacing"); m_Controls->tlParam1->setText("y-spacing"); m_Controls->tlParam1->setText("z-spacing"); } void QmitkPreprocessingResampling::ResetParameterPanel() { m_Controls->btnDoIt->setEnabled(true); m_Controls->buttonExecuteOnMultipleImages->setEnabled(true); m_Controls->cbHideOrig->setEnabled(true); } void QmitkPreprocessingResampling::ResetTwoImageOpPanel() { } void QmitkPreprocessingResampling::StartMultipleImagesButtonClicked() { for (auto currentSelectedNode : m_SelectedNodes) { m_SelectedImageNode->RemoveAllNodes(); *m_SelectedImageNode = currentSelectedNode; StartButtonClicked(); } } void QmitkPreprocessingResampling::StartButtonClicked() { if(!m_SelectedImageNode->GetNode()) return; this->BusyCursorOn(); mitk::Image::Pointer newImage; try { newImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); } catch ( std::exception &e ) { QString exceptionString = tr("An error occured during image loading:\n"); exceptionString.append( e.what() ); QMessageBox::warning( NULL, "Preprocessing - Resampling: ", exceptionString , QMessageBox::Ok, QMessageBox::NoButton ); this->BusyCursorOff(); return; } // check if input image is valid, casting does not throw exception when casting from 'NULL-Object' if ( (! newImage) || (newImage->IsInitialized() == false) ) { this->BusyCursorOff(); QMessageBox::warning( NULL, "Preprocessing - Resampling", tr("Input image is broken or not initialized. Returning."), QMessageBox::Ok, QMessageBox::NoButton ); return; } // check if operation is done on 4D a image time step if(newImage->GetDimension() > 3) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(newImage); timeSelector->SetTimeNr( ((QmitkSliderNavigatorWidget*)m_Controls->sliceNavigatorTime)->GetPos() ); timeSelector->Update(); newImage = timeSelector->GetOutput(); } // check if image or vector image ImageType::Pointer itkImage = ImageType::New(); VectorImageType::Pointer itkVecImage = VectorImageType::New(); int isVectorImage = newImage->GetPixelType().GetNumberOfComponents(); if(isVectorImage > 1) { CastToItkImage( newImage, itkVecImage ); } else { CastToItkImage( newImage, itkImage ); } std::stringstream nameAddition(""); double dparam1 = m_Controls->dsbParam1->value(); double dparam2 = m_Controls->dsbParam2->value(); double dparam3 = m_Controls->dsbParam3->value(); try{ std::string selectedInterpolator; ResampleImageFilterType::Pointer resampler = ResampleImageFilterType::New(); switch (m_SelectedInterpolation) { case LINEAR: { LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Linear"; break; } case NEAREST: { NearestInterpolatorType::Pointer interpolator = NearestInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Nearest"; break; } case SPLINE: { BSplineInterpolatorType::Pointer interpolator = BSplineInterpolatorType::New(); interpolator->SetSplineOrder(3); resampler->SetInterpolator(interpolator); selectedInterpolator = "B-Spline"; break; } default: { LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Linear"; break; } } resampler->SetInput( itkImage ); resampler->SetOutputOrigin( itkImage->GetOrigin() ); ImageType::SizeType input_size = itkImage->GetLargestPossibleRegion().GetSize(); ImageType::SpacingType input_spacing = itkImage->GetSpacing(); ImageType::SizeType output_size; ImageType::SpacingType output_spacing; if (dparam1 > 0) { output_size[0] = std::ceil(input_size[0] * (input_spacing[0] / dparam1)); output_spacing[0] = dparam1; } else { output_size[0] = std::ceil(input_size[0] * (-1.0 / dparam1)); output_spacing[0] = -1.0*input_spacing[0] * dparam1; } if (dparam2 > 0) { output_size[1] = std::ceil(input_size[1] * (input_spacing[1] / dparam2)); output_spacing[1] = dparam2; } else { output_size[1] = std::ceil(input_size[1] * (-1.0 / dparam2)); output_spacing[1] = -1.0*input_spacing[1] * dparam2; } if (dparam3 > 0) { output_size[2] = std::ceil(input_size[2] * (input_spacing[2] / dparam3)); output_spacing[2] = dparam3; } else { output_size[2] = std::ceil(input_size[2] * (-1.0 / dparam3)); output_spacing[2] = -1.0*input_spacing[2] * dparam3; } resampler->SetSize( output_size ); resampler->SetOutputSpacing( output_spacing ); resampler->SetOutputDirection( itkImage->GetDirection() ); resampler->UpdateLargestPossibleRegion(); ImageType::Pointer resampledImage = resampler->GetOutput(); newImage = mitk::ImportItkImage( resampledImage )->Clone(); nameAddition << "_Resampled_" << selectedInterpolator; std::cout << "Resampling successful." << std::endl; } catch (...) { this->BusyCursorOff(); QMessageBox::warning(NULL, "Warning", "Problem when applying filter operation. Check your input..."); return; } newImage->DisconnectPipeline(); // adjust level/window to new image mitk::LevelWindow levelwindow; levelwindow.SetAuto( newImage ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); levWinProp->SetLevelWindow( levelwindow ); // compose new image name std::string name = m_SelectedImageNode->GetNode()->GetName(); if (name.find(".pic.gz") == name.size() -7 ) { name = name.substr(0,name.size() -7); } name.append( nameAddition.str() ); // create final result MITK data storage node mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "levelwindow", levWinProp ); result->SetProperty( "name", mitk::StringProperty::New( name.c_str() ) ); result->SetData( newImage ); // for vector images, a different mapper is needed if(isVectorImage > 1) { mitk::VectorImageMapper2D::Pointer mapper = mitk::VectorImageMapper2D::New(); result->SetMapper(1,mapper); } // add new image to data storage and set as active to ease further processing GetDataStorage()->Add( result, m_SelectedImageNode->GetNode() ); if ( m_Controls->cbHideOrig->isChecked() == true ) m_SelectedImageNode->GetNode()->SetProperty( "visible", mitk::BoolProperty::New(false) ); // show the results mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->BusyCursorOff(); } void QmitkPreprocessingResampling::SelectInterpolator(int interpolator) { switch (interpolator) { case 0: { m_SelectedInterpolation = LINEAR; break; } case 1: { m_SelectedInterpolation = NEAREST; break; } case 2: { m_SelectedInterpolation = SPLINE; } } }