diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/resources/quantification.png b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/resources/quantification.png index 523e688813..d71a232e11 100644 Binary files a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/resources/quantification.png and b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/resources/quantification.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.cpp index 5709c730b7..bf4dc4f7c2 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.cpp @@ -1,384 +1,350 @@ /*=================================================================== 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 "QmitkODFDetailsView.h" #include #include #include #include #include #include #include #include #include #include #include #include const std::string QmitkODFDetailsView::VIEW_ID = "org.mitk.views.odfdetails"; QmitkODFDetailsView::QmitkODFDetailsView() : QmitkAbstractView() , m_Controls( 0 ) , m_OdfNormalization(0) , m_ImageNode(nullptr) { m_VtkActor = vtkActor::New(); m_VtkMapper = vtkPolyDataMapper::New(); m_Renderer = vtkRenderer::New(); m_VtkRenderWindow = vtkRenderWindow::New(); m_RenderWindowInteractor = vtkRenderWindowInteractor::New(); m_Camera = vtkCamera::New(); m_VtkRenderWindow->SetSize(300,300); } QmitkODFDetailsView::~QmitkODFDetailsView() { if (m_ImageNode.IsNotNull()) m_ImageNode->RemoveObserver( m_PropertyObserverTag ); } void QmitkODFDetailsView::Activated() { } void QmitkODFDetailsView::Deactivated() { } void QmitkODFDetailsView::Visible() { - mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); - if (renderWindow) - { - { - mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("axial"))->GetSliceNavigationController(); - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); - m_SliceObserverTag1 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); - } - - { - mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("sagittal"))->GetSliceNavigationController(); - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); - m_SliceObserverTag2 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); - } - - { - mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("coronal"))->GetSliceNavigationController(); - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); - m_SliceObserverTag3 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); - } - } } void QmitkODFDetailsView::Hidden() { - mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); - if (renderWindow) - { - mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("axial"))->GetSliceNavigationController(); - slicer->RemoveObserver(m_SliceObserverTag1); - slicer = renderWindow->GetQmitkRenderWindow(QString("sagittal"))->GetSliceNavigationController(); - slicer->RemoveObserver(m_SliceObserverTag2); - slicer = renderWindow->GetQmitkRenderWindow(QString("coronal"))->GetSliceNavigationController(); - slicer->RemoveObserver(m_SliceObserverTag3); - } } void QmitkODFDetailsView::SetFocus() { this->m_Controls->m_OverviewTextEdit->setFocus(); } void QmitkODFDetailsView::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::QmitkODFDetailsViewControls; m_Controls->setupUi( parent ); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_ODFRenderWidget->setVisible(false); + + + m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); + connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } } void QmitkODFDetailsView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { if (m_ImageNode.IsNotNull()) m_ImageNode->RemoveObserver( m_PropertyObserverTag ); m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_InputImageLabel->setText("mandatory"); m_ImageNode = nullptr; // iterate selection for (mitk::DataNode::Pointer node: nodes) { if( node.IsNotNull() && (dynamic_cast(node->GetData()) || dynamic_cast(node->GetData())) ) { m_Controls->m_InputImageLabel->setText(node->GetName().c_str()); m_ImageNode = node; } } UpdateOdf(); if (m_ImageNode.IsNotNull()) { - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); - m_PropertyObserverTag = m_ImageNode->AddObserver( itk::ModifiedEvent(), command ); - m_Controls->m_InputData->setTitle("Input Data"); } } void QmitkODFDetailsView::UpdateOdf() { try { m_Controls->m_OverviewBox->setVisible(true); if (m_ImageNode.IsNull() || !this->GetRenderWindowPart()) { m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_OverviewBox->setVisible(false); return; } // restore the input image label ( needed in case the last run resulted into an exception ) m_Controls->m_InputImageLabel->setText(m_ImageNode->GetName().c_str()); // ODF Normalization Property mitk::OdfNormalizationMethodProperty* nmp = dynamic_cast(m_ImageNode->GetProperty( "Normalization" )); if(nmp) m_OdfNormalization = nmp->GetNormalization(); m_TemplateOdf = itk::OrientationDistributionFunction::GetBaseMesh(); m_OdfTransform = vtkSmartPointer::New(); m_OdfTransform->Identity(); m_OdfVals = vtkSmartPointer::New(); m_OdfSource = vtkSmartPointer::New(); itk::OrientationDistributionFunction odf; mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition(); mitk::Point3D index; mitk::Image::Pointer img = dynamic_cast(m_ImageNode->GetData()); unsigned int *img_dimension = img->GetDimensions(); img->GetGeometry()->WorldToIndex(world, index); float sum = 0; float max = itk::NumericTraits::NonpositiveMin(); float min = itk::NumericTraits::max(); QString values; QString overviewText; // check if dynamic_cast successfull and if the crosshair position is inside of the geometry of the ODF data // otherwise possible crash for a scenario with multiple nodes if (dynamic_cast(m_ImageNode->GetData()) && ( m_ImageNode->GetData()->GetGeometry()->IsInside(world) ) ) { m_Controls->m_ODFRenderWidget->setVisible(true); m_Controls->m_OdfBox->setVisible(true); try { const mitk::OdfImage* Odf_image = dynamic_cast< mitk::OdfImage* >( m_ImageNode->GetData() ); // get access to the Odf image data with explicitely allowing exceptions if memory locked mitk::ImageReadAccessor readAccess( Odf_image, Odf_image->GetVolumeData(0), mitk::ImageAccessorBase::ExceptionIfLocked ); const float* Odf_cPtr = static_cast< const float*>(readAccess.GetData()); OdfVectorImgType::IndexType ind; ind[0] = (int)(index[0]+0.5); ind[1] = (int)(index[1]+0.5); ind[2] = (int)(index[2]+0.5); // pixel size = ODF_SAMPLING_SIZE // position offset = standard offset unsigned int offset_to_data = ODF_SAMPLING_SIZE * (ind[2] * img_dimension[1] * img_dimension[0] + ind[1] * img_dimension[0] + ind[0]); const float *pixel_data = Odf_cPtr + offset_to_data; for (int i=0; imax) max = val; if (val pd = odf.GetDirection(odf.GetPrincipleDiffusionDirection()); overviewText += "Main Diffusion:\n "+QString::number(pd[0])+"\n "+QString::number(pd[1])+"\n "+QString::number(pd[2])+"\n"; m_Controls->m_OdfValuesTextEdit->setText(values); m_Controls->m_OverviewTextEdit->setVisible(true); } catch( mitk::Exception &e ) { MITK_WARN << "LOCKED : " << e.what(); m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_OverviewTextEdit->setVisible(false); // reset the selection m_Controls->m_InputImageLabel->setText("Click image to restore rendering!"); } } else if (dynamic_cast(m_ImageNode->GetData()) && ( m_ImageNode->GetData()->GetGeometry()->IsInside(world) ) ) { m_Controls->m_ODFRenderWidget->setVisible(true); m_Controls->m_OdfBox->setVisible(false); const mitk::TensorImage* Odf_image = dynamic_cast< mitk::TensorImage*>(m_ImageNode->GetData()); // pixel access block try { // get access to the Odf image data with explicitely allowing exceptions if memory locked mitk::ImageReadAccessor readAccess( Odf_image, Odf_image->GetVolumeData(0), mitk::ImageAccessorBase::ExceptionIfLocked ); const float* Odf_cPtr = static_cast< const float*>(readAccess.GetData()); TensorImageType::IndexType ind; ind[0] = (int)(index[0]+0.5); ind[1] = (int)(index[1]+0.5); ind[2] = (int)(index[2]+0.5); // 6 - tensorsize // remaining computation - standard offset unsigned int offset_to_data = 6 * (ind[2] * img_dimension[1] * img_dimension[0] + ind[1] * img_dimension[0] + ind[0]); const float *pixel_data = Odf_cPtr + offset_to_data; float tensorelems[6] = { *(pixel_data ), *(pixel_data + 1), *(pixel_data + 2), *(pixel_data + 3), *(pixel_data + 4), *(pixel_data + 5), }; itk::DiffusionTensor3D tensor(tensorelems); odf.InitFromTensor(tensor); /** Array of eigen-values. */ typedef itk::FixedArray EigenValuesArrayType; /** Matrix of eigen-vectors. */ typedef itk::Matrix EigenVectorsMatrixType; EigenValuesArrayType eigenValues; EigenVectorsMatrixType eigenvectors; QString pos = QString::number(ind[0])+", "+QString::number(ind[1])+", "+QString::number(ind[2]); overviewText += "Coordinates: "+pos+"\n"; overviewText += "FA: "+QString::number(tensor.GetFractionalAnisotropy())+"\n"; overviewText += "RA: "+QString::number(tensor.GetRelativeAnisotropy())+"\n"; overviewText += "Trace: "+QString::number(tensor.GetTrace())+"\n"; tensor.ComputeEigenAnalysis(eigenValues,eigenvectors); overviewText += "Eigenvalues:\n "+QString::number(eigenValues[2])+"\n "+QString::number(eigenValues[1])+"\n "+QString::number(eigenValues[0])+"\n"; overviewText += "Main Diffusion:\n "+QString::number(eigenvectors(2, 0))+"\n "+QString::number(eigenvectors(2, 1))+"\n "+QString::number(eigenvectors(2, 2))+"\n"; overviewText += "Values:\n "+QString::number(tensorelems[0])+"\n "+QString::number(tensorelems[1])+"\n "+QString::number(tensorelems[2])+"\n "+QString::number(tensorelems[3])+"\n "+QString::number(tensorelems[4])+"\n "+QString::number(tensorelems[5])+"\n "+"\n"; m_Controls->m_OverviewTextEdit->setVisible(true); } // end pixel access block catch(mitk::Exception &e ) { MITK_WARN << "LOCKED : " << e.what(); m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_OverviewTextEdit->setVisible(false); // reset the selection m_Controls->m_InputImageLabel->setText("Click image to restore rendering!"); } } else { m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); overviewText += "Please reinit image geometry.\n"; } // proceed only if the render widget is visible which indicates that the // predecessing computations were successfull if( m_Controls->m_ODFRenderWidget->isVisible() ) { m_Controls->m_ODFDetailsWidget->SetParameters(odf); switch(m_OdfNormalization) { case 0: odf = odf.MinMaxNormalize(); break; case 1: odf = odf.MaxNormalize(); break; case 2: odf = odf.MaxNormalize(); break; default: odf = odf.MinMaxNormalize(); } m_Controls->m_ODFRenderWidget->GenerateODF(odf); m_Controls->m_OverviewTextEdit->setText(overviewText.toStdString().c_str()); } } catch(...) { QMessageBox::critical(0, "Error", "Data could not be analyzed. The image might be corrupted."); } } -void QmitkODFDetailsView::OnSliceChanged(const itk::EventObject& /*e*/) +void QmitkODFDetailsView::OnSliceChanged() { UpdateOdf(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.h index 9f1b389509..1eedc2087e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsView.h @@ -1,115 +1,117 @@ /*=================================================================== 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 _QMITKQmitkODFDetailsView_H_INCLUDED #define _QMITKQmitkODFDetailsView_H_INCLUDED #include #include #include "mitkILifecycleAwarePart.h" #include "ui_QmitkODFDetailsViewControls.h" #include #include #include #include #include #include #include #include #include #include #include #include #include +#include /*! \brief View displaying details of the orientation distribution function in the voxel at the current crosshair position. */ class QmitkODFDetailsView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { // 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; QmitkODFDetailsView(); virtual ~QmitkODFDetailsView(); typedef float TOdfPixelType; typedef itk::Vector OdfVectorType; typedef itk::Image OdfVectorImgType; typedef itk::DiffusionTensor3D< TOdfPixelType > TensorPixelType; typedef itk::Image< TensorPixelType, 3 > TensorImageType; virtual void CreateQtPartControl(QWidget *parent) override; - void OnSliceChanged(const itk::EventObject& e); protected slots: + void OnSliceChanged(); + protected: /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; virtual void SetFocus() override; virtual void Activated() override; virtual void Deactivated() override; virtual void Visible() override; virtual void Hidden() override; void UpdateOdf(); ///< called if slice position or datamanager selection has changed Ui::QmitkODFDetailsViewControls* m_Controls; /** observer flags */ int m_SliceObserverTag1; int m_SliceObserverTag2; int m_SliceObserverTag3; int m_PropertyObserverTag; /** ODF related variables like mesh structure, values etc. */ vtkPolyData* m_TemplateOdf; ///< spherical base mesh vtkSmartPointer m_OdfTransform; vtkSmartPointer m_OdfVals; vtkSmartPointer m_OdfSource; int m_OdfNormalization; ///< normalization method defined in the visualization view /** rendering of the ODF */ vtkActor* m_VtkActor; vtkPolyDataMapper* m_VtkMapper; vtkRenderer* m_Renderer; vtkRenderWindow* m_VtkRenderWindow; vtkRenderWindowInteractor* m_RenderWindowInteractor; vtkCamera* m_Camera; - - mitk::DataNode::Pointer m_ImageNode; + mitk::DataNode::Pointer m_ImageNode; + QmitkSliceNavigationListener m_SliceChangeListener; }; #endif // _QmitkODFDetailsView_H_INCLUDED