diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsView.cpp index 4064080103..8859bbc8f8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsView.cpp @@ -1,309 +1,370 @@ /*=================================================================== 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() - : QmitkFunctionality() - , m_Controls( 0 ) - , m_MultiWidget( NULL ) - , m_OdfNormalization(0) - , m_ImageNode(NULL) + : QmitkFunctionality() + , m_Controls( 0 ) + , m_MultiWidget( NULL ) + , m_OdfNormalization(0) + , m_ImageNode(NULL) { - 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); + 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() { } 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); - } + // 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); + } } void QmitkODFDetailsView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { - m_MultiWidget = &stdMultiWidget; - - { - mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget1->GetSliceNavigationController(); - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); - m_SliceObserverTag1 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); - } - - { - mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget2->GetSliceNavigationController(); - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); - m_SliceObserverTag2 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); - } - - { - mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget3->GetSliceNavigationController(); - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); - m_SliceObserverTag3 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); - } + m_MultiWidget = &stdMultiWidget; + + { + mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget1->GetSliceNavigationController(); + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); + m_SliceObserverTag1 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); + } + + { + mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget2->GetSliceNavigationController(); + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); + m_SliceObserverTag2 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); + } + + { + mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget3->GetSliceNavigationController(); + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); + m_SliceObserverTag3 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); + } } void QmitkODFDetailsView::StdMultiWidgetNotAvailable() { - { - mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget1->GetSliceNavigationController(); - slicer->RemoveObserver( m_SliceObserverTag1 ); - } + { + mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget1->GetSliceNavigationController(); + slicer->RemoveObserver( m_SliceObserverTag1 ); + } - { - mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget2->GetSliceNavigationController(); - slicer->RemoveObserver( m_SliceObserverTag2 ); - } + { + mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget2->GetSliceNavigationController(); + slicer->RemoveObserver( m_SliceObserverTag2 ); + } - { - mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget3->GetSliceNavigationController(); - slicer->RemoveObserver( m_SliceObserverTag3 ); - } + { + mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget3->GetSliceNavigationController(); + slicer->RemoveObserver( m_SliceObserverTag3 ); + } - m_MultiWidget = NULL; + m_MultiWidget = NULL; } void QmitkODFDetailsView::OnSelectionChanged( std::vector nodes ) { - if (m_ImageNode.IsNotNull()) - m_ImageNode->RemoveObserver( m_PropertyObserverTag ); + 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_Controls->m_InputData->setTitle("Please Select Input Data"); + m_Controls->m_InputImageLabel->setText("mandatory"); - m_ImageNode = NULL; - // iterate selection - for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) - { - mitk::DataNode::Pointer node = *it; + m_ImageNode = NULL; + // iterate selection + for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) + { + mitk::DataNode::Pointer node = *it; - if( node.IsNotNull() && (dynamic_cast(node->GetData()) || dynamic_cast(node->GetData())) ) - { - m_Controls->m_InputImageLabel->setText(node->GetName().c_str()); - m_ImageNode = node; - } + 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 ); + 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"); - } + m_Controls->m_InputData->setTitle("Input Data"); + } } void QmitkODFDetailsView::UpdateOdf() { - try + try + { + m_Controls->m_OverviewBox->setVisible(true); + if (m_ImageNode.IsNull() || !m_MultiWidget) { - m_Controls->m_OverviewBox->setVisible(true); - if (m_ImageNode.IsNull() || !m_MultiWidget) - { - m_Controls->m_ODFRenderWidget->setVisible(false); - m_Controls->m_OdfBox->setVisible(false); - m_Controls->m_OverviewBox->setVisible(false); - return; - } + m_Controls->m_ODFRenderWidget->setVisible(false); + m_Controls->m_OdfBox->setVisible(false); + m_Controls->m_OverviewBox->setVisible(false); + return; + } - // 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 = m_MultiWidget->GetCrossPosition(); - mitk::Point3D index; - mitk::Image::Pointer img = dynamic_cast(m_ImageNode->GetData()); - img->GetTimeSlicedGeometry()->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); - OdfVectorImgType::Pointer itkQBallImage = OdfVectorImgType::New(); - mitk::CastToItkImage(dynamic_cast(m_ImageNode->GetData()), itkQBallImage); - OdfVectorImgType::IndexType ind; - ind[0] = (int)(index[0]+0.5); - ind[1] = (int)(index[1]+0.5); - ind[2] = (int)(index[2]+0.5); - - OdfVectorImgType::PixelType pixel = itkQBallImage->GetPixel(ind); - - 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); - } - else if (dynamic_cast(m_ImageNode->GetData())) - { - m_Controls->m_ODFRenderWidget->setVisible(true); - m_Controls->m_OdfBox->setVisible(false); - TensorImageType::Pointer itkQBallImage = TensorImageType::New(); - mitk::CastToItkImage(dynamic_cast(m_ImageNode->GetData()), itkQBallImage); - - TensorImageType::IndexType ind; - ind[0] = (int)(index[0]+0.5); - ind[1] = (int)(index[1]+0.5); - ind[2] = (int)(index[2]+0.5); - - TensorImageType::PixelType pixel = itkQBallImage->GetPixel(ind); - - float tensorelems[6] = { - (float)pixel[0], - (float)pixel[1], - (float)pixel[2], - (float)pixel[3], - (float)pixel[4], - (float)pixel[5], - }; - itk::DiffusionTensor3D tensor(tensorelems); - - odf.InitFromTensor(tensor); - - - /** Array of eigen-values. */ - typedef itk::FixedArray EigenValuesArrayType; - /** Matrix of eigen-vectors. */ - typedef itk::Matrix MatrixType; - 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[0][0])+"\n "+QString::number(eigenVectors[1][0])+"\n "+QString::number(eigenVectors[2][0])+"\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"; - } - else - { - m_Controls->m_ODFRenderWidget->setVisible(false); - m_Controls->m_OdfBox->setVisible(false); - overviewText += "Please reinit image geometry.\n"; - } + // 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 = m_MultiWidget->GetCrossPosition(); + mitk::Point3D index; + mitk::Image::Pointer img = dynamic_cast(m_ImageNode->GetData()); + unsigned int *img_dimension = img->GetDimensions(); + img->GetTimeSlicedGeometry()->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); + OdfVectorImgType::Pointer itkQBallImage = OdfVectorImgType::New(); + + try + { + mitk::QBallImage* qball_image = dynamic_cast< mitk::QBallImage* >( m_ImageNode->GetData() ); - m_Controls->m_ODFDetailsWidget->SetParameters(odf); + // get access to the qball image data with explicitely allowing exceptions if memory locked + mitk::ImageReadAccessor readAccess( qball_image, qball_image->GetVolumeData(0), mitk::ImageAccessorBase::ExceptionIfLocked ); + const float* qball_cPtr = static_cast< const float*>(readAccess.GetData()); - switch(m_OdfNormalization) + 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 = QBALL_ODFSIZE + // position offset = standard offset + unsigned int offset_to_data = QBALL_ODFSIZE * (ind[2] * img_dimension[1] * img_dimension[0] + ind[1] * img_dimension[0] + ind[0]); + const float *pixel_data = qball_cPtr + offset_to_data; + + for (int i=0; imax) + max = val; + if (valm_ODFRenderWidget->GenerateODF(odf); - m_Controls->m_OverviewTextEdit->setText(overviewText.toStdString().c_str()); + float mean = sum/QBALL_ODFSIZE; + + QString pos = QString::number(ind[0])+", "+QString::number(ind[1])+", "+QString::number(ind[2]); + overviewText += "Coordinates: "+pos+"\n"; + overviewText += "GFA: "+QString::number(odf.GetGeneralizedFractionalAnisotropy())+"\n"; + overviewText += "Sum: "+QString::number(sum)+"\n"; + overviewText += "Mean: "+QString::number(mean)+"\n"; + overviewText += "Min: "+QString::number(min)+"\n"; + overviewText += "Max: "+QString::number(max)+"\n"; + vnl_vector_fixed 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::MemoryIsLockedException &e) + { + MITK_WARN << "LOCKED : " << e.what(); + m_Controls->m_ODFRenderWidget->setVisible(false); + m_Controls->m_OdfBox->setVisible(false); + m_Controls->m_OverviewTextEdit->setVisible(false); + } + catch( mitk::Exception &e) + { + MITK_WARN << "OTHER EXC: " << e.what(); + m_Controls->m_ODFRenderWidget->setVisible(false); + m_Controls->m_OdfBox->setVisible(false); + m_Controls->m_OverviewTextEdit->setVisible(false); + } } - catch(...) + else if (dynamic_cast(m_ImageNode->GetData())) + { + m_Controls->m_ODFRenderWidget->setVisible(true); + m_Controls->m_OdfBox->setVisible(false); + + mitk::TensorImage* qball_image = dynamic_cast< mitk::TensorImage*>(m_ImageNode->GetData()); + + // pixel access block + try + { + // get access to the qball image data with explicitely allowing exceptions if memory locked + mitk::ImageReadAccessor readAccess( qball_image, qball_image->GetVolumeData(0), mitk::ImageAccessorBase::ExceptionIfLocked ); + const float* qball_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 = qball_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 MatrixType; + 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[0][0])+"\n "+QString::number(eigenVectors[1][0])+"\n "+QString::number(eigenVectors[2][0])+"\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::MemoryIsLockedException &e) + { + MITK_WARN << "LOCKED : " << e.what(); + m_Controls->m_ODFRenderWidget->setVisible(false); + m_Controls->m_OdfBox->setVisible(false); + m_Controls->m_OverviewTextEdit->setVisible(false); + } + catch( mitk::Exception &e) + { + MITK_WARN << "OTHER EXC: " << e.what(); + m_Controls->m_ODFRenderWidget->setVisible(false); + m_Controls->m_OdfBox->setVisible(false); + m_Controls->m_OverviewTextEdit->setVisible(false); + } + } + 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() ) { - QMessageBox::critical(0, "Error", "Data could not be analyzed. The image might be corrupted."); + 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*/) { - UpdateOdf(); + UpdateOdf(); }