diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkExtractChannelFromRgbaImageFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkExtractChannelFromRgbaImageFilter.cpp index 3e03bb2de8..afc9b02bfc 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkExtractChannelFromRgbaImageFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkExtractChannelFromRgbaImageFilter.cpp @@ -1,171 +1,171 @@ /*=================================================================== 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 "itkExtractChannelFromRgbaImageFilter.h" // VTK #include #include #include // misc #include namespace itk{ template< class ReferenceImageType, class OutputImageType > ExtractChannelFromRgbaImageFilter< ReferenceImageType, OutputImageType >::ExtractChannelFromRgbaImageFilter(): m_Channel(RED) { } template< class ReferenceImageType, class OutputImageType > ExtractChannelFromRgbaImageFilter< ReferenceImageType, OutputImageType >::~ExtractChannelFromRgbaImageFilter() { } template< class ReferenceImageType, class OutputImageType > void ExtractChannelFromRgbaImageFilter< ReferenceImageType, OutputImageType >::GenerateData() { typename InputImageType::Pointer rgbaImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); typename InputImageType::RegionType region = rgbaImage->GetLargestPossibleRegion(); outputImage->SetSpacing( m_ReferenceImage->GetSpacing() ); // Set the image spacing outputImage->SetOrigin( m_ReferenceImage->GetOrigin() ); // Set the image origin outputImage->SetDirection( m_ReferenceImage->GetDirection() ); // Set the image direction outputImage->SetRegions( m_ReferenceImage->GetLargestPossibleRegion()); outputImage->Allocate(); outputImage->FillBuffer(0); float* outImageBufferPointer = outputImage->GetBufferPointer(); itk::Image< short, 3 >::Pointer counterImage = itk::Image< short, 3 >::New(); counterImage->SetSpacing( m_ReferenceImage->GetSpacing() ); // Set the image spacing counterImage->SetOrigin( m_ReferenceImage->GetOrigin() ); // Set the image origin counterImage->SetDirection( m_ReferenceImage->GetDirection() ); // Set the image direction counterImage->SetRegions( m_ReferenceImage->GetLargestPossibleRegion()); counterImage->Allocate(); counterImage->FillBuffer(0); short* counterImageBufferPointer = counterImage->GetBufferPointer(); int w = m_ReferenceImage->GetLargestPossibleRegion().GetSize().GetElement(0); int h = m_ReferenceImage->GetLargestPossibleRegion().GetSize().GetElement(1); int d = m_ReferenceImage->GetLargestPossibleRegion().GetSize().GetElement(2); typedef ImageRegionConstIterator< InputImageType > InImageIteratorType; InImageIteratorType rgbaIt(rgbaImage, region); rgbaIt.GoToBegin(); while(!rgbaIt.IsAtEnd()){ InPixelType x = rgbaIt.Get(); ++rgbaIt; itk::Point vertex; itk::Index<3> index = rgbaIt.GetIndex(); rgbaImage->TransformIndexToPhysicalPoint(index, vertex); outputImage->TransformPhysicalPointToIndex(vertex, index); itk::ContinuousIndex contIndex; outputImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); float frac_x = contIndex[0] - index[0]; float frac_y = contIndex[1] - index[1]; float frac_z = contIndex[2] - index[2]; int px = index[0]; if (frac_x<0) { px -= 1; frac_x += 1; } int py = index[1]; if (frac_y<0) { py -= 1; frac_y += 1; } int pz = index[2]; if (frac_z<0) { pz -= 1; frac_z += 1; } frac_x = 1-frac_x; frac_y = 1-frac_y; frac_z = 1-frac_z; // int coordinates inside image? if (px < 0 || px >= w-1) continue; if (py < 0 || py >= h-1) continue; if (pz < 0 || pz >= d-1) continue; - OutPixelType out; + OutPixelType out = 0.0f; switch (m_Channel) { case RED: out = (float)x.GetRed()/255; break; case GREEN: out = (float)x.GetGreen()/255; break; case BLUE: out = (float)x.GetBlue()/255; break; case ALPHA: out = (float)x.GetAlpha()/255; } outImageBufferPointer[( px + w*(py + h*pz ))] += out*( frac_x)*( frac_y)*( frac_z); outImageBufferPointer[( px + w*(py+1+ h*pz ))] += out*( frac_x)*(1-frac_y)*( frac_z); outImageBufferPointer[( px + w*(py + h*pz+h))] += out*( frac_x)*( frac_y)*(1-frac_z); outImageBufferPointer[( px + w*(py+1+ h*pz+h))] += out*( frac_x)*(1-frac_y)*(1-frac_z); outImageBufferPointer[( px+1 + w*(py + h*pz ))] += out*(1-frac_x)*( frac_y)*( frac_z); outImageBufferPointer[( px+1 + w*(py + h*pz+h))] += out*(1-frac_x)*( frac_y)*(1-frac_z); outImageBufferPointer[( px+1 + w*(py+1+ h*pz ))] += out*(1-frac_x)*(1-frac_y)*( frac_z); outImageBufferPointer[( px+1 + w*(py+1+ h*pz+h))] += out*(1-frac_x)*(1-frac_y)*(1-frac_z); counterImageBufferPointer[( px + w*(py + h*pz ))] += 1; counterImageBufferPointer[( px + w*(py+1+ h*pz ))] += 1; counterImageBufferPointer[( px + w*(py + h*pz+h))] += 1; counterImageBufferPointer[( px + w*(py+1+ h*pz+h))] += 1; counterImageBufferPointer[( px+1 + w*(py + h*pz ))] += 1; counterImageBufferPointer[( px+1 + w*(py + h*pz+h))] += 1; counterImageBufferPointer[( px+1 + w*(py+1+ h*pz ))] += 1; counterImageBufferPointer[( px+1 + w*(py+1+ h*pz+h))] += 1; } typedef ImageRegionIterator< OutputImageType > OutImageIteratorType; OutImageIteratorType outIt(outputImage, outputImage->GetLargestPossibleRegion()); outIt.GoToBegin(); typedef ImageRegionConstIterator< itk::Image< short, 3 > > CountImageIteratorType; CountImageIteratorType counterIt(counterImage, counterImage->GetLargestPossibleRegion()); counterIt.GoToBegin(); while(!outIt.IsAtEnd() && !counterIt.IsAtEnd()){ if (counterIt.Value()>0) outIt.Set(outIt.Value()/counterIt.Value()); ++outIt; ++counterIt; } } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp index c32bba8afe..41876e35d8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp @@ -1,2161 +1,2145 @@ /*=================================================================== 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 "QmitkPartialVolumeAnalysisView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "QmitkSliderNavigatorWidget.h" #include #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" #include "mitkImageTimeSelector.h" #include "mitkProperties.h" #include "mitkProgressBar.h" #include "mitkImageCast.h" #include "mitkImageToItk.h" #include "mitkITKImageImport.h" #include "mitkDataNodeObject.h" #include "mitkNodePredicateData.h" #include "mitkPlanarFigureInteractor.h" #include "mitkTensorImage.h" #include "mitkPlanarCircle.h" #include "mitkPlanarRectangle.h" #include "mitkPlanarPolygon.h" #include "mitkPartialVolumeAnalysisClusteringCalculator.h" #include "usModuleRegistry.h" #include #include "itkTensorDerivedMeasurementsFilter.h" #include "itkDiffusionTensor3D.h" #include "itkCartesianToPolarVectorImageFilter.h" #include "itkPolarToCartesianVectorImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkMaskImageFilter.h" #include "itkCastImageFilter.h" #include "itkImageMomentsCalculator.h" #include #include #include #include #include #define _USE_MATH_DEFINES #include #define PVA_PI M_PI const std::string QmitkPartialVolumeAnalysisView::VIEW_ID = "org.mitk.views.partialvolumeanalysisview"; class QmitkRequestStatisticsUpdateEvent : public QEvent { public: enum Type { StatisticsUpdateRequest = QEvent::MaxUser - 1025 }; QmitkRequestStatisticsUpdateEvent() : QEvent( (QEvent::Type) StatisticsUpdateRequest ) {}; }; typedef itk::Image ImageType; typedef itk::Image FloatImageType; typedef itk::Image, 3> VectorImageType; inline bool my_isnan(float x) { volatile float d = x; if(d!=d) return true; if(d==d) return false; return d != d; } QmitkPartialVolumeAnalysisView::QmitkPartialVolumeAnalysisView(QObject * /*parent*/, const char * /*name*/) : QmitkAbstractView(), - m_Controls( nullptr ), - m_TimeStepperAdapter( nullptr ), - m_MeasurementInfoRenderer(0), - m_MeasurementInfoAnnotation(0), - m_SelectedImageNodes( ), - m_SelectedImage( nullptr ), - m_SelectedMaskNode( nullptr ), - m_SelectedImageMask( nullptr ), - m_SelectedPlanarFigureNodes(0), - m_SelectedPlanarFigure( nullptr ), + m_Controls(nullptr), + m_TimeStepperAdapter(nullptr), + m_MeasurementInfoRenderer(nullptr), + m_MeasurementInfoAnnotation(nullptr), m_IsTensorImage(false), - m_FAImage(0), - m_RDImage(0), - m_ADImage(0), - m_MDImage(0), - m_CAImage(0), - // m_DirectionImage(0), - m_DirectionComp1Image(0), - m_DirectionComp2Image(0), - m_AngularErrorImage(0), m_SelectedRenderWindow(nullptr), m_LastRenderWindow(nullptr), - m_ImageObserverTag( -1 ), - m_ImageMaskObserverTag( -1 ), - m_PlanarFigureObserverTag( -1 ), - m_CurrentStatisticsValid( false ), - m_StatisticsUpdatePending( false ), + m_ImageObserverTag(-1), + m_ImageMaskObserverTag(-1), + m_PlanarFigureObserverTag(-1), + m_CurrentStatisticsValid(false), + m_StatisticsUpdatePending(false), m_GaussianSigmaChangedSliding(false), m_NumberBinsSliding(false), m_UpsamplingChangedSliding(false), - m_ClusteringResult(nullptr), m_EllipseCounter(0), m_RectangleCounter(0), m_PolygonCounter(0), m_CurrentFigureNodeInitialized(false), m_QuantifyClass(2), m_IconTexOFF(new QIcon(":/QmitkPartialVolumeAnalysisView/texIntOFFIcon.png")), m_IconTexON(new QIcon(":/QmitkPartialVolumeAnalysisView/texIntONIcon.png")), m_TexIsOn(true), m_Visible(false) { } QmitkPartialVolumeAnalysisView::~QmitkPartialVolumeAnalysisView() { if ( m_SelectedImage.IsNotNull() ) m_SelectedImage->RemoveObserver( m_ImageObserverTag ); if ( m_SelectedImageMask.IsNotNull() ) m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); if ( m_SelectedPlanarFigure.IsNotNull() ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); } this->GetDataStorage()->AddNodeEvent -= mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage ); m_SelectedPlanarFigureNodes->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedPlanarFigureNodes->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedPlanarFigureNodes->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedImageNodes->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedImageNodes->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); } void QmitkPartialVolumeAnalysisView::CreateQtPartControl(QWidget *parent) { if (m_Controls == nullptr) { m_Controls = new Ui::QmitkPartialVolumeAnalysisViewControls; m_Controls->setupUi(parent); this->CreateConnections(); } SetHistogramVisibility(); m_Controls->m_TextureIntON->setIcon(*m_IconTexON); m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); vtkTextProperty *textProp = vtkTextProperty::New(); textProp->SetColor(1.0, 1.0, 1.0); m_MeasurementInfoAnnotation = vtkCornerAnnotation::New(); m_MeasurementInfoAnnotation->SetMaximumFontSize(12); m_MeasurementInfoAnnotation->SetTextProperty(textProp); m_MeasurementInfoRenderer = vtkRenderer::New(); m_MeasurementInfoRenderer->AddActor(m_MeasurementInfoAnnotation); m_SelectedPlanarFigureNodes = mitk::DataStorageSelection::New(this->GetDataStorage(), false); m_SelectedPlanarFigureNodes->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedPlanarFigureNodes->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedPlanarFigureNodes->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes = mitk::DataStorageSelection::New(this->GetDataStorage(), false); m_SelectedImageNodes->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedImageNodes->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); this->GetDataStorage()->AddNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage ) ); Select(nullptr,true,true); SetAdvancedVisibility(); } void QmitkPartialVolumeAnalysisView::SetFocus() { m_Controls->m_CircleButton->setFocus(); } void QmitkPartialVolumeAnalysisView::SetHistogramVisibility() { m_Controls->m_HistogramWidget->setVisible(m_Controls->m_DisplayHistogramCheckbox->isChecked()); } void QmitkPartialVolumeAnalysisView::SetAdvancedVisibility() { m_Controls->frame_7->setVisible(m_Controls->m_AdvancedCheckbox->isChecked()); } void QmitkPartialVolumeAnalysisView::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_DisplayHistogramCheckbox, SIGNAL( clicked() ) , this, SLOT( SetHistogramVisibility() ) ); connect( m_Controls->m_AdvancedCheckbox, SIGNAL( clicked() ) , this, SLOT( SetAdvancedVisibility() ) ); connect( m_Controls->m_NumberBinsSlider, SIGNAL( sliderReleased () ), this, SLOT( NumberBinsReleasedSlider( ) ) ); connect( m_Controls->m_UpsamplingSlider, SIGNAL( sliderReleased( ) ), this, SLOT( UpsamplingReleasedSlider( ) ) ); connect( m_Controls->m_GaussianSigmaSlider, SIGNAL( sliderReleased( ) ), this, SLOT( GaussianSigmaReleasedSlider( ) ) ); connect( m_Controls->m_SimilarAnglesSlider, SIGNAL( sliderReleased( ) ), this, SLOT( SimilarAnglesReleasedSlider( ) ) ); connect( m_Controls->m_NumberBinsSlider, SIGNAL( valueChanged (int) ), this, SLOT( NumberBinsChangedSlider( int ) ) ); connect( m_Controls->m_UpsamplingSlider, SIGNAL( valueChanged( int ) ), this, SLOT( UpsamplingChangedSlider( int ) ) ); connect( m_Controls->m_GaussianSigmaSlider, SIGNAL( valueChanged( int ) ), this, SLOT( GaussianSigmaChangedSlider( int ) ) ); connect( m_Controls->m_SimilarAnglesSlider, SIGNAL( valueChanged( int ) ), this, SLOT( SimilarAnglesChangedSlider(int) ) ); connect( m_Controls->m_OpacitySlider, SIGNAL( valueChanged( int ) ), this, SLOT( OpacityChangedSlider(int) ) ); connect( (QObject*)(m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(ToClipBoard())); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawEllipseTriggered() ) ); connect( m_Controls->m_RectangleButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawRectangleTriggered() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawPolygonTriggered() ) ); connect( m_Controls->m_GreenRadio, SIGNAL( clicked(bool) ) , this, SLOT( GreenRadio(bool) ) ); connect( m_Controls->m_PartialVolumeRadio, SIGNAL( clicked(bool) ) , this, SLOT( PartialVolumeRadio(bool) ) ); connect( m_Controls->m_BlueRadio, SIGNAL( clicked(bool) ) , this, SLOT( BlueRadio(bool) ) ); connect( m_Controls->m_AllRadio, SIGNAL( clicked(bool) ) , this, SLOT( AllRadio(bool) ) ); connect( m_Controls->m_EstimateCircle, SIGNAL( clicked() ) , this, SLOT( EstimateCircle() ) ); connect( (QObject*)(m_Controls->m_TextureIntON), SIGNAL(clicked()), this, SLOT(TextIntON()) ); connect( m_Controls->m_ExportClusteringResultsButton, SIGNAL(clicked()), this, SLOT(ExportClusteringResults())); } } void QmitkPartialVolumeAnalysisView::ExportClusteringResults() { if (m_ClusteringResult.IsNull() || m_SelectedImage.IsNull()) return; mitk::BaseGeometry* geometry = m_SelectedImage->GetGeometry(); itk::Image< short, 3>::Pointer referenceImage = itk::Image< short, 3>::New(); itk::Vector newSpacing = geometry->GetSpacing(); mitk::Point3D newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); newOrigin[0] += bounds.GetElement(0); newOrigin[1] += bounds.GetElement(2); newOrigin[2] += bounds.GetElement(4); itk::Matrix newDirection; itk::ImageRegion<3> imageRegion; for (int i=0; i<3; i++) for (int j=0; j<3; j++) newDirection[j][i] = geometry->GetMatrixColumn(i)[j]/newSpacing[j]; imageRegion.SetSize(0, geometry->GetExtent(0)); imageRegion.SetSize(1, geometry->GetExtent(1)); imageRegion.SetSize(2, geometry->GetExtent(2)); // apply new image parameters referenceImage->SetSpacing( newSpacing ); referenceImage->SetOrigin( newOrigin ); referenceImage->SetDirection( newDirection ); referenceImage->SetRegions( imageRegion ); referenceImage->Allocate(); typedef itk::Image< float, 3 > OutType; mitk::Image::Pointer mitkInImage = dynamic_cast(m_ClusteringResult->GetData()); typedef itk::Image< itk::RGBAPixel, 3 > ItkRgbaImageType; typedef mitk::ImageToItk< ItkRgbaImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkInImage); caster->Update(); ItkRgbaImageType::Pointer itkInImage = caster->GetOutput(); typedef itk::ExtractChannelFromRgbaImageFilter< itk::Image< short, 3>, OutType > ExtractionFilterType; ExtractionFilterType::Pointer filter = ExtractionFilterType::New(); filter->SetInput(itkInImage); filter->SetChannel(ExtractionFilterType::ALPHA); filter->SetReferenceImage(referenceImage); filter->Update(); OutType::Pointer outImg = filter->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); node->SetName("Clustering Result"); GetDataStorage()->Add(node); } void QmitkPartialVolumeAnalysisView::EstimateCircle() { typedef itk::Image SegImageType; SegImageType::Pointer mask_itk = SegImageType::New(); typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(m_SelectedImageMask); caster->Update(); typedef itk::ImageMomentsCalculator< SegImageType > MomentsType; MomentsType::Pointer momentsCalc = MomentsType::New(); momentsCalc->SetImage(caster->GetOutput()); momentsCalc->Compute(); MomentsType::VectorType cog = momentsCalc->GetCenterOfGravity(); MomentsType::MatrixType axes = momentsCalc->GetPrincipalAxes(); MomentsType::VectorType moments = momentsCalc->GetPrincipalMoments(); // moments-coord conversion // third coordinate min oder max? // max-min = extent MomentsType::AffineTransformPointer trafo = momentsCalc->GetPhysicalAxesToPrincipalAxesTransform(); itk::ImageRegionIterator itimage(caster->GetOutput(), caster->GetOutput()->GetLargestPossibleRegion()); - itimage = itimage.Begin(); + itimage.GoToBegin(); double max = -9999999999.0; double min = 9999999999.0; while( !itimage.IsAtEnd() ) { if(itimage.Get()) { ImageType::IndexType index = itimage.GetIndex(); itk::Point point; caster->GetOutput()->TransformIndexToPhysicalPoint(index,point); itk::Point newPoint; newPoint = trafo->TransformPoint(point); if(newPoint[2]max) max = newPoint[2]; } ++itimage; } double extent = max - min; MITK_DEBUG << "EXTENT = " << extent; mitk::Point3D origin; mitk::Vector3D right, bottom, normal; double factor = 1000.0; mitk::FillVector3D(origin, cog[0]-factor*axes[1][0]-factor*axes[2][0], cog[1]-factor*axes[1][1]-factor*axes[2][1], cog[2]-factor*axes[1][2]-factor*axes[2][2]); // mitk::FillVector3D(normal, axis[0][0],axis[0][1],axis[0][2]); mitk::FillVector3D(bottom, 2*factor*axes[1][0], 2*factor*axes[1][1], 2*factor*axes[1][2]); mitk::FillVector3D(right, 2*factor*axes[2][0], 2*factor*axes[2][1], 2*factor*axes[2][2]); mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); - planegeometry->InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector()); + planegeometry->InitializeStandardPlane(right.GetVnlVector(), bottom.GetVnlVector()); planegeometry->SetOrigin(origin); double len1 = sqrt(axes[1][0]*axes[1][0] + axes[1][1]*axes[1][1] + axes[1][2]*axes[1][2]); double len2 = sqrt(axes[2][0]*axes[2][0] + axes[2][1]*axes[2][1] + axes[2][2]*axes[2][2]); mitk::Point2D point1; point1[0] = factor*len1; point1[1] = factor*len2; mitk::Point2D point2; point2[0] = factor*len1+extent*.5; point2[1] = factor*len2; mitk::PlanarCircle::Pointer circle = mitk::PlanarCircle::New(); circle->SetPlaneGeometry(planegeometry); circle->PlaceFigure( point1 ); circle->SetControlPoint(0,point1); circle->SetControlPoint(1,point2); //circle->SetCurrentControlPoint( point2 ); mitk::PlanarFigure::PolyLineType polyline = circle->GetPolyLine( 0 ); MITK_DEBUG << "SIZE of planar figure polyline: " << polyline.size(); AddFigureToDataStorage(circle, "Circle"); } bool QmitkPartialVolumeAnalysisView::AssertDrawingIsPossible(bool checked) { if (m_SelectedImageNodes->GetNode().IsNull()) { checked = false; this->HandleException("Please select an image!", dynamic_cast(this->parent()), true); return false; } //this->GetRenderWindowPart(OPEN)->EnableSlicingPlanes(false); return checked; } void QmitkPartialVolumeAnalysisView::ActionDrawEllipseTriggered() { bool checked = m_Controls->m_CircleButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); // using PV_ prefix for planar figures from this view // to distinguish them from that ones created throught the measurement view this->AddFigureToDataStorage(figure, QString("PV_Circle%1").arg(++m_EllipseCounter)); MITK_DEBUG << "PlanarCircle created ..."; } void QmitkPartialVolumeAnalysisView::ActionDrawRectangleTriggered() { bool checked = m_Controls->m_RectangleButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarRectangle::Pointer figure = mitk::PlanarRectangle::New(); // using PV_ prefix for planar figures from this view // to distinguish them from that ones created throught the measurement view this->AddFigureToDataStorage(figure, QString("PV_Rectangle%1").arg(++m_RectangleCounter)); MITK_DEBUG << "PlanarRectangle created ..."; } void QmitkPartialVolumeAnalysisView::ActionDrawPolygonTriggered() { bool checked = m_Controls->m_PolygonButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); // using PV_ prefix for planar figures from this view // to distinguish them from that ones created throught the measurement view this->AddFigureToDataStorage(figure, QString("PV_Polygon%1").arg(++m_PolygonCounter)); MITK_DEBUG << "PlanarPolygon created ..."; } void QmitkPartialVolumeAnalysisView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey, mitk::BaseProperty *property ) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); // Add custom property, if available if ( (propertyKey != nullptr) && (property != nullptr) ) { newNode->AddProperty( propertyKey, property ); } // figure drawn on the topmost layer / image this->GetDataStorage()->Add(newNode, m_SelectedImageNodes->GetNode() ); QList selectedNodes = this->GetDataManagerSelection(); - for(unsigned int i = 0; i < selectedNodes.size(); i++) + for(int i = 0; i < selectedNodes.size(); ++i) { selectedNodes[i]->SetSelected(false); } std::vector selectedPFNodes = m_SelectedPlanarFigureNodes->GetNodes(); - for(unsigned int i = 0; i < selectedPFNodes.size(); i++) + for(std::size_t i = 0; i < selectedPFNodes.size(); ++i) { selectedPFNodes[i]->SetSelected(false); } newNode->SetSelected(true); Select(newNode); } void QmitkPartialVolumeAnalysisView::PlanarFigureInitialized() { if(m_SelectedPlanarFigureNodes->GetNode().IsNull()) return; m_CurrentFigureNodeInitialized = true; this->Select(m_SelectedPlanarFigureNodes->GetNode()); m_Controls->m_CircleButton->setChecked(false); m_Controls->m_RectangleButton->setChecked(false); m_Controls->m_PolygonButton->setChecked(false); //this->GetRenderWindowPart(OPEN)->EnableSlicingPlanes(true); this->RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::PlanarFigureFocus(mitk::DataNode* node) { mitk::PlanarFigure* _PlanarFigure = 0; _PlanarFigure = dynamic_cast (node->GetData()); if (_PlanarFigure) { FindRenderWindow(node); const mitk::PlaneGeometry* _PlaneGeometry = _PlanarFigure->GetPlaneGeometry(); // make node visible if (m_SelectedRenderWindow) { mitk::Point3D centerP = _PlaneGeometry->GetOrigin(); m_SelectedRenderWindow->GetSliceNavigationController()->ReorientSlices( centerP, _PlaneGeometry->GetNormal()); m_SelectedRenderWindow->GetSliceNavigationController()->SelectSliceByPoint( centerP); } } } void QmitkPartialVolumeAnalysisView::FindRenderWindow(mitk::DataNode* node) { if (node && dynamic_cast (node->GetData())) { m_SelectedRenderWindow = 0; bool PlanarFigureInitializedWindow = false; foreach(QmitkRenderWindow * window, this->GetRenderWindowPart()->GetQmitkRenderWindows().values()) { if (!m_SelectedRenderWindow && node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, window->GetRenderer())) { m_SelectedRenderWindow = window; } } } } -void QmitkPartialVolumeAnalysisView::OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) +void QmitkPartialVolumeAnalysisView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList &nodes) { m_Controls->m_InputData->setTitle("Please Select Input Data"); if (!m_Visible) return; if ( nodes.empty() ) { if (m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } Select(nullptr, true, true); } for (int i=0; iRemoveOrphanImages(); bool somethingChanged = false; if(node.IsNull()) { somethingChanged = true; if(clearMaskOnFirstArgnullptr) { if ( (m_SelectedImageMask.IsNotNull()) && (m_ImageMaskObserverTag >= 0) ) { m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); m_ImageMaskObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_PlanarFigureObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_PlanarFigureObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_InitializedObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); m_InitializedObserverTag = -1; } m_SelectedPlanarFigure = nullptr; m_SelectedPlanarFigureNodes->RemoveAllNodes(); m_CurrentFigureNodeInitialized = false; m_SelectedRenderWindow = 0; m_SelectedMaskNode = nullptr; m_SelectedImageMask = nullptr; } if(clearImageOnFirstArgnullptr) { if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } m_SelectedImageNodes->RemoveAllNodes(); m_SelectedImage = nullptr; m_IsTensorImage = false; m_FAImage = nullptr; m_RDImage = nullptr; m_ADImage = nullptr; m_MDImage = nullptr; m_CAImage = nullptr; m_DirectionComp1Image = nullptr; m_DirectionComp2Image = nullptr; m_AngularErrorImage = nullptr; m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); } } else { typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer changeListener; changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::RequestStatisticsUpdate ); // Get selected element mitk::TensorImage *selectedTensorImage = dynamic_cast< mitk::TensorImage * >( node->GetData() ); mitk::Image *selectedImage = dynamic_cast< mitk::Image * >( node->GetData() ); mitk::PlanarFigure *selectedPlanar = dynamic_cast< mitk::PlanarFigure * >( node->GetData() ); bool isMask = false; bool isImage = false; bool isPlanar = false; bool isTensorImage = false; if (selectedTensorImage != nullptr) { isTensorImage = true; } else if(selectedImage != nullptr) { node->GetPropertyValue("binary", isMask); isImage = !isMask; } else if ( (selectedPlanar != nullptr) ) { isPlanar = true; } // image if(isImage && selectedImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } *m_SelectedImageNodes = node; m_SelectedImage = selectedImage; m_IsTensorImage = false; m_FAImage = nullptr; m_RDImage = nullptr; m_ADImage = nullptr; m_MDImage = nullptr; m_CAImage = nullptr; m_DirectionComp1Image = nullptr; m_DirectionComp2Image = nullptr; m_AngularErrorImage = nullptr; // Add change listeners to selected objects m_ImageObserverTag = m_SelectedImage->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); m_Controls->m_SelectedImageLabel->setText( m_SelectedImageNodes->GetNode()->GetName().c_str() ); } } //planar if(isPlanar) { if(selectedPlanar != m_SelectedPlanarFigure.GetPointer()) { MITK_DEBUG << "Planar selection changed"; somethingChanged = true; // Possibly previous change listeners if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_PlanarFigureObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_PlanarFigureObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_InitializedObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); m_InitializedObserverTag = -1; } m_SelectedPlanarFigure = selectedPlanar; *m_SelectedPlanarFigureNodes = node; m_CurrentFigureNodeInitialized = selectedPlanar->IsPlaced(); m_SelectedMaskNode = nullptr; m_SelectedImageMask = nullptr; m_PlanarFigureObserverTag = m_SelectedPlanarFigure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), changeListener ); if(!m_CurrentFigureNodeInitialized) { typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer initializationCommand; initializationCommand = ITKCommandType::New(); // set the callback function of the member command initializationCommand->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::PlanarFigureInitialized ); // add an observer m_InitializedObserverTag = selectedPlanar->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); } m_Controls->m_SelectedMaskLabel->setText( m_SelectedPlanarFigureNodes->GetNode()->GetName().c_str() ); PlanarFigureFocus(node); } } //mask this->m_Controls->m_EstimateCircle->setEnabled(isMask && selectedImage->GetDimension()==3); if(isMask && selectedImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImageMask.IsNotNull()) && (m_ImageMaskObserverTag >= 0) ) { m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); m_ImageMaskObserverTag = -1; } m_SelectedMaskNode = node; m_SelectedImageMask = selectedImage; m_SelectedPlanarFigure = nullptr; m_SelectedPlanarFigureNodes->RemoveAllNodes(); m_ImageMaskObserverTag = m_SelectedImageMask->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SelectedMaskLabel->setText( m_SelectedMaskNode->GetName().c_str() ); } } //tensor image if(isTensorImage && selectedTensorImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } *m_SelectedImageNodes = node; m_SelectedImage = selectedImage; m_IsTensorImage = true; ExtractTensorImages(selectedImage); // Add change listeners to selected objects m_ImageObserverTag = m_SelectedImage->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SimilarAnglesFrame->setVisible(true); m_Controls->m_SimilarAnglesLabel->setVisible(true); m_Controls->m_SelectedImageLabel->setText( m_SelectedImageNodes->GetNode()->GetName().c_str() ); } } } if(somethingChanged) { this->SetMeasurementInfoToRenderWindow(""); if(m_SelectedPlanarFigure.IsNull() && m_SelectedImageMask.IsNull() ) { m_Controls->m_SelectedMaskLabel->setText("mandatory"); m_Controls->m_ResampleOptionsFrame->setEnabled(false); m_Controls->m_HistogramWidget->setEnabled(false); m_Controls->m_ClassSelector->setEnabled(false); m_Controls->m_DisplayHistogramCheckbox->setEnabled(false); m_Controls->m_AdvancedCheckbox->setEnabled(false); m_Controls->frame_7->setEnabled(false); } else { m_Controls->m_ResampleOptionsFrame->setEnabled(true); m_Controls->m_HistogramWidget->setEnabled(true); m_Controls->m_ClassSelector->setEnabled(true); m_Controls->m_DisplayHistogramCheckbox->setEnabled(true); m_Controls->m_AdvancedCheckbox->setEnabled(true); m_Controls->frame_7->setEnabled(true); } // Clear statistics / histogram GUI if nothing is selected if ( m_SelectedImage.IsNull() ) { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_OpacityFrame->setEnabled(false); m_Controls->m_SelectedImageLabel->setText("mandatory"); } else { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); m_Controls->m_OpacityFrame->setEnabled(true); } if( !m_Visible || m_SelectedImage.IsNull() || (m_SelectedPlanarFigure.IsNull() && m_SelectedImageMask.IsNull()) ) { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; } else { m_Controls->m_InputData->setTitle("Input Data"); this->RequestStatisticsUpdate(); } } } void QmitkPartialVolumeAnalysisView::ShowClusteringResults() { typedef itk::Image MaskImageType; mitk::Image::Pointer mask = 0; MaskImageType::Pointer itkmask = 0; if(m_IsTensorImage && m_Controls->m_SimilarAnglesSlider->value() != 0) { typedef itk::Image AngularErrorImageType; typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(m_AngularErrorImage); caster->Update(); typedef itk::BinaryThresholdImageFilter< AngularErrorImageType, MaskImageType > ThreshType; ThreshType::Pointer thresh = ThreshType::New(); thresh->SetUpperThreshold((90-m_Controls->m_SimilarAnglesSlider->value())*(PVA_PI/180.0)); thresh->SetInsideValue(1.0); thresh->SetInput(caster->GetOutput()); thresh->Update(); itkmask = thresh->GetOutput(); mask = mitk::Image::New(); mask->InitializeByItk(itkmask.GetPointer()); mask->SetVolume(itkmask->GetBufferPointer()); // GetDataStorage()->Remove(m_newnode); // m_newnode = mitk::DataNode::New(); // m_newnode->SetData(mask); // m_newnode->SetName("masking node"); // m_newnode->SetIntProperty( "layer", 1002 ); // GetDataStorage()->Add(m_newnode, m_SelectedImageNodes->GetNode()); } mitk::Image::Pointer clusteredImage; ClusteringType::Pointer clusterer = ClusteringType::New(); if(m_QuantifyClass==3) { if(m_IsTensorImage) { double *green_fa, *green_rd, *green_ad, *green_md; //double *greengray_fa, *greengray_rd, *greengray_ad, *greengray_md; double *gray_fa, *gray_rd, *gray_ad, *gray_md; //double *redgray_fa, *redgray_rd, *redgray_ad, *redgray_md; double *red_fa, *red_rd, *red_ad, *red_md; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(0); mitk::Image::ConstPointer imgToCluster = tmpImg; red_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(3); mitk::Image::ConstPointer imgToCluster3 = tmpImg; red_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(4); mitk::Image::ConstPointer imgToCluster4 = tmpImg; red_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(5); mitk::Image::ConstPointer imgToCluster5 = tmpImg; red_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->b, mask); // clipboard QString clipboardText("FA\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText = clipboardText .arg(red_fa[0]).arg(red_fa[1]) .arg(gray_fa[0]).arg(gray_fa[1]) .arg(green_fa[0]).arg(green_fa[1]); QString clipboardText3("RD\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText3 = clipboardText3 .arg(red_rd[0]).arg(red_rd[1]) .arg(gray_rd[0]).arg(gray_rd[1]) .arg(green_rd[0]).arg(green_rd[1]); QString clipboardText4("AD\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText4 = clipboardText4 .arg(red_ad[0]).arg(red_ad[1]) .arg(gray_ad[0]).arg(gray_ad[1]) .arg(green_ad[0]).arg(green_ad[1]); QString clipboardText5("MD\t%1\t%2\t\t%3\t%4\t\t%5\t%6"); clipboardText5 = clipboardText5 .arg(red_md[0]).arg(red_md[1]) .arg(gray_md[0]).arg(gray_md[1]) .arg(green_md[0]).arg(green_md[1]); QApplication::clipboard()->setText(clipboardText+clipboardText3+clipboardText4+clipboardText5, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("%1 %2 %3 \n"); plainInfoText = plainInfoText .arg("Red ", 20) .arg("Gray ", 20) .arg("Green", 20); QString plainInfoText0("FA:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText0 = plainInfoText0 .arg(red_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(red_fa[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(gray_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(gray_fa[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(green_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(green_fa[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText3("RDx10³:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText3 = plainInfoText3 .arg(1000.0 * red_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_rd[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_rd[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_rd[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText4("ADx10³:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText4 = plainInfoText4 .arg(1000.0 * red_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_ad[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_ad[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_ad[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText5("MDx10³:%1 ± %2%3 ± %4%5 ± %6"); plainInfoText5 = plainInfoText5 .arg(1000.0 * red_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_md[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_md[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_md[1], -10, 'g', 2, QLatin1Char( ' ' )); this->SetMeasurementInfoToRenderWindow(plainInfoText+plainInfoText0+plainInfoText3+plainInfoText4+plainInfoText5); } else { double* green; double* gray; double* red; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; red = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->r); green = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->g); gray = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->b); // clipboard QString clipboardText("%1\t%2\t\t%3\t%4\t\t%5\t%6"); clipboardText = clipboardText.arg(red[0]).arg(red[1]) .arg(gray[0]).arg(gray[1]) .arg(green[0]).arg(green[1]); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("Red: %1 ± %2\nGray: %3 ± %4\nGreen: %5 ± %6"); plainInfoText = plainInfoText.arg(red[0]).arg(red[1]) .arg(gray[0]).arg(gray[1]) .arg(green[0]).arg(green[1]); this->SetMeasurementInfoToRenderWindow(plainInfoText); } clusteredImage = m_CurrentRGBClusteringResults->rgb; } else { if(m_IsTensorImage) { double *red_fa, *red_rd, *red_ad, *red_md; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(0); mitk::Image::ConstPointer imgToCluster = tmpImg; red_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(3); mitk::Image::ConstPointer imgToCluster3 = tmpImg; red_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(4); mitk::Image::ConstPointer imgToCluster4 = tmpImg; red_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(5); mitk::Image::ConstPointer imgToCluster5 = tmpImg; red_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentPerformClusteringResults->clusteredImage, mask); // clipboard QString clipboardText("FA\t%1\t%2\t"); clipboardText = clipboardText .arg(red_fa[0]).arg(red_fa[1]); QString clipboardText3("RD\t%1\t%2\t"); clipboardText3 = clipboardText3 .arg(red_rd[0]).arg(red_rd[1]); QString clipboardText4("AD\t%1\t%2\t"); clipboardText4 = clipboardText4 .arg(red_ad[0]).arg(red_ad[1]); QString clipboardText5("MD\t%1\t%2\t"); clipboardText5 = clipboardText5 .arg(red_md[0]).arg(red_md[1]); QApplication::clipboard()->setText(clipboardText+clipboardText3+clipboardText4+clipboardText5, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("%1 \n"); plainInfoText = plainInfoText .arg("Red ", 20); QString plainInfoText0("FA:%1 ± %2\n"); plainInfoText0 = plainInfoText0 .arg(red_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(red_fa[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText3("RDx10³:%1 ± %2\n"); plainInfoText3 = plainInfoText3 .arg(1000.0 * red_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_rd[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText4("ADx10³:%1 ± %2\n"); plainInfoText4 = plainInfoText4 .arg(1000.0 * red_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_ad[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText5("MDx10³:%1 ± %2"); plainInfoText5 = plainInfoText5 .arg(1000.0 * red_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_md[1], -10, 'g', 2, QLatin1Char( ' ' )); this->SetMeasurementInfoToRenderWindow(plainInfoText+plainInfoText0+plainInfoText3+plainInfoText4+plainInfoText5); } else { double* quant; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; quant = clusterer->PerformQuantification(imgToCluster, m_CurrentPerformClusteringResults->clusteredImage); // clipboard QString clipboardText("%1\t%2"); clipboardText = clipboardText.arg(quant[0]).arg(quant[1]); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("Measurement: %1 ± %2"); plainInfoText = plainInfoText.arg(quant[0]).arg(quant[1]); this->SetMeasurementInfoToRenderWindow(plainInfoText); } clusteredImage = m_CurrentPerformClusteringResults->displayImage; } if(mask.IsNotNull()) { typedef itk::Image,3> RGBImageType; typedef mitk::ImageToItk ClusterCasterType; ClusterCasterType::Pointer clCaster = ClusterCasterType::New(); clCaster->SetInput(clusteredImage); clCaster->Update(); clCaster->GetOutput(); typedef itk::MaskImageFilter< RGBImageType, MaskImageType, RGBImageType > MaskType; MaskType::Pointer masker = MaskType::New(); masker->SetInput1(clCaster->GetOutput()); masker->SetInput2(itkmask); masker->Update(); clusteredImage = mitk::Image::New(); clusteredImage->InitializeByItk(masker->GetOutput()); clusteredImage->SetVolume(masker->GetOutput()->GetBufferPointer()); } if(m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); } m_ClusteringResult = mitk::DataNode::New(); m_ClusteringResult->SetBoolProperty("helper object", true); m_ClusteringResult->SetIntProperty( "layer", 1000 ); m_ClusteringResult->SetBoolProperty("texture interpolation", m_TexIsOn); m_ClusteringResult->SetData(clusteredImage); m_ClusteringResult->SetName("Clusterprobs"); this->GetDataStorage()->Add(m_ClusteringResult, m_SelectedImageNodes->GetNode()); if(m_SelectedPlanarFigure.IsNotNull() && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { m_SelectedPlanarFigureNodes->GetNode()->SetIntProperty( "layer", 1001 ); } this->RequestRenderWindowUpdate(); } void QmitkPartialVolumeAnalysisView::UpdateStatistics() { if(!m_CurrentFigureNodeInitialized && m_SelectedPlanarFigure.IsNotNull()) { MITK_DEBUG << "Selected planar figure not initialized. No stats calculation performed."; return; } // Remove any cached images that are no longer referenced elsewhere this->RemoveOrphanImages(); if ( m_SelectedImage.IsNotNull() ) { // Check if a the selected image is a multi-channel image. If yes, statistics // cannot be calculated currently. if ( !m_IsTensorImage && m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 ) { QMessageBox::information( nullptr, "Warning", "Non-tensor multi-component images not supported."); m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; return; } m_CurrentStatisticsCalculator = nullptr; if(!m_IsTensorImage) { // Retrieve HistogramStatisticsCalculator from has map (or create a new one // for this image if non-existant) PartialVolumeAnalysisMapType::iterator it = m_PartialVolumeAnalysisMap.find( m_SelectedImage ); if ( it != m_PartialVolumeAnalysisMap.end() ) { m_CurrentStatisticsCalculator = it->second; } } if(m_CurrentStatisticsCalculator.IsNull()) { m_CurrentStatisticsCalculator = mitk::PartialVolumeAnalysisHistogramCalculator::New(); m_CurrentStatisticsCalculator->SetPlanarFigureThickness(m_Controls->m_PlanarFiguresThickness->value()); if(m_IsTensorImage) { m_CurrentStatisticsCalculator->SetImage( m_CAImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_FAImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_DirectionComp1Image ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_DirectionComp2Image ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_RDImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_ADImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_MDImage ); } else { m_CurrentStatisticsCalculator->SetImage( m_SelectedImage ); } m_PartialVolumeAnalysisMap[m_SelectedImage] = m_CurrentStatisticsCalculator; MITK_DEBUG << "Creating StatisticsCalculator"; } std::string maskName; std::string maskType; unsigned int maskDimension; if ( m_SelectedImageMask.IsNotNull() ) { mitk::PixelType pixelType = m_SelectedImageMask->GetPixelType(); MITK_DEBUG << pixelType.GetPixelTypeAsString(); if(pixelType.GetComponentTypeAsString() == "char") { MITK_DEBUG << "Pixel type is char instead of uchar"; return; } if(pixelType.GetBitsPerComponent() == 16) { //convert from ushort to uchar typedef itk::Image UCharImageType; UCharImageType::Pointer charImage; if(pixelType.GetComponentTypeAsString() == "short" ) { typedef itk::Image ShortImageType; ShortImageType::Pointer shortImage; mitk::CastToItkImage( m_SelectedImageMask, shortImage ); typedef itk::ImageDuplicator< ShortImageType > DuplicatorType; DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage( shortImage ); duplicator->Update(); typedef itk::CastImageFilter ImageCasterType; ImageCasterType::Pointer caster = ImageCasterType::New(); caster->SetInput( duplicator->GetOutput() ); caster->Update(); charImage = caster->GetOutput(); } else { typedef itk::Image UShortImageType; UShortImageType::Pointer shortImage; mitk::CastToItkImage( m_SelectedImageMask, shortImage ); typedef itk::ImageDuplicator< UShortImageType > DuplicatorType; DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage( shortImage ); duplicator->Update(); typedef itk::CastImageFilter ImageCasterType; ImageCasterType::Pointer caster = ImageCasterType::New(); caster->SetInput( duplicator->GetOutput() ); caster->Update(); charImage = caster->GetOutput(); } m_SelectedImageMask = nullptr; m_SelectedImageMask = mitk::Image::New(); m_SelectedImageMask->InitializeByItk( charImage.GetPointer() ); m_SelectedImageMask->SetVolume( charImage->GetBufferPointer() ); mitk::CastToMitkImage(charImage, m_SelectedImageMask); } m_CurrentStatisticsCalculator->SetImageMask( m_SelectedImageMask ); m_CurrentStatisticsCalculator->SetMaskingModeToImage(); maskName = m_SelectedMaskNode->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); maskDimension = 3; std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); } else if ( m_SelectedPlanarFigure.IsNotNull() && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { m_CurrentStatisticsCalculator->SetPlanarFigure( m_SelectedPlanarFigure ); m_CurrentStatisticsCalculator->SetMaskingModeToPlanarFigure(); maskName = m_SelectedPlanarFigureNodes->GetNode()->GetName(); maskType = m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; } else { m_CurrentStatisticsCalculator->SetMaskingModeToNone(); maskName = "-"; maskType = ""; maskDimension = 0; } bool statisticsChanged = false; bool statisticsCalculationSuccessful = false; // Initialize progress bar mitk::ProgressBar::GetInstance()->AddStepsToDo( 100 ); // Install listener for progress events and initialize progress bar typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer progressListener; progressListener = ITKCommandType::New(); progressListener->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::UpdateProgressBar ); unsigned long progressObserverTag = m_CurrentStatisticsCalculator ->AddObserver( itk::ProgressEvent(), progressListener ); ClusteringType::ParamsType *cparams = 0; ClusteringType::ClusterResultType *cresult = 0; ClusteringType::HistType *chist = 0; try { m_CurrentStatisticsCalculator->SetNumberOfBins(m_Controls->m_NumberBins->text().toInt()); m_CurrentStatisticsCalculator->SetUpsamplingFactor(m_Controls->m_Upsampling->text().toDouble()); m_CurrentStatisticsCalculator->SetGaussianSigma(m_Controls->m_GaussianSigma->text().toDouble()); // Compute statistics statisticsChanged = m_CurrentStatisticsCalculator->ComputeStatistics( ); mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; if(imgToCluster.IsNotNull()) { // perform clustering const HistogramType *histogram = m_CurrentStatisticsCalculator->GetHistogram( ); if(histogram != nullptr) { ClusteringType::Pointer clusterer = ClusteringType::New(); clusterer->SetStepsNumIntegration(200); clusterer->SetMaxIt(1000); mitk::Image::Pointer pFiberImg; if(m_QuantifyClass==3) { if(m_Controls->m_Quantiles->isChecked()) { m_CurrentRGBClusteringResults = clusterer->PerformRGBQuantiles(imgToCluster, histogram, m_Controls->m_q1->value(),m_Controls->m_q2->value()); } else { m_CurrentRGBClusteringResults = clusterer->PerformRGBClustering(imgToCluster, histogram); } pFiberImg = m_CurrentRGBClusteringResults->rgbChannels->r; cparams = m_CurrentRGBClusteringResults->params; cresult = m_CurrentRGBClusteringResults->result; chist = m_CurrentRGBClusteringResults->hist; } else { if(m_Controls->m_Quantiles->isChecked()) { m_CurrentPerformClusteringResults = clusterer->PerformQuantiles(imgToCluster, histogram, m_Controls->m_q1->value(),m_Controls->m_q2->value()); } else { m_CurrentPerformClusteringResults = clusterer->PerformClustering(imgToCluster, histogram, m_QuantifyClass); } pFiberImg = m_CurrentPerformClusteringResults->clusteredImage; cparams = m_CurrentPerformClusteringResults->params; cresult = m_CurrentPerformClusteringResults->result; chist = m_CurrentPerformClusteringResults->hist; } if(m_IsTensorImage) { m_AngularErrorImage = clusterer->CaculateAngularErrorImage( m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(1), m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(2), pFiberImg); // GetDataStorage()->Remove(m_newnode2); // m_newnode2 = mitk::DataNode::New(); // m_newnode2->SetData(m_AngularErrorImage); // m_newnode2->SetName(("AngularError")); // m_newnode2->SetIntProperty( "layer", 1003 ); // GetDataStorage()->Add(m_newnode2, m_SelectedImageNodes->GetNode()); // newnode = mitk::DataNode::New(); // newnode->SetData(m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(1)); // newnode->SetName(("Comp1")); // GetDataStorage()->Add(newnode, m_SelectedImageNodes->GetNode()); // newnode = mitk::DataNode::New(); // newnode->SetData(m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(2)); // newnode->SetName(("Comp2")); // GetDataStorage()->Add(newnode, m_SelectedImageNodes->GetNode()); } ShowClusteringResults(); } } statisticsCalculationSuccessful = true; } catch ( const std::runtime_error &e ) { QMessageBox::information( nullptr, "Warning", e.what()); } catch ( const std::exception &e ) { MITK_ERROR << "Caught exception: " << e.what(); QMessageBox::information( nullptr, "Warning", e.what()); } m_CurrentStatisticsCalculator->RemoveObserver( progressObserverTag ); // Make sure that progress bar closes mitk::ProgressBar::GetInstance()->Progress( 100 ); if ( statisticsCalculationSuccessful ) { if ( statisticsChanged ) { // Do not show any error messages m_CurrentStatisticsValid = true; } // m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); m_Controls->m_HistogramWidget->SetParameters( cparams, cresult, chist ); // m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); } else { m_Controls->m_SelectedMaskLabel->setText("mandatory"); // Clear statistics and histogram m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; // If a (non-closed) PlanarFigure is selected, display a line profile widget if ( m_SelectedPlanarFigure.IsNotNull() ) { // TODO: enable line profile widget //m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 1 ); //m_Controls->m_LineProfileWidget->SetImage( m_SelectedImage ); //m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); //m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); } } } } void QmitkPartialVolumeAnalysisView::SetMeasurementInfoToRenderWindow(const QString& text) { FindRenderWindow(m_SelectedPlanarFigureNodes->GetNode()); if(m_LastRenderWindow != m_SelectedRenderWindow) { if(m_LastRenderWindow) { QObject::disconnect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) , this, SLOT( OnRenderWindowDelete(QObject*) ) ); } m_LastRenderWindow = m_SelectedRenderWindow; if(m_LastRenderWindow) { QObject::connect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) , this, SLOT( OnRenderWindowDelete(QObject*) ) ); } } if(m_LastRenderWindow && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { if (!text.isEmpty()) { m_MeasurementInfoAnnotation->SetText(1, text.toLatin1().data()); mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->InsertForegroundRenderer( m_MeasurementInfoRenderer, true); } else { if (mitk::VtkLayerController::GetInstance( m_LastRenderWindow->GetRenderWindow()) ->IsRendererInserted( m_MeasurementInfoRenderer)) mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->RemoveRenderer( m_MeasurementInfoRenderer); } } else { mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); if ( renderWindowPart == nullptr ) { return; } if (!text.isEmpty()) { m_MeasurementInfoAnnotation->SetText(1, text.toLatin1().data()); mitk::VtkLayerController::GetInstance(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderWindow())->InsertForegroundRenderer( m_MeasurementInfoRenderer, true); } else { if (mitk::VtkLayerController::GetInstance( renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderWindow()) ->IsRendererInserted( m_MeasurementInfoRenderer)) mitk::VtkLayerController::GetInstance(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderWindow())->RemoveRenderer( m_MeasurementInfoRenderer); } } } void QmitkPartialVolumeAnalysisView::UpdateProgressBar() { mitk::ProgressBar::GetInstance()->Progress(); } void QmitkPartialVolumeAnalysisView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { QApplication::postEvent( this, new QmitkRequestStatisticsUpdateEvent ); m_StatisticsUpdatePending = true; } } void QmitkPartialVolumeAnalysisView::RemoveOrphanImages() { PartialVolumeAnalysisMapType::iterator it = m_PartialVolumeAnalysisMap.begin(); while ( it != m_PartialVolumeAnalysisMap.end() ) { mitk::Image *image = it->first; mitk::PartialVolumeAnalysisHistogramCalculator *calculator = it->second; ++it; mitk::NodePredicateData::Pointer hasImage = mitk::NodePredicateData::New( image ); if ( this->GetDataStorage()->GetNode( hasImage ) == nullptr ) { if ( m_SelectedImage == image ) { m_SelectedImage = nullptr; m_SelectedImageNodes->RemoveAllNodes(); } if ( m_CurrentStatisticsCalculator == calculator ) { m_CurrentStatisticsCalculator = nullptr; } m_PartialVolumeAnalysisMap.erase( image ); it = m_PartialVolumeAnalysisMap.begin(); } } } void QmitkPartialVolumeAnalysisView::ExtractTensorImages( mitk::Image::Pointer tensorimage) { typedef itk::Image< itk::DiffusionTensor3D, 3> TensorImageType; typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(tensorimage); caster->Update(); TensorImageType::Pointer image = caster->GetOutput(); typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer fa = measurementsCalculator->GetOutput(); m_FAImage = mitk::Image::New(); m_FAImage->InitializeByItk(fa.GetPointer()); m_FAImage->SetVolume(fa->GetBufferPointer()); // mitk::DataNode::Pointer node = mitk::DataNode::New(); // node->SetData(m_FAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::CA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer ca = measurementsCalculator->GetOutput(); m_CAImage = mitk::Image::New(); m_CAImage->InitializeByItk(ca.GetPointer()); m_CAImage->SetVolume(ca->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::RD); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer rd = measurementsCalculator->GetOutput(); m_RDImage = mitk::Image::New(); m_RDImage->InitializeByItk(rd.GetPointer()); m_RDImage->SetVolume(rd->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::AD); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer ad = measurementsCalculator->GetOutput(); m_ADImage = mitk::Image::New(); m_ADImage->InitializeByItk(ad.GetPointer()); m_ADImage->SetVolume(ad->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::RA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer md = measurementsCalculator->GetOutput(); m_MDImage = mitk::Image::New(); m_MDImage->InitializeByItk(md.GetPointer()); m_MDImage->SetVolume(md->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); typedef DirectionsFilterType::PeakImageType DirImageType; DirectionsFilterType::Pointer dirFilter = DirectionsFilterType::New(); dirFilter->SetInput(image ); dirFilter->SetUsePolarCoordinates(true); dirFilter->Update(); ItkUcharImgType::Pointer numDirImage = dirFilter->GetOutput(); DirImageType::Pointer dirImage = dirFilter->GetPeakImage(); itk::ImageRegionIterator itd(dirImage, dirImage->GetLargestPossibleRegion()); - itd = itd.Begin(); + itd.GoToBegin(); while( !itd.IsAtEnd() ) { DirImageType::PixelType direction = itd.Get(); direction = fabs(direction); itd.Set(direction); ++itd; } typedef itk::Image CompImageType; CompImageType::Pointer comp1 = CompImageType::New(); comp1->SetSpacing( numDirImage->GetSpacing() ); // Set the image spacing comp1->SetOrigin( numDirImage->GetOrigin() ); // Set the image origin comp1->SetDirection( numDirImage->GetDirection() ); // Set the image direction comp1->SetRegions( numDirImage->GetLargestPossibleRegion() ); comp1->Allocate(); CompImageType::Pointer comp2 = CompImageType::New(); comp2->SetSpacing( numDirImage->GetSpacing() ); // Set the image spacing comp2->SetOrigin( numDirImage->GetOrigin() ); // Set the image origin comp2->SetDirection( numDirImage->GetDirection() ); // Set the image direction comp2->SetRegions( numDirImage->GetLargestPossibleRegion() ); comp2->Allocate(); itk::ImageRegionIterator it1(comp1, comp1->GetLargestPossibleRegion()); itk::ImageRegionIterator it2(comp2, comp2->GetLargestPossibleRegion()); - it1 = it1.Begin(); - it2 = it2.Begin(); + it1.GoToBegin(); + it2.GoToBegin(); while( !it2.IsAtEnd() ) { DirImageType::IndexType peakIndex; peakIndex[0] = it1.GetIndex()[0]; peakIndex[1] = it1.GetIndex()[1]; peakIndex[2] = it1.GetIndex()[2]; peakIndex[3] = 1; it1.Set(dirImage->GetPixel(peakIndex)); peakIndex[3] = 2; it2.Set(dirImage->GetPixel(peakIndex)); ++it1; ++it2; } m_DirectionComp1Image = mitk::Image::New(); m_DirectionComp1Image->InitializeByItk(comp1.GetPointer()); m_DirectionComp1Image->SetVolume(comp1->GetBufferPointer()); m_DirectionComp2Image = mitk::Image::New(); m_DirectionComp2Image->InitializeByItk(comp2.GetPointer()); m_DirectionComp2Image->SetVolume(comp2->GetBufferPointer()); } void QmitkPartialVolumeAnalysisView::OnRenderWindowDelete(QObject * obj) { if(obj == m_LastRenderWindow) m_LastRenderWindow = 0; if(obj == m_SelectedRenderWindow) m_SelectedRenderWindow = 0; } bool QmitkPartialVolumeAnalysisView::event( QEvent *event ) { if ( event->type() == (QEvent::Type) QmitkRequestStatisticsUpdateEvent::StatisticsUpdateRequest ) { // Update statistics m_StatisticsUpdatePending = false; this->UpdateStatistics(); return true; } return false; } void QmitkPartialVolumeAnalysisView::Activated() { mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigure* figure = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; // finally add all nodes to the model for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figure = dynamic_cast(node->GetData()); if(figure) { figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( node ); } } } } void QmitkPartialVolumeAnalysisView::Deactivated() { } -void QmitkPartialVolumeAnalysisView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer reference) +void QmitkPartialVolumeAnalysisView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer) { this->SetMeasurementInfoToRenderWindow(""); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigure* figure = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; // finally add all nodes to the model for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figure = dynamic_cast(node->GetData()); if(figure) { figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor) figureInteractor->SetDataNode( nullptr ); } } } void QmitkPartialVolumeAnalysisView::Hidden() { if (m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } Select(nullptr, true, true); m_Visible = false; } void QmitkPartialVolumeAnalysisView::Visible() { m_Visible = true; berry::IWorkbenchPart::Pointer bla; if (!this->GetCurrentSelection().empty()) { this->OnSelectionChanged(bla, this->GetCurrentSelection()); } else { this->OnSelectionChanged(bla, this->GetDataManagerSelection()); } } void QmitkPartialVolumeAnalysisView::GreenRadio(bool checked) { if(checked) { m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 0; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::PartialVolumeRadio(bool checked) { if(checked) { m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 1; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::BlueRadio(bool checked) { if(checked) { m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 2; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::AllRadio(bool checked) { if(checked) { m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(false); } m_QuantifyClass = 3; RequestStatisticsUpdate(); } -void QmitkPartialVolumeAnalysisView::NumberBinsChangedSlider(int v ) +void QmitkPartialVolumeAnalysisView::NumberBinsChangedSlider(int) { m_Controls->m_NumberBins->setText(QString("%1").arg(m_Controls->m_NumberBinsSlider->value()*5.0)); } -void QmitkPartialVolumeAnalysisView::UpsamplingChangedSlider( int v) +void QmitkPartialVolumeAnalysisView::UpsamplingChangedSlider(int) { m_Controls->m_Upsampling->setText(QString("%1").arg(m_Controls->m_UpsamplingSlider->value()/10.0)); } -void QmitkPartialVolumeAnalysisView::GaussianSigmaChangedSlider(int v ) +void QmitkPartialVolumeAnalysisView::GaussianSigmaChangedSlider(int) { m_Controls->m_GaussianSigma->setText(QString("%1").arg(m_Controls->m_GaussianSigmaSlider->value()/100.0)); } -void QmitkPartialVolumeAnalysisView::SimilarAnglesChangedSlider(int v ) +void QmitkPartialVolumeAnalysisView::SimilarAnglesChangedSlider(int) { m_Controls->m_SimilarAngles->setText(QString("%1°").arg(90-m_Controls->m_SimilarAnglesSlider->value())); ShowClusteringResults(); } void QmitkPartialVolumeAnalysisView::OpacityChangedSlider(int v ) { if(m_SelectedImageNodes->GetNode().IsNotNull()) { float opacImag = 1.0f-(v-5)/5.0f; opacImag = opacImag < 0 ? 0 : opacImag; m_SelectedImageNodes->GetNode()->SetFloatProperty("opacity", opacImag); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } if(m_ClusteringResult.IsNotNull()) { float opacClust = v/5.0f; opacClust = opacClust > 1 ? 1 : opacClust; m_ClusteringResult->SetFloatProperty("opacity", opacClust); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkPartialVolumeAnalysisView::NumberBinsReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::UpsamplingReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::GaussianSigmaReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::SimilarAnglesReleasedSlider( ) { } void QmitkPartialVolumeAnalysisView::ToClipBoard() { std::vector* > vals = m_Controls->m_HistogramWidget->m_Vals; QString clipboardText; for (std::vector* >::iterator it = vals.begin(); it != vals.end(); ++it) { for (std::vector::iterator it2 = (**it).begin(); it2 != (**it).end(); ++it2) { clipboardText.append(QString("%1 \t").arg(*it2)); } clipboardText.append(QString("\n")); } QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); } void QmitkPartialVolumeAnalysisView::PropertyChanged(const mitk::DataNode* /*node*/, const mitk::BaseProperty* /*prop*/) { } void QmitkPartialVolumeAnalysisView::NodeChanged(const mitk::DataNode* /*node*/) { } void QmitkPartialVolumeAnalysisView::NodeRemoved(const mitk::DataNode* node) { if (dynamic_cast(node->GetData())) this->GetDataStorage()->Remove(m_ClusteringResult); if( node == m_SelectedPlanarFigureNodes->GetNode().GetPointer() || node == m_SelectedMaskNode.GetPointer() ) { this->Select(nullptr,true,false); SetMeasurementInfoToRenderWindow(""); } if( node == m_SelectedImageNodes->GetNode().GetPointer() ) { this->Select(nullptr,false,true); SetMeasurementInfoToRenderWindow(""); } } void QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage(const mitk::DataNode* node) { if(!m_Visible) return; mitk::DataNode* nonConstNode = const_cast(node); mitk::PlanarFigure* figure = dynamic_cast(nonConstNode->GetData()); if(figure) { // set interactor for new node (if not already set) mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( nonConstNode ); } // remove uninitialized old planars if( m_SelectedPlanarFigureNodes->GetNode().IsNotNull() && m_CurrentFigureNodeInitialized == false ) { this->GetDataStorage()->Remove(m_SelectedPlanarFigureNodes->GetNode()); } } } void QmitkPartialVolumeAnalysisView::TextIntON() { if(m_ClusteringResult.IsNotNull()) { if(m_TexIsOn) { m_Controls->m_TextureIntON->setIcon(*m_IconTexOFF); } else { m_Controls->m_TextureIntON->setIcon(*m_IconTexON); } m_ClusteringResult->SetBoolProperty("texture interpolation", !m_TexIsOn); m_TexIsOn = !m_TexIsOn; this->RequestRenderWindowUpdate(); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.h index 97236bb35a..83c9dd870f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.h @@ -1,273 +1,270 @@ /*=================================================================== 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. ===================================================================*/ #if !defined(QmitkPartialVolumeAnalysisView_H__INCLUDED) #define QmitkPartialVolumeAnalysisView_H__INCLUDED #include "ui_QmitkPartialVolumeAnalysisViewControls.h" #include #include #include // berry #include #include // itk #include #include #include // qmitk #include "QmitkStepperAdapter.h" #include "QmitkRenderWindow.h" // mitk #include "mitkPartialVolumeAnalysisHistogramCalculator.h" #include "mitkPlanarLine.h" #include #include "mitkDataStorageSelection.h" #include // vtk #include #include #include //#include "itkProcessObject.h" /*! \brief QmitkPartialVolumeAnalysis */ class QmitkPartialVolumeAnalysisView : public QmitkAbstractView, public mitk::IZombieViewPart//, public itk::ProcessObject { Q_OBJECT public: /*! \ Convenient typedefs */ typedef mitk::DataStorage::SetOfObjects ConstVector; typedef ConstVector::ConstPointer ConstVectorPointer; typedef ConstVector::ConstIterator ConstVectorIterator; typedef mitk::PartialVolumeAnalysisHistogramCalculator HistogramCalculatorType; typedef HistogramCalculatorType::HistogramType HistogramType; typedef mitk::PartialVolumeAnalysisClusteringCalculator ClusteringType; typedef itk::DiffusionTensorPrincipalDirectionImageFilter DirectionsFilterType; typedef itk::Image ItkUcharImgType; /*! \brief default constructor */ QmitkPartialVolumeAnalysisView(QObject *parent=0, const char *name=0); /*! \brief default destructor */ virtual ~QmitkPartialVolumeAnalysisView(); /*! \brief method for creating the widget containing the application controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget *parent) override; /*! \brief method for creating the connections of main and control widget */ virtual void CreateConnections(); virtual bool event( QEvent *event ) override; virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; virtual void Activated() override; virtual void Deactivated() override; virtual void ActivatedZombieView(berry::IWorkbenchPartReference::Pointer reference) override; virtual void Hidden() override; virtual void Visible() override; virtual void SetFocus() override; bool AssertDrawingIsPossible(bool checked); virtual void NodeChanged(const mitk::DataNode* node) override; virtual void PropertyChanged(const mitk::DataNode* node, const mitk::BaseProperty* prop); virtual void NodeRemoved(const mitk::DataNode* node) override; virtual void NodeAddedInDataStorage(const mitk::DataNode* node); virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = nullptr, mitk::BaseProperty *property = nullptr ); void PlanarFigureInitialized(); void PlanarFigureFocus(mitk::DataNode* node); void ShowClusteringResults(); static const std::string VIEW_ID; protected slots: void EstimateCircle(); void SetHistogramVisibility(); void SetAdvancedVisibility(); void NumberBinsChangedSlider(int v ); void UpsamplingChangedSlider( int v ); void GaussianSigmaChangedSlider( int v ); void SimilarAnglesChangedSlider(int v ); void OpacityChangedSlider(int v ); void NumberBinsReleasedSlider( ); void UpsamplingReleasedSlider( ); void GaussianSigmaReleasedSlider( ); void SimilarAnglesReleasedSlider( ); void ActionDrawEllipseTriggered(); void ActionDrawRectangleTriggered(); void ActionDrawPolygonTriggered(); void ToClipBoard(); void GreenRadio(bool checked); void PartialVolumeRadio(bool checked); void BlueRadio(bool checked); void AllRadio(bool checked); void OnRenderWindowDelete(QObject * obj); void TextIntON(); void ExportClusteringResults(); protected: /** \brief Issues a request to update statistics by sending an event to the * Qt event processing queue. * * Statistics update should only be executed after program execution returns * to the Qt main loop. This mechanism also prevents multiple execution of * updates where only one is required.*/ void RequestStatisticsUpdate(); /** \brief Recalculate statistics for currently selected image and mask and * update the GUI. */ void UpdateStatistics(); /** \brief Listener for progress events to update progress bar. */ void UpdateProgressBar(); /** \brief Removes any cached images which are no longer referenced elsewhere. */ void RemoveOrphanImages(); void Select( mitk::DataNode::Pointer node, bool clearMaskOnFirstArgnullptr=false, bool clearImageOnFirstArgnullptr=false ); void SetMeasurementInfoToRenderWindow(const QString& text); void FindRenderWindow(mitk::DataNode* node); void ExtractTensorImages( mitk::Image::Pointer tensorimage); typedef std::map< mitk::Image *, mitk::PartialVolumeAnalysisHistogramCalculator::Pointer > PartialVolumeAnalysisMapType; /*! * controls containing sliders for scrolling through the slices */ Ui::QmitkPartialVolumeAnalysisViewControls *m_Controls; QmitkStepperAdapter* m_TimeStepperAdapter; unsigned int m_CurrentTime; QString m_Clipboard; // result text rendering vtkRenderer * m_MeasurementInfoRenderer; vtkCornerAnnotation *m_MeasurementInfoAnnotation; // Image and mask data mitk::DataStorageSelection::Pointer m_SelectedImageNodes; mitk::Image::Pointer m_SelectedImage; mitk::DataNode::Pointer m_SelectedMaskNode; mitk::Image::Pointer m_SelectedImageMask; mitk::DataStorageSelection::Pointer m_SelectedPlanarFigureNodes; mitk::PlanarFigure::Pointer m_SelectedPlanarFigure; bool m_IsTensorImage; mitk::Image::Pointer m_FAImage; mitk::Image::Pointer m_CAImage; mitk::Image::Pointer m_RDImage; mitk::Image::Pointer m_ADImage; mitk::Image::Pointer m_MDImage; -// mitk::Image::Pointer m_DirectionImage; mitk::Image::Pointer m_DirectionComp1Image; mitk::Image::Pointer m_DirectionComp2Image; mitk::Image::Pointer m_AngularErrorImage; QmitkRenderWindow* m_SelectedRenderWindow; QmitkRenderWindow* m_LastRenderWindow; long m_ImageObserverTag; long m_ImageMaskObserverTag; long m_PlanarFigureObserverTag; // Hash map for associating one image statistics calculator with each iamge // (so that previously calculated histograms / statistics can be recovered // if a recalculation is not required) PartialVolumeAnalysisMapType m_PartialVolumeAnalysisMap; HistogramCalculatorType::Pointer m_CurrentStatisticsCalculator; bool m_CurrentStatisticsValid; bool m_StatisticsUpdatePending; bool m_GaussianSigmaChangedSliding; bool m_NumberBinsSliding; bool m_UpsamplingChangedSliding; - bool m_Visible; - mitk::DataNode::Pointer m_ClusteringResult; int m_EllipseCounter; int m_RectangleCounter; int m_PolygonCounter; - unsigned int m_InitializedObserverTag; + long m_InitializedObserverTag; bool m_CurrentFigureNodeInitialized; int m_QuantifyClass; ClusteringType::HelperStructPerformRGBClusteringRetval* m_CurrentRGBClusteringResults; ClusteringType::HelperStructPerformClusteringRetval *m_CurrentPerformClusteringResults; -// mitk::DataNode::Pointer m_newnode; -// mitk::DataNode::Pointer m_newnode2; QIcon* m_IconTexOFF; QIcon* m_IconTexON; bool m_TexIsOn; + + bool m_Visible; }; -#endif // !defined(QmitkPartialVolumeAnalysis_H__INCLUDED) +#endif diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/QmitkTbssRoiAnalysisWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/QmitkTbssRoiAnalysisWidget.cpp index e7220cdb35..8d48e6f0f7 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/QmitkTbssRoiAnalysisWidget.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/QmitkTbssRoiAnalysisWidget.cpp @@ -1,967 +1,967 @@ /*=================================================================== 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 "QmitkTbssRoiAnalysisWidget.h" #include "mitkImagePixelReadAccessor.h" #include "mitkPixelTypeMultiplex.h" #include #include #include #include QmitkTbssRoiAnalysisWidget::QmitkTbssRoiAnalysisWidget( QWidget * parent ) : QmitkPlotWidget(parent) { m_PlotPicker = new QwtPlotPicker(m_Plot->canvas()); m_PlotPicker->setStateMachine(new QwtPickerDragPointMachine()); m_PlotPicker->setTrackerMode(QwtPicker::ActiveOnly); m_PlottingFiberBundle = false; } void QmitkTbssRoiAnalysisWidget::DoPlotFiberBundles(mitk::FiberBundle *fib, mitk::Image* img, mitk::DataNode* startRoi, mitk::DataNode* endRoi, bool avg, int number) { TractContainerType tracts = CreateTracts(fib, startRoi, endRoi); TractContainerType resampledTracts = ParameterizeTracts(tracts, number); // Now we have the resampled tracts. Next we should use these points to read out the values mitkPixelTypeMultiplex3(PlotFiberBundles,img->GetImageDescriptor()->GetChannelTypeById(0),resampledTracts, img, avg); m_CurrentTracts = resampledTracts; } TractContainerType QmitkTbssRoiAnalysisWidget::CreateTracts(mitk::FiberBundle *fib, mitk::DataNode *startRoi, mitk::DataNode *endRoi) { mitk::PlaneGeometry* startGeometry2D = const_cast(dynamic_cast(startRoi->GetData())->GetPlaneGeometry()); mitk::PlaneGeometry* endGeometry2D = const_cast(dynamic_cast(endRoi->GetData())->GetPlaneGeometry()); mitk::Point3D startCenter = dynamic_cast(startRoi->GetData())->GetWorldControlPoint(0); //center Point of start roi mitk::Point3D endCenter = dynamic_cast(startRoi->GetData())->GetWorldControlPoint(0); //center Point of end roi mitk::FiberBundle::Pointer inStart = fib->ExtractFiberSubset(startRoi, nullptr); mitk::FiberBundle::Pointer inBoth = inStart->ExtractFiberSubset(endRoi, nullptr); int num = inBoth->GetNumFibers(); TractContainerType tracts; vtkSmartPointer fiberPolyData = inBoth->GetFiberPolyData(); vtkCellArray* lines = fiberPolyData->GetLines(); lines->InitTraversal(); // Now find out for each fiber which ROI is encountered first. If this is the startRoi, the direction is ok // Otherwise the plot should be in the reverse direction for( int fiberID( 0 ); fiberID < num; fiberID++ ) { vtkIdType numPointsInCell(0); vtkIdType* pointsInCell(nullptr); lines->GetNextCell ( numPointsInCell, pointsInCell ); int startId = 0; int endId = 0; mitk::ScalarType minDistStart = std::numeric_limits::max(); mitk::ScalarType minDistEnd = std::numeric_limits::max(); for( int pointInCellID( 0 ); pointInCellID < numPointsInCell ; pointInCellID++) { mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); mitk::Point3D point; point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; mitk::ScalarType distanceToStart = point.EuclideanDistanceTo(startCenter); mitk::ScalarType distanceToEnd = point.EuclideanDistanceTo(endCenter); if(distanceToStart < minDistStart) { minDistStart = distanceToStart; startId = pointInCellID; } if(distanceToEnd < minDistEnd) { minDistEnd = distanceToEnd; endId = pointInCellID; } } /* We found the start and end points of of the part that should be plottet for the current fiber. now we need to plot them. If the endId is smaller than the startId the plot order must be reversed*/ TractType singleTract; PointType point; if(startId < endId) { // Calculate the intersection of the ROI with the startRoi and decide if the startId is part of the roi or must be cut of mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ startId ] ); mitk::Vector3D p0; p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; p = fiberPolyData->GetPoint( pointsInCell[ startId+1 ] ); mitk::Vector3D p1; p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; // Check if p and p2 are both on the same side of the plane mitk::Vector3D normal = startGeometry2D->GetNormal(); mitk::Point3D pStart; pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2]; mitk::Point3D pSecond; pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2]; bool startOnPositive = startGeometry2D->IsAbove(pStart); bool secondOnPositive = startGeometry2D->IsAbove(pSecond); mitk::Vector3D onPlane; onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2]; if(! (secondOnPositive ^ startOnPositive) ) { /* startId and startId+1 lie on the same side of the plane, so we need need startId-1 to calculate the intersection with the planar figure*/ p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; } mitk::ScalarType d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); mitk::Vector3D newPoint = (p0-p1); point[0] = d*newPoint[0] + p0[0]; point[1] = d*newPoint[1] + p0[1]; point[2] = d*newPoint[2] + p0[2]; singleTract.push_back(point); if(! (secondOnPositive ^ startOnPositive) ) { /* StartId and startId+1 lie on the same side of the plane so startId is also part of the ROI*/ mitk::ScalarType *start = fiberPolyData->GetPoint( pointsInCell[startId] ); point[0] = start[0]; point[1] = start[1]; point[2] = start[2]; singleTract.push_back(point); } for( int pointInCellID( startId+1 ); pointInCellID < endId ; pointInCellID++) { // push back point mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; singleTract.push_back( point ); } /* endId must be included if endId and endId-1 lie on the same side of the plane defined by endRoi*/ p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; mitk::Point3D pLast; pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2]; mitk::Point3D pBeforeLast; pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2]; normal = endGeometry2D->GetNormal(); bool lastOnPositive = endGeometry2D->IsAbove(pLast); bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast); onPlane[0] = endCenter[0]; onPlane[1] = endCenter[1]; onPlane[2] = endCenter[2]; if(! (lastOnPositive ^ secondLastOnPositive) ) { /* endId and endId-1 lie on the same side of the plane, so we need need endId+1 to calculate the intersection with the planar figure. this should exist since we know that the fiber crosses the planar figure endId is also part of the tract and can be inserted here */ p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; singleTract.push_back( point ); p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] ); } d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); newPoint = (p0-p1); point[0] = d*newPoint[0] + p0[0]; point[1] = d*newPoint[1] + p0[1]; point[2] = d*newPoint[2] + p0[2]; singleTract.push_back(point); } else{ // Calculate the intersection of the ROI with the startRoi and decide if the startId is part of the roi or must be cut of mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ startId ] ); mitk::Vector3D p0; p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); mitk::Vector3D p1; p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; // Check if p and p2 are both on the same side of the plane mitk::Vector3D normal = startGeometry2D->GetNormal(); mitk::Point3D pStart; pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2]; mitk::Point3D pSecond; pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2]; bool startOnPositive = startGeometry2D->IsAbove(pStart); bool secondOnPositive = startGeometry2D->IsAbove(pSecond); mitk::Vector3D onPlane; onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2]; if(! (secondOnPositive ^ startOnPositive) ) { /* startId and startId+1 lie on the same side of the plane, so we need need startId-1 to calculate the intersection with the planar figure*/ p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; } mitk::ScalarType d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); mitk::Vector3D newPoint = (p0-p1); point[0] = d*newPoint[0] + p0[0]; point[1] = d*newPoint[1] + p0[1]; point[2] = d*newPoint[2] + p0[2]; singleTract.push_back(point); if(! (secondOnPositive ^ startOnPositive) ) { /* StartId and startId+1 lie on the same side of the plane so startId is also part of the ROI*/ mitk::ScalarType *start = fiberPolyData->GetPoint( pointsInCell[startId] ); point[0] = start[0]; point[1] = start[1]; point[2] = start[2]; singleTract.push_back(point); } for( int pointInCellID( startId-1 ); pointInCellID > endId ; pointInCellID--) { // push back point mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; singleTract.push_back( point ); } /* endId must be included if endId and endI+1 lie on the same side of the plane defined by endRoi*/ p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; mitk::Point3D pLast; pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2]; mitk::Point3D pBeforeLast; pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2]; bool lastOnPositive = endGeometry2D->IsAbove(pLast); bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast); normal = endGeometry2D->GetNormal(); onPlane[0] = endCenter[0]; onPlane[1] = endCenter[1]; onPlane[2] = endCenter[2]; if(! (lastOnPositive ^ secondLastOnPositive) ) { /* endId and endId+1 lie on the same side of the plane, so we need need endId-1 to calculate the intersection with the planar figure. this should exist since we know that the fiber crosses the planar figure endId is also part of the tract and can be inserted here */ p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; singleTract.push_back( point ); p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] ); } d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); newPoint = (p0-p1); point[0] = d*newPoint[0] + p0[0]; point[1] = d*newPoint[1] + p0[1]; point[2] = d*newPoint[2] + p0[2]; singleTract.push_back(point); } tracts.push_back(singleTract); } return tracts; } void QmitkTbssRoiAnalysisWidget::PlotFiberBetweenRois(mitk::FiberBundle *fib, mitk::Image* img, mitk::DataNode* startRoi, mitk::DataNode* endRoi, bool avg, int number) { if(fib == nullptr || img == nullptr || startRoi == nullptr || endRoi == nullptr) return; m_Fib = fib; m_CurrentImage = img; m_CurrentStartRoi = startRoi; m_CurrentEndRoi = endRoi; DoPlotFiberBundles(fib, img, startRoi, endRoi, avg, number); } void QmitkTbssRoiAnalysisWidget::ModifyPlot(int number, bool avg) { if(m_Fib == nullptr || m_CurrentTbssImage == nullptr || m_CurrentStartRoi == nullptr || m_CurrentEndRoi == nullptr) return; if(m_PlottingFiberBundle) { DoPlotFiberBundles(m_Fib, m_CurrentImage, m_CurrentStartRoi, m_CurrentEndRoi, avg, number); } else { PlotFiber4D(m_CurrentTbssImage, m_Fib, m_CurrentStartRoi, m_CurrentEndRoi, number); } } TractContainerType QmitkTbssRoiAnalysisWidget::ParameterizeTracts(TractContainerType tracts, int number) { TractContainerType resampledTracts; for(auto it = tracts.begin(); it != tracts.end(); ++it) { TractType resampledTract; TractType tract = *it; // Calculate the total length mitk::ScalarType totalLength = 0; if(tract.size() < 2) continue; PointType p0 = tract.at(0); for(unsigned int i = 1; i(resampledTract.size()) <= (number+1); position+=stepSize) { /* In case we walked to far we need to find the next segment we are on and on what relative position on that tract we are on. Small correction for rounding errors */ while(locationBetween > distance+0.001) { if(tractCounter == tract.size()) std::cout << "problem"; // Determine by what distance we are no on the next segment locationBetween = locationBetween - distance; p0 = p1; p1 = tract.at(tractCounter); tractCounter++; distance = p0.EuclideanDistanceTo(p1); } // Direction PointType::VectorType direction = p1-p0; direction.Normalize(); PointType newSample = p0 + direction*locationBetween; resampledTract.push_back(newSample); locationBetween += stepSize; } resampledTracts.push_back(resampledTract); } return resampledTracts; } mitk::Point3D QmitkTbssRoiAnalysisWidget::GetPositionInWorld(int index) { mitk::ScalarType xSum = 0.0; mitk::ScalarType ySum = 0.0; mitk::ScalarType zSum = 0.0; for(auto it = m_CurrentTracts.begin(); it!=m_CurrentTracts.end(); ++it) { TractType tract = *it; PointType p = tract.at(index); xSum += p[0]; ySum += p[1]; zSum += p[2]; } int number = m_CurrentTracts.size(); mitk::ScalarType xPos = xSum / number; mitk::ScalarType yPos = ySum / number; mitk::ScalarType zPos = zSum / number; mitk::Point3D pos; pos[0] = xPos; pos[1] = yPos; pos[2] = zPos; return pos; } std::vector< std::vector > QmitkTbssRoiAnalysisWidget::CalculateGroupProfiles() { MITK_INFO << "make profiles!"; std::vector< std::vector > profiles; int size = m_Projections->GetVectorLength(); for(int s=0; s profile; RoiType::iterator it; it = m_Roi.begin(); while(it != m_Roi.end()) { itk::Index<3> ix = *it; profile.push_back(m_Projections->GetPixel(ix).GetElement(s)); it++; } profiles.push_back(profile); } m_IndividualProfiles = profiles; // Calculate the averages // Here a check could be build in to check whether all profiles have // the same length, but this should normally be the case if the input // data were corrected with the TBSS Module. std::vector< std::vector > groupProfiles; std::vector< std::pair >::iterator it; it = m_Groups.begin(); int c = 0; //the current profile number while(it != m_Groups.end() && profiles.size() > 0) { std::pair p = *it; int size = p.second; //initialize a vector of the right length with zeroes std::vector averageProfile; for(unsigned int i=0; i > groupProfiles = CalculateGroupProfiles(); Plot(groupProfiles); } void QmitkTbssRoiAnalysisWidget::Plot(std::vector > groupProfiles) { this->Clear(); m_Vals.clear(); std::vector v1; std::vector xAxis; for(unsigned int i=0; iSetPlotTitle( title.c_str() ); QPen pen( Qt::SolidLine ); pen.setWidth(2); std::vector< std::pair >::iterator it; it = m_Groups.begin(); int c = 0; //the current profile number QColor colors[4] = {Qt::green, Qt::blue, Qt::yellow, Qt::red}; while(it != m_Groups.end() && groupProfiles.size() > 0) { std::pair< std::string, int > group = *it; pen.setColor(colors[c]); int curveId = this->InsertCurve( group.first.c_str() ); this->SetCurveData( curveId, xAxis, groupProfiles.at(c) ); this->SetCurvePen( curveId, pen ); c++; it++; } auto legend = new QwtLegend; this->SetLegend(legend, QwtPlot::RightLegend, 0.5); std::cout << m_Measure << std::endl; this->m_Plot->setAxisTitle(0, m_Measure.c_str()); this->m_Plot->setAxisTitle(3, "Position"); this->Replot(); } std::vector< std::vector > QmitkTbssRoiAnalysisWidget::CalculateGroupProfilesFibers(mitk::TbssImage::Pointer tbssImage, mitk::FiberBundle *fib, mitk::DataNode* startRoi, mitk::DataNode* endRoi, int number) { TractContainerType tracts = CreateTracts(fib, startRoi, endRoi); TractContainerType resampledTracts = ParameterizeTracts(tracts, number); int nTracts = resampledTracts.size(); this->Clear(); // For every group we have m fibers * n subjects of profiles to fill std::vector< std::vector > profiles; // calculate individual profiles by going through all n subjects int size = m_Projections->GetVectorLength(); for(int s=0; s profile; auto it = resampledTracts[t].begin(); while(it != resampledTracts[t].end()) { PointType p = *it; PointType index; tbssImage->GetGeometry()->WorldToIndex(p, index); itk::Index<3> ix; ix[0] = index[0]; ix[1] = index[1]; ix[2] = index[2]; // Get value from image profile.push_back(m_Projections->GetPixel(ix).GetElement(s)); it++; } profiles.push_back(profile); } } m_IndividualProfiles = profiles; // Now create the group averages (every group contains m fibers * n_i group members std::vector< std::pair >::iterator it; it = m_Groups.begin(); int c = 0; //the current profile number // Calculate the group averages std::vector< std::vector > groupProfiles; while(it != m_Groups.end() && profiles.size() > 0) { std::pair p = *it; int size = p.second; //initialize a vector of the right length with zeroes std::vector averageProfile; for(unsigned int i=0; i > groupProfiles = CalculateGroupProfilesFibers(tbssImage, fib, startRoi, endRoi, number); Plot(groupProfiles); } template -void QmitkTbssRoiAnalysisWidget::PlotFiberBundles(const mitk::PixelType ptype, TractContainerType tracts, mitk::Image *img, bool avg) +void QmitkTbssRoiAnalysisWidget::PlotFiberBundles(const mitk::PixelType, TractContainerType tracts, mitk::Image *img, bool avg) { m_PlottingFiberBundle = true; this->Clear(); auto it = tracts.begin(); std::vector< std::vector > profiles; mitk::ImagePixelReadAccessor imAccess(img,img->GetVolumeData(0)); it = tracts.begin(); while(it != tracts.end()) { TractType tract = *it; auto tractIt = tract.begin(); std::vector profile; while(tractIt != tract.end()) { PointType p = *tractIt; // Get value from image profile.push_back( (mitk::ScalarType) imAccess.GetPixelByWorldCoordinates(p) ); ++tractIt; } profiles.push_back(profile); std::cout << std::endl; ++it; } if(profiles.size() == 0) return; m_IndividualProfiles = profiles; std::string title = "Fiber bundle plot"; this->SetPlotTitle( title.c_str() ); // initialize average profile std::vector averageProfile; std::vector profile = profiles.at(0); // can do this because we checked the size of profiles before for(unsigned int i=0; i profile = *profit; std::vector xAxis; for(unsigned int i=0; iInsertCurve( "" ); this->SetCurveData( curveId, xAxis, profile ); ++profit; id++; } m_Average = averageProfile; if(avg) { // Draw the average profile std::vector xAxis; for(unsigned int i=0; iInsertCurve( "" ); this->SetCurveData( curveId, xAxis, averageProfile ); QPen pen( Qt::SolidLine ); pen.setWidth(3); pen.setColor(Qt::red); this->SetCurvePen( curveId, pen ); id++; } this->Replot(); } void QmitkTbssRoiAnalysisWidget::drawBar(int x) { m_Plot->detachItems(QwtPlotItem::Rtti_PlotMarker, true); QwtPlotMarker *mX = new QwtPlotMarker(); //mX->setLabel(QString::fromLatin1("selected point")); mX->setLabelAlignment(Qt::AlignLeft | Qt::AlignBottom); mX->setLabelOrientation(Qt::Vertical); mX->setLineStyle(QwtPlotMarker::VLine); mX->setLinePen(QPen(Qt::black, 0, Qt::SolidLine)); mX->setXValue(x); mX->attach(m_Plot); this->Replot(); } QmitkTbssRoiAnalysisWidget::~QmitkTbssRoiAnalysisWidget() { delete m_PlotPicker; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp index 3154134487..a15cd277a9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp @@ -1,502 +1,502 @@ /*=================================================================== 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 #include "QmitkTbssSkeletonizationView.h" #include #include #include #include #include // mitk #include #include #include #include // Qt #include #include //vtk #include #include // Boost #include const std::string QmitkTbssSkeletonizationView::VIEW_ID = "org.mitk.views.tbssskeletonization"; using namespace berry; QmitkTbssSkeletonizationView::QmitkTbssSkeletonizationView() : QmitkAbstractView() , m_Controls( 0 ) , m_Activated(false) { } QmitkTbssSkeletonizationView::~QmitkTbssSkeletonizationView() { } void QmitkTbssSkeletonizationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { //datamanager selection changed if (!this->IsActivated()) return; bool found3dImage = false; bool found4dImage = false; this->m_Controls->m_TubularName->setText(QString("Tubular Structure Mask: ")); this->m_Controls->m_TubularName->setEnabled(false); this->m_Controls->m_MeanLabel->setText(QString("Mean: ")); this->m_Controls->m_MeanLabel->setEnabled(false); this->m_Controls->m_PatientDataLabel->setText(QString("Patient Data: ")); this->m_Controls->m_PatientDataLabel->setEnabled(false); // iterate selection for (mitk::DataNode::Pointer node: nodes) { // only look at interesting types from valid nodes mitk::BaseData* nodeData = node->GetData(); std::string name = ""; node->GetStringProperty("name", name); if(nodeData) { if(QString("Image").compare(nodeData->GetNameOfClass())==0) { mitk::Image* img = static_cast(nodeData); if(img->GetDimension() == 3) { bool isBinary(false); node->GetBoolProperty("binary", isBinary); if(isBinary) { QString label("Tubular Structure Mask: "); label.append(QString(name.c_str())); this->m_Controls->m_TubularName->setText(label); this->m_Controls->m_TubularName->setEnabled(true); } else { found3dImage = true; QString label("Mean: "); label.append(QString(name.c_str())); this->m_Controls->m_MeanLabel->setText(label); this->m_Controls->m_MeanLabel->setEnabled(true); } } else if(img->GetDimension() == 4) { found4dImage = true; QString label("Patient Data: "); label.append(QString(name.c_str())); this->m_Controls->m_PatientDataLabel->setText(label); this->m_Controls->m_PatientDataLabel->setEnabled(true); } } } } this->m_Controls->m_Skeletonize->setEnabled(found3dImage); this->m_Controls->m_Project->setEnabled(found3dImage && found4dImage); this->m_Controls->m_OutputMask->setEnabled(found3dImage && found4dImage); this->m_Controls->m_OutputDistanceMap->setEnabled(found3dImage && found4dImage); } void QmitkTbssSkeletonizationView::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::QmitkTbssSkeletonizationViewControls; m_Controls->setupUi( parent ); this->CreateConnections(); } } void QmitkTbssSkeletonizationView::SetFocus() { m_Controls->m_Skeletonize->setFocus(); } void QmitkTbssSkeletonizationView::Activated() { m_Activated = true; } void QmitkTbssSkeletonizationView::Deactivated() { m_Activated = false; } bool QmitkTbssSkeletonizationView::IsActivated() const { return m_Activated; } void QmitkTbssSkeletonizationView::Visible() { } void QmitkTbssSkeletonizationView::Hidden() { } void QmitkTbssSkeletonizationView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_Skeletonize), SIGNAL(clicked()), this, SLOT(Skeletonize() )); connect( (QObject*)(m_Controls->m_Project), SIGNAL(clicked()), this, SLOT(Project() )); } } void QmitkTbssSkeletonizationView::Skeletonize() { typedef itk::SkeletonizationFilter SkeletonisationFilterType; SkeletonisationFilterType::Pointer skeletonizer = SkeletonisationFilterType::New(); QList nodes = this->GetDataManagerSelection(); mitk::Image::Pointer meanImage = mitk::Image::New(); std::string name = ""; for (auto node: nodes) { // process only on valid nodes mitk::BaseData* nodeData = node->GetData(); if(nodeData) { if(QString("Image").compare(nodeData->GetNameOfClass())==0) { bool isBinary(false); node->GetBoolProperty("binary", isBinary); mitk::Image* img = static_cast(nodeData); if(img->GetDimension() == 3 && !isBinary) { meanImage = img; name = node->GetName(); } } } } // Calculate skeleton FloatImageType::Pointer itkImg = FloatImageType::New(); mitk::CastToItkImage(meanImage, itkImg); skeletonizer->SetInput(itkImg); skeletonizer->Update(); FloatImageType::Pointer output = skeletonizer->GetOutput(); mitk::Image::Pointer mitkOutput = mitk::Image::New(); mitk::CastToMitkImage(output, mitkOutput); name += "_skeleton"; AddToDataStorage(mitkOutput, name); } void QmitkTbssSkeletonizationView::Project() { typedef itk::SkeletonizationFilter SkeletonisationFilterType; typedef itk::ProjectionFilter ProjectionFilterType; typedef itk::DistanceMapFilter DistanceMapFilterType; SkeletonisationFilterType::Pointer skeletonizer = SkeletonisationFilterType::New(); QList nodes = this->GetDataManagerSelection(); mitk::Image::Pointer meanImage = mitk::Image::New(); mitk::Image::Pointer subjects = mitk::Image::New(); mitk::Image::Pointer tubular = mitk::Image::New(); for (auto node: nodes) { // process only on valid nodes mitk::BaseData* nodeData = node->GetData(); if(nodeData) { if(QString("Image").compare(nodeData->GetNameOfClass())==0) { mitk::Image* img = static_cast(nodeData); if(img->GetDimension() == 3) { bool isBinary(false); node->GetBoolProperty("binary", isBinary); if(isBinary) { tubular = img; } else { meanImage = img; } } else if(img->GetDimension() == 4) { subjects = img; } } } } Float4DImageType::Pointer allFA; mitkPixelTypeMultiplex2(ConvertToItk,subjects->GetChannelDescriptor().GetPixelType(),subjects, allFA); // Calculate skeleton FloatImageType::Pointer itkImg = FloatImageType::New(); mitk::CastToItkImage(meanImage, itkImg); skeletonizer->SetInput(itkImg); skeletonizer->Update(); FloatImageType::Pointer output = skeletonizer->GetOutput(); mitk::Image::Pointer mitkOutput = mitk::Image::New(); mitk::CastToMitkImage(output, mitkOutput); AddToDataStorage(mitkOutput, "mean_FA_skeletonised"); // Retrieve direction image needed later by the projection filter DirectionImageType::Pointer directionImg = skeletonizer->GetVectorImage(); // Calculate distance image DistanceMapFilterType::Pointer distanceMapFilter = DistanceMapFilterType::New(); distanceMapFilter->SetInput(output); distanceMapFilter->Update(); FloatImageType::Pointer distanceMap = distanceMapFilter->GetOutput(); if(m_Controls->m_OutputDistanceMap->isChecked()) { mitk::Image::Pointer mitkDistance = mitk::Image::New(); mitk::CastToMitkImage(distanceMap, mitkDistance); AddToDataStorage(mitkDistance, "distance map"); } // Do projection // Ask a threshold to create a skeleton mask double threshold = -1.0; while(threshold == -1.0) { threshold = QInputDialog::getDouble(m_Controls->m_Skeletonize, tr("Specify the FA threshold"), tr("Threshold:"), QLineEdit::Normal, 0.2); if(threshold < 0.0 || threshold > 1.0) { QMessageBox msgBox; msgBox.setText("Please choose a value between 0 and 1"); msgBox.exec(); threshold = -1.0; } } typedef itk::BinaryThresholdImageFilter ThresholdFilterType; ThresholdFilterType::Pointer thresholder = ThresholdFilterType::New(); thresholder->SetInput(output); thresholder->SetLowerThreshold(threshold); thresholder->SetUpperThreshold(std::numeric_limits::max()); thresholder->SetOutsideValue(0); thresholder->SetInsideValue(1); thresholder->Update(); CharImageType::Pointer thresholdedImg = thresholder->GetOutput(); if(m_Controls->m_OutputMask->isChecked()) { mitk::Image::Pointer mitkThresholded = mitk::Image::New(); mitk::CastToMitkImage(thresholdedImg, mitkThresholded); std::string maskName = "skeleton_mask_at_" + boost::lexical_cast(threshold); AddToDataStorage(mitkThresholded, maskName); } CharImageType::Pointer itkTubular = CharImageType::New(); mitk::CastToItkImage(tubular, itkTubular); ProjectionFilterType::Pointer projectionFilter = ProjectionFilterType::New(); projectionFilter->SetDistanceMap(distanceMap); projectionFilter->SetDirections(directionImg); projectionFilter->SetAllFA(allFA); projectionFilter->SetTube(itkTubular); projectionFilter->SetSkeleton(thresholdedImg); projectionFilter->Project(); Float4DImageType::Pointer projected = projectionFilter->GetProjections(); mitk::Image::Pointer mitkProjections = mitk::Image::New(); mitk::CastToMitkImage(projected, mitkProjections); AddToDataStorage(mitkProjections, "all_FA_projected"); } void QmitkTbssSkeletonizationView::AddToDataStorage(mitk::Image* img, std::string name) { mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "name", mitk::StringProperty::New(name) ); result->SetData( img ); // add new image to data storage and set as active to ease further processing GetDataStorage()->Add( result ); } template -void QmitkTbssSkeletonizationView::ConvertToItk(mitk::PixelType ptype, mitk::Image* image, Float4DImageType::Pointer output) +void QmitkTbssSkeletonizationView::ConvertToItk(mitk::PixelType, mitk::Image* image, Float4DImageType::Pointer output) { output = Float4DImageType::New(); mitk::BaseGeometry* geo = image->GetGeometry(); mitk::Vector3D mitkSpacing = geo->GetSpacing(); mitk::Point3D mitkOrigin = geo->GetOrigin(); Float4DImageType::SpacingType spacing; spacing[0] = mitkSpacing[0]; spacing[1] = mitkSpacing[1]; spacing[2] = mitkSpacing[2]; spacing[3] = 1.0; // todo: check if spacing has length 4 Float4DImageType::PointType origin; origin[0] = mitkOrigin[0]; origin[1] = mitkOrigin[1]; origin[2] = mitkOrigin[2]; origin[3] = 0; Float4DImageType::SizeType size; size[0] = image->GetDimension(0); size[1] = image->GetDimension(1); size[2] = image->GetDimension(2); size[3] = image->GetDimension(3); Float4DImageType::DirectionType dir; vtkLinearTransform* lin = geo->GetVtkTransform(); vtkMatrix4x4 *m = lin->GetMatrix(); dir.Fill(0.0); for(int x=0; x<3; x++) { for(int y=0; y<3; y++) { dir[x][y] = m->GetElement(x,y); } } dir[3][3] = 1; output->SetSpacing(spacing); output->SetOrigin(origin); output->SetRegions(size); output->SetDirection(dir); output->Allocate(); if(image->GetDimension() == 4) { - int timesteps = image->GetDimension(3); + unsigned int timesteps = image->GetDimension(3); try{ // REPLACE THIS METHODE()ConvertToItk) WITH mitk::CastToItk // iterate through the subjects and copy data to output - for(int t=0; t inAcc(image,image->GetVolumeData(t)); - for(int x=0; xGetDimension(0); x++) + for(unsigned int x=0; xGetDimension(0); x++) { - for(int y=0; yGetDimension(1); y++) + for(unsigned int y=0; yGetDimension(1); y++) { - for(int z=0; zGetDimension(2); z++) + for(unsigned int z=0; zGetDimension(2); z++) { itk::Index<3> ix = {x, y, z}; itk::Index<4> ix4 = {x, y, z, t}; output->SetPixel(ix4, inAcc.GetPixelByIndex(ix)); } } } } } - catch(std::exception & e) + catch(const std::exception & e) { MITK_INFO << e.what(); } } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsView.cpp index b2368f1c00..c263290d28 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsView.cpp @@ -1,1141 +1,1141 @@ /*=================================================================== 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 #include "QmitkTractbasedSpatialStatisticsView.h" #include "mitkDataNodeObject.h" #include // Qt #include #include #include #include #include #include #include #include #include "vtkPoints.h" #include #include const std::string QmitkTractbasedSpatialStatisticsView::VIEW_ID = "org.mitk.views.tractbasedspatialstatistics"; using namespace berry; QmitkTractbasedSpatialStatisticsView::QmitkTractbasedSpatialStatisticsView() : QmitkAbstractView() , m_Controls( 0 ) , m_Activated(false) { } QmitkTractbasedSpatialStatisticsView::~QmitkTractbasedSpatialStatisticsView() { } void QmitkTractbasedSpatialStatisticsView::PerformChange() { m_Controls->m_RoiPlotWidget->ModifyPlot(m_Controls->m_Segments->value(), m_Controls->m_Average->isChecked()); } void QmitkTractbasedSpatialStatisticsView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { //datamanager selection changed if (!this->IsActivated()) return; // Check which datatypes are selected in the datamanager and enable/disable widgets accordingly bool foundTbssRoi = false; bool foundTbss = false; bool found3dImage = false; bool found4dImage = false; bool foundFiberBundle = false; bool foundStartRoi = false; bool foundEndRoi = false; - mitk::TbssRoiImage* roiImage; - mitk::TbssImage* image; - mitk::Image* img; - mitk::FiberBundle* fib; - mitk::DataNode* start; - mitk::DataNode* end; + mitk::TbssRoiImage* roiImage = nullptr; + mitk::TbssImage* image = nullptr; + mitk::Image* img = nullptr; + mitk::FiberBundle* fib = nullptr; + mitk::DataNode* start = nullptr; + mitk::DataNode* end = nullptr; m_CurrentStartRoi = nullptr; m_CurrentEndRoi = nullptr; for (mitk::DataNode::Pointer node: nodes) { // only look at interesting types // check for valid data mitk::BaseData* nodeData = node->GetData(); if( nodeData ) { if(QString("TbssRoiImage").compare(nodeData->GetNameOfClass())==0) { foundTbssRoi = true; roiImage = static_cast(nodeData); } else if (QString("TbssImage").compare(nodeData->GetNameOfClass())==0) { foundTbss = true; image = static_cast(nodeData); } else if(QString("Image").compare(nodeData->GetNameOfClass())==0) { img = static_cast(nodeData); if(img->GetDimension() == 3) { found3dImage = true; } else if(img->GetDimension() == 4) { found4dImage = true; } } else if (QString("FiberBundle").compare(nodeData->GetNameOfClass())==0) { foundFiberBundle = true; fib = static_cast(nodeData); this->m_CurrentFiberNode = node; } if(QString("PlanarCircle").compare(nodeData->GetNameOfClass())==0) { if(!foundStartRoi) { start = node; this->m_CurrentStartRoi = node; foundStartRoi = true; } else { end = node; this->m_CurrentEndRoi = node; foundEndRoi = true; } } } } this->m_Controls->m_CreateRoi->setEnabled(found3dImage); this->m_Controls->m_ImportFsl->setEnabled(found4dImage); if(foundTbss && foundTbssRoi) { this->Plot(image, roiImage); } else if(found3dImage && foundFiberBundle && foundStartRoi && foundEndRoi) { this->PlotFiberBundle(fib, img, start, end); } else if(found3dImage && foundFiberBundle) { this->PlotFiberBundle(fib, img); } else if(foundTbss && foundStartRoi && foundEndRoi && foundFiberBundle) { this->PlotFiber4D(image, fib, start, end); } if(found3dImage) { this->InitPointsets(); } this->m_Controls->m_Cut->setEnabled(foundFiberBundle && foundStartRoi && foundEndRoi); this->m_Controls->m_SegmentLabel->setEnabled(foundFiberBundle && foundStartRoi && foundEndRoi && (found3dImage || foundTbss)); this->m_Controls->m_Segments->setEnabled(foundFiberBundle && foundStartRoi && foundEndRoi && (found3dImage || foundTbss)); this->m_Controls->m_Average->setEnabled(foundFiberBundle && foundStartRoi && foundEndRoi && found3dImage); } void QmitkTractbasedSpatialStatisticsView::InitPointsets() { // Check if PointSetStart exsits, if not create it. m_P1 = this->GetDataStorage()->GetNamedNode("PointSetNode"); if (m_PointSetNode) { //m_PointSetNode = dynamic_cast(m_P1->GetData()); return; } if ((!m_P1) || (!m_PointSetNode)) { // create new ones m_PointSetNode = mitk::PointSet::New(); m_P1 = mitk::DataNode::New(); m_P1->SetData( m_PointSetNode ); m_P1->SetProperty( "name", mitk::StringProperty::New( "PointSet" ) ); m_P1->SetProperty( "opacity", mitk::FloatProperty::New( 1 ) ); m_P1->SetProperty( "helper object", mitk::BoolProperty::New(true) ); // CHANGE if wanted m_P1->SetProperty( "pointsize", mitk::FloatProperty::New( 0.1 ) ); m_P1->SetColor( 1.0, 0.0, 0.0 ); this->GetDataStorage()->Add(m_P1); m_Controls->m_PointWidget->SetPointSetNode(m_P1); auto renderWindowPart = this->GetRenderWindowPart(OPEN); auto axialSnc = renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController(); auto sagittalSnc = renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController(); auto coronalSnc = renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController(); m_Controls->m_PointWidget->AddSliceNavigationController(axialSnc); m_Controls->m_PointWidget->AddSliceNavigationController(sagittalSnc); m_Controls->m_PointWidget->AddSliceNavigationController(coronalSnc); } } void QmitkTractbasedSpatialStatisticsView::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::QmitkTractbasedSpatialStatisticsViewControls; m_Controls->setupUi( parent ); this->CreateConnections(); } // Table for the FSL TBSS import m_GroupModel = new QmitkTbssTableModel(); m_Controls->m_GroupInfo->setModel(m_GroupModel); } void QmitkTractbasedSpatialStatisticsView::SetFocus() { m_Controls->m_AddGroup->setFocus(); } void QmitkTractbasedSpatialStatisticsView::Activated() { m_Activated = true; } void QmitkTractbasedSpatialStatisticsView::Deactivated() { m_Activated = false; } bool QmitkTractbasedSpatialStatisticsView::IsActivated() const { return m_Activated; } void QmitkTractbasedSpatialStatisticsView::Visible() { } void QmitkTractbasedSpatialStatisticsView::Hidden() { } void QmitkTractbasedSpatialStatisticsView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_CreateRoi), SIGNAL(clicked()), this, SLOT(CreateRoi()) ); connect( (QObject*)(m_Controls->m_ImportFsl), SIGNAL(clicked()), this, SLOT(TbssImport()) ); connect( (QObject*)(m_Controls->m_AddGroup), SIGNAL(clicked()), this, SLOT(AddGroup()) ); connect( (QObject*)(m_Controls->m_RemoveGroup), SIGNAL(clicked()), this, SLOT(RemoveGroup()) ); connect( (QObject*)(m_Controls->m_Clipboard), SIGNAL(clicked()), this, SLOT(CopyToClipboard()) ); connect( m_Controls->m_RoiPlotWidget->m_PlotPicker, SIGNAL(selected(const QPointF&)), SLOT(Clicked(const QPointF&) ) ); connect( m_Controls->m_RoiPlotWidget->m_PlotPicker, SIGNAL(moved(const QPointF&)), SLOT(Clicked(const QPointF&) ) ); connect( (QObject*)(m_Controls->m_Cut), SIGNAL(clicked()), this, SLOT(Cut()) ); connect( (QObject*)(m_Controls->m_Average), SIGNAL(stateChanged(int)), this, SLOT(PerformChange()) ); connect( (QObject*)(m_Controls->m_Segments), SIGNAL(valueChanged(int)), this, SLOT(PerformChange()) ); } } void QmitkTractbasedSpatialStatisticsView::CopyToClipboard() { if(m_Controls->m_RoiPlotWidget->IsPlottingFiber()) { // Working with fiber bundles std::vector > profiles = m_Controls->m_RoiPlotWidget->GetIndividualProfiles(); QString clipboardText; for (std::vector >::iterator it = profiles.begin(); it != profiles.end(); ++it) { for (std::vector::iterator it2 = (*it).begin(); it2 != (*it).end(); ++it2) { clipboardText.append(QString("%1 \t").arg(*it2)); } clipboardText.append(QString("\n")); } if(m_Controls->m_Average->isChecked()) { std::vector averages = m_Controls->m_RoiPlotWidget->GetAverageProfile(); clipboardText.append(QString("\nAverage\n")); for (std::vector::iterator it2 = averages.begin(); it2 != averages.end(); ++it2) { clipboardText.append(QString("%1 \t").arg(*it2)); } } QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); } else{ // Working with TBSS Data if(m_Controls->m_Average->isChecked()) { std::vector > vals = m_Controls->m_RoiPlotWidget->GetVals(); QString clipboardText; for (std::vector >::iterator it = vals.begin(); it != vals.end(); ++it) { for (std::vector::iterator it2 = (*it).begin(); it2 != (*it).end(); ++it2) { clipboardText.append(QString("%1 \t").arg(*it2)); double d = *it2; std::cout << d <setText(clipboardText, QClipboard::Clipboard); } else { std::vector > vals = m_Controls->m_RoiPlotWidget->GetIndividualProfiles(); QString clipboardText; for (std::vector >::iterator it = vals.begin(); it != vals.end(); ++it) { for (std::vector::iterator it2 = (*it).begin(); it2 != (*it).end(); ++it2) { clipboardText.append(QString("%1 \t").arg(*it2)); double d = *it2; std::cout << d <setText(clipboardText, QClipboard::Clipboard); } } } void QmitkTractbasedSpatialStatisticsView::RemoveGroup() { QTableView *temp = static_cast(m_Controls->m_GroupInfo); QItemSelectionModel *selectionModel = temp->selectionModel(); QModelIndexList indices = selectionModel->selectedRows(); QModelIndex index; foreach(index, indices) { int row = index.row(); m_GroupModel->removeRows(row, 1, QModelIndex()); } } void QmitkTractbasedSpatialStatisticsView::AddGroup() { QString group("Group"); int number = 0; QPair pair(group, number); QList< QPair >list = m_GroupModel->getList(); if(!list.contains(pair)) { m_GroupModel->insertRows(0, 1, QModelIndex()); QModelIndex index = m_GroupModel->index(0, 0, QModelIndex()); m_GroupModel->setData(index, group, Qt::EditRole); index = m_GroupModel->index(0, 1, QModelIndex()); m_GroupModel->setData(index, number, Qt::EditRole); } } void QmitkTractbasedSpatialStatisticsView::TbssImport() { // Read groups from the interface mitk::TbssImporter::Pointer importer = mitk::TbssImporter::New(); QList< QPair >list = m_GroupModel->getList(); if(list.size() == 0) { QMessageBox msgBox; msgBox.setText("No study group information has been set yet."); msgBox.exec(); return; } std::vector < std::pair > groups; for(int i=0; i pair = list.at(i); std::string s = pair.first.toStdString(); int n = pair.second; std::pair p; p.first = s; p.second = n; groups.push_back(p); } importer->SetGroupInfo(groups); std::string minfo = m_Controls->m_MeasurementInfo->text().toStdString(); importer->SetMeasurementInfo(minfo); std::string name = ""; QList nodes = this->GetDataManagerSelection(); for (auto node: nodes) { if(QString("Image").compare(node->GetData()->GetNameOfClass())==0) { mitk::Image* img = static_cast(node->GetData()); if(img->GetDimension() == 4) { importer->SetImportVolume(img); name = node->GetName(); } } } mitk::TbssImage::Pointer tbssImage; tbssImage = importer->Import(); name += "_tbss"; AddTbssToDataStorage(tbssImage, name); } void QmitkTractbasedSpatialStatisticsView::AddTbssToDataStorage(mitk::Image* image, std::string name) { mitk::LevelWindow levelwindow; levelwindow.SetAuto( image ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); levWinProp->SetLevelWindow( levelwindow ); mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "name", mitk::StringProperty::New(name) ); result->SetData( image ); result->SetProperty( "levelwindow", levWinProp ); // add new image to data storage and set as active to ease further processing GetDataStorage()->Add( result ); // show the results mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkTractbasedSpatialStatisticsView::Clicked(const QPointF& pos) { int index = (int)pos.x(); if(m_Roi.size() > 0 && m_CurrentGeometry != nullptr && !m_Controls->m_RoiPlotWidget->IsPlottingFiber() ) { index = std::min( (int)m_Roi.size()-1, std::max(0, index) ); itk::Index<3> ix = m_Roi.at(index); mitk::Vector3D i; i[0] = ix[0]; i[1] = ix[1]; i[2] = ix[2]; mitk::Vector3D w; m_CurrentGeometry->IndexToWorld(i, w); mitk::Point3D origin = m_CurrentGeometry->GetOrigin(); mitk::Point3D p; p[0] = w[0] + origin[0]; p[1] = w[1] + origin[1]; p[2] = w[2] + origin[2]; this->GetRenderWindowPart()->SetSelectedPosition(p); m_Controls->m_RoiPlotWidget->drawBar(index); } else if(m_Controls->m_RoiPlotWidget->IsPlottingFiber() ) { mitk::Point3D point = m_Controls->m_RoiPlotWidget->GetPositionInWorld(index); this->GetRenderWindowPart()->SetSelectedPosition(point); } } void QmitkTractbasedSpatialStatisticsView::Cut() { mitk::BaseData* fibData = m_CurrentFiberNode->GetData(); mitk::FiberBundle* fib = static_cast(fibData); mitk::PlaneGeometry* startGeometry2D = const_cast(dynamic_cast(m_CurrentStartRoi->GetData())->GetPlaneGeometry()); mitk::PlaneGeometry* endGeometry2D = const_cast(dynamic_cast(m_CurrentEndRoi->GetData())->GetPlaneGeometry()); mitk::Point3D startCenter = dynamic_cast(m_CurrentStartRoi->GetData())->GetWorldControlPoint(0); //center Point of start roi mitk::Point3D endCenter = dynamic_cast(m_CurrentEndRoi->GetData())->GetWorldControlPoint(0); //center Point of end roi mitk::FiberBundle::Pointer inStart = fib->ExtractFiberSubset(m_CurrentStartRoi, nullptr); mitk::FiberBundle::Pointer inBoth = inStart->ExtractFiberSubset(m_CurrentEndRoi, nullptr); int num = inBoth->GetNumFibers(); vtkSmartPointer fiberPolyData = inBoth->GetFiberPolyData(); vtkCellArray* lines = fiberPolyData->GetLines(); lines->InitTraversal(); // initialize new vtk polydata vtkSmartPointer points = vtkSmartPointer::New(); vtkSmartPointer polyData = vtkSmartPointer::New(); vtkSmartPointer cells = vtkSmartPointer::New(); int pointIndex=0; // find start and endpoint for( int fiberID( 0 ); fiberID < num; fiberID++ ) { vtkIdType numPointsInCell(0); vtkIdType* pointsInCell(nullptr); lines->GetNextCell ( numPointsInCell, pointsInCell ); int startId = 0; int endId = 0; float minDistStart = std::numeric_limits::max(); float minDistEnd = std::numeric_limits::max(); vtkSmartPointer polyLine = vtkSmartPointer::New(); int lineIndex=0; for( int pointInCellID( 0 ); pointInCellID < numPointsInCell ; pointInCellID++) { double *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); mitk::Point3D point; point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; float distanceToStart = point.EuclideanDistanceTo(startCenter); float distanceToEnd = point.EuclideanDistanceTo(endCenter); if(distanceToStart < minDistStart) { minDistStart = distanceToStart; startId = pointInCellID; } if(distanceToEnd < minDistEnd) { minDistEnd = distanceToEnd; endId = pointInCellID; } } /* We found the start and end points of of the part that should be plottet for the current fiber. now we need to plot them. If the endId is smaller than the startId the plot order must be reversed*/ if(startId < endId) { double *p = fiberPolyData->GetPoint( pointsInCell[ startId ] ); mitk::Vector3D p0; p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; p = fiberPolyData->GetPoint( pointsInCell[ startId+1 ] ); mitk::Vector3D p1; p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; // Check if p and p2 are both on the same side of the plane mitk::Vector3D normal = startGeometry2D->GetNormal(); mitk::Point3D pStart; pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2]; bool startOnPositive = startGeometry2D->IsAbove(pStart); mitk::Point3D pSecond; pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2]; bool secondOnPositive = startGeometry2D->IsAbove(pSecond); // Calculate intersection with the plane mitk::Vector3D onPlane; onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2]; if(! (secondOnPositive ^ startOnPositive) ) { /* startId and startId+1 lie on the same side of the plane, so we need need startId-1 to calculate the intersection with the planar figure*/ p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; } double d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); mitk::Vector3D newPoint = (p0-p1); newPoint[0] = d*newPoint[0] + p0[0]; newPoint[1] = d*newPoint[1] + p0[1]; newPoint[2] = d*newPoint[2] + p0[2]; double insertPoint[3]; insertPoint[0] = newPoint[0]; insertPoint[1] = newPoint[1]; insertPoint[2] = newPoint[2]; // First insert the intersection with the start roi points->InsertNextPoint(insertPoint); polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; if(! (secondOnPositive ^ startOnPositive) ) { /* StartId and startId+1 lie on the same side of the plane so startId is also part of the ROI*/ double *start = fiberPolyData->GetPoint( pointsInCell[startId] ); points->InsertNextPoint(start); polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; } // Insert the rest up and to including endId-1 for( int pointInCellID( startId+1 ); pointInCellID < endId ; pointInCellID++) { // create new polyline for new polydata double *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); points->InsertNextPoint(p); // add point to line polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; } /* endId must be included if endId and endId-1 lie on the same side of the plane defined by endRoi*/ p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; mitk::Point3D pLast; pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2]; mitk::Point3D pBeforeLast; pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2]; bool lastOnPositive = endGeometry2D->IsAbove(pLast); bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast); normal = endGeometry2D->GetNormal(); onPlane[0] = endCenter[0]; onPlane[1] = endCenter[1]; onPlane[2] = endCenter[2]; if(! (lastOnPositive ^ secondLastOnPositive) ) { /* endId and endId-1 lie on the same side of the plane, so we need need endId+1 to calculate the intersection with the planar figure. this should exist since we know that the fiber crosses the planar figure endId is part of the roi so can also be included here*/ p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; double *end = fiberPolyData->GetPoint( pointsInCell[endId] ); points->InsertNextPoint(end); polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; } d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); newPoint = (p0-p1); newPoint[0] = d*newPoint[0] + p0[0]; newPoint[1] = d*newPoint[1] + p0[1]; newPoint[2] = d*newPoint[2] + p0[2]; insertPoint[0] = newPoint[0]; insertPoint[1] = newPoint[1]; insertPoint[2] = newPoint[2]; //Insert the Last Point (intersection with the end roi) points->InsertNextPoint(insertPoint); polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; } // Need to reverse walking order else{ double *p = fiberPolyData->GetPoint( pointsInCell[ startId ] ); mitk::Vector3D p0; p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); mitk::Vector3D p1; p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; // Check if p and p2 are both on the same side of the plane mitk::Vector3D normal = startGeometry2D->GetNormal(); mitk::Point3D pStart; pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2]; bool startOnPositive = startGeometry2D->IsAbove(pStart); mitk::Point3D pSecond; pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2]; bool secondOnPositive = startGeometry2D->IsAbove(pSecond); // Calculate intersection with the plane mitk::Vector3D onPlane; onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2]; if(! (secondOnPositive ^ startOnPositive) ) { /* startId and startId-1 lie on the same side of the plane, so we need need startId+1 to calculate the intersection with the planar figure*/ p = fiberPolyData->GetPoint( pointsInCell[ startId+1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; } double d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); mitk::Vector3D newPoint = (p0-p1); newPoint[0] = d*newPoint[0] + p0[0]; newPoint[1] = d*newPoint[1] + p0[1]; newPoint[2] = d*newPoint[2] + p0[2]; double insertPoint[3]; insertPoint[0] = newPoint[0]; insertPoint[1] = newPoint[1]; insertPoint[2] = newPoint[2]; // First insert the intersection with the start roi points->InsertNextPoint(insertPoint); polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; if(! (secondOnPositive ^ startOnPositive) ) { /* startId and startId-1 lie on the same side of the plane so endId is also part of the ROI*/ double *start = fiberPolyData->GetPoint( pointsInCell[startId] ); points->InsertNextPoint(start); polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; } // Insert the rest up and to including endId-1 for( int pointInCellID( startId-1 ); pointInCellID > endId ; pointInCellID--) { // create new polyline for new polydata double *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); points->InsertNextPoint(p); // add point to line polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; } /* startId must be included if startId and startId+ lie on the same side of the plane defined by endRoi*/ p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; mitk::Point3D pLast; pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2]; bool lastOnPositive = endGeometry2D->IsAbove(pLast); mitk::Point3D pBeforeLast; pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2]; bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast); onPlane[0] = endCenter[0]; onPlane[1] = endCenter[1]; onPlane[2] = endCenter[2]; if(! (lastOnPositive ^ secondLastOnPositive) ) { /* endId and endId+1 lie on the same side of the plane, so we need need endId-1 to calculate the intersection with the planar figure. this should exist since we know that the fiber crosses the planar figure*/ p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] ); p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; /* endId and endId+1 lie on the same side of the plane so startId is also part of the ROI*/ double *end = fiberPolyData->GetPoint( pointsInCell[endId] ); points->InsertNextPoint(end); polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; } d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); newPoint = (p0-p1); newPoint[0] = d*newPoint[0] + p0[0]; newPoint[1] = d*newPoint[1] + p0[1]; newPoint[2] = d*newPoint[2] + p0[2]; insertPoint[0] = newPoint[0]; insertPoint[1] = newPoint[1]; insertPoint[2] = newPoint[2]; //Insert the Last Point (intersection with the end roi) points->InsertNextPoint(insertPoint); polyLine->GetPointIds()->InsertId(lineIndex,pointIndex); lineIndex++; pointIndex++; } // add polyline to vtk cell array cells->InsertNextCell(polyLine); } // Add the points to the dataset polyData->SetPoints(points); // Add the lines to the dataset polyData->SetLines(cells); mitk::FiberBundle::Pointer cutBundle = mitk::FiberBundle::New(polyData); mitk::DataNode::Pointer cutNode = mitk::DataNode::New(); cutNode->SetData(cutBundle); std::string name = "fiberCut"; cutNode->SetName(name); GetDataStorage()->Add(cutNode); } void QmitkTractbasedSpatialStatisticsView::CreateRoi() { bool ok; double threshold = QInputDialog::getDouble(m_Controls->m_CreateRoi, tr("Set an FA threshold"), tr("Threshold:"), 0.2, 0.0, 1.0, 2, &ok); if(!ok) return; mitk::Image::Pointer image; QList nodes = this->GetDataManagerSelection(); for (auto node: nodes) { if(QString("Image").compare(node->GetData()->GetNameOfClass())==0) { mitk::Image* img = static_cast(node->GetData()); if(img->GetDimension() == 3) { image = img; } } } if(image.IsNull()) { return; } mitk::TractAnalyzer analyzer; analyzer.SetInputImage(image); analyzer.SetThreshold(threshold); m_PointSetNode = this->m_Controls->m_PointWidget->GetPointSet(); // Set Pointset to analyzer analyzer.SetPointSet(m_PointSetNode); // Run Analyzer try { analyzer.MakeRoi(); } catch (const mitk::Exception& e) { QMessageBox msgBox; msgBox.setText(QString::fromStdString(e.what())); msgBox.exec(); } // Obtain tbss roi image from analyzer mitk::TbssRoiImage::Pointer tbssRoi = analyzer.GetRoiImage(); tbssRoi->SetStructure(m_Controls->m_Structure->text().toStdString()); // get path description and set to interface std::string pathDescription = analyzer.GetPathDescription(); m_Controls->m_PathTextEdit->setPlainText(QString(pathDescription.c_str())); // Add roi image to datastorage AddTbssToDataStorage(tbssRoi, m_Controls->m_RoiName->text().toStdString()); } void QmitkTractbasedSpatialStatisticsView::PlotFiber4D(mitk::TbssImage* image, mitk::FiberBundle* fib, mitk::DataNode* startRoi, mitk::DataNode* endRoi) { if(m_Controls->m_TabWidget->currentWidget() == m_Controls->m_MeasureTAB) { m_CurrentGeometry = image->GetGeometry(); m_Controls->m_RoiPlotWidget->SetGroups(image->GetGroupInfo()); m_Controls->m_RoiPlotWidget->SetProjections(image->GetImage()); m_Controls->m_RoiPlotWidget->SetMeasure( image->GetMeasurementInfo() ); m_Controls->m_RoiPlotWidget->PlotFiber4D(image, fib, startRoi, endRoi, m_Controls->m_Segments->value()); } } void QmitkTractbasedSpatialStatisticsView:: PlotFiberBundle(mitk::FiberBundle *fib, mitk::Image* img, mitk::DataNode* startRoi, mitk::DataNode* endRoi) { bool avg = m_Controls->m_Average->isChecked(); int segments = m_Controls->m_Segments->value(); m_Controls->m_RoiPlotWidget->PlotFiberBetweenRois(fib, img, startRoi ,endRoi, avg, segments); m_Controls->m_RoiPlotWidget->SetPlottingFiber(true); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } void QmitkTractbasedSpatialStatisticsView::Plot(mitk::TbssImage* image, mitk::TbssRoiImage* roiImage) { if(m_Controls->m_TabWidget->currentWidget() == m_Controls->m_MeasureTAB) { std::vector< itk::Index<3> > roi = roiImage->GetRoi(); m_Roi = roi; m_CurrentGeometry = image->GetGeometry(); std::string structure = roiImage->GetStructure(); m_Controls->m_RoiPlotWidget->SetGroups(image->GetGroupInfo()); m_Controls->m_RoiPlotWidget->SetProjections(image->GetImage()); m_Controls->m_RoiPlotWidget->SetRoi(roi); m_Controls->m_RoiPlotWidget->SetStructure(structure); m_Controls->m_RoiPlotWidget->SetMeasure( image->GetMeasurementInfo() ); m_Controls->m_RoiPlotWidget->DrawProfiles(); } m_Controls->m_RoiPlotWidget->SetPlottingFiber(false); } diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.cpp b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.cpp index 9f1092ab0b..1c06fa010c 100644 --- a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.cpp @@ -1,391 +1,391 @@ /*=================================================================== 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 "DoseVisualizationPreferencePage.h" #include "mitkRTUIConstants.h" #include #include #include #include #include #include #include #include #include #include #include "mitkIsoLevelsGenerator.h" #include "org_mitk_gui_qt_dosevisualization_Activator.h" DoseVisualizationPreferencePage::DoseVisualizationPreferencePage() : m_MainControl(0), m_Controls(0), m_referenceDoseChanged(false), m_presetMapChanged(false), m_globalVisChanged(false) { } DoseVisualizationPreferencePage::~DoseVisualizationPreferencePage() { delete m_LevelSetModel; delete m_DoseColorDelegate; delete m_DoseValueDelegate; delete m_DoseVisualDelegate; delete m_Controls; } void DoseVisualizationPreferencePage::Init(berry::IWorkbench::Pointer ) { } void DoseVisualizationPreferencePage::CreateQtControl(QWidget* parent) { berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); m_DoseVisNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); m_LevelSetModel = new QmitkIsoDoseLevelSetModel(this); m_DoseColorDelegate = new QmitkDoseColorDelegate(this); m_DoseValueDelegate = new QmitkDoseValueDelegate(this); m_DoseVisualDelegate = new QmitkDoseVisualStyleDelegate(this); m_MainControl = new QWidget(parent); m_Controls = new Ui::DoseVisualizationPreferencePageControls; m_Controls->setupUi( m_MainControl ); this->m_Controls->isoLevelSetView->setModel(m_LevelSetModel); this->m_Controls->isoLevelSetView->setItemDelegateForColumn(0,m_DoseColorDelegate); this->m_Controls->isoLevelSetView->setItemDelegateForColumn(1,m_DoseValueDelegate); this->m_Controls->isoLevelSetView->setItemDelegateForColumn(2,m_DoseVisualDelegate); this->m_Controls->isoLevelSetView->setItemDelegateForColumn(3,m_DoseVisualDelegate); this->m_Controls->isoLevelSetView->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_Controls->spinReferenceDose, SIGNAL(valueChanged(double)), m_LevelSetModel, SLOT(setReferenceDose(double))); connect(m_Controls->spinReferenceDose, SIGNAL(valueChanged(double)), this, SLOT(OnReferenceDoseChanged(double))); connect(m_Controls->checkGlobalSync, SIGNAL(toggled(bool)), m_Controls->spinReferenceDose, SLOT(setEnabled(bool))); connect(m_Controls->radioAbsDose, SIGNAL(toggled(bool)), m_LevelSetModel, SLOT(setShowAbsoluteDose(bool))); connect(m_Controls->isoLevelSetView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnShowContextMenuIsoSet(const QPoint&))); connect(m_Controls->listPresets, SIGNAL(currentItemChanged ( QListWidgetItem *, QListWidgetItem *)), this, SLOT(OnCurrentItemChanged ( QListWidgetItem *, QListWidgetItem *))); connect(m_Controls->btnAddPreset, SIGNAL(clicked(bool)), this, SLOT(OnAddPresetClicked(bool))); connect(m_Controls->btnDelPreset, SIGNAL(clicked(bool)), this, SLOT(OnDelPresetClicked(bool))); connect(m_Controls->btnResetPreset, SIGNAL(clicked(bool)), this, SLOT(OnResetPresetClicked(bool))); connect(m_Controls->btnDelLevel, SIGNAL(clicked(bool)), this, SLOT(OnDelLevelClicked(bool))); connect(m_Controls->btnAddLevel, SIGNAL(clicked(bool)), this, SLOT(OnAddLevelClicked(bool))); connect(m_Controls->checkGlobalVisColorWash, SIGNAL(toggled(bool)), this, SLOT(OnGlobalVisChanged(bool))); connect(m_Controls->checkGlobalVisIsoLine, SIGNAL(toggled(bool)), this, SLOT(OnGlobalVisChanged(bool))); this->Update(); } QWidget* DoseVisualizationPreferencePage::GetQtControl() const { return m_MainControl; } bool DoseVisualizationPreferencePage::PerformOk() { m_DoseVisNode->PutBool(mitk::RTUIConstants::DOSE_DISPLAY_ABSOLUTE_ID.c_str(),m_Controls->radioAbsDose->isChecked()); m_DoseVisNode->PutBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_COLORWASH_ID.c_str(),m_Controls->checkGlobalVisColorWash->isChecked()); m_DoseVisNode->PutBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_ISOLINES_ID.c_str(),m_Controls->checkGlobalVisIsoLine->isChecked()); m_DoseVisNode->PutDouble(mitk::RTUIConstants::REFERENCE_DOSE_ID.c_str(),m_Controls->spinReferenceDose->value()); m_DoseVisNode->PutBool(mitk::RTUIConstants::GLOBAL_REFERENCE_DOSE_SYNC_ID.c_str(), m_Controls->checkGlobalSync->isChecked()); mitk::StorePresetsMap(this->m_Presets); if (this->m_Presets.find(this->m_selectedPresetName)==this->m_Presets.end()) { //the preset currently selected in the application is not available any more. Change it to a valid one. mitk::SetSelectedPresetName(this->m_Presets.begin()->first); } if (this->m_LevelSetModel->isModified()) { this->m_presetMapChanged = true; } if (m_referenceDoseChanged) { mitk::SignalReferenceDoseChange(m_Controls->checkGlobalSync->isChecked(), m_Controls->spinReferenceDose->value(), mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()); } if (m_presetMapChanged) { mitk::SignalPresetMapChange(mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()); } if(m_globalVisChanged) { mitk::SignalGlobalVisChange(m_Controls->checkGlobalSync->isChecked(), m_Controls->checkGlobalVisIsoLine->isChecked(), m_Controls->checkGlobalVisColorWash->isChecked(), mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()); } return true; } void DoseVisualizationPreferencePage::PerformCancel() { } void DoseVisualizationPreferencePage::Update() { m_Controls->checkGlobalVisColorWash->setChecked(m_DoseVisNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_COLORWASH_ID.c_str(), true)); m_Controls->checkGlobalVisIsoLine->setChecked(m_DoseVisNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_ISOLINES_ID.c_str(), true)); m_Controls->radioAbsDose->setChecked(m_DoseVisNode->GetBool(mitk::RTUIConstants::DOSE_DISPLAY_ABSOLUTE_ID.c_str(), true)); m_Controls->radioRelDose->setChecked(!(m_DoseVisNode->GetBool(mitk::RTUIConstants::DOSE_DISPLAY_ABSOLUTE_ID.c_str(), false))); m_Controls->spinReferenceDose->setValue(m_DoseVisNode->GetDouble(mitk::RTUIConstants::REFERENCE_DOSE_ID.c_str(), mitk::RTUIConstants::DEFAULT_REFERENCE_DOSE_VALUE)); m_Controls->checkGlobalSync->setChecked(m_DoseVisNode->GetBool(mitk::RTUIConstants::GLOBAL_REFERENCE_DOSE_SYNC_ID.c_str(), true)); m_referenceDoseChanged = false; m_presetMapChanged = false; m_globalVisChanged = false; this->m_Presets = mitk::LoadPresetsMap(); if(m_Presets.empty()) return; this->m_selectedPresetName = mitk::GetSelectedPresetName(); UpdatePresetsWidgets(); } mitk::IsoDoseLevelSet* DoseVisualizationPreferencePage::GetSelectedIsoLevelSet() { QListWidgetItem* selectedItem = m_Controls->listPresets->currentItem(); mitk::IsoDoseLevelSet::Pointer result; if (selectedItem) { result = m_Presets[selectedItem->text().toStdString()]; } return result; } void DoseVisualizationPreferencePage::UpdateLevelSetWidgets() { this->m_Controls->btnAddLevel->setEnabled(this->GetSelectedIsoLevelSet()!=nullptr); QModelIndex selectedIndex = m_Controls->isoLevelSetView->currentIndex(); this->m_Controls->btnDelLevel->setEnabled(this->GetSelectedIsoLevelSet()!=nullptr && selectedIndex.isValid()); } void DoseVisualizationPreferencePage::UpdatePresetsWidgets() { m_Controls->listPresets->clear(); QListWidgetItem* selectedItem = nullptr; for (PresetMapType::iterator pos = m_Presets.begin(); pos != m_Presets.end(); ++pos) { QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(pos->first)); if (!selectedItem) { selectedItem = item; } m_Controls->listPresets->addItem(item); } if (selectedItem) { m_Controls->listPresets->setCurrentItem(selectedItem); } if (this->m_LevelSetModel->isModified()) { this->m_presetMapChanged = true; } this->m_LevelSetModel->setIsoDoseLevelSet(this->GetSelectedIsoLevelSet()); m_Controls->btnDelPreset->setEnabled((m_Controls->listPresets->currentItem() != nullptr) && (m_Controls->listPresets->count()>1)); } -void DoseVisualizationPreferencePage::OnCurrentItemChanged ( QListWidgetItem * currentItem, QListWidgetItem * previousItem) +void DoseVisualizationPreferencePage::OnCurrentItemChanged (QListWidgetItem*, QListWidgetItem*) { this->m_LevelSetModel->setIsoDoseLevelSet(this->GetSelectedIsoLevelSet()); } void DoseVisualizationPreferencePage::OnShowContextMenuIsoSet(const QPoint& pos) { QPoint globalPos = m_Controls->isoLevelSetView->viewport()->mapToGlobal(pos); QModelIndex selectedIndex = m_Controls->isoLevelSetView->currentIndex(); QMenu viewMenu; QAction* addLevelAct = viewMenu.addAction("Add new level"); QAction* delLevelAct = viewMenu.addAction("Delete selected level"); delLevelAct->setEnabled(selectedIndex.isValid()); viewMenu.addSeparator(); QAction* invertIsoLineAct = viewMenu.addAction("Invert iso line visibility"); QAction* activateIsoLineAct = viewMenu.addAction("Activate all iso lines"); QAction* deactivateIsoLineAct = viewMenu.addAction("Deactivate all iso lines"); viewMenu.addSeparator(); QAction* invertColorWashAct = viewMenu.addAction("Invert color wash visibility"); QAction* activateColorWashAct = viewMenu.addAction("Activate all color wash levels"); QAction* deactivateColorWashAct = viewMenu.addAction("Deactivate all color wash levels"); viewMenu.addSeparator(); QAction* swapAct = viewMenu.addAction("Swap iso line/color wash visibility"); QAction* selectedItem = viewMenu.exec(globalPos); if (selectedItem == invertIsoLineAct) { this->m_LevelSetModel->invertVisibilityIsoLines(); } else if (selectedItem == activateIsoLineAct) { this->m_LevelSetModel->switchVisibilityIsoLines(true); } else if (selectedItem == deactivateIsoLineAct) { this->m_LevelSetModel->switchVisibilityIsoLines(false); } else if (selectedItem == invertColorWashAct) { this->m_LevelSetModel->invertVisibilityColorWash(); } else if (selectedItem == activateColorWashAct) { this->m_LevelSetModel->switchVisibilityColorWash(true); } else if (selectedItem == deactivateColorWashAct) { this->m_LevelSetModel->switchVisibilityColorWash(false); } else if (selectedItem == swapAct) { this->m_LevelSetModel->swapVisibility(); } else if (selectedItem == addLevelAct) { this->m_LevelSetModel->addLevel(); } else if (selectedItem == delLevelAct) { this->m_LevelSetModel->deleteLevel(selectedIndex); } } -void DoseVisualizationPreferencePage::OnAddPresetClicked(bool checked) +void DoseVisualizationPreferencePage::OnAddPresetClicked(bool) { bool done = false; QString name = tr("new_preset"); while (!done) { bool ok; name = QInputDialog::getText(m_MainControl, tr("Define name of new preset."), tr("Preset name:"), QLineEdit::Normal, name, &ok); if (!ok) { return; //cancled by user; } bool uniqueName = m_Presets.find(name.toStdString()) == m_Presets.end(); if (!uniqueName) { QMessageBox box; box.setText(tr("New preset name is not unique. Please, choose another one.")); box.exec(); } bool validName = name.indexOf(tr("/")) ==-1; if (!validName) { QMessageBox box; box.setText(tr("New preset name is not valid. Please don't use \"/\".")); box.exec(); } done = uniqueName && validName; } mitk::IsoDoseLevelSet::Pointer newSet = mitk::GeneratIsoLevels_Virtuos(); m_Presets.insert(std::make_pair(name.toStdString(),newSet)); m_presetMapChanged = true; UpdatePresetsWidgets(); } -void DoseVisualizationPreferencePage::OnDelPresetClicked(bool checked) +void DoseVisualizationPreferencePage::OnDelPresetClicked(bool) { QListWidgetItem* selectedItem = m_Controls->listPresets->currentItem(); if (selectedItem) { if (m_Controls->listPresets->count() > 1) { m_Presets.erase(selectedItem->text().toStdString()); m_presetMapChanged = true; this->UpdatePresetsWidgets(); } } } -void DoseVisualizationPreferencePage::OnResetPresetClicked(bool checked) +void DoseVisualizationPreferencePage::OnResetPresetClicked(bool) { QMessageBox box; box.setText("Do you want to reset the presets?"); box.setInformativeText("If you reset the presets. All user defined presets will be removed and the default presets will be loaded."); box.setStandardButtons(QMessageBox::Yes | QMessageBox::No); box.setDefaultButton(QMessageBox::No); int ret = box.exec(); if (ret == QMessageBox::Yes) { mitk::IsoDoseLevelSet::Pointer newSet = mitk::GeneratIsoLevels_Virtuos(); m_Presets.clear(); m_Presets.insert(std::make_pair("Virtuos",newSet)); m_presetMapChanged = true; UpdatePresetsWidgets(); } } -void DoseVisualizationPreferencePage::OnAddLevelClicked(bool checked) +void DoseVisualizationPreferencePage::OnAddLevelClicked(bool) { this->m_LevelSetModel->addLevel(); } -void DoseVisualizationPreferencePage::OnDelLevelClicked(bool checked) +void DoseVisualizationPreferencePage::OnDelLevelClicked(bool) { QModelIndex selectedIndex = m_Controls->isoLevelSetView->currentIndex(); if (!selectedIndex.isValid()) { selectedIndex = m_Controls->isoLevelSetView->indexAt(QPoint(1,1)); } this->m_LevelSetModel->deleteLevel(selectedIndex); } -void DoseVisualizationPreferencePage::OnReferenceDoseChanged(double dose) +void DoseVisualizationPreferencePage::OnReferenceDoseChanged(double) { this->m_referenceDoseChanged = true; } -void DoseVisualizationPreferencePage::OnGlobalVisChanged(bool vis) +void DoseVisualizationPreferencePage::OnGlobalVisChanged(bool) { this->m_globalVisChanged = true; } diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.cpp b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.cpp index e4e94787de..4570726c07 100644 --- a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.cpp +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.cpp @@ -1,750 +1,748 @@ /*=================================================================== 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. ===================================================================*/ // Qt #include #include // Blueberry #include #include // MITK #include #include #include #include // Qmitk #include "RTDoseVisualizer.h" #include #include #include #include #include #include #include #include #include #include #include "org_mitk_gui_qt_dosevisualization_Activator.h" #include #include #include #include "QmitkRenderWindow.h" #include "vtkDecimatePro.h" const std::string RTDoseVisualizer::VIEW_ID = "org.mitk.views.rt.dosevisualization"; RTDoseVisualizer::RTDoseVisualizer() { m_selectedNode = nullptr; m_selectedPresetName = ""; m_internalUpdate = false; m_PrescribedDose_Data = 0.0; m_freeIsoValuesCount = 0; } RTDoseVisualizer::~RTDoseVisualizer() { delete m_LevelSetModel; delete m_DoseColorDelegate; delete m_DoseValueDelegate; delete m_DoseVisualDelegate; } void RTDoseVisualizer::SetFocus(){} void RTDoseVisualizer::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); m_LevelSetModel = new QmitkIsoDoseLevelSetModel(this); m_LevelSetModel->setVisibilityEditOnly(true); m_DoseColorDelegate = new QmitkDoseColorDelegate(this); m_DoseValueDelegate = new QmitkDoseValueDelegate(this); m_DoseVisualDelegate = new QmitkDoseVisualStyleDelegate(this); this->UpdateByPreferences(); this->ActualizeIsoLevelsForAllDoseDataNodes(); this->ActualizeReferenceDoseForAllDoseDataNodes(); this->ActualizeDisplayStyleForAllDoseDataNodes(); this->m_Controls.isoLevelSetView->setModel(m_LevelSetModel); this->m_Controls.isoLevelSetView->setItemDelegateForColumn(0,m_DoseColorDelegate); this->m_Controls.isoLevelSetView->setItemDelegateForColumn(1,m_DoseValueDelegate); this->m_Controls.isoLevelSetView->setItemDelegateForColumn(2,m_DoseVisualDelegate); this->m_Controls.isoLevelSetView->setItemDelegateForColumn(3,m_DoseVisualDelegate); this->m_Controls.isoLevelSetView->setContextMenuPolicy(Qt::CustomContextMenu); this->m_Controls.btnRemoveFreeValue->setDisabled(true); this->m_Controls.doseBtn->setVisible(false); connect(m_Controls.spinReferenceDose, SIGNAL(valueChanged(double)), this, SLOT(OnReferenceDoseChanged(double))); connect(m_Controls.spinReferenceDose, SIGNAL(valueChanged(double)), m_LevelSetModel, SLOT(setReferenceDose(double))); connect(m_Controls.radioAbsDose, SIGNAL(toggled(bool)), m_LevelSetModel, SLOT(setShowAbsoluteDose(bool))); connect(m_Controls.radioAbsDose, SIGNAL(toggled(bool)), this, SLOT(OnAbsDoseToggled(bool))); connect(m_Controls.btnAddFreeValue, SIGNAL(clicked()), this, SLOT(OnAddFreeValueClicked())); connect(m_Controls.btnRemoveFreeValue, SIGNAL(clicked()), this, SLOT(OnRemoveFreeValueClicked())); connect(m_Controls.checkGlobalVisColorWash, SIGNAL(toggled(bool)), this, SLOT(OnGlobalVisColorWashToggled(bool))); connect(m_Controls.checkGlobalVisIsoLine, SIGNAL(toggled(bool)), this, SLOT(OnGlobalVisIsoLineToggled(bool))); connect(m_Controls.isoLevelSetView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnShowContextMenuIsoSet(const QPoint&))); connect(m_Controls.comboPresets, SIGNAL(currentIndexChanged ( const QString&)), this, SLOT(OnCurrentPresetChanged(const QString&))); connect(m_Controls.btnUsePrescribedDose, SIGNAL(clicked()), this, SLOT(OnUsePrescribedDoseClicked())); connect(m_Controls.isoLevelSetView->model(), SIGNAL( modelReset()), this, SLOT(OnDataChangedInIsoLevelSetView())); connect(m_Controls.doseBtn, SIGNAL(clicked()), this, SLOT(OnDoseClicked())); ctkServiceReference ref = mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()->getServiceReference(); ctkDictionary propsForSlot; if (ref) { ctkEventAdmin* eventAdmin = mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()->getService(ref); propsForSlot[ctkEventConstants::EVENT_TOPIC] = mitk::RTCTKEventConstants::TOPIC_ISO_DOSE_LEVEL_PRESETS_CHANGED.c_str(); eventAdmin->subscribeSlot(this, SLOT(OnHandleCTKEventPresetsChanged(ctkEvent)), propsForSlot); propsForSlot[ctkEventConstants::EVENT_TOPIC] = mitk::RTCTKEventConstants::TOPIC_REFERENCE_DOSE_CHANGED.c_str(); eventAdmin->subscribeSlot(this, SLOT(OnHandleCTKEventReferenceDoseChanged(ctkEvent)), propsForSlot); propsForSlot[ctkEventConstants::EVENT_TOPIC] = mitk::RTCTKEventConstants::TOPIC_GLOBAL_VISIBILITY_CHANGED.c_str(); eventAdmin->subscribeSlot(this, SLOT(OnHandleCTKEventGlobalVisChanged(ctkEvent)), propsForSlot); } this->UpdateBySelectedNode(); } void RTDoseVisualizer::OnReferenceDoseChanged(double value) { if (! m_internalUpdate) { mitk::DoseValueAbs referenceDose = 0.0; bool globalSync = mitk::GetReferenceDoseValue(referenceDose); if (globalSync) { mitk::SetReferenceDoseValue(globalSync, value); this->ActualizeReferenceDoseForAllDoseDataNodes(); } else { if (this->m_selectedNode.IsNotNull()) { this->m_selectedNode->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), value); mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); if (isoDoseNode.IsNotNull()) isoDoseNode->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), value); } } if (this->m_selectedNode.IsNotNull()) { this->UpdateColorWashTransferFunction(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } void RTDoseVisualizer::OnAddFreeValueClicked() { QColor newColor; //Use HSV schema of QColor to calculate a different color depending on the //number of already existing free iso lines. newColor.setHsv((m_freeIsoValuesCount*85)%360,255,255); mitk::IsoDoseLevel::ColorType mColor; mColor[0]=newColor.redF(); mColor[1]=newColor.greenF(); mColor[2]=newColor.blueF(); mitk::IsoDoseLevelVector::Pointer freeIsoDoseVector; mitk::IsoDoseLevelVectorProperty::Pointer propIsoVector; mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); if (isoDoseNode.IsNotNull()) { propIsoVector = dynamic_cast(isoDoseNode->GetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str())); freeIsoDoseVector = propIsoVector->GetValue(); if (freeIsoDoseVector.IsNull()) mitk::IsoDoseLevelVector::Pointer freeIsoDoseVector = mitk::IsoDoseLevelVector::New(); mitk::IsoDoseLevel::Pointer newLevel = mitk::IsoDoseLevel::New(0.5, mColor, true, false); freeIsoDoseVector->InsertElement(m_freeIsoValuesCount, newLevel); propIsoVector = mitk::IsoDoseLevelVectorProperty::New(freeIsoDoseVector); isoDoseNode->SetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str(), propIsoVector); m_freeIsoValuesCount++; this->m_Controls.btnRemoveFreeValue->setEnabled(true); //Update Widget this->UpdateFreeIsoValues(); //Update Rendering this->ActualizeFreeIsoLine(); } } void RTDoseVisualizer::OnRemoveFreeValueClicked() { int index = this->m_Controls.listFreeValues->currentRow(); - if (index > m_freeIsoValuesCount || index < 0) + if (index > static_cast(m_freeIsoValuesCount) || index < 0) return; mitk::IsoDoseLevelVectorProperty::Pointer propfreeIsoVec; mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); propfreeIsoVec = dynamic_cast(isoDoseNode->GetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str())); mitk::IsoDoseLevelVector::Pointer freeIsoDoseLevelVec = propfreeIsoVec->GetValue(); if(freeIsoDoseLevelVec->IndexExists(index)) { //freeIsoDoseLevelVec->DeleteIndex(index); freeIsoDoseLevelVec->erase(freeIsoDoseLevelVec->begin()+index); --m_freeIsoValuesCount; if(m_freeIsoValuesCount == 0) this->m_Controls.btnRemoveFreeValue->setEnabled(true); this->UpdateFreeIsoValues(); this->ActualizeFreeIsoLine(); } } void RTDoseVisualizer::OnUsePrescribedDoseClicked() { m_Controls.spinReferenceDose->setValue(this->m_PrescribedDose_Data); } void RTDoseVisualizer::OnDoseClicked() { auto nodes = this->GetDataManagerSelection(); for (auto node : nodes) { mitk::ConfigureNodeAsDoseNode(node, 50); node->Modified(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void RTDoseVisualizer::OnDataChangedInIsoLevelSetView() { //colorwash visibility changed, update the colorwash this->UpdateColorWashTransferFunction(); if(m_selectedNode.IsNotNull()) { //Hack: This is a dirty hack to reinit the isodose contour node. Only if the node (or property) has changed the rendering process register the RequestUpdateAll //Only way to render the isoline by changes without a global reinit mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); if (isoDoseNode.IsNotNull()) isoDoseNode->Modified(); // Reinit if visibility of colorwash or isodoselevel changed mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void RTDoseVisualizer::OnShowContextMenuIsoSet(const QPoint& pos) { QPoint globalPos = m_Controls.isoLevelSetView->viewport()->mapToGlobal(pos); QMenu viewMenu; QAction* invertIsoLineAct = viewMenu.addAction("Invert iso line visibility"); QAction* activateIsoLineAct = viewMenu.addAction("Activate all iso lines"); QAction* deactivateIsoLineAct = viewMenu.addAction("Deactivate all iso lines"); viewMenu.addSeparator(); QAction* invertColorWashAct = viewMenu.addAction("Invert color wash visibility"); QAction* activateColorWashAct = viewMenu.addAction("Activate all color wash levels"); QAction* deactivateColorWashAct = viewMenu.addAction("Deactivate all color wash levels"); viewMenu.addSeparator(); QAction* swapAct = viewMenu.addAction("Swap iso line/color wash visibility"); // ... QAction* selectedItem = viewMenu.exec(globalPos); if (selectedItem == invertIsoLineAct) { this->m_LevelSetModel->invertVisibilityIsoLines(); } else if (selectedItem == activateIsoLineAct) { this->m_LevelSetModel->switchVisibilityIsoLines(true); } else if (selectedItem == deactivateIsoLineAct) { this->m_LevelSetModel->switchVisibilityIsoLines(false); } else if (selectedItem == invertColorWashAct) { this->m_LevelSetModel->invertVisibilityColorWash(); } else if (selectedItem == activateColorWashAct) { this->m_LevelSetModel->switchVisibilityColorWash(true); } else if (selectedItem == deactivateColorWashAct) { this->m_LevelSetModel->switchVisibilityColorWash(false); } else if (selectedItem == swapAct) { this->m_LevelSetModel->swapVisibility(); } } void RTDoseVisualizer::UpdateFreeIsoValues() { this->m_Controls.listFreeValues->clear(); mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); if (isoDoseNode.IsNotNull()) { mitk::IsoDoseLevelVectorProperty::Pointer propfreeIsoVec; propfreeIsoVec = dynamic_cast(isoDoseNode->GetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str())); mitk::IsoDoseLevelVector::Pointer freeIsoDoseLevelVec = propfreeIsoVec->GetValue(); for (mitk::IsoDoseLevelVector::Iterator pos = freeIsoDoseLevelVec->Begin(); pos != freeIsoDoseLevelVec->End(); ++pos) { QListWidgetItem* item = new QListWidgetItem; item->setSizeHint(QSize(0, 25)); QmitkFreeIsoDoseLevelWidget* widget = new QmitkFreeIsoDoseLevelWidget; float pref; m_selectedNode->GetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), pref); widget->setIsoDoseLevel(pos.Value()); widget->setReferenceDose(pref); connect(m_Controls.spinReferenceDose, SIGNAL(valueChanged(double)), widget, SLOT(setReferenceDose(double))); connect(widget, SIGNAL(ColorChanged(mitk::IsoDoseLevel*)), this, SLOT(ActualizeFreeIsoLine())); connect(widget, SIGNAL(ValueChanged(mitk::IsoDoseLevel*, mitk::DoseValueRel)), this, SLOT(ActualizeFreeIsoLine())); connect(widget, SIGNAL(VisualizationStyleChanged(mitk::IsoDoseLevel*)), this, SLOT(ActualizeFreeIsoLine())); this->m_Controls.listFreeValues->addItem(item); this->m_Controls.listFreeValues->setItemWidget(item, widget); } } } void RTDoseVisualizer::ActualizeFreeIsoLine() { if(m_selectedNode.IsNotNull()) { //Hack: This is a dirty hack to reinit the isodose contour node. Only if the node (or property) has changed the rendering process register the RequestUpdateAll //Only way to render the isoline by changes without a global reinit mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); if (isoDoseNode.IsNotNull()) isoDoseNode->Modified(); // Reinit if visibility of colorwash or isodoselevel changed mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void RTDoseVisualizer::OnAbsDoseToggled(bool showAbs) { if (! m_internalUpdate) { mitk::SetDoseDisplayAbsolute(showAbs); this->ActualizeDisplayStyleForAllDoseDataNodes(); } } void RTDoseVisualizer::OnGlobalVisColorWashToggled(bool showColorWash) { if (m_selectedNode.IsNotNull()) { m_selectedNode->SetBoolProperty(mitk::RTConstants::DOSE_SHOW_COLORWASH_PROPERTY_NAME.c_str(), showColorWash); //The rendering mode could be set in the dose mapper: Refactoring! mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New(); if(showColorWash) renderingMode->SetValue(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR); else renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); m_selectedNode->SetProperty("Image Rendering.Mode", renderingMode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void RTDoseVisualizer::OnGlobalVisIsoLineToggled(bool showIsoLines) { if (m_selectedNode.IsNotNull()) { mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); if (isoDoseNode.IsNotNull()) { isoDoseNode->SetBoolProperty(mitk::RTConstants::DOSE_SHOW_ISOLINES_PROPERTY_NAME.c_str(), showIsoLines); //toggle the visibility of the free isolevel sliders this->m_Controls.listFreeValues->setEnabled(showIsoLines); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } void RTDoseVisualizer::UpdateColorWashTransferFunction() { //Generating the Colorwash vtkSmartPointer transferFunction = vtkSmartPointer::New(); if(m_selectedNode.IsNotNull()) { mitk::IsoDoseLevelSetProperty::Pointer propIsoSet = dynamic_cast(m_selectedNode->GetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str())); mitk::IsoDoseLevelSet::Pointer isoDoseLevelSet = propIsoSet->GetValue(); float referenceDose; m_selectedNode->GetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(),referenceDose); mitk::TransferFunction::ControlPoints scalarOpacityPoints; scalarOpacityPoints.push_back( std::make_pair(0, 1 ) ); //Backgroud transferFunction->AddHSVPoint(((isoDoseLevelSet->Begin())->GetDoseValue()*referenceDose)-0.001,0,0,0,1.0,1.0); for(mitk::IsoDoseLevelSet::ConstIterator itIsoDoseLevel = isoDoseLevelSet->Begin(); itIsoDoseLevel != isoDoseLevelSet->End(); ++itIsoDoseLevel) { float *hsv = new float[3]; //used for transfer rgb to hsv vtkSmartPointer cCalc = vtkSmartPointer::New(); if(itIsoDoseLevel->GetVisibleColorWash()) { cCalc->RGBToHSV(itIsoDoseLevel->GetColor()[0],itIsoDoseLevel->GetColor()[1],itIsoDoseLevel->GetColor()[2],&hsv[0],&hsv[1],&hsv[2]); transferFunction->AddHSVPoint(itIsoDoseLevel->GetDoseValue()*referenceDose,hsv[0],hsv[1],hsv[2],1.0,1.0); } else { scalarOpacityPoints.push_back( std::make_pair(itIsoDoseLevel->GetDoseValue()*referenceDose, 1 ) ); } } mitk::TransferFunction::Pointer mitkTransFunc = mitk::TransferFunction::New(); mitk::TransferFunctionProperty::Pointer mitkTransFuncProp = mitk::TransferFunctionProperty::New(); mitkTransFunc->SetColorTransferFunction(transferFunction); mitkTransFunc->SetScalarOpacityPoints(scalarOpacityPoints); mitkTransFuncProp->SetValue(mitkTransFunc); m_selectedNode->SetProperty("Image Rendering.Transfer Function", mitkTransFuncProp); } } -void RTDoseVisualizer::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, - const QList& nodes ) +void RTDoseVisualizer::OnSelectionChanged( berry::IWorkbenchPart::Pointer, + const QList&) { QList dataNodes = this->GetDataManagerSelection(); mitk::DataNode* selectedNode = nullptr; if (!dataNodes.empty()) { bool isDoseNode = ModalityIsRTDose(dataNodes[0].GetPointer()); if (isDoseNode) { selectedNode = dataNodes[0]; } } if (selectedNode != m_selectedNode.GetPointer()) { m_selectedNode = selectedNode; } UpdateBySelectedNode(); } void RTDoseVisualizer::UpdateBySelectedNode() { m_Controls.groupNodeSpecific->setEnabled(m_selectedNode.IsNotNull()); m_Controls.groupFreeValues->setEnabled(m_selectedNode.IsNotNull()); m_Controls.checkGlobalVisColorWash->setEnabled(m_selectedNode.IsNotNull()); m_Controls.checkGlobalVisIsoLine->setEnabled(m_selectedNode.IsNotNull()); m_Controls.isoLevelSetView->setEnabled(m_selectedNode.IsNotNull()); if(m_selectedNode.IsNull()) { m_Controls.NrOfFractions->setText(QString("N/A. No dose selected")); m_Controls.prescribedDoseSpecific->setText(QString("N/A. No dose selected")); } else { //dose specific information int fracCount = 1; m_selectedNode->GetIntProperty(mitk::RTConstants::DOSE_FRACTION_COUNT_PROPERTY_NAME.c_str(), fracCount); m_Controls.NrOfFractions->setText(QString::number(fracCount)); m_PrescribedDose_Data = 0.0; auto prescibedDoseProperty = m_selectedNode->GetData()->GetProperty(mitk::RTConstants::PRESCRIBED_DOSE_PROPERTY_NAME.c_str()); auto prescribedDoseGenericProperty = dynamic_cast*>(prescibedDoseProperty.GetPointer()); m_PrescribedDose_Data = prescribedDoseGenericProperty->GetValue(); m_Controls.prescribedDoseSpecific->setText(QString::number(m_PrescribedDose_Data)); //free iso lines mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); if (isoDoseNode) { mitk::IsoDoseLevelVectorProperty::Pointer propIsoVector; propIsoVector = dynamic_cast(isoDoseNode->GetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str())); if (propIsoVector.IsNull()) { mitk::IsoDoseLevelVector::Pointer freeIsoValues = mitk::IsoDoseLevelVector::New(); propIsoVector = mitk::IsoDoseLevelVectorProperty::New(freeIsoValues); isoDoseNode->SetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str(), propIsoVector); } UpdateFreeIsoValues(); //global dose issues //ATM the IsoDoseContours have an own (helper) node which is a child of dose node; Will be fixed with the doseMapper refactoring bool showIsoLine = mitk::GetGlobalIsolineVis(); isoDoseNode->GetBoolProperty(mitk::RTConstants::DOSE_SHOW_ISOLINES_PROPERTY_NAME.c_str(), showIsoLine); m_Controls.checkGlobalVisIsoLine->setChecked(showIsoLine); } bool showColorWash = mitk::GetGlobalColorwashVis(); m_selectedNode->GetBoolProperty(mitk::RTConstants::DOSE_SHOW_COLORWASH_PROPERTY_NAME.c_str(),showColorWash); m_Controls.checkGlobalVisColorWash->setChecked(showColorWash); float referenceDose = 0.0; m_selectedNode->GetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(),referenceDose); m_Controls.spinReferenceDose->setValue(referenceDose); mitk::IsoDoseLevelSetProperty::Pointer propIsoSet = dynamic_cast(m_selectedNode->GetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str())); if (propIsoSet) { this->m_LevelSetModel->setIsoDoseLevelSet(propIsoSet->GetValue()); } } } void RTDoseVisualizer::NodeRemoved(const mitk::DataNode* node) { mitk::DataStorage::SetOfObjects::ConstPointer childNodes = this->GetDataStorage()->GetDerivations(node); mitk::DataStorage::SetOfObjects::const_iterator iterChildNodes = childNodes->begin(); while (iterChildNodes != childNodes->end()) { this->GetDataStorage()->Remove((*iterChildNodes)); ++iterChildNodes; } } void RTDoseVisualizer::NodeChanged(const mitk::DataNode *node) { bool isdose = ModalityIsRTDose(node); if(isdose) { bool isvisible = true; if(node->GetBoolProperty("visible", isvisible)) { mitk::DataStorage::SetOfObjects::ConstPointer childNodes = this->GetDataStorage()->GetDerivations(node); mitk::DataStorage::SetOfObjects::const_iterator iterChildNodes = childNodes->begin(); while (iterChildNodes != childNodes->end()) { (*iterChildNodes)->SetVisibility(isvisible); ++iterChildNodes; } } } } void RTDoseVisualizer::UpdateByPreferences() { m_Presets = mitk::LoadPresetsMap(); m_internalUpdate = true; m_Controls.comboPresets->clear(); this->m_selectedPresetName = mitk::GetSelectedPresetName(); m_Controls.checkGlobalVisIsoLine->setChecked(mitk::GetGlobalIsolineVis()); m_Controls.checkGlobalVisColorWash->setChecked(mitk::GetGlobalColorwashVis()); if(m_Presets.empty()) return; int index = 0; int selectedIndex = -1; for (mitk::PresetMapType::const_iterator pos = m_Presets.begin(); pos != m_Presets.end(); ++pos, ++index) { m_Controls.comboPresets->addItem(QString(pos->first.c_str())); if (this->m_selectedPresetName == pos->first) { selectedIndex = index; } } if (selectedIndex == -1) { selectedIndex = 0; MITK_WARN << "Error. Iso dose level preset specified in preferences does not exist. Preset name: "<m_selectedPresetName; this->m_selectedPresetName = m_Presets.begin()->first; mitk::SetSelectedPresetName(this->m_selectedPresetName); MITK_INFO << "Changed selected iso dose level preset to first existing preset. New preset name: "<m_selectedPresetName; } m_Controls.comboPresets->setCurrentIndex(selectedIndex); this->m_LevelSetModel->setIsoDoseLevelSet(this->m_Presets[this->m_selectedPresetName]); mitk::DoseValueAbs referenceDose = 0.0; bool globalSync = mitk::GetReferenceDoseValue(referenceDose); if (globalSync || this->m_selectedNode.IsNull()) { m_Controls.spinReferenceDose->setValue(referenceDose); } bool displayAbsoluteDose = mitk::GetDoseDisplayAbsolute(); m_Controls.radioAbsDose->setChecked(displayAbsoluteDose); m_Controls.radioRelDose->setChecked(!displayAbsoluteDose); this->m_LevelSetModel->setShowAbsoluteDose(displayAbsoluteDose); m_internalUpdate = false; } void RTDoseVisualizer::OnCurrentPresetChanged(const QString& presetName) { if (! m_internalUpdate) { mitk::SetSelectedPresetName(presetName.toStdString()); this->UpdateByPreferences(); this->ActualizeIsoLevelsForAllDoseDataNodes(); this->UpdateBySelectedNode(); } } void RTDoseVisualizer::ActualizeIsoLevelsForAllDoseDataNodes() { std::string presetName = mitk::GetSelectedPresetName(); mitk::PresetMapType presetMap = mitk::LoadPresetsMap(); mitk::NodePredicateProperty::Pointer isDoseNode = mitk::NodePredicateProperty::New("modality", mitk::StringProperty::New("RTDOSE")); mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetSubset(isDoseNode); if(presetMap.empty()) return; mitk::IsoDoseLevelSet* selectedPreset = presetMap[presetName]; if (!selectedPreset) { mitkThrow() << "Error. Cannot actualize iso dose level preset. Selected preset does not exist. Preset name: "<begin(); pos != nodes->end(); ++pos) { mitk::IsoDoseLevelSet::Pointer clonedPreset = selectedPreset->Clone(); mitk::IsoDoseLevelSetProperty::Pointer propIsoSet = mitk::IsoDoseLevelSetProperty::New(clonedPreset); (*pos)->SetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str(),propIsoSet); } } void RTDoseVisualizer::ActualizeReferenceDoseForAllDoseDataNodes() { /** @TODO Klären ob diese präsentations info genauso wie*/ mitk::DoseValueAbs value = 0; bool sync = mitk::GetReferenceDoseValue(value); if (sync) { mitk::NodePredicateProperty::Pointer isDoseNode = mitk::NodePredicateProperty::New("modality", mitk::StringProperty::New("RTDOSE")); mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetSubset(isDoseNode); for(mitk::DataStorage::SetOfObjects::const_iterator pos = nodes->begin(); pos != nodes->end(); ++pos) { (*pos)->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), value); //ATM the IsoDoseContours have an own (helper) node which is a child of dose node; Will be fixed with the doseMapper refactoring mitk::DataStorage::SetOfObjects::ConstPointer childNodes = this->GetDataStorage()->GetDerivations(*pos); mitk::DataStorage::SetOfObjects::const_iterator iterChildNodes = childNodes->begin(); while (iterChildNodes != childNodes->end()) { (*iterChildNodes)->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), value); ++iterChildNodes; } } } } void RTDoseVisualizer::ActualizeDisplayStyleForAllDoseDataNodes() { /** @TODO Klären ob diese präsentations info global oder auch per node gespeichert wird*/ } -void RTDoseVisualizer::OnHandleCTKEventReferenceDoseChanged(const ctkEvent& event) +void RTDoseVisualizer::OnHandleCTKEventReferenceDoseChanged(const ctkEvent&) { mitk::DoseValueAbs referenceDose = 0.0; - bool globalSync = mitk::GetReferenceDoseValue(referenceDose); - this->m_Controls.spinReferenceDose->setValue(referenceDose); } -void RTDoseVisualizer::OnHandleCTKEventGlobalVisChanged(const ctkEvent& event) +void RTDoseVisualizer::OnHandleCTKEventGlobalVisChanged(const ctkEvent&) { this->m_Controls.checkGlobalVisIsoLine->setChecked(mitk::GetGlobalIsolineVis()); this->m_Controls.checkGlobalVisColorWash->setChecked(mitk::GetGlobalColorwashVis()); } -void RTDoseVisualizer::OnHandleCTKEventPresetsChanged(const ctkEvent& event) +void RTDoseVisualizer::OnHandleCTKEventPresetsChanged(const ctkEvent&) { std::string currentPresetName = mitk::GetSelectedPresetName(); this->OnCurrentPresetChanged(QString::fromStdString(currentPresetName)); } //ATM the IsoDoseContours have an own (helper) node which is a child of dose node; Will be fixed with the doseMapper refactoring mitk::DataNode::Pointer RTDoseVisualizer::GetIsoDoseNode(mitk::DataNode::Pointer doseNode) { mitk::DataStorage::SetOfObjects::ConstPointer childNodes = this->GetDataStorage()->GetDerivations(doseNode); if (childNodes->empty()) { return nullptr; } else { return doseNode = (*childNodes->begin()); } } bool RTDoseVisualizer::ModalityIsRTDose(const mitk::DataNode* dataNode) const { auto data = dataNode->GetData(); if (!data) { return false; } auto modalityProperty = data->GetProperty("modality"); auto modalityGenericProperty = dynamic_cast*>(modalityProperty.GetPointer()); if (!modalityGenericProperty) { return false; } std::string modality = modalityGenericProperty->GetValue(); return modality == "RTDOSE"; } diff --git a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.batch/src/internal/QmitkMatchPointBatchProcessor.cpp b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.batch/src/internal/QmitkMatchPointBatchProcessor.cpp index c05d39ccfc..b86f2b2419 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.batch/src/internal/QmitkMatchPointBatchProcessor.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.batch/src/internal/QmitkMatchPointBatchProcessor.cpp @@ -1,742 +1,742 @@ /*=================================================================== 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 "org_mitk_gui_qt_matchpoint_algorithm_batch_Activator.h" // Blueberry #include #include #include #include // Mitk #include #include #include #include #include #include #include // Qt #include #include #include #include // MatchPoint #include #include #include #include #include #include #include // Qmitk #include "QmitkMatchPointBatchProcessor.h" const std::string QmitkMatchPointBatchProcessor::VIEW_ID = "org.mitk.views.matchpoint.algorithm.batchprocessing"; QmitkMatchPointBatchProcessor::QmitkMatchPointBatchProcessor() : m_Parent(nullptr), m_LoadedDLLHandle(nullptr), m_LoadedAlgorithm(nullptr) { m_CanLoadAlgorithm = false; m_ValidInputs = false; m_Working = false; } QmitkMatchPointBatchProcessor::~QmitkMatchPointBatchProcessor() { // remove selection service berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); if (s) { s->RemoveSelectionListener(m_AlgorithmSelectionListener.data()); } } void QmitkMatchPointBatchProcessor::SetFocus() { } void QmitkMatchPointBatchProcessor::CreateConnections() { // show first page m_Controls.m_tabs->setCurrentIndex(0); // ------ // Tab 1 - Shared library loading interface // ------ connect(m_Controls.m_pbLoadSelected, SIGNAL(clicked()), this, SLOT(OnLoadAlgorithmButtonPushed())); // ----- // Tab 2 - Input // ----- connect(m_Controls.m_pbLockTarget, SIGNAL(clicked()), this, SLOT(OnLockTargetButtonPushed())); connect(m_Controls.m_pbLockMoving, SIGNAL(clicked()), this, SLOT(OnLockMovingButtonPushed())); // ----- // Tab 3 - Execution // ----- connect(m_Controls.m_pbStartReg, SIGNAL(clicked()), this, SLOT(OnStartRegBtnPushed())); } const map::deployment::DLLInfo* QmitkMatchPointBatchProcessor::GetSelectedAlgorithmDLL() const { return m_SelectedAlgorithmInfo; } void QmitkMatchPointBatchProcessor::OnSelectedAlgorithmChanged() { std::stringstream descriptionString; ::map::deployment::DLLInfo::ConstPointer currentItemInfo = GetSelectedAlgorithmDLL(); if (!currentItemInfo) { Error(QString("No valid algorithm is selected. ABORTING.")); return; } m_Controls.m_teAlgorithmDetails->updateInfo(currentItemInfo); m_Controls.m_lbSelectedAlgorithm->setText(QString::fromStdString( currentItemInfo->getAlgorithmUID().getName())); // enable loading m_CanLoadAlgorithm = true; this->UpdateAlgorithmSelectionGUI(); } void QmitkMatchPointBatchProcessor::OnLoadAlgorithmButtonPushed() { map::deployment::DLLInfo::ConstPointer dllInfo = GetSelectedAlgorithmDLL(); if (!dllInfo) { Error(QString("No valid algorithm is selected. Cannot load algorithm. ABORTING.")); return; } ::map::deployment::DLLHandle::Pointer tempDLLHandle = ::map::deployment::openDeploymentDLL( dllInfo->getLibraryFilePath()); ::map::algorithm::RegistrationAlgorithmBase::Pointer tempAlgorithm = ::map::deployment::getRegistrationAlgorithm(tempDLLHandle); if (tempAlgorithm.IsNull()) { Error(QString("Error. Cannot load selected algorithm.")); return; } this->m_LoadedAlgorithm = tempAlgorithm; this->m_LoadedDLLHandle = tempDLLHandle; this->m_Controls.m_AlgoConfigurator->setAlgorithm(m_LoadedAlgorithm); this->CheckInputs(); this->ConfigureRegistrationControls(); this->ConfigureProgressInfos(); this->m_Controls.m_tabs->setCurrentIndex(1); this->UpdateAlgorithmSelectionGUI(); } void QmitkMatchPointBatchProcessor::OnLockTargetButtonPushed() { if (this->m_Controls.m_pbLockTarget->isChecked()) { if (this->m_spSelectedTargetNode.IsNotNull()) { this->m_spSelectedTargetNode->SetSelected(false); this->GetDataStorage()->Modified(); } } this->CheckInputs(); this->ConfigureRegistrationControls(); } void QmitkMatchPointBatchProcessor::OnLockMovingButtonPushed() { if (this->m_Controls.m_pbLockMoving->isChecked()) { if (!this->m_selectedMovingNodes.empty()) { for (NodeListType::const_iterator pos = m_selectedMovingNodes.begin(); pos != m_selectedMovingNodes.end(); ++pos) { (*pos)->SetSelected(false); } this->GetDataStorage()->Modified(); } } this->CheckInputs(); this->ConfigureRegistrationControls(); } void QmitkMatchPointBatchProcessor::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); m_Controls.m_teLog->append(QString("") + msg + QString("")); } void QmitkMatchPointBatchProcessor::UpdateAlgorithmSelectionGUI() { m_Controls.m_pbLoadSelected->setEnabled(m_CanLoadAlgorithm); } void QmitkMatchPointBatchProcessor::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; m_AlgorithmSelectionListener.reset(new berry::SelectionChangedAdapter(this, &QmitkMatchPointBatchProcessor::OnAlgorithmSelectionChanged)); // register selection listener GetSite()->GetWorkbenchWindow()->GetSelectionService()->AddSelectionListener( m_AlgorithmSelectionListener.data()); this->CreateConnections(); this->UpdateAlgorithmSelectionGUI(); this->CheckInputs(); this->ConfigureProgressInfos(); this->ConfigureRegistrationControls(); berry::ISelection::ConstPointer selection = GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.matchpoint.algorithm.browser"); this->UpdateAlgorithmSelection(selection); } void QmitkMatchPointBatchProcessor::CheckInputs() { bool validMoving = false; bool validTarget = false; NodeListType dataNodes = this->GetSelectedDataNodes(); //first set the internal nodes according to selection if (!m_Controls.m_pbLockTarget->isChecked()) { mitk::DataNode::Pointer targetNode = nullptr; if (dataNodes.size() > 0) { targetNode = dataNodes.front(); dataNodes.pop_front(); mitk::Image* targetImage = dynamic_cast(targetNode->GetData()); if (targetImage) { if (m_LoadedAlgorithm.IsNotNull()) { if (targetImage->GetDimension() != m_LoadedAlgorithm->getTargetDimensions()) { m_Controls.m_lbTargetName->setText(QString("wrong image dimension. ") + QString::number(m_LoadedAlgorithm->getTargetDimensions()) + QString("D needed")); } else { validTarget = true; } } else { validTarget = true; } if (validTarget) { m_Controls.m_lbTargetName->setText(QString::fromStdString(targetNode->GetName())); } } } this->m_spSelectedTargetNode = targetNode; } else { validTarget = true; } if (this->m_spSelectedTargetNode.IsNull()) { m_Controls.m_lbTargetName->setText(QString("no data selected!")); } if (!m_Controls.m_pbLockMoving->isChecked()) { m_selectedMovingNodes.clear(); this->m_Controls.m_listMovingNames->clear(); if (dataNodes.size() > 0) { for (NodeListType::const_iterator pos = dataNodes.begin(); pos != dataNodes.end(); ++pos) { this->m_Controls.m_listMovingNames->addItem(QString::fromStdString((*pos)->GetName())); } } m_selectedMovingNodes = dataNodes; validMoving = !m_selectedMovingNodes.empty(); } else { validMoving = true; } if (this->m_selectedMovingNodes.size() == 0) { this->m_Controls.m_listMovingNames->addItem(QString("no data selected!")); } this->m_Controls.m_pbLockMoving->setEnabled(this->m_selectedMovingNodes.size() > 0); this->m_Controls.m_pbLockTarget->setEnabled(this->m_spSelectedTargetNode.IsNotNull()); m_ValidInputs = validMoving && validTarget; } mitk::DataStorage::SetOfObjects::Pointer QmitkMatchPointBatchProcessor::GetRegNodes() const { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetAll(); mitk::DataStorage::SetOfObjects::Pointer result = mitk::DataStorage::SetOfObjects::New(); for (mitk::DataStorage::SetOfObjects::const_iterator pos = nodes->begin(); pos != nodes->end(); ++pos) { if (mitk::MITKRegistrationHelper::IsRegNode(*pos)) { result->push_back(*pos); } } return result; } QList QmitkMatchPointBatchProcessor::GetSelectedDataNodes() { NodeListType nodes = m_currentlySelectedNodes; //this->GetDataManagerSelection(); NodeListType result; /**@TODO rework to use mitk node filter mechanism*/ for (NodeListType::iterator pos = nodes.begin(); pos != nodes.end(); ++pos) { mitk::Image* image = dynamic_cast((*pos)->GetData()); if (image) { result.push_back(*pos); } } return result; } std::string QmitkMatchPointBatchProcessor::GetDefaultRegJobName() const { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetRegNodes().GetPointer(); mitk::DataStorage::SetOfObjects::ElementIdentifier estimatedIndex = nodes->Size(); bool isUnique = false; std::string result = "Unnamed Reg"; while (!isUnique) { ++estimatedIndex; result = "Reg #" +::map::core::convert::toStr(estimatedIndex); isUnique = this->GetDataStorage()->GetNamedNode(result) == nullptr; } return result; } void QmitkMatchPointBatchProcessor::ConfigureRegistrationControls() { m_Controls.m_pageSelection->setEnabled(!m_Working); m_Controls.m_leRegJobName->setEnabled(!m_Working); m_Controls.m_pbStartReg->setEnabled(false); /**@TODO reactivate as soon as crex processor allows to stop batch processing.*/ //m_Controls.m_pbStopReg->setEnabled(false); //m_Controls.m_pbStopReg->setVisible(false); if (m_LoadedAlgorithm.IsNotNull()) { m_Controls.m_pageSettings->setEnabled(!m_Working); m_Controls.m_pageExecution->setEnabled(true); m_Controls.m_pbStartReg->setEnabled(m_ValidInputs && !m_Working); ///////////////////////////////////////////// - const IStoppableAlgorithm* pIterativ = dynamic_cast - (m_LoadedAlgorithm.GetPointer()); + //const IStoppableAlgorithm* pIterativ = dynamic_cast + // (m_LoadedAlgorithm.GetPointer()); /**@TODO reactivate as soon as crex processor allows to stop batch processing.*/ //if (pIterativ) //{ // m_Controls.m_pbStopReg->setVisible(pIterativ->isStoppable()); //} ////if the stop button is set to visible and the algorithm is working -> ////then the algorithm is stoppable, thus enable the button. //m_Controls.m_pbStopReg->setEnabled(m_Controls.m_pbStopReg->isVisible() && m_Working); this->m_Controls.m_lbLoadedAlgorithmName->setText( QString::fromStdString(m_LoadedAlgorithm->getUID()->toStr())); } else { m_Controls.m_pageSettings->setEnabled(false); m_Controls.m_pageExecution->setEnabled(false); this->m_Controls.m_lbLoadedAlgorithmName->setText( QString("no algorithm loaded!")); } if (!m_Working) { this->m_Controls.m_leRegJobName->setText(QString::fromStdString(this->GetDefaultRegJobName())); } } void QmitkMatchPointBatchProcessor::ConfigureProgressInfos() { const IIterativeAlgorithm* pIterative = dynamic_cast (m_LoadedAlgorithm.GetPointer()); const IMultiResAlgorithm* pMultiRes = dynamic_cast (m_LoadedAlgorithm.GetPointer()); m_Controls.m_progBarIteration->setVisible(pIterative); m_Controls.m_lbProgBarIteration->setVisible(pIterative); if (pIterative) { QString format = "%p% (%v/%m)"; if (!pIterative->hasMaxIterationCount()) { format = "%v"; m_Controls.m_progBarIteration->setMaximum(0); } else { m_Controls.m_progBarIteration->setMaximum(pIterative->getMaxIterations()); } m_Controls.m_progBarIteration->setFormat(format); } if (pMultiRes) { m_Controls.m_progBarLevel->setMaximum(pMultiRes->getResolutionLevels()); } else { m_Controls.m_progBarLevel->setMaximum(1); } m_Controls.m_progBarJob->setMaximum(this->m_selectedMovingNodes.size()); m_Controls.m_progBarJob->reset(); m_Controls.m_progBarIteration->reset(); m_Controls.m_progBarLevel->reset(); } void QmitkMatchPointBatchProcessor::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& nodes) { m_currentlySelectedNodes = nodes; if (!m_Working) { CheckInputs(); ConfigureRegistrationControls(); } } void QmitkMatchPointBatchProcessor::OnStartRegBtnPushed() { this->m_Working = true; //////////////////////////////// //configure GUI this->ConfigureProgressInfos(); this->ConfigureRegistrationControls(); if (m_Controls.m_checkClearLog->checkState() == Qt::Checked) { this->m_Controls.m_teLog->clear(); } this->m_nextNodeToSpawn = 0; SpawnNextJob(); } bool QmitkMatchPointBatchProcessor::SpawnNextJob() { - if (this->m_nextNodeToSpawn < this->m_selectedMovingNodes.size()) + if (static_cast(this->m_nextNodeToSpawn) < this->m_selectedMovingNodes.size()) { QmitkRegistrationJob* pJob = new QmitkRegistrationJob(m_LoadedAlgorithm); pJob->setAutoDelete(true); pJob->m_spTargetData = this->m_spSelectedTargetNode->GetData(); pJob->m_spMovingData = this->m_selectedMovingNodes[m_nextNodeToSpawn]->GetData(); pJob->m_TargetDataUID = mitk::EnsureUID(this->m_spSelectedTargetNode->GetData()); pJob->m_MovingDataUID = mitk::EnsureUID(this->m_selectedMovingNodes[m_nextNodeToSpawn]->GetData()); QString jobName = m_Controls.m_leRegJobName->text() + QString(" ") + QString::fromStdString( this->m_selectedMovingNodes[m_nextNodeToSpawn]->GetName()); pJob->m_JobName = jobName.toStdString(); pJob->m_StoreReg = m_Controls.m_checkStoreReg->checkState() == Qt::Checked; connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnRegJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnRegJobFinished())); connect(pJob, SIGNAL(RegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), this, SLOT(OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(MapResultNodeIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), this, SLOT(OnMapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(AlgorithmInfo(QString)), this, SLOT(OnAlgorithmInfo(QString))); connect(pJob, SIGNAL(AlgorithmStatusChanged(QString)), this, SLOT(OnAlgorithmStatusChanged(QString))); connect(pJob, SIGNAL(AlgorithmIterated(QString, bool, unsigned long)), this, SLOT(OnAlgorithmIterated(QString, bool, unsigned long))); connect(pJob, SIGNAL(LevelChanged(QString, bool, unsigned long)), this, SLOT(OnLevelChanged(QString, bool, unsigned long))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); this->m_nextNodeToSpawn++; return true; } return false; } void QmitkMatchPointBatchProcessor::OnRegJobFinished() { if (SpawnNextJob()) { m_Controls.m_teLog->append( QString("

Commencing new registration job...

")); m_Controls.m_progBarJob->setValue(this->m_nextNodeToSpawn); } else { this->m_Working = false; this->GetRenderWindowPart()->RequestUpdate(); this->CheckInputs(); this->ConfigureRegistrationControls(); this->ConfigureProgressInfos(); } }; void QmitkMatchPointBatchProcessor::OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer spResultRegistration, const QmitkRegistrationJob* pRegJob) { mitk::DataNode::Pointer spResultRegistrationNode = mitk::generateRegistrationResultNode( pRegJob->m_JobName, spResultRegistration, pRegJob->GetLoadedAlgorithm()->getUID()->toStr(), pRegJob->m_MovingDataUID, pRegJob->m_TargetDataUID); if (pRegJob->m_StoreReg) { m_Controls.m_teLog->append( QString(" Storing registration object in data manager ... ")); this->GetDataStorage()->Add(spResultRegistrationNode); this->GetRenderWindowPart()->RequestUpdate(); } if (m_Controls.m_checkMapEntity->checkState() == Qt::Checked) { QmitkMappingJob* pMapJob = new QmitkMappingJob(); pMapJob->setAutoDelete(true); pMapJob->m_spInputData = pRegJob->m_spMovingData; pMapJob->m_InputDataUID = pRegJob->m_MovingDataUID; pMapJob->m_spRegNode = spResultRegistrationNode; pMapJob->m_doGeometryRefinement = false; pMapJob->m_spRefGeometry = pRegJob->m_spTargetData->GetGeometry()->Clone().GetPointer(); pMapJob->m_MappedName = pRegJob->m_JobName + std::string(" mapped"); pMapJob->m_allowUndefPixels = true; pMapJob->m_paddingValue = 100; pMapJob->m_allowUnregPixels = true; pMapJob->m_errorValue = 200; pMapJob->m_InterpolatorLabel = "Linear Interpolation"; pMapJob->m_InterpolatorType = mitk::ImageMappingInterpolator::Linear; connect(pMapJob, SIGNAL(Error(QString)), this, SLOT(OnMapJobError(QString))); connect(pMapJob, SIGNAL(MapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), this, SLOT(OnMapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), Qt::BlockingQueuedConnection); connect(pMapJob, SIGNAL(AlgorithmInfo(QString)), this, SLOT(OnAlgorithmInfo(QString))); m_Controls.m_teLog->append( QString("Started mapping input data...")); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pMapJob); } }; void QmitkMatchPointBatchProcessor::OnMapJobError(QString err) { Error(err); }; void QmitkMatchPointBatchProcessor::OnMapResultIsAvailable(mitk::BaseData::Pointer spMappedData, const QmitkMappingJob* job) { m_Controls.m_teLog->append(QString("Mapped entity stored. Name: ") + QString::fromStdString(job->m_MappedName) + QString("")); mitk::DataNode::Pointer spMappedNode = mitk::generateMappedResultNode(job->m_MappedName, spMappedData, job->GetRegistration()->getRegistrationUID(), job->m_InputDataUID, job->m_doGeometryRefinement, job->m_InterpolatorLabel); this->GetDataStorage()->Add(spMappedNode); this->GetRenderWindowPart()->RequestUpdate(); }; void QmitkMatchPointBatchProcessor::OnStopRegBtnPushed() { if (m_LoadedAlgorithm.IsNotNull()) { IStoppableAlgorithm* pIterativ = dynamic_cast(m_LoadedAlgorithm.GetPointer()); if (pIterativ && pIterativ->isStoppable()) { if (pIterativ->stopAlgorithm()) { } else { } /**@TODO reactivate as soon as crex processor allows to stop batch processing.*/ //m_Controls.m_pbStopReg->setEnabled(false); } else { } } } void QmitkMatchPointBatchProcessor::OnRegJobError(QString err) { Error(err); }; void QmitkMatchPointBatchProcessor::OnAlgorithmIterated(QString info, bool hasIterationCount, unsigned long currentIteration) { if (hasIterationCount) { m_Controls.m_progBarIteration->setValue(currentIteration); } m_Controls.m_teLog->append(info); }; void QmitkMatchPointBatchProcessor::OnLevelChanged(QString info, bool hasLevelCount, unsigned long currentLevel) { if (hasLevelCount) { m_Controls.m_progBarLevel->setValue(currentLevel); } m_Controls.m_teLog->append(QString("") + info + QString("")); }; void QmitkMatchPointBatchProcessor::OnAlgorithmStatusChanged(QString info) { m_Controls.m_teLog->append(QString("") + info + QString(" ")); }; void QmitkMatchPointBatchProcessor::OnAlgorithmInfo(QString info) { m_Controls.m_teLog->append(QString("") + info + QString("")); }; void QmitkMatchPointBatchProcessor::UpdateAlgorithmSelection(berry::ISelection::ConstPointer selection) { mitk::MAPAlgorithmInfoSelection::ConstPointer currentSelection = selection.Cast(); if (currentSelection) { mitk::MAPAlgorithmInfoSelection::AlgorithmInfoVectorType infoVector = currentSelection->GetSelectedAlgorithmInfo(); if (!infoVector.empty()) { // only the first selection is of interest, the rest will be skipped. this->m_SelectedAlgorithmInfo = infoVector[0]; } } this->OnSelectedAlgorithmChanged(); }; void QmitkMatchPointBatchProcessor::OnAlgorithmSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection) { // check for null selection if (selection.IsNull()) { return; } if (sourcepart != this) { UpdateAlgorithmSelection(selection); } } diff --git a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.batch/src/internal/QmitkMatchPointBatchProcessor.h b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.batch/src/internal/QmitkMatchPointBatchProcessor.h index abf1cd2569..74afb22de7 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.batch/src/internal/QmitkMatchPointBatchProcessor.h +++ b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.batch/src/internal/QmitkMatchPointBatchProcessor.h @@ -1,201 +1,203 @@ /*=================================================================== 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 __Q_MITK_MATCHPOINT_BATCH_PROCESSOR_H #define __Q_MITK_MATCHPOINT_BATCH_PROCESSOR_H #include #include #include "ui_QmitkMatchPointBatchProcessor.h" // MatchPoint #include #include #include #include #include #include #include class QmitkRegistrationJob; class QmitkMappingJob; /*! \brief View for registration batch processing based on MatchPoint This view composes the GUI and implements the business logic needed to allow registration batch processing (one target, many moving images). \ingroup ${plugin_target}_internal */ class QmitkMatchPointBatchProcessor : public QmitkAbstractView { // 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; /** * Creates smartpointer typedefs */ berryObjectMacro(QmitkMatchPointBatchProcessor) QmitkMatchPointBatchProcessor(); ~QmitkMatchPointBatchProcessor(); protected slots: /** * @brief Connect all GUI elements to its corresponding slots */ virtual void CreateConnections(); /// \brief Called when the user clicks the GUI button void OnLoadAlgorithmButtonPushed(); void OnSelectedAlgorithmChanged(); void OnLockMovingButtonPushed(); void OnLockTargetButtonPushed(); void OnStartRegBtnPushed(); void OnStopRegBtnPushed(); void OnRegJobError(QString err); void OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer spResultRegistration, const QmitkRegistrationJob* pRegJob); void OnRegJobFinished(); void OnMapJobError(QString err); void OnMapResultIsAvailable(mitk::BaseData::Pointer spMappedData, const QmitkMappingJob* job); void OnAlgorithmIterated(QString info, bool hasIterationCount, unsigned long currentIteration); void OnLevelChanged(QString info, bool hasLevelCount, unsigned long currentLevel); void OnAlgorithmStatusChanged(QString info); void OnAlgorithmInfo(QString info); protected: virtual void CreateQtPartControl(QWidget* parent); virtual void SetFocus(); /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& nodes); private: typedef QList NodeListType; /** Spawns a registration job for the next selected moving node (see m_nextNodeToSpawn). * If no nodes are left, no job will be spawned and false is returned. * If at least one node is left, a job will be spawned, m_nextNodeToSpawn will be incremented * and true will be returned.*/ bool SpawnNextJob(); /** * @brief Adapt the visibility of GUI elements depending on the current data loaded */ void UpdateAlgorithmSelectionGUI(); void Error(QString msg); void UpdateAlgorithmList(); /** * checks if appropriated nodes are selected in the data manager. If nodes are selected, * they are stored in m_spSelectedTargetNode and m_selectedMovingNodes. It also sets the info labels accordingly.*/ void CheckInputs(); /** * Updates the state of registration control buttons. Regarding to selected * inputs, loaded algorithm and its state.*/ void ConfigureRegistrationControls(); /** * Configures the progress bars according to the chosen algorithm. */ void ConfigureProgressInfos(); /** Methods returns a list of all nodes selected in the data manager that do * NOT contain registration wrappers. The list may be empty if nothing is * selected or no appropriate data node is selected.*/ NodeListType GetSelectedDataNodes(); /** Methods returns a list of all nodes in the data manager containing a registration wrapper. * The list may be empty.*/ mitk::DataStorage::SetOfObjects::Pointer GetRegNodes() const; /** Returns a proposal for a (unique) default reg job name */ std::string GetDefaultRegJobName() const; /** Returns the Pointer to the DLL info of the algorithm currently selected by the system. The info is received via m_SelectionListener. @return If there is no item selected the returning pointer will be null. */ const map::deployment::DLLInfo* GetSelectedAlgorithmDLL() const; //! [Qt Selection Listener method and pointer] /** * @brief Method of berry::ISelectionListener that implements the selection listener functionality. * @param sourcepart The workbench part responsible for the selection change. * @param selection This parameter holds the current selection. * * @see ISelectionListener */ void OnAlgorithmSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection); void UpdateAlgorithmSelection(berry::ISelection::ConstPointer selection); friend struct berry::SelectionChangedAdapter; + + QWidget* m_Parent; + /** @brief this pointer holds the algorithm selection listener */ QScopedPointer m_AlgorithmSelectionListener; ::map::deployment::DLLHandle::Pointer m_LoadedDLLHandle; ::map::algorithm::RegistrationAlgorithmBase::Pointer m_LoadedAlgorithm; ::map::deployment::DLLInfo::ConstPointer m_SelectedAlgorithmInfo; typedef map::algorithm::facet::IterativeAlgorithmInterface IIterativeAlgorithm; typedef map::algorithm::facet::MultiResRegistrationAlgorithmInterface IMultiResAlgorithm; typedef map::algorithm::facet::StoppableAlgorithmInterface IStoppableAlgorithm; /**All selected nodes stored by OnSelectionChanged()*/ NodeListType m_currentlySelectedNodes; mitk::DataNode::Pointer m_spSelectedTargetNode; NodeListType m_selectedMovingNodes; /**indicates the next selected moving nodes that should be spawned as job.*/ unsigned int m_nextNodeToSpawn; // boolean variables to control visibility of GUI elements bool m_CanLoadAlgorithm; bool m_ValidInputs; bool m_Working; - QWidget* m_Parent; Ui::MatchPointAdvancedControls m_Controls; }; #endif // MatchPoint_h diff --git a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.browser/src/internal/QmitkMatchPointBrowser.cpp b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.browser/src/internal/QmitkMatchPointBrowser.cpp index 88b43797b3..1c7032649a 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.browser/src/internal/QmitkMatchPointBrowser.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.browser/src/internal/QmitkMatchPointBrowser.cpp @@ -1,264 +1,264 @@ /*=================================================================== 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 "org_mitk_gui_qt_matchpoint_algorithm_browser_Activator.h" // Blueberry #include #include #include // Qmitk #include "QmitkMatchPointBrowser.h" // Qt #include #include #include #include //MITK #include #include "MatchPointBrowserConstants.h" #include "mitkAlgorithmInfoSelectionProvider.h" // MatchPoint #include #include #include #include #include const std::string QmitkMatchPointBrowser::VIEW_ID = "org.mitk.views.matchpoint.algorithm.browser"; QmitkMatchPointBrowser::QmitkMatchPointBrowser() : m_Parent(nullptr), m_LoadedDLLHandle(nullptr), m_LoadedAlgorithm(nullptr) { } QmitkMatchPointBrowser::~QmitkMatchPointBrowser() { } void QmitkMatchPointBrowser::OnPreferencesChanged(const berry::IBerryPreferences* /*prefs*/) { this->OnSearchFolderButtonPushed(); } void QmitkMatchPointBrowser::CreateConnections() { connect(m_Controls.m_pbSearchFolder, SIGNAL(clicked()), this, SLOT(OnSearchFolderButtonPushed())); connect(m_Controls.m_algoTreeView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(OnAlgoListSelectionChanged(const QModelIndex&))); connect(m_Controls.pbClearSearch, SIGNAL(clicked()), m_Controls.lineSearch, SLOT(clear())); connect(m_Controls.lineSearch, SIGNAL(textChanged(const QString&)), this, SLOT(OnSearchChanged(const QString&))); } void QmitkMatchPointBrowser::OnSearchFolderButtonPushed() { RetrieveAndStorePreferenceValues(); // test if some folder list non-empty int folderCount = m_currentSearchPaths.count(); if (!folderCount) { Error(QString("No search folder selected for MatchPoint algorithm browser! Please set search paths in the MatchPoint preference page.")); m_DLLInfoList.clear(); } else { map::deployment::DLLDirectoryBrowser::Pointer browser = map::deployment::DLLDirectoryBrowser::New(); foreach(QString path, m_currentSearchPaths) { browser->addDLLSearchLocation(path.toStdString()); } browser->update(); m_DLLInfoList = browser->getLibraryInfos(); } m_Controls.groupWarning->setVisible(m_DLLInfoList.empty()); m_Controls.groupList->setVisible(!m_DLLInfoList.empty()); m_algModel->SetAlgorithms(m_DLLInfoList); m_Controls.lineSearch->clear(); } void QmitkMatchPointBrowser::OnAlgoListSelectionChanged(const QModelIndex& index) { QVariant vIndex = index.data(Qt::UserRole).toInt(); map::deployment::DLLInfo::ConstPointer currentItemInfo = nullptr; if (vIndex.isValid()) { - int algListIndex = vIndex.toInt(); + std::size_t algListIndex = vIndex.toInt(); if (algListIndex < m_DLLInfoList.size()) { currentItemInfo = m_DLLInfoList[algListIndex]; } } m_Controls.m_teAlgorithmDetails->updateInfo(currentItemInfo); if (currentItemInfo) { //update selection provider mitk::MAPAlgorithmInfoSelection::Pointer infoSelection = mitk::MAPAlgorithmInfoSelection::Pointer( new mitk::MAPAlgorithmInfoSelection(currentItemInfo)); this->m_SelectionProvider->SetInfoSelection(infoSelection); } } void QmitkMatchPointBrowser::OnSearchChanged(const QString& text) { m_filterProxy->setFilterRegExp(text); m_filterProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); }; void QmitkMatchPointBrowser::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; m_algModel = new QmitkAlgorithmListModel(parent); m_filterProxy = new QSortFilterProxyModel(parent); //! [Qt Selection Provider registration] // create new qt selection provider m_SelectionProvider = new mitk::AlgorithmInfoSelectionProvider(); m_filterProxy->setSourceModel(m_algModel); m_filterProxy->setDynamicSortFilter(true); m_filterProxy->setFilterKeyColumn(-1); m_Controls.m_algoTreeView->setModel(m_filterProxy); m_Controls.m_algoTreeView->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.m_algoTreeView->header()->setStretchLastSection(false); m_Controls.m_algoTreeView->header()->setSectionResizeMode(0, QHeaderView::Stretch); m_Controls.m_algoTreeView->setColumnHidden(3, true); this->CreateConnections(); } void QmitkMatchPointBrowser::SetSelectionProvider() { this->GetSite()->SetSelectionProvider(m_SelectionProvider); } void QmitkMatchPointBrowser::SetFocus() { } void QmitkMatchPointBrowser::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); } void QmitkMatchPointBrowser::RetrieveAndStorePreferenceValues() { berry::IBerryPreferences::Pointer prefs = this->RetrievePreferences(); bool loadApplicationDir = prefs->GetBool( MatchPointBrowserConstants::LOAD_FROM_APPLICATION_DIR.c_str(), true); bool loadHomeDir = prefs->GetBool(MatchPointBrowserConstants::LOAD_FROM_HOME_DIR.c_str(), false); bool loadCurrentDir = prefs->GetBool(MatchPointBrowserConstants::LOAD_FROM_CURRENT_DIR.c_str(), false); bool loadAutoLoadDir = prefs->GetBool(MatchPointBrowserConstants::LOAD_FROM_AUTO_LOAD_DIR.c_str(), false); // Get some default application paths. QStringList newPaths; // Here we can use the preferences to set up the builder, if (loadApplicationDir) { newPaths << QCoreApplication::applicationDirPath(); } if (loadHomeDir) { newPaths << QDir::homePath(); } if (loadCurrentDir) { newPaths << QDir::currentPath(); } if (loadAutoLoadDir) { char* deployedAlgorithmLoadPath = getenv("MAP_MDRA_LOAD_PATH"); if (deployedAlgorithmLoadPath != nullptr) { // The load path may in fact be a semi-colon or colon separated list of directories, not just one. QString paths(deployedAlgorithmLoadPath); #ifdef Q_OS_WIN32 QString pathSeparator(";"); #else QString pathSeparator(":"); #endif QStringList splitPath = paths.split(pathSeparator, QString::SkipEmptyParts); foreach(QString path, splitPath) { QDir dir = QDir(path); newPaths << dir.absolutePath(); } } } // We get additional directory paths from preferences. QString pathString = prefs->Get(MatchPointBrowserConstants::MDAR_DIRECTORIES_NODE_NAME.c_str(), tr("")); QStringList additionalPaths = pathString.split(";", QString::SkipEmptyParts); newPaths << additionalPaths; QString additionalAlgorirthmsString = prefs->Get( MatchPointBrowserConstants::MDAR_FILES_NODE_NAME.c_str(), tr("")); additionalPaths = additionalAlgorirthmsString.split(";", QString::SkipEmptyParts); newPaths << additionalPaths; m_currentSearchPaths = newPaths; } berry::IBerryPreferences::Pointer QmitkMatchPointBrowser::RetrievePreferences() { berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); assert(prefService); QString id = tr("/") + QString::fromStdString(MatchPointBrowserConstants::VIEW_ID); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node(id)) .Cast(); assert(prefs); return prefs; } diff --git a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.cpp b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.cpp index d6a145d1a8..03c9c3317d 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.cpp @@ -1,977 +1,977 @@ /*=================================================================== 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 "org_mitk_gui_qt_matchpoint_algorithmcontrol_Activator.h" // Blueberry #include #include #include #include // Mitk #include #include #include #include #include #include #include #include #include #include // Qmitk #include "QmitkMatchPoint.h" #include #include // Qt #include #include #include #include #include // MatchPoint #include #include #include #include #include #include #include #include #include const std::string QmitkMatchPoint::VIEW_ID = "org.mitk.views.matchpoint.algorithm.control"; QmitkMatchPoint::QmitkMatchPoint() : m_Parent(nullptr), m_LoadedDLLHandle(nullptr), m_LoadedAlgorithm(nullptr) { m_CanLoadAlgorithm = false; m_ValidInputs = false; m_Working = false; m_spSelectedTargetData = nullptr; m_spSelectedMovingData = nullptr; m_spSelectedTargetMaskData = nullptr; m_spSelectedMovingMaskData = nullptr; } QmitkMatchPoint::~QmitkMatchPoint() { // remove selection service berry::ISelectionService* s = this->GetSite()->GetWorkbenchWindow()->GetSelectionService(); if (s) { s->RemoveSelectionListener(m_AlgorithmSelectionListener.data()); } } void QmitkMatchPoint::SetFocus() { } void QmitkMatchPoint::CreateConnections() { connect(m_Controls.checkMovingMask, SIGNAL(toggled(bool)), this, SLOT(OnMaskCheckBoxToggeled(bool))); connect(m_Controls.checkTargetMask, SIGNAL(toggled(bool)), this, SLOT(OnMaskCheckBoxToggeled(bool))); // ------ // Tab 1 - Shared library loading interface // ------ connect(m_Controls.m_pbLoadSelected, SIGNAL(clicked()), this, SLOT(OnLoadAlgorithmButtonPushed())); // ----- // Tab 2 - Execution // ----- connect(m_Controls.m_pbStartReg, SIGNAL(clicked()), this, SLOT(OnStartRegBtnPushed())); connect(m_Controls.m_pbStopReg, SIGNAL(clicked()), this, SLOT(OnStopRegBtnPushed())); connect(m_Controls.m_pbSaveLog, SIGNAL(clicked()), this, SLOT(OnSaveLogBtnPushed())); } const map::deployment::DLLInfo* QmitkMatchPoint::GetSelectedAlgorithmDLL() const { return m_SelectedAlgorithmInfo; } -void QmitkMatchPoint::OnMaskCheckBoxToggeled(bool checked) +void QmitkMatchPoint::OnMaskCheckBoxToggeled(bool) { if (!m_Working) { CheckInputs(); ConfigureRegistrationControls(); } }; void QmitkMatchPoint::OnSelectedAlgorithmChanged() { std::stringstream descriptionString; ::map::deployment::DLLInfo::ConstPointer currentItemInfo = GetSelectedAlgorithmDLL(); if (!currentItemInfo) { Error(QString("No valid algorithm is selected. ABORTING.")); return; } m_Controls.m_teAlgorithmDetails->updateInfo(currentItemInfo); m_Controls.m_lbSelectedAlgorithm->setText(QString::fromStdString( currentItemInfo->getAlgorithmUID().getName())); // enable loading m_CanLoadAlgorithm = true; this->AdaptFolderGUIElements(); } void QmitkMatchPoint::OnLoadAlgorithmButtonPushed() { map::deployment::DLLInfo::ConstPointer dllInfo = GetSelectedAlgorithmDLL(); if (!dllInfo) { Error(QString("No valid algorithm is selected. Cannot load algorithm. ABORTING.")); return; } ::map::deployment::DLLHandle::Pointer tempDLLHandle = ::map::deployment::openDeploymentDLL( dllInfo->getLibraryFilePath()); ::map::algorithm::RegistrationAlgorithmBase::Pointer tempAlgorithm = ::map::deployment::getRegistrationAlgorithm(tempDLLHandle); if (tempAlgorithm.IsNull()) { Error(QString("Error. Cannot load selected algorithm.")); return; } this->m_LoadedAlgorithm = tempAlgorithm; this->m_LoadedDLLHandle = tempDLLHandle; this->m_Controls.m_AlgoConfigurator->setAlgorithm(m_LoadedAlgorithm); m_Controls.checkMovingMask->setChecked(false); m_Controls.checkTargetMask->setChecked(false); this->AdaptFolderGUIElements(); this->CheckInputs(); this->ConfigureRegistrationControls(); this->ConfigureProgressInfos(); this->m_Controls.m_tabs->setCurrentIndex(1); } void QmitkMatchPoint::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); m_Controls.m_teLog->append(QString("") + msg + QString("")); } void QmitkMatchPoint::AdaptFolderGUIElements() { m_Controls.m_pbLoadSelected->setEnabled(m_CanLoadAlgorithm); } void QmitkMatchPoint::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; m_Controls.checkMovingMask->setChecked(false); m_Controls.checkTargetMask->setChecked(false); m_Controls.m_tabs->setCurrentIndex(0); m_AlgorithmSelectionListener.reset(new berry::SelectionChangedAdapter(this, &QmitkMatchPoint::OnAlgorithmSelectionChanged)); // register selection listener GetSite()->GetWorkbenchWindow()->GetSelectionService()->AddSelectionListener( m_AlgorithmSelectionListener.data()); this->CreateConnections(); this->AdaptFolderGUIElements(); this->CheckInputs(); this->ConfigureProgressInfos(); this->ConfigureRegistrationControls(); berry::ISelection::ConstPointer selection = GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.matchpoint.algorithm.browser"); this->UpdateAlgorithmSelection(selection); } bool QmitkMatchPoint::CheckInputs() { bool validMoving = false; bool validTarget = false; bool validMovingMask = false; bool validTargetMask = false; mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer maskPredicate = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); if (m_LoadedAlgorithm.IsNull()) { m_Controls.m_lbMovingName->setText(QString("No algorithm seleted!")); m_spSelectedMovingNode = nullptr; m_spSelectedMovingData = nullptr; m_Controls.m_lbTargetName->setText(QString("No algorithm seleted!")); m_spSelectedTargetNode = nullptr; m_spSelectedTargetData = nullptr; m_spSelectedMovingMaskNode = nullptr; m_spSelectedMovingMaskData = nullptr; m_spSelectedTargetMaskNode = nullptr; m_spSelectedTargetMaskData = nullptr; } else { QList nodes = this->GetDataManagerSelection(); mitk::Image* movingImage = nullptr; mitk::PointSet* movingPointSet = nullptr; mitk::Image* targetImage = nullptr; mitk::PointSet* targetPointSet = nullptr; mitk::Image* movingMaskImage = nullptr; mitk::Image* targetMaskImage = nullptr; typedef ::map::core::continuous::Elements<3>::InternalPointSetType InternalDefaultPointSetType; typedef ::map::algorithm::facet::PointSetRegistrationAlgorithmInterface PointSetRegInterface; typedef ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<3, 3> MaskRegInterface; PointSetRegInterface* pPointSetInterface = dynamic_cast (m_LoadedAlgorithm.GetPointer()); MaskRegInterface* pMaskInterface = dynamic_cast(m_LoadedAlgorithm.GetPointer()); if (nodes.count() < 1) { m_Controls.m_lbMovingName->setText(QString("no data selected!")); m_spSelectedMovingNode = nullptr; m_spSelectedMovingData = nullptr; } else { m_spSelectedMovingNode = nodes.front(); m_spSelectedMovingData = m_spSelectedMovingNode->GetData(); movingImage = dynamic_cast(m_spSelectedMovingNode->GetData()); movingPointSet = dynamic_cast(m_spSelectedMovingNode->GetData()); if (movingPointSet && pPointSetInterface) { validMoving = true; } else if (movingImage && !pPointSetInterface) { if (movingImage->GetDimension() - 1 == m_LoadedAlgorithm->getMovingDimensions() && movingImage->GetTimeSteps() > 1) { //images has multiple time steps and a time step has the correct dimensionality mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(movingImage); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); m_spSelectedMovingData = imageTimeSelector->GetOutput(); validMoving = true; m_Controls.m_teLog->append( QString("Selected moving image has multiple time steps. First time step is used as moving image.")); } else if (movingImage->GetDimension() != m_LoadedAlgorithm->getMovingDimensions()) { m_Controls.m_lbMovingName->setText(QString("wrong image dimension. ") + QString::number(m_LoadedAlgorithm->getMovingDimensions()) + QString("D needed")); } else { validMoving = true; } } else { m_Controls.m_lbMovingName->setText(QString("no supported data selected!")); } nodes.removeFirst(); } if (nodes.count() < 1) { m_Controls.m_lbTargetName->setText(QString("no data selected!")); m_spSelectedTargetNode = nullptr; m_spSelectedTargetData = nullptr; } else { m_spSelectedTargetNode = nodes.front(); m_spSelectedTargetData = m_spSelectedTargetNode->GetData(); targetImage = dynamic_cast(m_spSelectedTargetNode->GetData()); targetPointSet = dynamic_cast(m_spSelectedTargetNode->GetData()); if (targetPointSet && pPointSetInterface) { validTarget = true; } else if (targetImage && !pPointSetInterface) { if (targetImage->GetDimension() - 1 == m_LoadedAlgorithm->getTargetDimensions() && targetImage->GetTimeSteps() > 1) { //images has multiple time steps and a time step has the correct dimensionality mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(targetImage); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); m_spSelectedTargetData = imageTimeSelector->GetOutput(); validTarget = true; m_Controls.m_teLog->append( QString("Selected target image has multiple time steps. First time step is used as target image.")); } else if (targetImage->GetDimension() != m_LoadedAlgorithm->getTargetDimensions()) { m_Controls.m_lbTargetName->setText(QString("wrong image dimension. ") + QString::number(m_LoadedAlgorithm->getTargetDimensions()) + QString("D needed")); } else { validTarget = true; } } else { m_Controls.m_lbTargetName->setText(QString("no supported data selected!")); } nodes.removeFirst(); } if (m_Controls.checkMovingMask->isChecked()) { if (nodes.count() < 1) { m_Controls.m_lbMovingMaskName->setText(QString("no data selected!")); m_spSelectedMovingMaskNode = nullptr; m_spSelectedMovingMaskData = nullptr; } else { m_spSelectedMovingMaskNode = nodes.front(); m_spSelectedMovingMaskData = nullptr; movingMaskImage = dynamic_cast(m_spSelectedMovingMaskNode->GetData()); bool isMask = maskPredicate->CheckNode(m_spSelectedMovingMaskNode); if (!isMask) { m_Controls.m_lbMovingMaskName->setText(QString("no mask selected!")); } else if (movingMaskImage && pMaskInterface) { if (movingMaskImage->GetDimension() - 1 == m_LoadedAlgorithm->getMovingDimensions() && movingMaskImage->GetTimeSteps() > 1) { //images has multiple time steps and a time step has the correct dimensionality mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(movingMaskImage); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); m_spSelectedMovingMaskData = imageTimeSelector->GetOutput(); validMovingMask = true; m_Controls.m_teLog->append( QString("Selected moving mask has multiple time steps. First time step is used as moving mask.")); } else if (movingMaskImage->GetDimension() != m_LoadedAlgorithm->getMovingDimensions()) { m_Controls.m_lbMovingMaskName->setText(QString("wrong image dimension. ") + QString::number(m_LoadedAlgorithm->getMovingDimensions()) + QString("D needed")); } else { m_spSelectedMovingMaskData = movingMaskImage; validMovingMask = true; } } else { m_Controls.m_lbMovingMaskName->setText( QString("no supported data selected!")); } nodes.removeFirst(); } } else { m_Controls.m_lbMovingMaskName->setText(QString("mask deactivated")); validMovingMask = true; m_spSelectedMovingMaskNode = nullptr; m_spSelectedMovingMaskData = nullptr; } if (m_Controls.checkTargetMask->isChecked()) { if (nodes.count() < 1) { m_Controls.m_lbTargetMaskName->setText(QString("no data selected!")); m_spSelectedTargetMaskNode = nullptr; m_spSelectedTargetMaskData = nullptr; } else { m_spSelectedTargetMaskNode = nodes.front(); m_spSelectedTargetMaskData = nullptr; targetMaskImage = dynamic_cast(m_spSelectedTargetMaskNode->GetData()); bool isMask = maskPredicate->CheckNode(m_spSelectedTargetMaskNode); if (!isMask) { m_Controls.m_lbTargetMaskName->setText(QString("no mask selected!")); } else if (targetMaskImage && pMaskInterface) { if (targetMaskImage->GetDimension() - 1 == m_LoadedAlgorithm->getTargetDimensions() && targetMaskImage->GetTimeSteps() > 1) { //images has multiple time steps and a time step has the correct dimensionality mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(targetMaskImage); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); m_spSelectedTargetMaskData = imageTimeSelector->GetOutput(); validTargetMask = true; m_Controls.m_teLog->append( QString("Selected target mask has multiple time steps. First time step is used as target mask.")); } else if (targetMaskImage->GetDimension() != m_LoadedAlgorithm->getTargetDimensions()) { m_Controls.m_lbTargetMaskName->setText(QString("wrong image dimension. ") + QString::number(m_LoadedAlgorithm->getTargetDimensions()) + QString("D needed")); } else { m_spSelectedTargetMaskData = targetMaskImage; validTargetMask = true; } } else { m_Controls.m_lbTargetMaskName->setText( QString("no supported data selected!")); } } } else { m_Controls.m_lbTargetMaskName->setText(QString("mask deactivated")); validTargetMask = true; m_spSelectedTargetMaskNode = nullptr; m_spSelectedTargetMaskData = nullptr; } } if (validMoving) { m_Controls.m_lbMovingName->setText(QString::fromStdString(GetInputNodeDisplayName( m_spSelectedMovingNode))); } if (validTarget) { m_Controls.m_lbTargetName->setText(QString::fromStdString(GetInputNodeDisplayName( m_spSelectedTargetNode))); } if (validMovingMask && m_Controls.checkMovingMask->isChecked()) { m_Controls.m_lbMovingMaskName->setText(QString::fromStdString(GetInputNodeDisplayName( m_spSelectedMovingMaskNode))); } if (validTargetMask && m_Controls.checkTargetMask->isChecked()) { m_Controls.m_lbTargetMaskName->setText(QString::fromStdString(GetInputNodeDisplayName( m_spSelectedTargetMaskNode))); } m_ValidInputs = validMoving && validTarget && validMovingMask && validTargetMask; return m_ValidInputs; } std::string QmitkMatchPoint::GetInputNodeDisplayName(const mitk::DataNode* node) const { std::string result = "UNDEFINED/nullptr"; if (node) { result = node->GetName(); const mitk::PointSet* pointSet = dynamic_cast(node->GetData()); if (pointSet) { mitk::DataStorage::SetOfObjects::ConstPointer sources = this->GetDataStorage()->GetSources(node); if (sources.IsNotNull() && sources->Size() > 0) { result = result + " (" + sources->GetElement(0)->GetName() + ")"; } } } return result; } mitk::DataStorage::SetOfObjects::Pointer QmitkMatchPoint::GetRegNodes() const { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetAll(); mitk::DataStorage::SetOfObjects::Pointer result = mitk::DataStorage::SetOfObjects::New(); for (mitk::DataStorage::SetOfObjects::const_iterator pos = nodes->begin(); pos != nodes->end(); ++pos) { if (mitk::MITKRegistrationHelper::IsRegNode(*pos)) { result->push_back(*pos); } } return result; } std::string QmitkMatchPoint::GetDefaultRegJobName() const { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetRegNodes().GetPointer(); mitk::DataStorage::SetOfObjects::ElementIdentifier estimatedIndex = nodes->Size(); bool isUnique = false; std::string result = "Unnamed Reg"; while (!isUnique) { ++estimatedIndex; result = "Reg #" +::map::core::convert::toStr(estimatedIndex); isUnique = this->GetDataStorage()->GetNamedNode(result) == nullptr; } return result; } void QmitkMatchPoint::ConfigureRegistrationControls() { m_Controls.m_tabSelection->setEnabled(!m_Working); m_Controls.m_leRegJobName->setEnabled(!m_Working); m_Controls.groupMasks->setEnabled(!m_Working); m_Controls.m_pbStartReg->setEnabled(false); m_Controls.m_pbStopReg->setEnabled(false); m_Controls.m_pbStopReg->setVisible(false); m_Controls.m_lbMovingMaskName->setVisible(m_Controls.checkMovingMask->isChecked()); m_Controls.m_lbTargetMaskName->setVisible(m_Controls.checkTargetMask->isChecked()); if (m_LoadedAlgorithm.IsNotNull()) { m_Controls.m_tabSettings->setEnabled(!m_Working); m_Controls.m_tabExecution->setEnabled(true); m_Controls.m_pbStartReg->setEnabled(m_ValidInputs && !m_Working); m_Controls.m_leRegJobName->setEnabled(!m_Working); m_Controls.m_checkMapEntity->setEnabled(!m_Working); m_Controls.m_checkStoreReg->setEnabled(!m_Working); const IStoppableAlgorithm* pIterativ = dynamic_cast (m_LoadedAlgorithm.GetPointer()); if (pIterativ) { m_Controls.m_pbStopReg->setVisible(pIterativ->isStoppable()); } typedef ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<3, 3> MaskRegInterface; const MaskRegInterface* pMaskReg = dynamic_cast (m_LoadedAlgorithm.GetPointer()); m_Controls.groupMasks->setVisible(pMaskReg != nullptr); //if the stop button is set to visible and the algorithm is working -> //then the algorithm is stoppable, thus enable the button. m_Controls.m_pbStopReg->setEnabled(m_Controls.m_pbStopReg->isVisible() && m_Working); this->m_Controls.m_lbLoadedAlgorithmName->setText( QString::fromStdString(m_LoadedAlgorithm->getUID()->toStr())); } else { m_Controls.m_tabSettings->setEnabled(false); m_Controls.m_tabExecution->setEnabled(false); this->m_Controls.m_lbLoadedAlgorithmName->setText( QString("no algorithm loaded!")); m_Controls.groupMasks->setVisible(false); } if (!m_Working) { this->m_Controls.m_leRegJobName->setText(QString::fromStdString(this->GetDefaultRegJobName())); } } void QmitkMatchPoint::ConfigureProgressInfos() { const IIterativeAlgorithm* pIterative = dynamic_cast (m_LoadedAlgorithm.GetPointer()); const IMultiResAlgorithm* pMultiRes = dynamic_cast (m_LoadedAlgorithm.GetPointer()); m_Controls.m_progBarIteration->setVisible(pIterative); m_Controls.m_lbProgBarIteration->setVisible(pIterative); if (pIterative) { QString format = "%p% (%v/%m)"; if (!pIterative->hasMaxIterationCount()) { format = "%v"; m_Controls.m_progBarIteration->setMaximum(0); } else { m_Controls.m_progBarIteration->setMaximum(pIterative->getMaxIterations()); } m_Controls.m_progBarIteration->setFormat(format); } if (pMultiRes) { m_Controls.m_progBarLevel->setMaximum(pMultiRes->getResolutionLevels()); } else { m_Controls.m_progBarLevel->setMaximum(1); } m_Controls.m_progBarIteration->reset(); m_Controls.m_progBarLevel->reset(); } -void QmitkMatchPoint::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, - const QList& nodes) +void QmitkMatchPoint::OnSelectionChanged(berry::IWorkbenchPart::Pointer, + const QList&) { if (!m_Working) { CheckInputs(); ConfigureRegistrationControls(); } } void QmitkMatchPoint::OnStartRegBtnPushed() { this->m_Working = true; //////////////////////////////// //configure GUI this->ConfigureProgressInfos(); m_Controls.m_progBarIteration->reset(); m_Controls.m_progBarLevel->reset(); this->ConfigureRegistrationControls(); if (m_Controls.m_checkClearLog->checkState() == Qt::Checked) { this->m_Controls.m_teLog->clear(); } ///////////////////////// //create job and put it into the thread pool QmitkRegistrationJob* pJob = new QmitkRegistrationJob(m_LoadedAlgorithm); pJob->setAutoDelete(true); pJob->m_spTargetData = m_spSelectedTargetData; pJob->m_spMovingData = m_spSelectedMovingData; pJob->m_TargetDataUID = mitk::EnsureUID(this->m_spSelectedTargetNode->GetData()); pJob->m_MovingDataUID = mitk::EnsureUID(this->m_spSelectedMovingNode->GetData()); if (m_spSelectedTargetMaskData.IsNotNull()) { pJob->m_spTargetMask = m_spSelectedTargetMaskData; pJob->m_TargetMaskDataUID = mitk::EnsureUID(this->m_spSelectedTargetMaskNode->GetData()); } if (m_spSelectedMovingMaskData.IsNotNull()) { pJob->m_spMovingMask = m_spSelectedMovingMaskData; pJob->m_MovingMaskDataUID = mitk::EnsureUID(this->m_spSelectedMovingMaskNode->GetData()); } pJob->m_JobName = m_Controls.m_leRegJobName->text().toStdString(); pJob->m_StoreReg = m_Controls.m_checkStoreReg->checkState() == Qt::Checked; connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnRegJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnRegJobFinished())); connect(pJob, SIGNAL(RegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), this, SLOT(OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(AlgorithmInfo(QString)), this, SLOT(OnAlgorithmInfo(QString))); connect(pJob, SIGNAL(AlgorithmStatusChanged(QString)), this, SLOT(OnAlgorithmStatusChanged(QString))); connect(pJob, SIGNAL(AlgorithmIterated(QString, bool, unsigned long)), this, SLOT(OnAlgorithmIterated(QString, bool, unsigned long))); connect(pJob, SIGNAL(LevelChanged(QString, bool, unsigned long)), this, SLOT(OnLevelChanged(QString, bool, unsigned long))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } void QmitkMatchPoint::OnStopRegBtnPushed() { if (m_LoadedAlgorithm.IsNotNull()) { IStoppableAlgorithm* pIterativ = dynamic_cast(m_LoadedAlgorithm.GetPointer()); if (pIterativ && pIterativ->isStoppable()) { if (pIterativ->stopAlgorithm()) { } else { } m_Controls.m_pbStopReg->setEnabled(false); } else { } } } void QmitkMatchPoint::OnSaveLogBtnPushed() { QDateTime currentTime = QDateTime::currentDateTime(); QString fileName = tr("registration_log_") + currentTime.toString(tr("yyyy-MM-dd_hh-mm-ss")) + tr(".txt"); fileName = QFileDialog::getSaveFileName(nullptr, tr("Save registration log"), fileName, tr("Text files (*.txt)")); if (fileName.isEmpty()) { QMessageBox::critical(nullptr, tr("No file selected!"), tr("Cannot save registration log file. Please selected a file.")); } else { std::ofstream file; std::ios_base::openmode iOpenFlag = std::ios_base::out | std::ios_base::trunc; file.open(fileName.toStdString().c_str(), iOpenFlag); if (!file.is_open()) { mitkThrow() << "Cannot open or create specified file to save. File path: " << fileName.toStdString(); } file << this->m_Controls.m_teLog->toPlainText().toStdString() << std::endl; file.close(); } } void QmitkMatchPoint::OnRegJobError(QString err) { Error(err); }; void QmitkMatchPoint::OnRegJobFinished() { this->m_Working = false; this->GetRenderWindowPart()->RequestUpdate(); this->CheckInputs(); this->ConfigureRegistrationControls(); this->ConfigureProgressInfos(); }; void QmitkMatchPoint::OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer spResultRegistration, const QmitkRegistrationJob* pRegJob) { mitk::DataNode::Pointer spResultRegistrationNode = mitk::generateRegistrationResultNode( pRegJob->m_JobName, spResultRegistration, pRegJob->GetLoadedAlgorithm()->getUID()->toStr(), pRegJob->m_MovingDataUID, pRegJob->m_TargetDataUID); if (pRegJob->m_StoreReg) { m_Controls.m_teLog->append( QString(" Storing registration object in data manager ... ")); this->GetDataStorage()->Add(spResultRegistrationNode); this->GetRenderWindowPart()->RequestUpdate(); } if (m_Controls.m_checkMapEntity->checkState() == Qt::Checked) { QmitkMappingJob* pMapJob = new QmitkMappingJob(); pMapJob->setAutoDelete(true); pMapJob->m_spInputData = pRegJob->m_spMovingData; pMapJob->m_InputDataUID = pRegJob->m_MovingDataUID; pMapJob->m_spRegNode = spResultRegistrationNode; pMapJob->m_doGeometryRefinement = false; pMapJob->m_spRefGeometry = pRegJob->m_spTargetData->GetGeometry()->Clone().GetPointer(); pMapJob->m_MappedName = pRegJob->m_JobName + std::string(" mapped moving data"); pMapJob->m_allowUndefPixels = true; pMapJob->m_paddingValue = 100; pMapJob->m_allowUnregPixels = true; pMapJob->m_errorValue = 200; pMapJob->m_InterpolatorLabel = "Linear Interpolation"; pMapJob->m_InterpolatorType = mitk::ImageMappingInterpolator::Linear; connect(pMapJob, SIGNAL(Error(QString)), this, SLOT(OnMapJobError(QString))); connect(pMapJob, SIGNAL(MapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), this, SLOT(OnMapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), Qt::BlockingQueuedConnection); connect(pMapJob, SIGNAL(AlgorithmInfo(QString)), this, SLOT(OnAlgorithmInfo(QString))); m_Controls.m_teLog->append( QString("Started mapping input data...")); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pMapJob); } }; void QmitkMatchPoint::OnMapJobError(QString err) { Error(err); }; void QmitkMatchPoint::OnMapResultIsAvailable(mitk::BaseData::Pointer spMappedData, const QmitkMappingJob* job) { m_Controls.m_teLog->append(QString("Mapped entity stored. Name: ") + QString::fromStdString(job->m_MappedName) + QString("")); mitk::DataNode::Pointer spMappedNode = mitk::generateMappedResultNode(job->m_MappedName, spMappedData, job->GetRegistration()->getRegistrationUID(), job->m_InputDataUID, job->m_doGeometryRefinement, job->m_InterpolatorLabel); this->GetDataStorage()->Add(spMappedNode); this->GetRenderWindowPart()->RequestUpdate(); }; void QmitkMatchPoint::OnAlgorithmIterated(QString info, bool hasIterationCount, unsigned long currentIteration) { if (hasIterationCount) { m_Controls.m_progBarIteration->setValue(currentIteration); } m_Controls.m_teLog->append(info); }; void QmitkMatchPoint::OnLevelChanged(QString info, bool hasLevelCount, unsigned long currentLevel) { if (hasLevelCount) { m_Controls.m_progBarLevel->setValue(currentLevel); } m_Controls.m_teLog->append(QString("") + info + QString("")); }; void QmitkMatchPoint::OnAlgorithmStatusChanged(QString info) { m_Controls.m_teLog->append(QString("") + info + QString(" ")); }; void QmitkMatchPoint::OnAlgorithmInfo(QString info) { m_Controls.m_teLog->append(QString("") + info + QString("")); }; void QmitkMatchPoint::OnAlgorithmSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection) { // check for null selection if (selection.IsNull()) { return; } if (sourcepart != this) { UpdateAlgorithmSelection(selection); } } void QmitkMatchPoint::UpdateAlgorithmSelection(berry::ISelection::ConstPointer selection) { mitk::MAPAlgorithmInfoSelection::ConstPointer currentSelection = selection.Cast(); if (currentSelection) { mitk::MAPAlgorithmInfoSelection::AlgorithmInfoVectorType infoVector = currentSelection->GetSelectedAlgorithmInfo(); if (!infoVector.empty()) { // only the first selection is of interest, the rest will be skipped. this->m_SelectedAlgorithmInfo = infoVector[0]; } } this->OnSelectedAlgorithmChanged(); }; diff --git a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.h b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.h index 7e5a4dc48f..cf5b6226ae 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.h +++ b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.h @@ -1,207 +1,209 @@ /*=================================================================== 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 __Q_MITK_MATCHPOINT_H #define __Q_MITK_MATCHPOINT_H #include #include #include "ui_QmitkMatchPointControls.h" #include // MatchPoint #include #include #include #include #include #include #include class QmitkRegistrationJob; class QmitkMappingJob; /*! \brief MatchPoint \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class QmitkMatchPoint : public QmitkAbstractView { // 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; /** * Creates smartpointer typedefs */ berryObjectMacro(QmitkMatchPoint) QmitkMatchPoint(); ~QmitkMatchPoint(); protected slots: /** * @brief Connect all GUI elements to its corresponding slots */ virtual void CreateConnections(); /// \brief Called when the user clicks the GUI button void OnMaskCheckBoxToggeled(bool checked); void OnLoadAlgorithmButtonPushed(); void OnSelectedAlgorithmChanged(); void OnStartRegBtnPushed(); void OnStopRegBtnPushed(); void OnSaveLogBtnPushed(); void OnRegJobError(QString err); void OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer spResultRegistration, const QmitkRegistrationJob* pRegJob); void OnRegJobFinished(); void OnMapJobError(QString err); void OnMapResultIsAvailable(mitk::BaseData::Pointer spMappedData, const QmitkMappingJob* job); void OnAlgorithmIterated(QString info, bool hasIterationCount, unsigned long currentIteration); void OnLevelChanged(QString info, bool hasLevelCount, unsigned long currentLevel); void OnAlgorithmStatusChanged(QString info); void OnAlgorithmInfo(QString info); protected: virtual void CreateQtPartControl(QWidget* parent); virtual void SetFocus(); /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& nodes); private: /** * @brief Adapt the visibility of GUI elements depending on the current data loaded */ void AdaptFolderGUIElements(); void Error(QString msg); void UpdateAlgorithmList(); /** * checks if appropriated nodes are selected in the data manager. If nodes are selected, * they are stored m_MovingData and m_TargetData. It also sets the info lables accordingly. * @return True: All inputs are set and valid (images). False: At least one input is not set * or invalid */ bool CheckInputs(); /** * Updates the state of registration control buttons. Regarding to selected * inputs, loaded algorithm and its state.*/ void ConfigureRegistrationControls(); /** * Configures the progress bars according to the chosen algorithm. */ void ConfigureProgressInfos(); /** Methods returns a list of all nodes in the data manager containing a registration wrapper. * The list may be empty.*/ mitk::DataStorage::SetOfObjects::Pointer GetRegNodes() const; /** Returns a proposal for a (unique) default reg job name */ std::string GetDefaultRegJobName() const; /** Returns the display name of the passed node. Normally it is just node->GetName(). * if the node contains a point set it is additionally checked if the point set node * has a source node and its name will be added in parentheses.*/ std::string GetInputNodeDisplayName(const mitk::DataNode* node) const; /** Returns the Pointer to the DLL info of the algorithm currently selected by the system. The info is received via m_AlgorithmSelectionListener. @return If there is no item selected the returning pointer will be null. */ const map::deployment::DLLInfo* GetSelectedAlgorithmDLL() const; //! [Qt Selection Listener method and pointer] /** * @brief Method of berry::ISelectionListener that implements the selection listener functionality. * @param sourcepart The workbench part responsible for the selection change. * @param selection This parameter holds the current selection. * * @see ISelectionListener */ void OnAlgorithmSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection); void UpdateAlgorithmSelection(berry::ISelection::ConstPointer selection); friend struct berry::SelectionChangedAdapter; + + QWidget* m_Parent; + /** @brief this pointer holds the algorithm selection listener */ QScopedPointer m_AlgorithmSelectionListener; ::map::deployment::DLLHandle::Pointer m_LoadedDLLHandle; ::map::algorithm::RegistrationAlgorithmBase::Pointer m_LoadedAlgorithm; ::map::deployment::DLLInfo::ConstPointer m_SelectedAlgorithmInfo; typedef map::algorithm::facet::IterativeAlgorithmInterface IIterativeAlgorithm; typedef map::algorithm::facet::MultiResRegistrationAlgorithmInterface IMultiResAlgorithm; typedef map::algorithm::facet::StoppableAlgorithmInterface IStoppableAlgorithm; mitk::DataNode::Pointer m_spSelectedTargetNode; mitk::DataNode::Pointer m_spSelectedMovingNode; /*Data of the selected target node that should be used for registration. Can be the direct return of node->GetData(), but can also be a sub set (like a special time frame).*/ mitk::BaseData::ConstPointer m_spSelectedTargetData; /*Data of the selected moving node that should be used for registration. Can be the direct return of node->GetData(), but can also be a sub set (like a special time frame).*/ mitk::BaseData::ConstPointer m_spSelectedMovingData; mitk::DataNode::Pointer m_spSelectedTargetMaskNode; mitk::DataNode::Pointer m_spSelectedMovingMaskNode; /*Data of the selected target mask node that should be used for registration. Can be the direct return of node->GetData(), but can also be a sub set (like a special time frame).*/ mitk::Image::ConstPointer m_spSelectedTargetMaskData; /*Data of the selected moving mask node that should be used for registration. Can be the direct return of node->GetData(), but can also be a sub set (like a special time frame).*/ mitk::Image::ConstPointer m_spSelectedMovingMaskData; // boolean variables to control visibility of GUI elements bool m_CanLoadAlgorithm; bool m_ValidInputs; bool m_Working; - QWidget* m_Parent; Ui::MatchPointAdvancedControls m_Controls; }; #endif // MatchPoint_h diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp index c6b0dd5b45..8cf7305b4e 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp @@ -1,352 +1,355 @@ /*=================================================================== 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 "mitkRegVisPropertyTags.h" #include "mitkMatchPointPropertyTags.h" #include "mitkRegEvaluationObject.h" #include "mitkRegistrationHelper.h" #include "mitkRegEvaluationMapper2D.h" #include // Qmitk #include "QmitkRenderWindow.h" #include "QmitkMatchPointRegistrationEvaluator.h" // Qt #include #include #include const std::string QmitkMatchPointRegistrationEvaluator::VIEW_ID = "org.mitk.views.matchpoint.registration.evaluator"; +const std::string QmitkMatchPointRegistrationEvaluator::HelperNodeName = + "RegistrationEvaluationHelper"; + QmitkMatchPointRegistrationEvaluator::QmitkMatchPointRegistrationEvaluator() - : m_Parent(nullptr), m_activeEvaluation(false), m_autoMoving(false), m_autoTarget(false), m_currentSelectedTimeStep(0), HelperNodeName("RegistrationEvaluationHelper") + : m_Parent(nullptr), m_activeEvaluation(false), m_autoMoving(false), m_autoTarget(false), m_currentSelectedTimeStep(0) { m_currentSelectedPosition.Fill(0.0); } QmitkMatchPointRegistrationEvaluator::~QmitkMatchPointRegistrationEvaluator() { if (this->m_selectedEvalNode.IsNotNull() && this->GetDataStorage().IsNotNull()) { this->GetDataStorage()->Remove(this->m_selectedEvalNode); } } void QmitkMatchPointRegistrationEvaluator::SetFocus() { } void QmitkMatchPointRegistrationEvaluator::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); } void QmitkMatchPointRegistrationEvaluator::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; connect(m_Controls.pbEval, SIGNAL(clicked()), this, SLOT(OnEvalBtnPushed())); connect(m_Controls.pbStop, SIGNAL(clicked()), this, SLOT(OnStopBtnPushed())); connect(m_Controls.evalSettings, SIGNAL(SettingsChanged(mitk::DataNode*)), this, SLOT(OnSettingsChanged(mitk::DataNode*))); this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); m_selectedEvalNode = this->GetDataStorage()->GetNamedNode(HelperNodeName); this->CheckInputs(); this->ConfigureControls(); } void QmitkMatchPointRegistrationEvaluator::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } void QmitkMatchPointRegistrationEvaluator::RenderWindowPartDeactivated( mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void QmitkMatchPointRegistrationEvaluator::CheckInputs() { if (!m_activeEvaluation) { QList dataNodes = this->GetDataManagerSelection(); this->m_autoMoving = false; this->m_autoTarget = false; this->m_spSelectedMovingNode = nullptr; this->m_spSelectedTargetNode = nullptr; this->m_spSelectedRegNode = nullptr; if (dataNodes.size() > 0) { //test if auto select works if (mitk::MITKRegistrationHelper::IsRegNode(dataNodes[0]) && dataNodes[0]->GetData()) { this->m_spSelectedRegNode = dataNodes[0]; dataNodes.pop_front(); mitk::BaseProperty* uidProp = m_spSelectedRegNode->GetData()->GetProperty(mitk::Prop_RegAlgMovingData); if (uidProp) { //search for the moving node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); this->m_spSelectedMovingNode = this->GetDataStorage()->GetNode(predicate); this->m_autoMoving = this->m_spSelectedMovingNode.IsNotNull(); } uidProp = m_spSelectedRegNode->GetData()->GetProperty(mitk::Prop_RegAlgTargetData); if (uidProp) { //search for the target node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); this->m_spSelectedTargetNode = this->GetDataStorage()->GetNode(predicate); this->m_autoTarget = this->m_spSelectedTargetNode.IsNotNull(); } } //if still nodes are selected -> ignore possible auto select if (!dataNodes.empty()) { mitk::Image* inputImage = dynamic_cast(dataNodes[0]->GetData()); if (inputImage) { this->m_spSelectedMovingNode = dataNodes[0]; this->m_autoMoving = false; dataNodes.pop_front(); } } if (!dataNodes.empty()) { mitk::Image* inputImage = dynamic_cast(dataNodes[0]->GetData()); if (inputImage) { this->m_spSelectedTargetNode = dataNodes[0]; this->m_autoTarget = false; dataNodes.pop_front(); } } } } } -void QmitkMatchPointRegistrationEvaluator::OnSelectionChanged(berry::IWorkbenchPart::Pointer source, - const QList& nodes) +void QmitkMatchPointRegistrationEvaluator::OnSelectionChanged(berry::IWorkbenchPart::Pointer, + const QList&) { this->CheckInputs(); this->ConfigureControls(); }; void QmitkMatchPointRegistrationEvaluator::NodeRemoved(const mitk::DataNode* node) { if (node == this->m_spSelectedMovingNode || node == this->m_spSelectedRegNode || node == this->m_spSelectedTargetNode || node == this->m_selectedEvalNode) { if (node == this->m_selectedEvalNode) { this->m_selectedEvalNode = nullptr; } this->OnStopBtnPushed(); MITK_INFO << "Stopped current MatchPoint evaluation session, because at least one relevant node was removed from storage."; } } void QmitkMatchPointRegistrationEvaluator::ConfigureControls() { //configure input data widgets if (this->m_spSelectedRegNode.IsNull()) { if (this->m_spSelectedMovingNode.IsNotNull() && this->m_spSelectedTargetNode.IsNotNull()) { m_Controls.lbRegistrationName->setText( QString("No registration selected! Direct comparison")); } else { m_Controls.lbRegistrationName->setText( QString("No registration selected!")); } } else { m_Controls.lbRegistrationName->setText(QString::fromStdString( this->m_spSelectedRegNode->GetName())); } if (this->m_spSelectedMovingNode.IsNull()) { m_Controls.lbMovingName->setText(QString("no moving image selected!")); } else { if (this->m_autoMoving) { m_Controls.lbMovingName->setText(QString("") + QString::fromStdString( this->m_spSelectedMovingNode->GetName()) + QString(" (auto selected)")); } else { m_Controls.lbMovingName->setText(QString::fromStdString(this->m_spSelectedMovingNode->GetName())); } } if (this->m_spSelectedTargetNode.IsNull()) { m_Controls.lbTargetName->setText(QString("no target image selected!")); } else { if (this->m_autoTarget) { m_Controls.lbTargetName->setText(QString("") + QString::fromStdString( this->m_spSelectedTargetNode->GetName()) + QString(" (auto selected)")); } else { m_Controls.lbTargetName->setText(QString::fromStdString(this->m_spSelectedTargetNode->GetName())); } } //config settings widget this->m_Controls.evalSettings->setVisible(m_activeEvaluation); this->m_Controls.pbEval->setEnabled(this->m_spSelectedMovingNode.IsNotNull() && this->m_spSelectedTargetNode.IsNotNull()); this->m_Controls.pbEval->setVisible(!m_activeEvaluation); this->m_Controls.pbStop->setVisible(m_activeEvaluation); this->m_Controls.lbMovingName->setEnabled(!m_activeEvaluation); this->m_Controls.lbRegistrationName->setEnabled(!m_activeEvaluation); this->m_Controls.lbTargetName->setEnabled(!m_activeEvaluation); } void QmitkMatchPointRegistrationEvaluator::OnSliceChanged() { mitk::Point3D currentSelectedPosition = GetRenderWindowPart()->GetSelectedPosition(nullptr); unsigned int currentSelectedTimeStep = GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); if (m_currentSelectedPosition != currentSelectedPosition || m_currentSelectedTimeStep != currentSelectedTimeStep || m_selectedNodeTime > m_currentPositionTime) { //the current position has been changed or the selected node has been changed since the last position validation -> check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimeStep = currentSelectedTimeStep; m_currentPositionTime.Modified(); if (this->m_selectedEvalNode.IsNotNull()) { this->m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalCurrentPosition, mitk::GenericProperty::New(currentSelectedPosition)); } } } void QmitkMatchPointRegistrationEvaluator::OnSettingsChanged(mitk::DataNode*) { this->GetRenderWindowPart()->RequestUpdate(); }; void QmitkMatchPointRegistrationEvaluator::OnEvalBtnPushed() { //reinit view - mitk::RenderingManager::GetInstance()->InitializeViews(m_spSelectedTargetNode->GetData()->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(m_spSelectedTargetNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RegEvaluationObject::Pointer regEval = mitk::RegEvaluationObject::New(); mitk::MAPRegistrationWrapper::Pointer reg; if (m_spSelectedRegNode.IsNotNull()) { reg = dynamic_cast(this->m_spSelectedRegNode->GetData()); } else { //generate a dymme reg to use reg = mitk::GenerateIdentityRegistration3D(); } regEval->SetRegistration(reg); regEval->SetTargetNode(this->m_spSelectedTargetNode); regEval->SetMovingNode(this->m_spSelectedMovingNode); if (this->m_selectedEvalNode.IsNotNull()) { this->GetDataStorage()->Remove(this->m_selectedEvalNode); } this->m_selectedEvalNode = mitk::DataNode::New(); this->m_selectedEvalNode->SetData(regEval); - + mitk::RegEvaluationMapper2D::SetDefaultProperties(this->m_selectedEvalNode); this->m_selectedEvalNode->SetName(HelperNodeName); this->m_selectedEvalNode->SetBoolProperty("helper object", true); this->GetDataStorage()->Add(this->m_selectedEvalNode); this->m_Controls.evalSettings->SetNode(this->m_selectedEvalNode); this->OnSliceChanged(); this->GetRenderWindowPart()->RequestUpdate(); this->m_activeEvaluation = true; this->CheckInputs(); this->ConfigureControls(); } void QmitkMatchPointRegistrationEvaluator::OnStopBtnPushed() { this->m_activeEvaluation = false; if (this->m_selectedEvalNode.IsNotNull()) { this->GetDataStorage()->Remove(this->m_selectedEvalNode); } this->m_selectedEvalNode = nullptr; this->m_Controls.evalSettings->SetNode(this->m_selectedEvalNode); this->CheckInputs(); this->ConfigureControls(); this->GetRenderWindowPart()->RequestUpdate(); } diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.h b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.h index d0536f01d4..725cbbaf72 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.h +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.h @@ -1,123 +1,123 @@ /*=================================================================== 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 __Q_MITK_MATCHPOINT_REGISTRATION_EVALUATOR_H #define __Q_MITK_MATCHPOINT_REGISTRATION_EVALUATOR_H #include #include #include #include "ui_QmitkMatchPointRegistrationEvaluator.h" /*! \brief QmitkMatchPointRegistrationEvaluator \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class QmitkMatchPointRegistrationEvaluator : public QmitkAbstractView, public mitk::IRenderWindowPartListener -{ +{ // 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: +public: static const std::string VIEW_ID; /** * Creates smartpointer typedefs */ berryObjectMacro(QmitkMatchPointRegistrationEvaluator) QmitkMatchPointRegistrationEvaluator(); ~QmitkMatchPointRegistrationEvaluator(); virtual void CreateQtPartControl(QWidget *parent); protected slots: /// \brief Called when the user clicks the GUI button void OnEvalBtnPushed(); void OnStopBtnPushed(); void OnSettingsChanged(mitk::DataNode*); void OnSliceChanged(); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, const QList& nodes) override; virtual void NodeRemoved(const mitk::DataNode* node) override; virtual void SetFocus(); virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart); virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart); Ui::MatchPointRegistrationEvaluatorControls m_Controls; private: QWidget *m_Parent; void Error(QString msg); /** Methods returns a list of all eval nodes in the data manager.*/ QList GetEvalNodes(); /** * Checks if appropriated nodes are selected in the data manager. If nodes are selected, * they are stored m_spSelectedRegNode, m_spSelectedInputNode and m_spSelectedRefNode. * They are also checked for vadility and stored in m_ValidInput,... . * It also sets the info lables accordingly.*/ void CheckInputs(); /** * Updates the state of controls regarding to selected eval object.*/ void ConfigureControls(); mitk::DataNode::Pointer m_selectedEvalNode; QmitkSliceNavigationListener m_SliceChangeListener; itk::TimeStamp m_selectedNodeTime; itk::TimeStamp m_currentPositionTime; + bool m_activeEvaluation; + bool m_autoMoving; + bool m_autoTarget; + /** @brief currently valid selected position in the inspector*/ mitk::Point3D m_currentSelectedPosition; /** @brief indicates if the currently selected position is valid for the currently selected fit. * This it is within the input image */ unsigned int m_currentSelectedTimeStep; mitk::DataNode::Pointer m_spSelectedRegNode; mitk::DataNode::Pointer m_spSelectedMovingNode; mitk::DataNode::Pointer m_spSelectedTargetNode; - bool m_autoTarget; - bool m_autoMoving; - bool m_activeEvaluation; - - const std::string HelperNodeName; + static const std::string HelperNodeName; }; #endif // MatchPoint_h diff --git a/Plugins/org.mitk.gui.qt.matchpoint.framereg/src/internal/QmitkMatchPointFrameCorrection.cpp b/Plugins/org.mitk.gui.qt.matchpoint.framereg/src/internal/QmitkMatchPointFrameCorrection.cpp index 3e1192c6e3..bd3391a8d7 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.framereg/src/internal/QmitkMatchPointFrameCorrection.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.framereg/src/internal/QmitkMatchPointFrameCorrection.cpp @@ -1,820 +1,818 @@ /*=================================================================== 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 "org_mitk_gui_qt_matchpoint_framereg_Activator.h" // Blueberry #include #include #include #include // Mitk #include #include #include #include #include #include #include #include #include #include // Qmitk #include "QmitkMatchPointFrameCorrection.h" #include #include // Qt #include #include #include #include #include // MatchPoint #include #include #include #include #include #include #include #include #include const std::string QmitkMatchPointFrameCorrection::VIEW_ID = "org.mitk.views.matchpoint.algorithm.framereg"; QmitkMatchPointFrameCorrection::QmitkMatchPointFrameCorrection() : m_Parent(nullptr), m_LoadedDLLHandle(nullptr), m_LoadedAlgorithm(nullptr), m_CanLoadAlgorithm(false), m_ValidInputs(false), m_Working(false) { m_spSelectedTargetData = nullptr; m_spSelectedTargetMaskData = nullptr; } QmitkMatchPointFrameCorrection::~QmitkMatchPointFrameCorrection() { // remove selection service berry::ISelectionService* s = this->GetSite()->GetWorkbenchWindow()->GetSelectionService(); if (s) { s->RemoveSelectionListener(m_AlgorithmSelectionListener.data()); } } void QmitkMatchPointFrameCorrection::SetFocus() { } void QmitkMatchPointFrameCorrection::CreateConnections() { connect(m_Controls.checkTargetMask, SIGNAL(toggled(bool)), this, SLOT(OnMaskCheckBoxToggeled(bool))); // ------ // Tab 1 - Shared library loading interface // ------ connect(m_Controls.m_pbLoadSelected, SIGNAL(clicked()), this, SLOT(OnLoadAlgorithmButtonPushed())); // ----- // Tab 2 - Execution // ----- connect(m_Controls.m_pbStartReg, SIGNAL(clicked()), this, SLOT(OnStartRegBtnPushed())); connect(m_Controls.m_pbSaveLog, SIGNAL(clicked()), this, SLOT(OnSaveLogBtnPushed())); // ----- // Tab 4 - Frames // ----- connect(m_Controls.m_btnFrameSelAll, SIGNAL(clicked()), this, SLOT(OnFramesSelectAllPushed())); connect(m_Controls.m_btnFrameDeSelAll, SIGNAL(clicked()), this, SLOT(OnFramesDeSelectAllPushed())); connect(m_Controls.m_btnFrameInvert, SIGNAL(clicked()), this, SLOT(OnFramesInvertPushed())); } const map::deployment::DLLInfo* QmitkMatchPointFrameCorrection::GetSelectedAlgorithmDLL() const { return m_SelectedAlgorithmInfo; } -void QmitkMatchPointFrameCorrection::OnMaskCheckBoxToggeled(bool checked) +void QmitkMatchPointFrameCorrection::OnMaskCheckBoxToggeled(bool) { if (!m_Working) { CheckInputs(); ConfigureRegistrationControls(); } }; void QmitkMatchPointFrameCorrection::OnSelectedAlgorithmChanged() { std::stringstream descriptionString; ::map::deployment::DLLInfo::ConstPointer currentItemInfo = GetSelectedAlgorithmDLL(); if (!currentItemInfo) { return; } m_Controls.m_teAlgorithmDetails->updateInfo(currentItemInfo); m_Controls.m_lbSelectedAlgorithm->setText(QString::fromStdString( currentItemInfo->getAlgorithmUID().getName())); // enable loading m_CanLoadAlgorithm = true; this->AdaptFolderGUIElements(); } void QmitkMatchPointFrameCorrection::OnLoadAlgorithmButtonPushed() { map::deployment::DLLInfo::ConstPointer dllInfo = GetSelectedAlgorithmDLL(); if (!dllInfo) { Error(QString("No valid algorithm is selected. Cannot load algorithm. ABORTING.")); return; } ::map::deployment::DLLHandle::Pointer tempDLLHandle = ::map::deployment::openDeploymentDLL( dllInfo->getLibraryFilePath()); ::map::algorithm::RegistrationAlgorithmBase::Pointer tempAlgorithm = ::map::deployment::getRegistrationAlgorithm(tempDLLHandle); if (tempAlgorithm.IsNull()) { Error(QString("Error. Cannot load selected algorithm.")); return; } this->m_LoadedAlgorithm = tempAlgorithm; this->m_LoadedDLLHandle = tempDLLHandle; this->m_Controls.m_AlgoConfigurator->setAlgorithm(m_LoadedAlgorithm); m_Controls.checkTargetMask->setChecked(false); this->AdaptFolderGUIElements(); this->CheckInputs(); this->ConfigureRegistrationControls(); this->ConfigureProgressInfos(); this->m_Controls.m_tabs->setCurrentIndex(1); } void QmitkMatchPointFrameCorrection::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); m_Controls.m_teLog->append(QString("") + msg + QString("")); } void QmitkMatchPointFrameCorrection::AdaptFolderGUIElements() { m_Controls.m_pbLoadSelected->setEnabled(m_CanLoadAlgorithm); } void QmitkMatchPointFrameCorrection::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; m_Controls.checkTargetMask->setChecked(false); m_Controls.m_tabs->setCurrentIndex(0); m_Controls.m_mapperSettings->AllowSampling(false); m_AlgorithmSelectionListener.reset(new berry::SelectionChangedAdapter(this, &QmitkMatchPointFrameCorrection::OnAlgorithmSelectionChanged)); // register selection listener GetSite()->GetWorkbenchWindow()->GetSelectionService()->AddSelectionListener( m_AlgorithmSelectionListener.data()); this->CreateConnections(); this->AdaptFolderGUIElements(); this->CheckInputs(); this->ConfigureProgressInfos(); this->ConfigureRegistrationControls(); berry::ISelection::ConstPointer selection = GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.matchpoint.algorithm.browser"); this->UpdateAlgorithmSelection(selection); } bool QmitkMatchPointFrameCorrection::CheckInputs() { bool validTarget = false; bool validTargetMask = false; mitk::DataNode::Pointer oldTargetNode = m_spSelectedTargetNode; mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer maskPredicate = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); if (m_LoadedAlgorithm.IsNull()) { m_Controls.m_lbLoadedAlgorithmName->setText( QString("No algorithm seleted!")); m_spSelectedTargetNode = nullptr; m_spSelectedTargetData = nullptr; m_spSelectedTargetMaskNode = nullptr; m_spSelectedTargetMaskData = nullptr; } else { QList nodes = this->GetDataManagerSelection(); mitk::Image* targetImage = nullptr; - mitk::PointSet* targetPointSet = nullptr; - mitk::Image* targetMaskImage = nullptr; typedef ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<3, 3> MaskRegInterface; MaskRegInterface* pMaskInterface = dynamic_cast(m_LoadedAlgorithm.GetPointer()); if (nodes.count() < 1) { m_Controls.m_lbTargetName->setText(QString("no data selected!")); m_spSelectedTargetNode = nullptr; m_spSelectedTargetData = nullptr; } else { m_spSelectedTargetNode = nodes.front(); m_spSelectedTargetData = m_spSelectedTargetNode->GetData(); targetImage = dynamic_cast(m_spSelectedTargetNode->GetData()); if (targetImage) { if (targetImage->GetTimeSteps() < 1) { m_Controls.m_lbTargetName->setText(QString("Image has no mulitple time steps")); } else if (targetImage->GetDimension() != m_LoadedAlgorithm->getTargetDimensions() + 1) { m_Controls.m_lbTargetName->setText(QString("wrong image dimension. ") + QString::number(m_LoadedAlgorithm->getTargetDimensions()) + QString("D+t needed")); } else { validTarget = true; } } else { m_Controls.m_lbTargetName->setText(QString("no supported data selected!")); } nodes.removeFirst(); } if (m_Controls.checkTargetMask->isChecked()) { if (nodes.count() < 1) { m_Controls.m_lbTargetMaskName->setText(QString("no data selected!")); m_spSelectedTargetMaskNode = nullptr; m_spSelectedTargetMaskData = nullptr; } else { m_spSelectedTargetMaskNode = nodes.front(); m_spSelectedTargetMaskData = nullptr; targetMaskImage = dynamic_cast(m_spSelectedTargetMaskNode->GetData()); bool isMask = maskPredicate->CheckNode(m_spSelectedTargetMaskNode); if (!isMask) { m_Controls.m_lbTargetMaskName->setText(QString("no mask selected!")); } else if (targetMaskImage && pMaskInterface) { m_spSelectedTargetMaskData = targetMaskImage; validTargetMask = true; } else { m_Controls.m_lbTargetMaskName->setText( QString("no supported data selected!")); } } } else { m_Controls.m_lbTargetMaskName->setText(QString("mask deactivated")); validTargetMask = true; m_spSelectedTargetMaskNode = nullptr; m_spSelectedTargetMaskData = nullptr; } } if (validTarget) { m_Controls.m_lbTargetName->setText(QString::fromStdString(GetInputNodeDisplayName( m_spSelectedTargetNode))); if (oldTargetNode != m_spSelectedTargetNode) { ConfigureFrameList(); } } else { m_Controls.m_listFrames->clear(); } if (validTargetMask && m_Controls.checkTargetMask->isChecked()) { m_Controls.m_lbTargetMaskName->setText(QString::fromStdString(GetInputNodeDisplayName( m_spSelectedTargetMaskNode))); } m_ValidInputs = validTarget && validTargetMask; return m_ValidInputs; } std::string QmitkMatchPointFrameCorrection::GetInputNodeDisplayName(const mitk::DataNode* node) const { std::string result = "UNDEFINED/nullptr"; if (node) { result = node->GetName(); const mitk::PointSet* pointSet = dynamic_cast(node->GetData()); if (pointSet) { mitk::DataStorage::SetOfObjects::ConstPointer sources = this->GetDataStorage()->GetSources(node); if (sources.IsNotNull() && sources->Size() > 0) { result = result + " (" + sources->GetElement(0)->GetName() + ")"; } } } return result; } mitk::DataStorage::SetOfObjects::Pointer QmitkMatchPointFrameCorrection::GetRegNodes() const { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetAll(); mitk::DataStorage::SetOfObjects::Pointer result = mitk::DataStorage::SetOfObjects::New(); for (mitk::DataStorage::SetOfObjects::const_iterator pos = nodes->begin(); pos != nodes->end(); ++pos) { if (mitk::MITKRegistrationHelper::IsRegNode(*pos)) { result->push_back(*pos); } } return result; } std::string QmitkMatchPointFrameCorrection::GetDefaultJobName() const { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetRegNodes().GetPointer(); mitk::DataStorage::SetOfObjects::ElementIdentifier newIndex = 0; bool isUnique = false; std::string baseName = "corrected #"; if (m_spSelectedTargetNode.IsNotNull()) { baseName = m_spSelectedTargetNode->GetName() + "corrected #"; } std::string result = baseName; while (!isUnique) { ++newIndex; result = baseName + ::map::core::convert::toStr(newIndex); isUnique = this->GetDataStorage()->GetNamedNode(result) == nullptr; } return result; } void QmitkMatchPointFrameCorrection::ConfigureRegistrationControls() { m_Controls.m_tabSelection->setEnabled(!m_Working); m_Controls.m_leRegJobName->setEnabled(!m_Working); m_Controls.groupMasks->setEnabled(!m_Working); m_Controls.m_pbStartReg->setEnabled(false); m_Controls.m_lbTargetMaskName->setVisible(m_Controls.checkTargetMask->isChecked()); if (m_LoadedAlgorithm.IsNotNull()) { m_Controls.m_tabSettings->setEnabled(!m_Working); m_Controls.m_tabExclusion->setEnabled(!m_Working); m_Controls.m_tabExecution->setEnabled(true); m_Controls.m_pbStartReg->setEnabled(m_ValidInputs && !m_Working); m_Controls.m_leRegJobName->setEnabled(!m_Working); typedef ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<3, 3> MaskRegInterface; const MaskRegInterface* pMaskReg = dynamic_cast (m_LoadedAlgorithm.GetPointer()); m_Controls.groupMasks->setVisible(pMaskReg != nullptr); this->m_Controls.m_lbLoadedAlgorithmName->setText( QString::fromStdString(m_LoadedAlgorithm->getUID()->toStr())); } else { m_Controls.m_tabSettings->setEnabled(false); m_Controls.m_tabExclusion->setEnabled(false); m_Controls.m_tabExecution->setEnabled(false); this->m_Controls.m_lbLoadedAlgorithmName->setText( QString("no algorithm loaded!")); m_Controls.groupMasks->setVisible(false); } if (!m_Working) { this->m_Controls.m_leRegJobName->setText(QString::fromStdString(this->GetDefaultJobName())); } } void QmitkMatchPointFrameCorrection::ConfigureProgressInfos() { const IIterativeAlgorithm* pIterative = dynamic_cast (m_LoadedAlgorithm.GetPointer()); const IMultiResAlgorithm* pMultiRes = dynamic_cast (m_LoadedAlgorithm.GetPointer()); m_Controls.m_progBarIteration->setVisible(pIterative); m_Controls.m_lbProgBarIteration->setVisible(pIterative); if (pIterative) { QString format = "%p% (%v/%m)"; if (!pIterative->hasMaxIterationCount()) { format = "%v"; m_Controls.m_progBarIteration->setMaximum(0); } else { m_Controls.m_progBarIteration->setMaximum(pIterative->getMaxIterations()); } m_Controls.m_progBarIteration->setFormat(format); } if (pMultiRes) { m_Controls.m_progBarLevel->setMaximum(pMultiRes->getResolutionLevels()); } else { m_Controls.m_progBarLevel->setMaximum(1); } m_Controls.m_progBarIteration->reset(); m_Controls.m_progBarLevel->reset(); m_Controls.m_progBarFrame->reset(); } void QmitkMatchPointFrameCorrection::ConfigureFrameList() { m_Controls.m_listFrames->clear(); if (m_spSelectedTargetData.IsNotNull()) { mitk::TimeGeometry::ConstPointer tg = m_spSelectedTargetData->GetTimeGeometry(); for (unsigned int i = 1; i < tg->CountTimeSteps(); ++i) { QString lable = "Timepoint #" + QString::number(i) + QString(" (") + QString::number( tg->GetMinimumTimePoint(i)) + QString(" ms - " + QString::number(tg->GetMaximumTimePoint( i)) + QString(" ms)")); QListWidgetItem* item = new QListWidgetItem(lable, m_Controls.m_listFrames); item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); item->setCheckState(Qt::Checked); } } } void QmitkMatchPointFrameCorrection::OnFramesSelectAllPushed() { - for (unsigned int row = 0; row < m_Controls.m_listFrames->count(); row++) + for (int row = 0; row < m_Controls.m_listFrames->count(); row++) { QListWidgetItem* item = m_Controls.m_listFrames->item(row); item->setCheckState(Qt::Checked); } }; void QmitkMatchPointFrameCorrection::OnFramesDeSelectAllPushed() { - for (unsigned int row = 0; row < m_Controls.m_listFrames->count(); row++) + for (int row = 0; row < m_Controls.m_listFrames->count(); row++) { QListWidgetItem* item = m_Controls.m_listFrames->item(row); item->setCheckState(Qt::Unchecked); } }; void QmitkMatchPointFrameCorrection::OnFramesInvertPushed() { - for (unsigned int row = 0; row < m_Controls.m_listFrames->count(); row++) + for (int row = 0; row < m_Controls.m_listFrames->count(); row++) { QListWidgetItem* item = m_Controls.m_listFrames->item(row); if (item->checkState() == Qt::Unchecked) { item->setCheckState(Qt::Checked); } else { item->setCheckState(Qt::Unchecked); } } }; mitk::TimeFramesRegistrationHelper::IgnoreListType QmitkMatchPointFrameCorrection::GenerateIgnoreList() const { mitk::TimeFramesRegistrationHelper::IgnoreListType result; - for (unsigned int row = 0; row < m_Controls.m_listFrames->count(); row++) + for (int row = 0; row < m_Controls.m_listFrames->count(); row++) { QListWidgetItem* item = m_Controls.m_listFrames->item(row); if (item->checkState() == Qt::Unchecked) { result.push_back(row + 1); } } return result; } -void QmitkMatchPointFrameCorrection::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, - const QList& nodes) +void QmitkMatchPointFrameCorrection::OnSelectionChanged(berry::IWorkbenchPart::Pointer, + const QList&) { if (!m_Working) { CheckInputs(); ConfigureRegistrationControls(); } } void QmitkMatchPointFrameCorrection::OnStartRegBtnPushed() { this->m_Working = true; //////////////////////////////// //configure GUI this->ConfigureProgressInfos(); m_Controls.m_progBarIteration->reset(); m_Controls.m_progBarLevel->reset(); this->ConfigureRegistrationControls(); if (m_Controls.m_checkClearLog->checkState() == Qt::Checked) { this->m_Controls.m_teLog->clear(); } ///////////////////////// //create job and put it into the thread pool QmitkFramesRegistrationJob* pJob = new QmitkFramesRegistrationJob(m_LoadedAlgorithm); pJob->setAutoDelete(true); pJob->m_spTargetData = m_spSelectedTargetData; pJob->m_TargetDataUID = mitk::EnsureUID(this->m_spSelectedTargetNode->GetData()); pJob->m_IgnoreList = this->GenerateIgnoreList(); if (m_spSelectedTargetMaskData.IsNotNull()) { pJob->m_spTargetMask = m_spSelectedTargetMaskData; pJob->m_TargetMaskDataUID = mitk::EnsureUID(this->m_spSelectedTargetMaskNode->GetData()); } pJob->m_MappedName = m_Controls.m_leRegJobName->text().toStdString(); m_Controls.m_mapperSettings->ConfigureJobSettings(pJob); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnRegJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnRegJobFinished())); connect(pJob, SIGNAL(ResultIsAvailable(mitk::Image::Pointer, const QmitkFramesRegistrationJob*)), this, SLOT(OnMapResultIsAvailable(mitk::Image::Pointer, const QmitkFramesRegistrationJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(AlgorithmInfo(QString)), this, SLOT(OnAlgorithmInfo(QString))); connect(pJob, SIGNAL(AlgorithmStatusChanged(QString)), this, SLOT(OnAlgorithmStatusChanged(QString))); connect(pJob, SIGNAL(AlgorithmIterated(QString, bool, unsigned long)), this, SLOT(OnAlgorithmIterated(QString, bool, unsigned long))); connect(pJob, SIGNAL(LevelChanged(QString, bool, unsigned long)), this, SLOT(OnLevelChanged(QString, bool, unsigned long))); connect(pJob, SIGNAL(FrameRegistered(double)), this, SLOT(OnFrameRegistered(double))); connect(pJob, SIGNAL(FrameMapped(double)), this, SLOT(OnFrameMapped(double))); connect(pJob, SIGNAL(FrameProcessed(double)), this, SLOT(OnFrameProcessed(double))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } void QmitkMatchPointFrameCorrection::OnSaveLogBtnPushed() { QDateTime currentTime = QDateTime::currentDateTime(); QString fileName = tr("registration_log_") + currentTime.toString(tr("yyyy-MM-dd_hh-mm-ss")) + tr(".txt"); fileName = QFileDialog::getSaveFileName(nullptr, tr("Save registration log"), fileName, tr("Text files (*.txt)")); if (fileName.isEmpty()) { QMessageBox::critical(nullptr, tr("No file selected!"), tr("Cannot save registration log file. Please selected a file.")); } else { std::ofstream file; std::ios_base::openmode iOpenFlag = std::ios_base::out | std::ios_base::trunc; file.open(fileName.toStdString().c_str(), iOpenFlag); if (!file.is_open()) { mitkThrow() << "Cannot open or create specified file to save. File path: " << fileName.toStdString(); } file << this->m_Controls.m_teLog->toPlainText().toStdString() << std::endl; file.close(); } } void QmitkMatchPointFrameCorrection::OnRegJobError(QString err) { Error(err); }; void QmitkMatchPointFrameCorrection::OnRegJobFinished() { this->m_Working = false; this->GetRenderWindowPart()->RequestUpdate(); this->CheckInputs(); this->ConfigureRegistrationControls(); this->ConfigureProgressInfos(); }; void QmitkMatchPointFrameCorrection::OnMapResultIsAvailable(mitk::Image::Pointer spMappedData, const QmitkFramesRegistrationJob* job) { m_Controls.m_teLog->append(QString("Corrected image stored. Name: ") + QString::fromStdString(job->m_MappedName) + QString("")); mitk::DataNode::Pointer spResultNode = mitk::generateMappedResultNode(job->m_MappedName, spMappedData.GetPointer(), "", job->m_TargetDataUID, false, job->m_InterpolatorLabel); this->GetDataStorage()->Add(spResultNode, this->m_spSelectedTargetNode); this->GetRenderWindowPart()->RequestUpdate(); }; void QmitkMatchPointFrameCorrection::OnMapJobError(QString err) { Error(err); }; void QmitkMatchPointFrameCorrection::OnAlgorithmIterated(QString info, bool hasIterationCount, unsigned long currentIteration) { if (hasIterationCount) { m_Controls.m_progBarIteration->setValue(currentIteration); } m_Controls.m_teLog->append(info); }; void QmitkMatchPointFrameCorrection::OnLevelChanged(QString info, bool hasLevelCount, unsigned long currentLevel) { if (hasLevelCount) { m_Controls.m_progBarLevel->setValue(currentLevel); } m_Controls.m_teLog->append(QString("") + info + QString("")); }; void QmitkMatchPointFrameCorrection::OnAlgorithmStatusChanged(QString info) { m_Controls.m_teLog->append(QString("") + info + QString(" ")); }; void QmitkMatchPointFrameCorrection::OnAlgorithmInfo(QString info) { m_Controls.m_teLog->append(QString("") + info + QString("")); }; void QmitkMatchPointFrameCorrection::OnFrameProcessed(double progress) { m_Controls.m_teLog->append(QString("Frame processed...")); m_Controls.m_progBarFrame->setValue(100 * progress); }; void QmitkMatchPointFrameCorrection::OnFrameRegistered(double progress) { m_Controls.m_teLog->append(QString("Frame registered...")); m_Controls.m_progBarFrame->setValue(100 * progress); }; void QmitkMatchPointFrameCorrection::OnFrameMapped(double progress) { m_Controls.m_teLog->append(QString("Frame mapped...")); m_Controls.m_progBarFrame->setValue(100 * progress); }; void QmitkMatchPointFrameCorrection::OnAlgorithmSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection) { // check for null selection if (selection.IsNull()) { return; } if (sourcepart != this) { UpdateAlgorithmSelection(selection); } } void QmitkMatchPointFrameCorrection::UpdateAlgorithmSelection(berry::ISelection::ConstPointer selection) { mitk::MAPAlgorithmInfoSelection::ConstPointer currentSelection = selection.Cast(); if (currentSelection) { mitk::MAPAlgorithmInfoSelection::AlgorithmInfoVectorType infoVector = currentSelection->GetSelectedAlgorithmInfo(); if (!infoVector.empty()) { // only the first selection is of interest, the rest will be skipped. this->m_SelectedAlgorithmInfo = infoVector[0]; } } this->OnSelectedAlgorithmChanged(); }; diff --git a/Plugins/org.mitk.gui.qt.matchpoint.framereg/src/internal/QmitkMatchPointFrameCorrection.h b/Plugins/org.mitk.gui.qt.matchpoint.framereg/src/internal/QmitkMatchPointFrameCorrection.h index d815dad6b1..0cc6c1f155 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.framereg/src/internal/QmitkMatchPointFrameCorrection.h +++ b/Plugins/org.mitk.gui.qt.matchpoint.framereg/src/internal/QmitkMatchPointFrameCorrection.h @@ -1,203 +1,205 @@ /*=================================================================== 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 __Q_MITK_MATCHPOINT_FRAME_CORRECTION_H #define __Q_MITK_MATCHPOINT_FRAME_CORRECTION_H #include #include #include "ui_QmitkMatchPointFrameCorrectionControls.h" #include // MatchPoint #include #include #include #include #include #include #include #include /*! \brief View for motion artefact correction of images. The view utalizes MatchPoint registration algorithms and the mitk::TimeFramesRegistrationHelper and implemnts the GUI business logic to make frame correction aka motion artefact correction on 3D+t images. */ class QmitkMatchPointFrameCorrection : public QmitkAbstractView { // 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; /** * Creates smartpointer typedefs */ berryObjectMacro(QmitkMatchPointFrameCorrection) QmitkMatchPointFrameCorrection(); ~QmitkMatchPointFrameCorrection(); protected slots: /** * @brief Connect all GUI elements to its corresponding slots */ virtual void CreateConnections(); /// \brief Called when the user clicks the GUI button void OnMaskCheckBoxToggeled(bool checked); void OnLoadAlgorithmButtonPushed(); void OnSelectedAlgorithmChanged(); void OnStartRegBtnPushed(); void OnSaveLogBtnPushed(); void OnFramesSelectAllPushed(); void OnFramesDeSelectAllPushed(); void OnFramesInvertPushed(); void OnRegJobError(QString err); void OnRegJobFinished(); void OnMapJobError(QString err); void OnMapResultIsAvailable(mitk::Image::Pointer spMappedData, const QmitkFramesRegistrationJob* job); void OnAlgorithmIterated(QString info, bool hasIterationCount, unsigned long currentIteration); void OnLevelChanged(QString info, bool hasLevelCount, unsigned long currentLevel); void OnAlgorithmStatusChanged(QString info); void OnAlgorithmInfo(QString info); void OnFrameProcessed(double progress); void OnFrameRegistered(double progress); void OnFrameMapped(double progress); protected: virtual void CreateQtPartControl(QWidget* parent); virtual void SetFocus(); /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& nodes); private: /** * @brief Adapt the visibility of GUI elements depending on the current data loaded */ void AdaptFolderGUIElements(); void Error(QString msg); void UpdateAlgorithmList(); /** * checks if appropriated nodes are selected in the data manager. If nodes are selected, * they are stored m_MovingData and m_TargetData. It also sets the info lables accordingly. * @return True: All inputs are set and valid (images). False: At least one input is not set * or invalid */ bool CheckInputs(); /** * Updates the state of registration control buttons. Regarding to selected * inputs, loaded algorithm and its state.*/ void ConfigureRegistrationControls(); /** * Configures the progress bars according to the chosen algorithm. */ void ConfigureProgressInfos(); /**configure the frame list widget based on the selected target.*/ void ConfigureFrameList(); /**generates the ignore list based on the frame list widget selection.*/ mitk::TimeFramesRegistrationHelper::IgnoreListType GenerateIgnoreList() const; /** Methods returns a list of all nodes in the data manager containing a registration wrapper. * The list may be empty.*/ mitk::DataStorage::SetOfObjects::Pointer GetRegNodes() const; /** Returns a proposal for a (unique) default reg job name */ std::string GetDefaultJobName() const; /** Returns the display name of the passed node. Normally it is just node->GetName(). * if the node contains a point set it is additionally checked if the point set node * has a source node and its name will be added in parentheses.*/ std::string GetInputNodeDisplayName(const mitk::DataNode* node) const; /** Returns the Pointer to the DLL info of the algorithm currently selected by the system. The info is received via m_AlgorithmSelectionListener. @return If there is no item selected the returning pointer will be null. */ const map::deployment::DLLInfo* GetSelectedAlgorithmDLL() const; //! [Qt Selection Listener method and pointer] /** * @brief Method of berry::ISelectionListener that implements the selection listener functionality. * @param sourcepart The workbench part responsible for the selection change. * @param selection This parameter holds the current selection. * * @see ISelectionListener */ void OnAlgorithmSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection); void UpdateAlgorithmSelection(berry::ISelection::ConstPointer selection); friend struct berry::SelectionChangedAdapter; + + QWidget* m_Parent; + /** @brief this pointer holds the algorithm selection listener */ QScopedPointer m_AlgorithmSelectionListener; ::map::deployment::DLLHandle::Pointer m_LoadedDLLHandle; ::map::algorithm::RegistrationAlgorithmBase::Pointer m_LoadedAlgorithm; ::map::deployment::DLLInfo::ConstPointer m_SelectedAlgorithmInfo; typedef map::algorithm::facet::IterativeAlgorithmInterface IIterativeAlgorithm; typedef map::algorithm::facet::MultiResRegistrationAlgorithmInterface IMultiResAlgorithm; typedef map::algorithm::facet::StoppableAlgorithmInterface IStoppableAlgorithm; mitk::DataNode::Pointer m_spSelectedTargetNode; /*Data of the selected target node that should be used for registration. Can be the direct return of node->GetData(), but can also be a sub set (like a special time frame).*/ mitk::BaseData::ConstPointer m_spSelectedTargetData; mitk::DataNode::Pointer m_spSelectedTargetMaskNode; mitk::Image::ConstPointer m_spSelectedTargetMaskData; // boolean variables to control visibility of GUI elements bool m_CanLoadAlgorithm; bool m_ValidInputs; bool m_Working; - QWidget* m_Parent; Ui::MatchPointFrameCorrectionControls m_Controls; }; #endif // MatchPoint_h diff --git a/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.cpp b/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.cpp index 8f95d19412..524c0fcee7 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.cpp @@ -1,747 +1,750 @@ /*=================================================================== 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 "mitkRegVisPropertyTags.h" #include "mitkMatchPointPropertyTags.h" #include "mitkRegEvaluationObject.h" #include "mitkRegistrationHelper.h" #include "mitkRegEvaluationMapper2D.h" #include #include #include // Qmitk #include "QmitkRenderWindow.h" #include "QmitkMatchPointRegistrationManipulator.h" #include // Qt #include #include #include #include //MatchPoint #include #include #include #include #include #include #include const std::string QmitkMatchPointRegistrationManipulator::VIEW_ID = "org.mitk.views.matchpoint.registration.manipulator"; +const std::string QmitkMatchPointRegistrationManipulator::HelperNodeName = + "RegistrationManipulationEvaluationHelper"; + QmitkMatchPointRegistrationManipulator::QmitkMatchPointRegistrationManipulator() - : m_Parent(nullptr), m_activeManipulation(false), m_autoMoving(false), m_autoTarget(false), m_currentSelectedTimeStep(0), HelperNodeName("RegistrationManipulationEvaluationHelper"), - m_internalUpdate(false) + : m_Parent(nullptr), m_activeManipulation(false), m_autoMoving(false), m_autoTarget(false), + m_currentSelectedTimeStep(0), m_internalUpdate(false) { m_currentSelectedPosition.Fill(0.0); } QmitkMatchPointRegistrationManipulator::~QmitkMatchPointRegistrationManipulator() { if (this->m_EvalNode.IsNotNull() && this->GetDataStorage().IsNotNull()) { this->GetDataStorage()->Remove(this->m_EvalNode); } } void QmitkMatchPointRegistrationManipulator::SetFocus() { } void QmitkMatchPointRegistrationManipulator::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); } void QmitkMatchPointRegistrationManipulator::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; connect(m_Controls.pbStart, SIGNAL(clicked()), this, SLOT(OnStartBtnPushed())); connect(m_Controls.pbCancel, SIGNAL(clicked()), this, SLOT(OnCancelBtnPushed())); connect(m_Controls.pbStore, SIGNAL(clicked()), this, SLOT(OnStoreBtnPushed())); connect(m_Controls.evalSettings, SIGNAL(SettingsChanged(mitk::DataNode*)), this, SLOT(OnSettingsChanged(mitk::DataNode*))); connect(m_Controls.radioSelectedReg, SIGNAL(toggled(bool)), m_Controls.lbRegistrationName, SLOT(setVisible(bool))); connect(m_Controls.slideRotX, SIGNAL(valueChanged(int)), this, SLOT(OnRotXSlideChanged(int))); connect(m_Controls.sbRotX, SIGNAL(valueChanged(double)), this, SLOT(OnRotXChanged(double))); connect(m_Controls.slideRotY, SIGNAL(valueChanged(int)), this, SLOT(OnRotYSlideChanged(int))); connect(m_Controls.sbRotY, SIGNAL(valueChanged(double)), this, SLOT(OnRotYChanged(double))); connect(m_Controls.slideRotZ, SIGNAL(valueChanged(int)), this, SLOT(OnRotZSlideChanged(int))); connect(m_Controls.sbRotZ, SIGNAL(valueChanged(double)), this, SLOT(OnRotZChanged(double))); connect(m_Controls.slideTransX, SIGNAL(valueChanged(int)), this, SLOT(OnTransXSlideChanged(int))); connect(m_Controls.sbTransX, SIGNAL(valueChanged(double)), this, SLOT(OnTransXChanged(double))); connect(m_Controls.slideTransY, SIGNAL(valueChanged(int)), this, SLOT(OnTransYSlideChanged(int))); connect(m_Controls.sbTransY, SIGNAL(valueChanged(double)), this, SLOT(OnTransYChanged(double))); connect(m_Controls.slideTransZ, SIGNAL(valueChanged(int)), this, SLOT(OnTransZSlideChanged(int))); connect(m_Controls.sbTransZ, SIGNAL(valueChanged(double)), this, SLOT(OnTransZChanged(double))); connect(m_Controls.comboCenter, SIGNAL(currentIndexChanged(int)), this, SLOT(OnCenterTypeChanged(int))); this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); m_Controls.radioNewReg->setChecked(true); m_Controls.groupScale->setVisible(false); m_Controls.lbRegistrationName->setVisible(false); m_EvalNode = this->GetDataStorage()->GetNamedNode(HelperNodeName); this->CheckInputs(); this->StopSession(); this->ConfigureControls(); } void QmitkMatchPointRegistrationManipulator::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } void QmitkMatchPointRegistrationManipulator::RenderWindowPartDeactivated( mitk::IRenderWindowPart* renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void QmitkMatchPointRegistrationManipulator::CheckInputs() { if (!m_activeManipulation) { QList dataNodes = this->GetDataManagerSelection(); this->m_autoMoving = false; this->m_autoTarget = false; this->m_SelectedMovingNode = nullptr; this->m_SelectedTargetNode = nullptr; this->m_SelectedPreRegNode = nullptr; this->m_SelectedPreReg = nullptr; if (dataNodes.size() > 0) { //test if auto select works if (mitk::MITKRegistrationHelper::IsRegNode(dataNodes[0])) { mitk::DataNode::Pointer regNode = dataNodes[0]; dataNodes.pop_front(); mitk::MAPRegistrationWrapper* regWrapper = dynamic_cast(regNode->GetData()); if (regWrapper) { this->m_SelectedPreReg = dynamic_cast(regWrapper->GetRegistration()); } if (this->m_SelectedPreReg.IsNotNull()) { this->m_SelectedPreRegNode = regNode; mitk::BaseProperty* uidProp = m_SelectedPreRegNode->GetData()->GetProperty(mitk::Prop_RegAlgMovingData); if (uidProp) { //search for the moving node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); this->m_SelectedMovingNode = this->GetDataStorage()->GetNode(predicate); this->m_autoMoving = this->m_SelectedMovingNode.IsNotNull(); } uidProp = m_SelectedPreRegNode->GetData()->GetProperty(mitk::Prop_RegAlgTargetData); if (uidProp) { //search for the target node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); this->m_SelectedTargetNode = this->GetDataStorage()->GetNode(predicate); this->m_autoTarget = this->m_SelectedTargetNode.IsNotNull(); } } } //if still nodes are selected -> ignore possible auto select if (!dataNodes.empty()) { mitk::Image* inputImage = dynamic_cast(dataNodes[0]->GetData()); if (inputImage) { this->m_SelectedMovingNode = dataNodes[0]; this->m_autoMoving = false; dataNodes.pop_front(); } } if (!dataNodes.empty()) { mitk::Image* inputImage = dynamic_cast(dataNodes[0]->GetData()); if (inputImage) { this->m_SelectedTargetNode = dataNodes[0]; this->m_autoTarget = false; dataNodes.pop_front(); } } } } } -void QmitkMatchPointRegistrationManipulator::OnSelectionChanged(berry::IWorkbenchPart::Pointer source, - const QList& nodes) +void QmitkMatchPointRegistrationManipulator::OnSelectionChanged(berry::IWorkbenchPart::Pointer, + const QList&) { this->CheckInputs(); this->ConfigureControls(); }; void QmitkMatchPointRegistrationManipulator::NodeRemoved(const mitk::DataNode* node) { if (node == this->m_SelectedMovingNode || node == this->m_SelectedTargetNode || node == this->m_EvalNode) { if (node == this->m_EvalNode) { this->m_EvalNode = nullptr; } this->OnCancelBtnPushed(); MITK_INFO << "Stopped current MatchPoint manual registration session, because at least one relevant node was removed from storage."; } } void QmitkMatchPointRegistrationManipulator::ConfigureControls() { //configure input data widgets if (this->m_SelectedPreRegNode.IsNull()) { m_Controls.lbRegistrationName->setText( QString("No registration selected!")); } else { m_Controls.lbRegistrationName->setText(QString::fromStdString( this->m_SelectedPreRegNode->GetName())); } if (this->m_SelectedMovingNode.IsNull()) { m_Controls.lbMovingName->setText(QString("no moving image selected!")); } else { if (this->m_autoMoving) { m_Controls.lbMovingName->setText(QString("") + QString::fromStdString( this->m_SelectedMovingNode->GetName()) + QString(" (auto selected)")); } else { m_Controls.lbMovingName->setText(QString::fromStdString(this->m_SelectedMovingNode->GetName())); } } if (this->m_SelectedTargetNode.IsNull()) { m_Controls.lbTargetName->setText(QString("no target image selected!")); } else { if (this->m_autoTarget) { m_Controls.lbTargetName->setText(QString("") + QString::fromStdString( this->m_SelectedTargetNode->GetName()) + QString(" (auto selected)")); } else { m_Controls.lbTargetName->setText(QString::fromStdString(this->m_SelectedTargetNode->GetName())); } } if (!m_activeManipulation) { QString name = "ManuelRegistration"; if (m_SelectedPreRegNode.IsNotNull()) { name = QString::fromStdString(m_SelectedPreRegNode->GetName()) + " manual refined"; } this->m_Controls.lbNewRegName->setText(name); } //config settings widget this->m_Controls.groupReg->setEnabled(!m_activeManipulation); this->m_Controls.lbMovingName->setEnabled(!m_activeManipulation); this->m_Controls.lbTargetName->setEnabled(!m_activeManipulation); this->m_Controls.pbStart->setEnabled(this->m_SelectedMovingNode.IsNotNull() && this->m_SelectedTargetNode.IsNotNull() && !m_activeManipulation); this->m_Controls.lbNewRegName->setEnabled(m_activeManipulation); this->m_Controls.checkMapEntity->setEnabled(m_activeManipulation); this->m_Controls.tabWidget->setEnabled(m_activeManipulation); this->m_Controls.pbCancel->setEnabled(m_activeManipulation); this->m_Controls.pbStore->setEnabled(m_activeManipulation); this->UpdateTransformWidgets(); } void QmitkMatchPointRegistrationManipulator::InitSession() { this->m_InverseCurrentTransform = TransformType::New(); this->m_InverseCurrentTransform->SetIdentity(); this->m_DirectCurrentTransform = TransformType::New(); this->m_DirectCurrentTransform->SetIdentity(); this->m_CurrentRegistrationWrapper = mitk::MAPRegistrationWrapper::New(); m_CurrentRegistration = MAPRegistrationType::New(); this->m_CurrentRegistrationWrapper->SetRegistration(m_CurrentRegistration); ::map::core::RegistrationManipulator manipulator(m_CurrentRegistration); ::map::core::PreCachedRegistrationKernel<3, 3>::Pointer kernel = ::map::core::PreCachedRegistrationKernel<3, 3>::New(); manipulator.setDirectMapping(::map::core::NullRegistrationKernel < 3, 3 >::New()); if (this->m_Controls.radioNewReg->isChecked()) { //new registration kernel->setTransformModel(m_InverseCurrentTransform); manipulator.setInverseMapping(kernel); //init to map the image centers auto movingCenter = m_SelectedMovingNode->GetData()->GetTimeGeometry()->GetCenterInWorld(); auto targetCenter = m_SelectedTargetNode->GetData()->GetTimeGeometry()->GetCenterInWorld(); auto offset = targetCenter - movingCenter; m_DirectCurrentTransform->SetOffset(offset); m_DirectCurrentTransform->GetInverse(m_InverseCurrentTransform); } else { //use selected pre registration as baseline itk::CompositeTransform < ::map::core::continuous::ScalarType, 3>::Pointer compTransform = itk::CompositeTransform < ::map::core::continuous::ScalarType, 3>::New(); const map::core::RegistrationKernel<3, 3>* preKernel = dynamic_cast*>(&this->m_SelectedPreReg->getInverseMapping()); compTransform->AddTransform(preKernel->getTransformModel()->Clone()); compTransform->AddTransform(this->m_InverseCurrentTransform); kernel->setTransformModel(compTransform); manipulator.setInverseMapping(kernel); } m_Controls.comboCenter->setCurrentIndex(0); this->ConfigureTransformCenter(0); //set bounds of the translation slider widget to have sensible ranges auto currenttrans = m_DirectCurrentTransform->GetTranslation(); this->m_Controls.slideTransX->setMinimum(currenttrans[0] - 250); this->m_Controls.slideTransY->setMinimum(currenttrans[1] - 250); this->m_Controls.slideTransZ->setMinimum(currenttrans[2] - 250); this->m_Controls.slideTransX->setMaximum(currenttrans[0] + 250); this->m_Controls.slideTransY->setMaximum(currenttrans[1] + 250); this->m_Controls.slideTransZ->setMaximum(currenttrans[2] + 250); //reinit view - mitk::RenderingManager::GetInstance()->InitializeViews(m_SelectedTargetNode->GetData()->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(m_SelectedTargetNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); //generate evaluation node mitk::RegEvaluationObject::Pointer regEval = mitk::RegEvaluationObject::New(); regEval->SetRegistration(this->m_CurrentRegistrationWrapper); regEval->SetTargetNode(this->m_SelectedTargetNode); regEval->SetMovingNode(this->m_SelectedMovingNode); this->m_EvalNode = mitk::DataNode::New(); this->m_EvalNode->SetData(regEval); mitk::RegEvaluationMapper2D::SetDefaultProperties(this->m_EvalNode); this->m_EvalNode->SetName(HelperNodeName); this->m_EvalNode->SetBoolProperty("helper object", true); this->GetDataStorage()->Add(this->m_EvalNode); this->m_Controls.evalSettings->SetNode(this->m_EvalNode); this->m_activeManipulation = true; }; void QmitkMatchPointRegistrationManipulator::StopSession() { this->m_InverseCurrentTransform = TransformType::New(); this->m_InverseCurrentTransform->SetIdentity(); this->m_DirectCurrentTransform = TransformType::New(); this->m_DirectCurrentTransform->SetIdentity(); this->m_CurrentRegistration = nullptr; this->m_CurrentRegistrationWrapper = nullptr; if (this->m_EvalNode.IsNotNull()) { this->GetDataStorage()->Remove(this->m_EvalNode); } this->m_EvalNode = nullptr; this->m_activeManipulation = false; }; void QmitkMatchPointRegistrationManipulator::UpdateTransformWidgets() { this->m_internalUpdate = true; this->m_Controls.sbTransX->setValue(this->m_DirectCurrentTransform->GetTranslation()[0]); this->m_Controls.sbTransY->setValue(this->m_DirectCurrentTransform->GetTranslation()[1]); this->m_Controls.sbTransZ->setValue(this->m_DirectCurrentTransform->GetTranslation()[2]); this->m_Controls.slideTransX->setValue(this->m_DirectCurrentTransform->GetTranslation()[0]); this->m_Controls.slideTransY->setValue(this->m_DirectCurrentTransform->GetTranslation()[1]); this->m_Controls.slideTransZ->setValue(this->m_DirectCurrentTransform->GetTranslation()[2]); this->m_Controls.sbRotX->setValue(this->m_DirectCurrentTransform->GetAngleX()*(180 / boost::math::double_constants::pi)); this->m_Controls.sbRotY->setValue(this->m_DirectCurrentTransform->GetAngleY()*(180 / boost::math::double_constants::pi)); this->m_Controls.sbRotZ->setValue(this->m_DirectCurrentTransform->GetAngleZ()*(180 / boost::math::double_constants::pi)); this->m_Controls.slideRotX->setValue(this->m_DirectCurrentTransform->GetAngleX()*(180 / boost::math::double_constants::pi)); this->m_Controls.slideRotY->setValue(this->m_DirectCurrentTransform->GetAngleY()*(180 / boost::math::double_constants::pi)); this->m_Controls.slideRotZ->setValue(this->m_DirectCurrentTransform->GetAngleZ()*(180 / boost::math::double_constants::pi)); this->m_internalUpdate = false; }; void QmitkMatchPointRegistrationManipulator::UpdateTransform(bool updateRotation) { if (updateRotation) { if (m_Controls.comboCenter->currentIndex() == 2) { ConfigureTransformCenter(2); } this->m_DirectCurrentTransform->SetRotation(this->m_Controls.sbRotX->value()*(boost::math::double_constants::pi / 180), this->m_Controls.sbRotY->value()*(boost::math::double_constants::pi / 180), this->m_Controls.sbRotZ->value()*(boost::math::double_constants::pi / 180)); } else { TransformType::OutputVectorType trans; trans[0] = this->m_Controls.sbTransX->value(); trans[1] = this->m_Controls.sbTransY->value(); trans[2] = this->m_Controls.sbTransZ->value(); this->m_DirectCurrentTransform->SetTranslation(trans); } this->m_DirectCurrentTransform->GetInverse(this->m_InverseCurrentTransform); this->UpdateTransformWidgets(); this->m_EvalNode->Modified(); this->m_CurrentRegistrationWrapper->Modified(); this->GetRenderWindowPart()->RequestUpdate(); }; void QmitkMatchPointRegistrationManipulator::OnSliceChanged() { mitk::Point3D currentSelectedPosition = GetRenderWindowPart()->GetSelectedPosition(nullptr); unsigned int currentSelectedTimeStep = GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); if (m_currentSelectedPosition != currentSelectedPosition || m_currentSelectedTimeStep != currentSelectedTimeStep || m_selectedNodeTime > m_currentPositionTime) { //the current position has been changed or the selected node has been changed since the last position validation -> check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimeStep = currentSelectedTimeStep; m_currentPositionTime.Modified(); if (this->m_EvalNode.IsNotNull()) { this->m_EvalNode->SetProperty(mitk::nodeProp_RegEvalCurrentPosition, mitk::GenericProperty::New(currentSelectedPosition)); } if (m_activeManipulation && m_Controls.comboCenter->currentIndex() == 2) { //update transform with the current position. OnCenterTypeChanged(m_Controls.comboCenter->currentIndex()); } } } void QmitkMatchPointRegistrationManipulator::OnSettingsChanged(mitk::DataNode*) { this->GetRenderWindowPart()->RequestUpdate(); }; void QmitkMatchPointRegistrationManipulator::OnStartBtnPushed() { this->InitSession(); this->OnSliceChanged(); this->GetRenderWindowPart()->RequestUpdate(); this->CheckInputs(); this->ConfigureControls(); } void QmitkMatchPointRegistrationManipulator::OnCancelBtnPushed() { this->StopSession(); this->CheckInputs(); this->ConfigureControls(); this->GetRenderWindowPart()->RequestUpdate(); } void QmitkMatchPointRegistrationManipulator::OnStoreBtnPushed() { mitk::MAPRegistrationWrapper::Pointer newRegWrapper = mitk::MAPRegistrationWrapper::New(); MAPRegistrationType::Pointer newReg = MAPRegistrationType::New(); newRegWrapper->SetRegistration(newReg); ::map::core::RegistrationManipulator manipulator(newReg); ::map::core::PreCachedRegistrationKernel<3, 3>::Pointer kernel = ::map::core::PreCachedRegistrationKernel<3, 3>::New(); kernel->setTransformModel(m_InverseCurrentTransform); ::map::core::PreCachedRegistrationKernel<3, 3>::Pointer kernel2 = ::map::core::PreCachedRegistrationKernel<3, 3>::New(); kernel2->setTransformModel(m_InverseCurrentTransform->GetInverseTransform()); manipulator.setInverseMapping(kernel); manipulator.setDirectMapping(kernel2); if (this->m_Controls.radioSelectedReg->isChecked()) { //compine registration with selected pre registration as baseline typedef ::map::core::RegistrationCombinator CombinatorType; CombinatorType::Pointer combinator = CombinatorType::New(); newReg = combinator->process(*m_SelectedPreReg,*newReg); newRegWrapper->SetRegistration(newReg); } mitk::DataNode::Pointer spResultRegistrationNode = mitk::generateRegistrationResultNode( this->m_Controls.lbNewRegName->text().toStdString(), newRegWrapper, "org.mitk::manual_registration", mitk::EnsureUID(m_SelectedMovingNode->GetData()), mitk::EnsureUID(m_SelectedTargetNode->GetData())); this->GetDataStorage()->Add(spResultRegistrationNode); if (m_Controls.checkMapEntity->checkState() == Qt::Checked) { QmitkMappingJob* pMapJob = new QmitkMappingJob(); pMapJob->setAutoDelete(true); pMapJob->m_spInputData = this->m_SelectedMovingNode->GetData(); pMapJob->m_InputDataUID = mitk::EnsureUID(m_SelectedMovingNode->GetData()); pMapJob->m_spRegNode = spResultRegistrationNode; pMapJob->m_doGeometryRefinement = false; pMapJob->m_spRefGeometry = this->m_SelectedTargetNode->GetData()->GetGeometry()->Clone().GetPointer(); pMapJob->m_MappedName = this->m_Controls.lbNewRegName->text().toStdString() + std::string(" mapped moving data"); pMapJob->m_allowUndefPixels = true; pMapJob->m_paddingValue = 100; pMapJob->m_allowUnregPixels = true; pMapJob->m_errorValue = 200; pMapJob->m_InterpolatorLabel = "Linear Interpolation"; pMapJob->m_InterpolatorType = mitk::ImageMappingInterpolator::Linear; connect(pMapJob, SIGNAL(Error(QString)), this, SLOT(OnMapJobError(QString))); connect(pMapJob, SIGNAL(MapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), this, SLOT(OnMapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), Qt::BlockingQueuedConnection); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pMapJob); } this->StopSession(); this->CheckInputs(); this->ConfigureControls(); this->GetRenderWindowPart()->RequestUpdate(); } void QmitkMatchPointRegistrationManipulator::OnMapResultIsAvailable(mitk::BaseData::Pointer spMappedData, const QmitkMappingJob* job) { mitk::DataNode::Pointer spMappedNode = mitk::generateMappedResultNode(job->m_MappedName, spMappedData, job->GetRegistration()->getRegistrationUID(), job->m_InputDataUID, job->m_doGeometryRefinement, job->m_InterpolatorLabel); this->GetDataStorage()->Add(spMappedNode); this->GetRenderWindowPart()->RequestUpdate(); }; void QmitkMatchPointRegistrationManipulator::OnRotXChanged(double x) { if (!m_internalUpdate) { m_internalUpdate = true; this->m_Controls.slideRotX->setValue(x); m_internalUpdate = false; this->UpdateTransform(true); } }; void QmitkMatchPointRegistrationManipulator::OnRotXSlideChanged(int x) { if (!m_internalUpdate) { this->m_Controls.sbRotX->setValue(x); } }; void QmitkMatchPointRegistrationManipulator::OnRotYChanged(double y) { if (!m_internalUpdate) { m_internalUpdate = true; this->m_Controls.slideRotY->setValue(y); m_internalUpdate = false; this->UpdateTransform(true); } }; void QmitkMatchPointRegistrationManipulator::OnRotYSlideChanged(int y) { if (!m_internalUpdate) { this->m_Controls.sbRotY->setValue(y); } }; void QmitkMatchPointRegistrationManipulator::OnRotZChanged(double z) { if (!m_internalUpdate) { m_internalUpdate = true; this->m_Controls.slideRotZ->setValue(z); m_internalUpdate = false; this->UpdateTransform(true); } }; void QmitkMatchPointRegistrationManipulator::OnRotZSlideChanged(int z) { if (!m_internalUpdate) { this->m_Controls.sbRotZ->setValue(z); } }; void QmitkMatchPointRegistrationManipulator::OnTransXChanged(double x) { if (!m_internalUpdate) { m_internalUpdate = true; this->m_Controls.slideTransX->setValue(x); m_internalUpdate = false; this->UpdateTransform(); } }; void QmitkMatchPointRegistrationManipulator::OnTransXSlideChanged(int x) { if (!m_internalUpdate) { this->m_Controls.sbTransX->setValue(x); } }; void QmitkMatchPointRegistrationManipulator::OnTransYChanged(double y) { if (!m_internalUpdate) { m_internalUpdate = true; this->m_Controls.slideTransY->setValue(y); m_internalUpdate = false; this->UpdateTransform(); } }; void QmitkMatchPointRegistrationManipulator::OnTransYSlideChanged(int y) { if (!m_internalUpdate) { this->m_Controls.sbTransY->setValue(y); } }; void QmitkMatchPointRegistrationManipulator::OnTransZChanged(double z) { if (!m_internalUpdate) { m_internalUpdate = true; this->m_Controls.slideTransZ->setValue(z); m_internalUpdate = false; this->UpdateTransform(); } }; void QmitkMatchPointRegistrationManipulator::OnTransZSlideChanged(int z) { if (!m_internalUpdate) { this->m_Controls.sbTransZ->setValue(z); } }; void QmitkMatchPointRegistrationManipulator::OnCenterTypeChanged(int index) { ConfigureTransformCenter(index); this->UpdateTransformWidgets(); if (this->m_EvalNode.IsNotNull()) { this->m_EvalNode->Modified(); } this->m_CurrentRegistrationWrapper->Modified(); this->GetRenderWindowPart()->RequestUpdate(); }; void QmitkMatchPointRegistrationManipulator::ConfigureTransformCenter(int centerType) { auto offset = m_DirectCurrentTransform->GetOffset(); if (centerType == 0) { //image center auto center = m_SelectedMovingNode->GetData()->GetTimeGeometry()->GetCenterInWorld(); m_DirectCurrentTransform->SetCenter(center); } else if (centerType == 1) { //world origin TransformType::OutputPointType itkCenter; itkCenter.Fill(0.0); m_DirectCurrentTransform->SetCenter(itkCenter); } else { //current selected point auto newCenter = m_InverseCurrentTransform->TransformPoint(m_currentSelectedPosition); m_DirectCurrentTransform->SetCenter(newCenter); } m_DirectCurrentTransform->SetOffset(offset); m_DirectCurrentTransform->GetInverse(m_InverseCurrentTransform); }; diff --git a/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.h b/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.h index 4450abb0f0..092b3f2d7f 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.h +++ b/Plugins/org.mitk.gui.qt.matchpoint.manipulator/src/internal/QmitkMatchPointRegistrationManipulator.h @@ -1,175 +1,175 @@ /*=================================================================== 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 __Q_MITK_MATCHPOINT_REGISTRATION_MANIPULATOR_H #define __Q_MITK_MATCHPOINT_REGISTRATION_MANIPULATOR_H #include #include #include #include #include #include "ui_QmitkMatchPointRegistrationManipulator.h" class QmitkMappingJob; /*! \brief QmitkMatchPointRegistrationManipulator \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class QmitkMatchPointRegistrationManipulator : public QmitkAbstractView, public mitk::IRenderWindowPartListener -{ +{ // 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: +public: static const std::string VIEW_ID; /** * Creates smartpointer typedefs */ berryObjectMacro(QmitkMatchPointRegistrationManipulator) QmitkMatchPointRegistrationManipulator(); ~QmitkMatchPointRegistrationManipulator(); virtual void CreateQtPartControl(QWidget *parent); protected slots: /// \brief Called when the user clicks the GUI button void OnStartBtnPushed(); void OnCancelBtnPushed(); void OnStoreBtnPushed(); void OnSettingsChanged(mitk::DataNode*); void OnRotXChanged(double); void OnRotYChanged(double); void OnRotZChanged(double); void OnTransXChanged(double); void OnTransYChanged(double); void OnTransZChanged(double); void OnRotXSlideChanged(int); void OnRotYSlideChanged(int); void OnRotZSlideChanged(int); void OnTransXSlideChanged(int); void OnTransYSlideChanged(int); void OnTransZSlideChanged(int); void OnCenterTypeChanged(int); void OnSliceChanged(); void OnMapResultIsAvailable(mitk::BaseData::Pointer spMappedData, const QmitkMappingJob* job); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, const QList& nodes) override; virtual void NodeRemoved(const mitk::DataNode* node) override; virtual void SetFocus(); virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart); virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart); Ui::MatchPointRegistrationManipulatorControls m_Controls; private: QWidget *m_Parent; void Error(QString msg); /** Methods returns a list of all eval nodes in the data manager.*/ QList GetEvalNodes(); /** * Checks if appropriated nodes are selected in the data manager. If nodes are selected, * they are stored m_spSelectedRegNode, m_spSelectedInputNode and m_spSelectedRefNode. * They are also checked for vadility.*/ void CheckInputs(); /** * Updates the state of controls regarding to the state of the view and it objects.*/ void ConfigureControls(); /** Initialize the state of the view, so the manipulation can start.*/ void InitSession(); /** Stops session, removes all obsolite members (e.g. RegEvalObject). After that the view is in a valid but inactive state.*/ void StopSession(); /** * Updates the widgets that manipulate the transform according to the transform.*/ void UpdateTransformWidgets(); /** * Updates the transform according to the widgets that manipulate the transform.*/ void UpdateTransform(bool updateRotation = false); void ConfigureTransformCenter(int centerType); mitk::DataNode::Pointer m_EvalNode; QmitkSliceNavigationListener m_SliceChangeListener; itk::TimeStamp m_selectedNodeTime; itk::TimeStamp m_currentPositionTime; + bool m_activeManipulation; + bool m_autoMoving; + bool m_autoTarget; + /** @brief currently valid selected position in the inspector*/ mitk::Point3D m_currentSelectedPosition; /** @brief indicates if the currently selected position is valid for the currently selected fit. * This it is within the input image */ unsigned int m_currentSelectedTimeStep; mitk::DataNode::Pointer m_SelectedPreRegNode; mitk::DataNode::Pointer m_SelectedMovingNode; mitk::DataNode::Pointer m_SelectedTargetNode; mitk::MAPRegistrationWrapper::Pointer m_CurrentRegistrationWrapper; typedef itk::Euler3DTransform<::map::core::continuous::ScalarType> TransformType; TransformType::Pointer m_InverseCurrentTransform; TransformType::Pointer m_DirectCurrentTransform; typedef map::core::Registration<3, 3> MAPRegistrationType; MAPRegistrationType::Pointer m_CurrentRegistration; MAPRegistrationType::ConstPointer m_SelectedPreReg; - bool m_autoTarget; - bool m_autoMoving; - bool m_activeManipulation; - bool m_internalUpdate; - const std::string HelperNodeName; + static const std::string HelperNodeName; }; #endif // MatchPoint_h diff --git a/Plugins/org.mitk.gui.qt.matchpoint.mapper/src/internal/QmitkMatchPointMapper.cpp b/Plugins/org.mitk.gui.qt.matchpoint.mapper/src/internal/QmitkMatchPointMapper.cpp index 56c0a13b97..1a2cf0e9be 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.mapper/src/internal/QmitkMatchPointMapper.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.mapper/src/internal/QmitkMatchPointMapper.cpp @@ -1,681 +1,681 @@ /*=================================================================== 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 "org_mitk_gui_qt_matchpoint_mapper_Activator.h" // Blueberry #include #include // Mitk #include #include #include #include "mitkImageMappingHelper.h" #include "mitkMAPRegistrationWrapper.h" #include "mitkMatchPointPropertyTags.h" #include "mitkRegistrationHelper.h" #include #include #include #include #include #include #include #include // Qmitk #include "QmitkMatchPointMapper.h" // Qt #include #include #include #include const std::string QmitkMatchPointMapper::VIEW_ID = "org.mitk.views.matchpoint.mapper"; QmitkMatchPointMapper::QmitkMatchPointMapper() : m_Parent(nullptr), m_preparedForBinaryInput(false) { } void QmitkMatchPointMapper::SetFocus() { //m_Controls.buttonPerformImageProcessing->setFocus(); } void QmitkMatchPointMapper::CreateConnections() { // show first page m_Controls.m_tabs->setCurrentIndex(0); connect(m_Controls.m_pbLockReg, SIGNAL(clicked()), this, SLOT(OnLockRegButtonPushed())); connect(m_Controls.m_pbLockInput, SIGNAL(clicked()), this, SLOT(OnLockInputButtonPushed())); connect(m_Controls.m_pbLockRef, SIGNAL(clicked()), this, SLOT(OnLockReferenceButtonPushed())); connect(m_Controls.m_cbManualRef, SIGNAL(clicked()), this, SLOT(OnManualRefChecked())); connect(m_Controls.m_cbLinkFactors, SIGNAL(clicked()), this, SLOT(OnLinkSampleFactorChecked())); connect(m_Controls.m_sbXFactor, SIGNAL(valueChanged(double)), this, SLOT(OnXFactorChanged(double))); connect(m_Controls.m_pbMap, SIGNAL(clicked()), this, SLOT(OnMapBtnPushed())); connect(m_Controls.m_pbRefine, SIGNAL(clicked()), this, SLOT(OnRefineBtnPushed())); } void QmitkMatchPointMapper::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); m_Controls.m_teLog->append(QString("") + msg + QString("")); } void QmitkMatchPointMapper::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; this->CreateConnections(); this->CheckInputs(); this->ConfigureProgressInfos(); this->ConfigureMappingControls(); } /** Method checks if the currently selected reg node has a direct kernel that * can be decomposed in a rotation matrix and a offset. If this is true, true * is returned. In all other cases false is returned.*/ bool QmitkMatchPointMapper::IsAbleToRefineGeometry() const { bool result = false; if (this->m_spSelectedRegNode.IsNotNull()) { const mitk::MAPRegistrationWrapper* wrapper = dynamic_cast (this->m_spSelectedRegNode->GetData()); //if the helper does not return null, we can refine the geometry. result = mitk::MITKRegistrationHelper::getAffineMatrix(wrapper, false).IsNotNull(); } return result; } bool QmitkMatchPointMapper::IsBinaryInput() const { mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer maskPredicate = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); bool result = false; if(this->m_spSelectedInputNode.IsNotNull()) { result = maskPredicate->CheckNode(this->m_spSelectedInputNode); } return result; } bool QmitkMatchPointMapper::IsPointSetInput() const { bool result = false; if (this->m_spSelectedInputNode.IsNotNull()) { result = dynamic_cast(this->m_spSelectedInputNode->GetData()) != nullptr; } return result; } mitk::DataNode::Pointer QmitkMatchPointMapper::GetSelectedRegNode() { mitk::DataNode::Pointer spResult = nullptr; typedef QList NodeListType; NodeListType nodes = this->GetDataManagerSelection(); for (NodeListType::iterator pos = nodes.begin(); pos != nodes.end(); ++pos) { if (mitk::MITKRegistrationHelper::IsRegNode(*pos)) { spResult = *pos; break; } } return spResult; } QList QmitkMatchPointMapper::GetSelectedDataNodes() { typedef QList NodeListType; NodeListType nodes = this->GetDataManagerSelection(); NodeListType result; for (NodeListType::iterator pos = nodes.begin(); pos != nodes.end(); ++pos) { if (!mitk::MITKRegistrationHelper::IsRegNode(*pos)) { result.push_back(*pos); } } return result; } mitk::DataNode::Pointer QmitkMatchPointMapper::GetAutoRefNodeByReg() { mitk::DataNode::Pointer spResult = nullptr; if (this->m_spSelectedRegNode.IsNotNull() && this->m_spSelectedRegNode->GetData()) { std::string nodeName; mitk::BaseProperty* uidProp = m_spSelectedRegNode->GetData()->GetProperty(mitk::Prop_RegAlgTargetData); if (uidProp) { //search for the target node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); spResult = this->GetDataStorage()->GetNode(predicate); } } if (spResult.IsNull() && this->m_spSelectedInputNode.IsNotNull()) { //no really reference is available -> use the input as reference spResult = this->m_spSelectedInputNode; m_Controls.m_teLog->append( QString("Cannot determine reference automatically. Use input image as reference.")); } return spResult; } void QmitkMatchPointMapper::CheckInputs() { mitk::DataNode::Pointer regNode = this->GetSelectedRegNode(); QList dataNodes = this->GetSelectedDataNodes(); //first set the internal nodes according to selection if (!m_Controls.m_pbLockReg->isChecked()) { this->m_spSelectedRegNode = regNode; } if (!m_Controls.m_pbLockInput->isChecked()) { mitk::DataNode::Pointer inputNode = nullptr; if (dataNodes.size() > 0) { inputNode = dataNodes[0]; } this->m_spSelectedInputNode = inputNode; } if (!(m_Controls.m_cbManualRef->isChecked())) { this->m_spSelectedRefNode = this->GetAutoRefNodeByReg(); } else { if (!m_Controls.m_pbLockRef->isChecked()) { mitk::DataNode::Pointer refNode = nullptr; int relevantIndex = 1; if (m_Controls.m_pbLockInput->isChecked()) { //the input is locked thus use the first selected data node relevantIndex = 0; } if (dataNodes.size() > relevantIndex) { refNode = dataNodes[relevantIndex]; } this->m_spSelectedRefNode = refNode; } } //second, check validity of the selected nodes this->CheckNodesValidity(this->m_ValidReg, this->m_ValidInput, this->m_ValidRef); //third, configure widgets if (this->m_spSelectedRegNode.IsNull()) { m_Controls.m_lbRegistrationName->setText( QString("no registration selected!")); } else { if (this->m_ValidReg) { m_Controls.m_lbRegistrationName->setText(QString::fromStdString( this->m_spSelectedRegNode->GetName())); } else { m_Controls.m_lbRegistrationName->setText(QString("") + QString::fromStdString( this->m_spSelectedRegNode->GetName()) + QString("")); } } if (this->m_spSelectedInputNode.IsNull()) { m_Controls.m_lbInputName->setText(QString("no input selected!")); } else { if (this->m_ValidInput) { m_Controls.m_lbInputName->setText(QString::fromStdString(this->m_spSelectedInputNode->GetName())); } else { m_Controls.m_lbInputName->setText(QString("") + QString::fromStdString( this->m_spSelectedInputNode->GetName()) + QString("")); } } if (this->m_spSelectedRefNode.IsNull()) { if (this->m_ValidRef) { m_Controls.m_lbReferenceName->setText(QString("input needs no reference needed")); } else { m_Controls.m_lbReferenceName->setText(QString("no reference selected!")); } } else { if (this->m_ValidRef) { m_Controls.m_lbReferenceName->setText(QString::fromStdString(this->m_spSelectedRefNode->GetName())); if (this->m_spSelectedRefNode->GetData() && this->m_spSelectedRefNode->GetData()->GetTimeSteps() > 1) { m_Controls.m_teLog->append( QString("Selected reference image has multiple time steps. Only geometry of time step 1 is used as reference.")); } } else { m_Controls.m_lbReferenceName->setText(QString("") + QString::fromStdString( this->m_spSelectedRefNode->GetName()) + QString("")); } } this->m_Controls.m_pbLockInput->setEnabled(this->m_spSelectedInputNode.IsNotNull()); this->m_Controls.m_pbLockReg->setEnabled(this->m_spSelectedRegNode.IsNotNull()); this->m_Controls.m_pbLockRef->setEnabled(this->m_spSelectedRefNode.IsNotNull()); } void QmitkMatchPointMapper::CheckNodesValidity(bool& validReg, bool& validInput, bool& validRef) { validReg = this->m_spSelectedRegNode.IsNotNull(); validInput = this->m_spSelectedInputNode.IsNotNull(); validRef = this->m_spSelectedRefNode.IsNotNull(); if (this->m_spSelectedRegNode.IsNotNull()) { if (this->m_spSelectedInputNode.IsNotNull()) { validInput = false; const mitk::MAPRegistrationWrapper* wrapper = dynamic_cast < const mitk::MAPRegistrationWrapper* > (m_spSelectedRegNode->GetData()); mitk::Image* inputImage = dynamic_cast(m_spSelectedInputNode->GetData()); if (inputImage && wrapper) { if (inputImage->GetDimension() - 1 == wrapper->GetMovingDimensions() && inputImage->GetTimeSteps() > 1) { //images has multiple time steps and a time step has the correct dimensionality validInput = true; } if (inputImage->GetDimension() == wrapper->GetMovingDimensions()) { validInput = true; } } if (this->IsPointSetInput() && wrapper) { if (wrapper->GetMovingDimensions() == 3) { validInput = true; } } } if (this->m_spSelectedRefNode.IsNotNull()) { validRef = false; const mitk::MAPRegistrationWrapper* wrapper = dynamic_cast < const mitk::MAPRegistrationWrapper* > (m_spSelectedRegNode->GetData()); mitk::BaseGeometry* geometry = nullptr; if (m_spSelectedRefNode->GetData()) { geometry = m_spSelectedRefNode->GetData()->GetGeometry(); } if (geometry && wrapper) { if (wrapper->GetTargetDimensions() == 3) { validRef = true; } else if (wrapper->GetTargetDimensions() == 2) { mitk::BaseGeometry::BoundsArrayType bounds = geometry->GetBounds(); if (bounds[4] != 0 || bounds[5] != 0) { //array "bounds" is constructed as [min Dim1, max Dim1, min Dim2, max Dim2, min Dim3, max Dim3] //therfore [4] and [5] must be 0 validRef = true; } } } } else if (this->IsPointSetInput()) { validRef = true; } } } void QmitkMatchPointMapper::ConfigureMappingControls() { this->m_Controls.m_pbMap->setEnabled(this->m_ValidInput && this->m_ValidRef && (this->m_ValidReg || this->m_spSelectedRegNode.IsNull())); this->m_Controls.m_pbRefine->setEnabled(this->m_ValidInput && this->m_ValidReg && this->IsAbleToRefineGeometry() && !this->IsPointSetInput()); this->m_Controls.m_pbLockRef->setEnabled(this->m_Controls.m_cbManualRef->isChecked()); this->m_Controls.m_lbReferenceName->setEnabled(this->m_Controls.m_cbManualRef->isChecked()); if (this->m_ValidInput && this->m_ValidReg) { this->m_Controls.m_leMappedName->setText(tr("mapped_by_") + QString::fromStdString( m_spSelectedRegNode->GetName())); } else { this->m_Controls.m_leMappedName->setText(tr("mappedData")); } if (this->IsBinaryInput() != this->m_preparedForBinaryInput) { if (this->IsBinaryInput()) { m_Controls.m_teLog->append( QString("Binary input (mask) detected. Preparing for mask mapping (default interpolation: nearest neigbour; padding value: 0)")); this->m_Controls.m_comboInterpolator->setCurrentIndex(0); this->m_Controls.m_sbErrorValue->setValue(0); this->m_Controls.m_sbPaddingValue->setValue(0); } else { this->m_Controls.m_comboInterpolator->setCurrentIndex(1); } this->m_preparedForBinaryInput = this->IsBinaryInput(); } OnLinkSampleFactorChecked(); } void QmitkMatchPointMapper::ConfigureProgressInfos() { } -void QmitkMatchPointMapper::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, - const QList& nodes) +void QmitkMatchPointMapper::OnSelectionChanged(berry::IWorkbenchPart::Pointer, + const QList&) { this->CheckInputs(); this->ConfigureMappingControls(); } void QmitkMatchPointMapper::OnLockRegButtonPushed() { if (this->m_Controls.m_pbLockReg->isChecked()) { if (this->m_spSelectedRegNode.IsNotNull()) { this->m_spSelectedRegNode->SetSelected(false); this->GetDataStorage()->Modified(); } } this->CheckInputs(); this->ConfigureMappingControls(); } void QmitkMatchPointMapper::OnLockInputButtonPushed() { if (this->m_Controls.m_pbLockInput->isChecked()) { if (this->m_spSelectedInputNode.IsNotNull()) { this->m_spSelectedInputNode->SetSelected(false); this->GetDataStorage()->Modified(); } } this->CheckInputs(); this->ConfigureMappingControls(); } void QmitkMatchPointMapper::OnLockReferenceButtonPushed() { if (this->m_Controls.m_pbLockRef->isChecked()) { if (this->m_spSelectedRefNode.IsNotNull()) { this->m_spSelectedRefNode->SetSelected(false); this->GetDataStorage()->Modified(); } } this->CheckInputs(); this->ConfigureMappingControls(); } void QmitkMatchPointMapper::OnManualRefChecked() { this->CheckInputs(); this->ConfigureMappingControls(); } void QmitkMatchPointMapper::OnLinkSampleFactorChecked() { this->m_Controls.m_sbYFactor->setEnabled(!(this->m_Controls.m_cbLinkFactors->isChecked())); this->m_Controls.m_sbZFactor->setEnabled(!(this->m_Controls.m_cbLinkFactors->isChecked())); if (m_Controls.m_cbLinkFactors->isChecked()) { this->m_Controls.m_sbYFactor->setValue(this->m_Controls.m_sbXFactor->value()); this->m_Controls.m_sbZFactor->setValue(this->m_Controls.m_sbXFactor->value()); } } void QmitkMatchPointMapper::OnMapBtnPushed() { SpawnMappingJob(); } void QmitkMatchPointMapper::OnRefineBtnPushed() { SpawnMappingJob(true); } void QmitkMatchPointMapper::SpawnMappingJob(bool doGeometryRefinement) { if (m_Controls.m_checkClearLog->checkState() == Qt::Checked) { this->m_Controls.m_teLog->clear(); } ///////////////////////// //create job and put it into the thread pool QmitkMappingJob* pJob = new QmitkMappingJob(); pJob->setAutoDelete(true); pJob->m_spInputData = this->m_spSelectedInputNode->GetData(); pJob->m_InputDataUID = mitk::EnsureUID(this->m_spSelectedInputNode->GetData()); pJob->m_doGeometryRefinement = doGeometryRefinement; pJob->m_spRegNode = m_spSelectedRegNode; if (m_spSelectedRegNode.IsNull()) { pJob->m_spRegNode = mitk::DataNode::New(); pJob->m_spRegNode->SetData(mitk::GenerateIdentityRegistration3D().GetPointer()); pJob->m_spRegNode->SetName("Auto_Generated_Identity_Transform"); m_Controls.m_teLog->append( QString("No registration selected. Preforming mapping with identity transform")); } if (!doGeometryRefinement) { pJob->m_spRefGeometry = m_spSelectedRefNode->GetData()->GetGeometry()->Clone().GetPointer(); //check for super/sub sampling if (m_Controls.m_groupActivateSampling->isChecked()) { //change the pixel count and spacing of the geometry mitk::BaseGeometry::BoundsArrayType geoBounds = pJob->m_spRefGeometry->GetBounds(); mitk::Vector3D geoSpacing = pJob->m_spRefGeometry->GetSpacing(); geoSpacing[0] = geoSpacing[0] / m_Controls.m_sbXFactor->value(); geoSpacing[1] = geoSpacing[1] / m_Controls.m_sbYFactor->value(); geoSpacing[2] = geoSpacing[2] / m_Controls.m_sbZFactor->value(); geoBounds[1] = geoBounds[1] * m_Controls.m_sbXFactor->value(); geoBounds[3] = geoBounds[3] * m_Controls.m_sbYFactor->value(); geoBounds[5] = geoBounds[5] * m_Controls.m_sbZFactor->value(); pJob->m_spRefGeometry->SetBounds(geoBounds); pJob->m_spRefGeometry->SetSpacing(geoSpacing); } } pJob->m_MappedName = m_Controls.m_leMappedName->text().toStdString(); pJob->m_allowUndefPixels = m_Controls.m_groupAllowUndefPixels->isChecked(); pJob->m_paddingValue = m_Controls.m_sbPaddingValue->value(); pJob->m_allowUnregPixels = m_Controls.m_groupAllowUnregPixels->isChecked(); pJob->m_errorValue = m_Controls.m_sbErrorValue->value(); pJob->m_InterpolatorLabel = m_Controls.m_comboInterpolator->currentText().toStdString(); switch (m_Controls.m_comboInterpolator->currentIndex()) { case 0: pJob->m_InterpolatorType = mitk::ImageMappingInterpolator::NearestNeighbor; break; case 1: pJob->m_InterpolatorType = mitk::ImageMappingInterpolator::Linear; break; case 2: pJob->m_InterpolatorType = mitk::ImageMappingInterpolator::BSpline_3; break; case 3: pJob->m_InterpolatorType = mitk::ImageMappingInterpolator::WSinc_Hamming; break; case 4: pJob->m_InterpolatorType = mitk::ImageMappingInterpolator::WSinc_Welch; break; } connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnMapJobError(QString))); connect(pJob, SIGNAL(MapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), this, SLOT(OnMapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(AlgorithmInfo(QString)), this, SLOT(OnMappingInfo(QString))); m_Controls.m_teLog->append(QString("Started mapping job. Name: ") + m_Controls.m_leMappedName->text() + QString("")); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } void QmitkMatchPointMapper::OnMapJobError(QString err) { Error(err); }; void QmitkMatchPointMapper::OnMapResultIsAvailable(mitk::BaseData::Pointer spMappedData, const QmitkMappingJob* job) { m_Controls.m_teLog->append(QString("Mapped entity stored. Name: ") + QString::fromStdString(job->m_MappedName) + QString("")); mitk::DataNode::Pointer spMappedNode = mitk::generateMappedResultNode(job->m_MappedName, spMappedData, job->GetRegistration()->getRegistrationUID(), job->m_InputDataUID, job->m_doGeometryRefinement, job->m_InterpolatorLabel); this->GetDataStorage()->Add(spMappedNode); this->GetRenderWindowPart()->RequestUpdate(); this->CheckInputs(); this->ConfigureMappingControls(); }; void QmitkMatchPointMapper::OnMappingInfo(QString info) { m_Controls.m_teLog->append(QString("") + info + QString("")); }; void QmitkMatchPointMapper::OnXFactorChanged(double d) { if (m_Controls.m_cbLinkFactors->isChecked()) { this->m_Controls.m_sbYFactor->setValue(d); this->m_Controls.m_sbZFactor->setValue(d); } } diff --git a/Plugins/org.mitk.gui.qt.matchpoint.visualizer/src/internal/QmitkMatchPointRegistrationVisualizer.cpp b/Plugins/org.mitk.gui.qt.matchpoint.visualizer/src/internal/QmitkMatchPointRegistrationVisualizer.cpp index b9cba1d251..b5ab8e4c07 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.visualizer/src/internal/QmitkMatchPointRegistrationVisualizer.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.visualizer/src/internal/QmitkMatchPointRegistrationVisualizer.cpp @@ -1,846 +1,846 @@ /*=================================================================== 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 "org_mitk_gui_qt_matchpoint_visualizer_Activator.h" // Blueberry #include #include // Mitk #include #include #include #include #include "mitkRegVisDirectionProperty.h" #include "mitkRegVisStyleProperty.h" #include "mitkRegVisColorStyleProperty.h" #include "mitkRegVisPropertyTags.h" #include "mitkRegVisHelper.h" #include "mitkMatchPointPropertyTags.h" #include "mitkRegistrationHelper.h" // Qmitk #include "QmitkMatchPointRegistrationVisualizer.h" // Qt #include #include const std::string QmitkMatchPointRegistrationVisualizer::VIEW_ID = "org.mitk.views.matchpoint.visualizer"; QmitkMatchPointRegistrationVisualizer::QmitkMatchPointRegistrationVisualizer() : m_Parent(nullptr), m_internalUpdateGuard(false), m_spSelectedFOVRefNode(nullptr), m_spSelectedRegNode(nullptr) { } void QmitkMatchPointRegistrationVisualizer::SetFocus() { //m_Controls->buttonPerformImageProcessing->setFocus(); } void QmitkMatchPointRegistrationVisualizer::CreateConnections() { // show first page connect(m_Controls->m_pbLockReg, SIGNAL(clicked()), this, SLOT(OnLockRegButtonPushed())); connect(m_Controls->m_pbStyleGrid, SIGNAL(clicked()), this, SLOT(OnStyleButtonPushed())); connect(m_Controls->m_pbStyleGlyph, SIGNAL(clicked()), this, SLOT(OnStyleButtonPushed())); connect(m_Controls->m_pbStylePoints, SIGNAL(clicked()), this, SLOT(OnStyleButtonPushed())); connect(m_Controls->m_comboDirection, SIGNAL(currentIndexChanged(int)), this, SLOT(OnDirectionChanged(int))); connect(m_Controls->m_pbUpdateViz, SIGNAL(clicked()), this, SLOT(OnUpdateBtnPushed())); connect(m_Controls->m_pbUseFOVRef, SIGNAL(clicked()), this, SLOT(OnUseFOVRefBtnPushed())); connect(m_Controls->radioColorUni, SIGNAL(toggled(bool)), m_Controls->btnUniColor, SLOT(setEnabled(bool))); connect(m_Controls->radioColorVecMag, SIGNAL(toggled(bool)), m_Controls->groupColorCoding, SLOT(setEnabled(bool))); connect(m_Controls->m_pbStyleGrid, SIGNAL(toggled(bool)), m_Controls->tabGrid, SLOT(setEnabled(bool))); connect(m_Controls->cbVevMagInterlolate, SIGNAL(toggled(bool)), this, SLOT(OnColorInterpolationChecked(bool))); } void QmitkMatchPointRegistrationVisualizer::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); } void QmitkMatchPointRegistrationVisualizer::CreateQtPartControl(QWidget* parent) { m_Controls = new Ui::MatchPointRegVisControls; // create GUI widgets from the Qt Designer's .ui file m_Controls->setupUi(parent); m_Parent = parent; this->m_Controls->btnVecMagColorSmall->setDisplayColorName(false); this->m_Controls->btnVecMagColorMedium->setDisplayColorName(false); this->m_Controls->btnVecMagColorLarge->setDisplayColorName(false); this->m_Controls->btnVecMagColorNeg->setDisplayColorName(false); this->m_Controls->btnUniColor->setDisplayColorName(false); this->m_Controls->btnStartGridColor->setDisplayColorName(false); this->CreateConnections(); this->m_Controls->radioColorUni->setChecked(false); this->m_Controls->radioColorVecMag->setChecked(true); this->CheckInputs(); this->LoadStateFromNode(); this->ConfigureVisualizationControls(); } mitk::MAPRegistrationWrapper* QmitkMatchPointRegistrationVisualizer::GetCurrentRegistration() { mitk::MAPRegistrationWrapper* result = nullptr; if (this->m_spSelectedRegNode.IsNotNull()) { result = dynamic_cast(this->m_spSelectedRegNode->GetData()); assert(result); } return result; } mitk::DataNode::Pointer QmitkMatchPointRegistrationVisualizer::GetSelectedRegNode() const { mitk::DataNode::Pointer spResult = nullptr; typedef QList NodeListType; NodeListType nodes = this->GetDataManagerSelection(); for (NodeListType::iterator pos = nodes.begin(); pos != nodes.end(); ++pos) { if (mitk::MITKRegistrationHelper::IsRegNode(*pos)) { spResult = *pos; break; } } return spResult; } mitk::DataNode::Pointer QmitkMatchPointRegistrationVisualizer::GetRefNodeOfReg(bool target) const { mitk::DataNode::Pointer spResult = nullptr; if (this->m_spSelectedRegNode.IsNotNull() && m_spSelectedRegNode->GetData()) { std::string nodeName; mitk::BaseProperty* uidProp; if (target) { uidProp = m_spSelectedRegNode->GetData()->GetProperty(mitk::Prop_RegAlgTargetData); } else { uidProp = m_spSelectedRegNode->GetData()->GetProperty(mitk::Prop_RegAlgMovingData); } if (uidProp) { //search for the target node mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New(mitk::Prop_UID, uidProp); spResult = this->GetDataStorage()->GetNode(predicate); } } return spResult; } mitk::DataNode::Pointer QmitkMatchPointRegistrationVisualizer::GetSelectedDataNode() { typedef QList NodeListType; NodeListType nodes = this->GetDataManagerSelection(); mitk::DataNode::Pointer result; for (NodeListType::iterator pos = nodes.begin(); pos != nodes.end(); ++pos) { if (!mitk::MITKRegistrationHelper::IsRegNode(*pos) && (*pos)->GetData() && (*pos)->GetData()->GetGeometry()) { result = *pos; break; } } return result; } void QmitkMatchPointRegistrationVisualizer::CheckInputs() { mitk::DataNode::Pointer regNode = this->GetSelectedRegNode(); if (!m_Controls->m_pbLockReg->isChecked()) { this->m_spSelectedRegNode = regNode; } this->InitRegNode(); mitk::DataNode::Pointer fovNode = this->GetSelectedDataNode(); if (!m_Controls->m_pbLockFOVRef->isChecked()) { this->m_spSelectedFOVRefNode = fovNode; } } void QmitkMatchPointRegistrationVisualizer::ConfigureVisualizationControls() { if (!m_internalUpdateGuard) { m_internalUpdateGuard = true; m_Controls->groupViz->setVisible(this->m_spSelectedRegNode.IsNotNull()); m_Controls->m_pbUpdateViz->setEnabled(this->m_spSelectedRegNode.IsNotNull()); m_Controls->m_boxSettings->setEnabled(this->m_spSelectedRegNode.IsNotNull()); m_Controls->m_boxStyles->setEnabled(this->m_spSelectedRegNode.IsNotNull()); this->ActualizeRegInfo(this->GetCurrentRegistration()); if (this->m_spSelectedRegNode.IsNull()) { m_Controls->m_lbRegistrationName->setText( QString("no registration selected!")); } else { m_Controls->m_lbRegistrationName->setText(QString::fromStdString( this->m_spSelectedRegNode->GetName())); } this->m_Controls->m_pbLockReg->setEnabled(this->m_spSelectedRegNode.IsNotNull()); this->m_Controls->m_pbUseFOVRef->setEnabled(this->m_spSelectedRegNode.IsNotNull() && this->m_spSelectedFOVRefNode.IsNotNull()); this->m_Controls->m_checkUseRefSize->setEnabled(this->m_spSelectedRegNode.IsNotNull() && this->m_spSelectedFOVRefNode.IsNotNull()); this->m_Controls->m_checkUseRefOrigin->setEnabled(this->m_spSelectedRegNode.IsNotNull() && this->m_spSelectedFOVRefNode.IsNotNull()); this->m_Controls->m_checkUseRefSpacing->setEnabled(this->m_spSelectedRegNode.IsNotNull() && this->m_spSelectedFOVRefNode.IsNotNull()); this->m_Controls->m_pbLockFOVRef->setEnabled(this->m_spSelectedFOVRefNode.IsNotNull()); if (this->m_spSelectedFOVRefNode.IsNull()) { m_Controls->m_lbFOVRef->setText(QString("no valid reference selected!")); } else { m_Controls->m_lbFOVRef->setText(QString::fromStdString(this->m_spSelectedFOVRefNode->GetName())); } m_internalUpdateGuard = false; } } void QmitkMatchPointRegistrationVisualizer::StoreStateInNode() { if (this->m_spSelectedRegNode.IsNotNull()) { //general this->m_spSelectedRegNode->SetProperty(mitk::nodeProp_RegVisDirection, mitk::RegVisDirectionProperty::New(this->m_Controls->m_comboDirection->currentIndex())); this->m_spSelectedRegNode->SetBoolProperty(mitk::nodeProp_RegVisGrid, this->m_Controls->m_pbStyleGrid->isChecked()); this->m_spSelectedRegNode->SetBoolProperty(mitk::nodeProp_RegVisGlyph, this->m_Controls->m_pbStyleGlyph->isChecked()); this->m_spSelectedRegNode->SetBoolProperty(mitk::nodeProp_RegVisPoints, this->m_Controls->m_pbStylePoints->isChecked()); //Visualization if (this->m_Controls->radioColorUni->isChecked()) { this->m_spSelectedRegNode->SetProperty(mitk::nodeProp_RegVisColorStyle, mitk::RegVisColorStyleProperty::New(0)); } else { this->m_spSelectedRegNode->SetProperty(mitk::nodeProp_RegVisColorStyle, mitk::RegVisColorStyleProperty::New(1)); } float tmpColor[3]; tmpColor[0] = this->m_Controls->btnUniColor->color().redF(); tmpColor[1] = this->m_Controls->btnUniColor->color().greenF(); tmpColor[2] = this->m_Controls->btnUniColor->color().blueF(); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColorUni, mitk::ColorProperty::New(tmpColor), nullptr, true); tmpColor[0] = this->m_Controls->btnVecMagColorNeg->color().redF(); tmpColor[1] = this->m_Controls->btnVecMagColorNeg->color().greenF(); tmpColor[2] = this->m_Controls->btnVecMagColorNeg->color().blueF(); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor1Value, mitk::ColorProperty::New(tmpColor), nullptr, true); tmpColor[0] = this->m_Controls->btnVecMagColorSmall->color().redF(); tmpColor[1] = this->m_Controls->btnVecMagColorSmall->color().greenF(); tmpColor[2] = this->m_Controls->btnVecMagColorSmall->color().blueF(); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor2Value, mitk::ColorProperty::New(tmpColor), nullptr, true); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor2Magnitude, mitk::DoubleProperty::New(this->m_Controls->sbVecMagSmall->value()), nullptr, true); tmpColor[0] = this->m_Controls->btnVecMagColorMedium->color().redF(); tmpColor[1] = this->m_Controls->btnVecMagColorMedium->color().greenF(); tmpColor[2] = this->m_Controls->btnVecMagColorMedium->color().blueF(); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor3Value, mitk::ColorProperty::New(tmpColor), nullptr, true); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor3Magnitude, mitk::DoubleProperty::New(this->m_Controls->sbVecMagMedium->value()), nullptr, true); tmpColor[0] = this->m_Controls->btnVecMagColorLarge->color().redF(); tmpColor[1] = this->m_Controls->btnVecMagColorLarge->color().greenF(); tmpColor[2] = this->m_Controls->btnVecMagColorLarge->color().blueF(); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor4Value, mitk::ColorProperty::New(tmpColor), nullptr, true); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor4Magnitude, mitk::DoubleProperty::New(this->m_Controls->sbVecMagLarge->value()), nullptr, true); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColorInterpolate, mitk::BoolProperty::New(this->m_Controls->cbVevMagInterlolate->isChecked()), nullptr, true); //Grid Settings this->m_spSelectedRegNode->SetIntProperty(mitk::nodeProp_RegVisGridFrequence, this->m_Controls->m_sbGridFrequency->value()); this->m_spSelectedRegNode->SetBoolProperty(mitk::nodeProp_RegVisGridShowStart, this->m_Controls->m_groupShowStartGrid->isChecked()); tmpColor[0] = this->m_Controls->btnStartGridColor->color().redF(); tmpColor[1] = this->m_Controls->btnStartGridColor->color().greenF(); tmpColor[2] = this->m_Controls->btnStartGridColor->color().blueF(); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisGridStartColor, mitk::ColorProperty::New(tmpColor), nullptr, true); //FOV mitk::Vector3D value; value[0] = this->m_Controls->m_sbFOVSizeX->value(); value[1] = this->m_Controls->m_sbFOVSizeY->value(); value[2] = this->m_Controls->m_sbFOVSizeZ->value(); this->m_spSelectedRegNode->SetProperty(mitk::nodeProp_RegVisFOVSize, mitk::Vector3DProperty::New(value)); value[0] = this->m_Controls->m_sbGridSpX->value(); value[1] = this->m_Controls->m_sbGridSpY->value(); value[2] = this->m_Controls->m_sbGridSpZ->value(); this->m_spSelectedRegNode->SetProperty(mitk::nodeProp_RegVisFOVSpacing, mitk::Vector3DProperty::New(value)); mitk::Point3D origin; origin[0] = this->m_Controls->m_sbFOVOriginX->value(); origin[1] = this->m_Controls->m_sbFOVOriginY->value(); origin[2] = this->m_Controls->m_sbFOVOriginZ->value(); this->m_spSelectedRegNode->SetProperty(mitk::nodeProp_RegVisFOVOrigin, mitk::Point3dProperty::New(origin)); mitk::Vector3D orientationRow1; mitk::Vector3D orientationRow2; mitk::Vector3D orientationRow3; orientationRow1.SetVnlVector(m_FOVRefOrientation.GetVnlMatrix().get_row(0)); orientationRow2.SetVnlVector(m_FOVRefOrientation.GetVnlMatrix().get_row(1)); orientationRow3.SetVnlVector(m_FOVRefOrientation.GetVnlMatrix().get_row(2)); this->m_spSelectedRegNode->SetProperty(mitk::nodeProp_RegVisFOVOrientation1, mitk::Vector3DProperty::New(orientationRow1)); this->m_spSelectedRegNode->SetProperty(mitk::nodeProp_RegVisFOVOrientation2, mitk::Vector3DProperty::New(orientationRow2)); this->m_spSelectedRegNode->SetProperty(mitk::nodeProp_RegVisFOVOrientation3, mitk::Vector3DProperty::New(orientationRow3)); } } void QmitkMatchPointRegistrationVisualizer::LoadStateFromNode() { if (this->m_spSelectedRegNode.IsNotNull()) { mitk::RegVisDirectionProperty* directionProp = nullptr; if (this->m_spSelectedRegNode->GetProperty(directionProp, mitk::nodeProp_RegVisDirection)) { this->m_Controls->m_comboDirection->setCurrentIndex(directionProp->GetValueAsId()); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisDirection) + QString(" has not the assumed type.")); } bool styleActive = false; if (this->m_spSelectedRegNode->GetBoolProperty(mitk::nodeProp_RegVisGrid, styleActive)) { this->m_Controls->m_pbStyleGrid->setChecked(styleActive); this->m_Controls->tabGrid->setEnabled(styleActive); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisGrid) + QString(" has not the assumed type.")); } if (this->m_spSelectedRegNode->GetBoolProperty(mitk::nodeProp_RegVisGlyph, styleActive)) { this->m_Controls->m_pbStyleGlyph->setChecked(styleActive); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisGlyph) + QString(" has not the assumed type.")); } if (this->m_spSelectedRegNode->GetBoolProperty(mitk::nodeProp_RegVisPoints, styleActive)) { this->m_Controls->m_pbStylePoints->setChecked(styleActive); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisPoints) + QString(" has not the assumed type.")); } /////////////////////////////////////////////////////// //visualization mitk::RegVisColorStyleProperty* colorStyleProp = nullptr; if (this->m_spSelectedRegNode->GetProperty(colorStyleProp, mitk::nodeProp_RegVisColorStyle)) { this->m_Controls->radioColorUni->setChecked(colorStyleProp->GetValueAsId() == 0); this->m_Controls->radioColorVecMag->setChecked(colorStyleProp->GetValueAsId() == 1); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisColorStyle) + QString(" has not the assumed type.")); } QColor tmpColor; float colorUni[3] = { 0.0, 0.0, 0.0 }; this->m_spSelectedRegNode->GetColor(colorUni, nullptr, mitk::nodeProp_RegVisColorUni); tmpColor.setRgbF(colorUni[0], colorUni[1], colorUni[2]); this->m_Controls->btnUniColor->setColor(tmpColor); float color1[3] = { 0.0, 0.0, 0.0 }; this->m_spSelectedRegNode->GetColor(color1, nullptr, mitk::nodeProp_RegVisColor1Value); tmpColor.setRgbF(color1[0], color1[1], color1[2]); this->m_Controls->btnVecMagColorNeg->setColor(tmpColor); float color2[3] = { 0.25, 0.25, 0.25 }; this->m_spSelectedRegNode->GetColor(color2, nullptr, mitk::nodeProp_RegVisColor2Value); tmpColor.setRgbF(color2[0], color2[1], color2[2]); this->m_Controls->btnVecMagColorSmall->setColor(tmpColor); float color3[3] = { 0.5, 0.5, 0.5 }; this->m_spSelectedRegNode->GetColor(color3, nullptr, mitk::nodeProp_RegVisColor3Value); tmpColor.setRgbF(color3[0], color3[1], color3[2]); this->m_Controls->btnVecMagColorMedium->setColor(tmpColor); float color4[3] = { 1.0, 1.0, 1.0 }; this->m_spSelectedRegNode->GetColor(color4, nullptr, mitk::nodeProp_RegVisColor4Value); tmpColor.setRgbF(color4[0], color4[1], color4[2]); this->m_Controls->btnVecMagColorLarge->setColor(tmpColor); double mag2 = 0; this->m_spSelectedRegNode->GetPropertyValue(mitk::nodeProp_RegVisColor2Magnitude, mag2); double mag3 = 0; this->m_spSelectedRegNode->GetPropertyValue(mitk::nodeProp_RegVisColor3Magnitude, mag3); double mag4 = 0; this->m_spSelectedRegNode->GetPropertyValue(mitk::nodeProp_RegVisColor4Magnitude, mag4); bool interpolate = true; this->m_spSelectedRegNode->GetBoolProperty(mitk::nodeProp_RegVisColorInterpolate, interpolate); this->m_Controls->sbVecMagSmall->setValue(mag2); this->m_Controls->sbVecMagMedium->setValue(mag3); this->m_Controls->sbVecMagLarge->setValue(mag4); this->m_Controls->cbVevMagInterlolate->setChecked(interpolate); /////////////////////////////////////////////////////// //Grid general bool showStart = false; if (this->m_spSelectedRegNode->GetBoolProperty(mitk::nodeProp_RegVisGridShowStart, showStart)) { this->m_Controls->m_groupShowStartGrid->setChecked(showStart); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisGridShowStart) + QString(" is not correctly defined.")); } int gridFrequ = 5; if (this->m_spSelectedRegNode->GetIntProperty(mitk::nodeProp_RegVisGridFrequence, gridFrequ)) { this->m_Controls->m_sbGridFrequency->setValue(gridFrequ); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisGridFrequence) + QString(" is not correctly defined.")); } float colorStart[3] = { 0.0, 0.0, 0.0 }; this->m_spSelectedRegNode->GetColor(colorStart, nullptr, mitk::nodeProp_RegVisGridStartColor); tmpColor.setRgbF(colorStart[0], colorStart[1], colorStart[2]); this->m_Controls->btnStartGridColor->setColor(tmpColor); /////////////////////////////////////////////////////// //FOV mitk::Vector3DProperty* valueProp = nullptr; if (this->m_spSelectedRegNode->GetProperty(valueProp, mitk::nodeProp_RegVisFOVSize)) { this->m_Controls->m_sbFOVSizeX->setValue(valueProp->GetValue()[0]); this->m_Controls->m_sbFOVSizeY->setValue(valueProp->GetValue()[1]); this->m_Controls->m_sbFOVSizeZ->setValue(valueProp->GetValue()[2]); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisFOVSize) + QString(" is not correctly defined.")); } if (this->m_spSelectedRegNode->GetProperty(valueProp, mitk::nodeProp_RegVisFOVSpacing)) { this->m_Controls->m_sbGridSpX->setValue(valueProp->GetValue()[0]); this->m_Controls->m_sbGridSpY->setValue(valueProp->GetValue()[1]); this->m_Controls->m_sbGridSpZ->setValue(valueProp->GetValue()[2]); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisFOVSpacing) + QString(" is not correctly defined.")); } mitk::Point3dProperty* originProp = nullptr; if (this->m_spSelectedRegNode->GetProperty(originProp, mitk::nodeProp_RegVisFOVOrigin)) { this->m_Controls->m_sbFOVOriginX->setValue(originProp->GetValue()[0]); this->m_Controls->m_sbFOVOriginY->setValue(originProp->GetValue()[1]); this->m_Controls->m_sbFOVOriginZ->setValue(originProp->GetValue()[2]); } else { this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( mitk::nodeProp_RegVisFOVOrigin) + QString(" is not correctly defined.")); } mitk::Vector3DProperty* orientationProp1; mitk::Vector3DProperty* orientationProp2; mitk::Vector3DProperty* orientationProp3; if (this->m_spSelectedRegNode->GetProperty(orientationProp1, mitk::nodeProp_RegVisFOVOrientation1) && this->m_spSelectedRegNode->GetProperty(orientationProp2, mitk::nodeProp_RegVisFOVOrientation2) && this->m_spSelectedRegNode->GetProperty(orientationProp3, mitk::nodeProp_RegVisFOVOrientation3)) { this->m_Controls->m_sbFOVOriginX->setValue(originProp->GetValue()[0]); this->m_Controls->m_sbFOVOriginY->setValue(originProp->GetValue()[1]); this->m_Controls->m_sbFOVOriginZ->setValue(originProp->GetValue()[2]); m_FOVRefOrientation.GetVnlMatrix().set_row(0, orientationProp1->GetValue().GetVnlVector()); m_FOVRefOrientation.GetVnlMatrix().set_row(1, orientationProp2->GetValue().GetVnlVector()); m_FOVRefOrientation.GetVnlMatrix().set_row(2, orientationProp3->GetValue().GetVnlVector()); } else { m_FOVRefOrientation.SetIdentity(); this->Error(QString("Cannot configure plugin controlls correctly. One of the node propertiesy ") + QString(mitk::nodeProp_RegVisFOVOrientation1) + QString(mitk::nodeProp_RegVisFOVOrientation2) + QString(mitk::nodeProp_RegVisFOVOrientation3) + QString(" is not correctly defined.")); } this->UpdateOrientationMatrixWidget(); } } void QmitkMatchPointRegistrationVisualizer::CheckAndSetDefaultFOVRef() { //check if node has a default reference node. mitk::DataNode::Pointer defaultRef = this->GetRefNodeOfReg( this->m_Controls->m_comboDirection->currentIndex() == 1); //direction value 1 = show inverse mapping -> we need the target image used for the registration. //if there is a default node and no m_spSelectedFOVRefNode is set -> set default node and transfer values if (defaultRef.IsNotNull() && this->m_spSelectedFOVRefNode.IsNull() && !(this->m_Controls->m_pbLockFOVRef->isDown())) { //there is a default ref and no ref lock -> select default ref and transfer its values this->m_spSelectedFOVRefNode = defaultRef; this->m_Controls->m_checkUseRefSize->setChecked(true); this->m_Controls->m_checkUseRefOrigin->setChecked(true); this->m_Controls->m_checkUseRefSpacing->setChecked(true); this->m_Controls->m_checkUseRefOrientation->setChecked(true); //auto transfere values this->OnUseFOVRefBtnPushed(); } } void QmitkMatchPointRegistrationVisualizer::OnSelectionChanged( - berry::IWorkbenchPart::Pointer /*source*/, - const QList& nodes) + berry::IWorkbenchPart::Pointer, + const QList&) { this->CheckInputs(); this->LoadStateFromNode(); this->CheckAndSetDefaultFOVRef(); this->ConfigureVisualizationControls(); } void QmitkMatchPointRegistrationVisualizer::ActualizeRegInfo(mitk::MAPRegistrationWrapper* currentReg) { std::stringstream descriptionString; m_Controls->m_teRegInfo->clear(); if (currentReg) { descriptionString << "Moving dimension: " << currentReg->GetMovingDimensions() << "
"; descriptionString << "Target dimension: " << currentReg->GetTargetDimensions() << "
"; descriptionString << "Limited moving representation: " << currentReg->HasLimitedMovingRepresentation() << "
"; descriptionString << "Limited target representation: " << currentReg->HasLimitedTargetRepresentation() << "
"; mitk::MAPRegistrationWrapper::TagMapType tagMap = currentReg->GetTags(); descriptionString << "
Tags:
"; for (mitk::MAPRegistrationWrapper::TagMapType::const_iterator pos = tagMap.begin(); pos != tagMap.end(); ++pos) { descriptionString << pos->first << " : " << pos->second << "
"; } } else { descriptionString << "no registration selected!"; } m_Controls->m_teRegInfo->insertHtml(QString::fromStdString(descriptionString.str())); } -void QmitkMatchPointRegistrationVisualizer::OnDirectionChanged(int index) +void QmitkMatchPointRegistrationVisualizer::OnDirectionChanged(int) { this->CheckAndSetDefaultFOVRef(); this->ConfigureVisualizationControls(); }; void QmitkMatchPointRegistrationVisualizer::OnLockRegButtonPushed() { if (this->m_Controls->m_pbLockReg->isChecked()) { if (this->m_spSelectedRegNode.IsNotNull()) { this->m_spSelectedRegNode->SetSelected(false); this->GetDataStorage()->Modified(); } } this->CheckInputs(); this->ConfigureVisualizationControls(); } void QmitkMatchPointRegistrationVisualizer::OnUpdateBtnPushed() { this->StoreStateInNode(); mitk::Geometry3D::Pointer gridDesc; unsigned int gridFrequ = 5; mitk::GetGridGeometryFromNode(this->m_spSelectedRegNode, gridDesc, gridFrequ); this->GetCurrentRegistration()->SetGeometry(gridDesc); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } void QmitkMatchPointRegistrationVisualizer::OnStyleButtonPushed() { } void QmitkMatchPointRegistrationVisualizer::OnColorInterpolationChecked(bool checked) { if (checked) { this->m_Controls->labelVecMagSmall->setText(QString("=")); this->m_Controls->labelVecMagMedium->setText(QString("=")); this->m_Controls->labelVecMagLarge->setText(QString("=")); } else { this->m_Controls->labelVecMagSmall->setText(QString(">")); this->m_Controls->labelVecMagMedium->setText(QString(">")); this->m_Controls->labelVecMagLarge->setText(QString(">")); } }; mitk::ScalarType QmitkMatchPointRegistrationVisualizer::GetSaveSpacing(mitk::ScalarType gridRes, mitk::ScalarType spacing, unsigned int maxGridRes) const { mitk::ScalarType newSpacing = spacing; mitk::ScalarType scaling = gridRes / maxGridRes; if (scaling > 1.0) { newSpacing = spacing * scaling; } return newSpacing; } void QmitkMatchPointRegistrationVisualizer::OnUseFOVRefBtnPushed() { if (this->m_spSelectedFOVRefNode.IsNotNull()) { assert(this->m_spSelectedFOVRefNode->GetData()); assert(this->m_spSelectedFOVRefNode->GetData()->GetGeometry()); mitk::BaseGeometry* gridRef = this->m_spSelectedFOVRefNode->GetData()->GetGeometry(); mitk::Vector3D spacing = gridRef->GetSpacing(); mitk::Point3D origin = gridRef->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = gridRef->GetBounds(); mitk::AffineTransform3D::ConstPointer fovTransform = gridRef->GetIndexToWorldTransform(); if (this->m_Controls->m_checkUseRefSize->isChecked()) { this->m_Controls->m_sbFOVSizeX->setValue((bounds[1] - bounds[0])*spacing[0]); this->m_Controls->m_sbFOVSizeY->setValue((bounds[3] - bounds[2])*spacing[1]); this->m_Controls->m_sbFOVSizeZ->setValue((bounds[5] - bounds[4])*spacing[2]); } if (this->m_Controls->m_checkUseRefSpacing->isChecked()) { this->m_Controls->m_sbGridSpX->setValue(GetSaveSpacing((bounds[1] - bounds[0]), spacing[0], 20)); this->m_Controls->m_sbGridSpY->setValue(GetSaveSpacing((bounds[3] - bounds[2]), spacing[1], 20)); this->m_Controls->m_sbGridSpZ->setValue(GetSaveSpacing((bounds[5] - bounds[4]), spacing[2], 20)); } if (this->m_Controls->m_checkUseRefOrigin->isChecked()) { this->m_Controls->m_sbFOVOriginX->setValue(origin[0]); this->m_Controls->m_sbFOVOriginY->setValue(origin[1]); this->m_Controls->m_sbFOVOriginZ->setValue(origin[2]); } if (this->m_Controls->m_checkUseRefOrientation->isChecked()) { this->m_FOVRefOrientation = fovTransform->GetMatrix(); this->UpdateOrientationMatrixWidget(); } } } void QmitkMatchPointRegistrationVisualizer::UpdateOrientationMatrixWidget() { for (unsigned int r = 0; r < 3; ++r) { for (unsigned int c = 0; c < 3; ++c) { this->m_Controls->m_tableOrientation->item(r, c)->setText(QString::number(this->m_FOVRefOrientation.GetVnlMatrix().get(r, c))); } } } void QmitkMatchPointRegistrationVisualizer::InitRegNode() { if (this->m_spSelectedRegNode.IsNotNull()) { this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisGrid, mitk::BoolProperty::New(true)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisGlyph, mitk::BoolProperty::New(false)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisPoints, mitk::BoolProperty::New(false)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisDirection, mitk::RegVisDirectionProperty::New()); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColorStyle, mitk::RegVisColorStyleProperty::New(1)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColorUni, mitk::ColorProperty::New(0, 0.5, 0)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisGridFrequence, mitk::IntProperty::New(3)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisGridShowStart, mitk::BoolProperty::New(false)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisGridStartColor, mitk::ColorProperty::New(0.5, 0, 0)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisFOVSize, mitk::Vector3DProperty::New(mitk::Vector3D(100.0))); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisFOVSpacing, mitk::Vector3DProperty::New(mitk::Vector3D(5.0))); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor1Value, mitk::ColorProperty::New(0, 0, 0.5)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor2Value, mitk::ColorProperty::New(0, 0.7, 0)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor2Magnitude, mitk::DoubleProperty::New(1)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor3Value, mitk::ColorProperty::New(1, 1, 0)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor3Magnitude, mitk::DoubleProperty::New(5)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor4Value, mitk::ColorProperty::New(1, 0, 0)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColor4Magnitude, mitk::DoubleProperty::New(15)); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisColorInterpolate, mitk::BoolProperty::New(true)); mitk::Point3D origin; origin.Fill(0.0); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisFOVOrigin, mitk::Point3dProperty::New(mitk::Point3D(origin))); mitk::Vector3D vec(0.0); vec.SetElement(0, 1.0); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisFOVOrientation1, mitk::Vector3DProperty::New(vec)); vec.Fill(0.0); vec.SetElement(1, 1.0); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisFOVOrientation2, mitk::Vector3DProperty::New(vec)); vec.Fill(0.0); vec.SetElement(2, 1.0); this->m_spSelectedRegNode->AddProperty(mitk::nodeProp_RegVisFOVOrientation3, mitk::Vector3DProperty::New(vec)); } } diff --git a/Plugins/org.mitk.gui.qt.xnat/src/internal/QmitkXnatTreeBrowserView.cpp b/Plugins/org.mitk.gui.qt.xnat/src/internal/QmitkXnatTreeBrowserView.cpp index 00f2b38a5a..e8a954e2ad 100644 --- a/Plugins/org.mitk.gui.qt.xnat/src/internal/QmitkXnatTreeBrowserView.cpp +++ b/Plugins/org.mitk.gui.qt.xnat/src/internal/QmitkXnatTreeBrowserView.cpp @@ -1,1354 +1,1342 @@ /*=================================================================== 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 "QmitkXnatTreeBrowserView.h" // Qmitk #include "org_mitk_gui_qt_xnatinterface_Activator.h" // Blueberry #include // CTK XNAT Core #include #include #include #include #include #include "ctkXnatFile.h" #include #include #include #include #include #include #include #include // MITK XNAT #include #include #include #include #include #include #include // Qt #include #include #include #include #include #include #include #include #include #include #include #include #include // Poco #include const QString QmitkXnatTreeBrowserView::VIEW_ID = "org.mitk.views.xnat.treebrowser"; static bool isDirWriteable(QDir myDir) { const QFileInfoList tmpInfo = myDir.entryInfoList(); foreach (QFileInfo f, tmpInfo) { if(f.fileName() == ".") return f.isWritable(); } return true; } static bool doesDirExist(QDir myDir) { if (!myDir.exists()) { if(!myDir.mkpath(".")) { MITK_INFO << "Path Creation Failed."; return false; } } return true; } QmitkXnatTreeBrowserView::QmitkXnatTreeBrowserView() : m_DataStorageServiceTracker(mitk::org_mitk_gui_qt_xnatinterface_Activator::GetContext()), m_TreeModel(new QmitkXnatTreeModel()), m_Tracker(0), m_DownloadPath(berry::Platform::GetPreferencesService()->GetSystemPreferences()->Node(VIEW_ID)->Get("Download Path", "")), m_SilentMode(false) { m_DataStorageServiceTracker.open(); // Set DownloadPath if (m_DownloadPath.isEmpty()) { QString xnatFolder = "XNAT_DOWNLOADS"; QDir dir(mitk::org_mitk_gui_qt_xnatinterface_Activator::GetContext()->getDataFile("").absoluteFilePath()); dir.mkdir(xnatFolder); dir.setPath(dir.path() + "/" + xnatFolder); m_DownloadPath = dir.path() + "/"; } } QmitkXnatTreeBrowserView::~QmitkXnatTreeBrowserView() { m_DataStorageServiceTracker.close(); delete m_TreeModel; delete m_Tracker; } void QmitkXnatTreeBrowserView::SetFocus() { } void QmitkXnatTreeBrowserView::FilePathNotAvailableWarning(QString file) { MITK_INFO << "Download of " << file.toStdString() << " failed! Download Path not available!"; QMessageBox::critical(m_Controls.treeView, "Download failed!", "Download of " + file + " failed!\nDownload Path " + m_DownloadPath + " not available. \n\nChange Download Path in Settings!"); QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); _PreferencesDialog.SetSelectedPage("org.mitk.gui.qt.application.XnatConnectionPreferencePage"); _PreferencesDialog.exec(); m_Controls.groupBox->hide(); } void QmitkXnatTreeBrowserView::ToggleConnection() { ctkXnatSession* session = 0; try { session = mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetService( mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetServiceReference()); } catch (std::invalid_argument) { mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatSessionManager()->CreateXnatSession(); session = mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetService( mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetServiceReference()); } if (session != 0 && session->isOpen()) { mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatSessionManager()->CloseXnatSession(); m_Controls.btnXnatConnect->setToolTip("Connect"); m_Controls.btnXnatConnect->setIcon(QIcon(":/xnat-plugin/xnat-connect.png")); CleanUp(); } else if (session != 0 && !session->isOpen()) { try { mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatSessionManager()->OpenXnatSession(); m_Controls.btnXnatConnect->setToolTip("Disconnect"); m_Controls.btnXnatConnect->setIcon(QIcon(":/xnat-plugin/xnat-disconnect.png")); m_Controls.searchField->setEnabled(true); m_Controls.searchModeBox->setEnabled(true); } catch (const ctkXnatAuthenticationException& auth) { MITK_INFO << auth.message().toStdString(); mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatSessionManager()->CloseXnatSession(); QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); _PreferencesDialog.SetSelectedPage("org.mitk.gui.qt.application.XnatConnectionPreferencePage"); _PreferencesDialog.exec(); } catch (const ctkException& e) { MITK_INFO << e.message().toStdString(); mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatSessionManager()->CloseXnatSession(); QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); _PreferencesDialog.SetSelectedPage("org.mitk.gui.qt.application.XnatConnectionPreferencePage"); _PreferencesDialog.exec(); } catch (...) { QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); _PreferencesDialog.SetSelectedPage("org.mitk.gui.qt.application.XnatConnectionPreferencePage"); _PreferencesDialog.exec(); } } } void QmitkXnatTreeBrowserView::CreateQtPartControl(QWidget *parent) { // Create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Controls.treeView->setModel(m_TreeModel); m_Controls.treeView->header()->hide(); m_Controls.treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_Controls.treeView->setAcceptDrops(true); m_Controls.treeView->setDropIndicatorShown(true); m_Controls.treeView->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.treeView->setContextMenuPolicy(Qt::CustomContextMenu); m_Controls.groupBox->hide(); m_Controls.wgtExperimentInfo->hide(); m_Controls.wgtSubjectInfo->hide(); m_Controls.wgtProjectInfo->hide(); m_Tracker = new mitk::XnatSessionTracker(mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()); m_ContextMenu = new QMenu(m_Controls.treeView); connect(m_Controls.treeView, SIGNAL(clicked(const QModelIndex&)), SLOT(ItemSelected(const QModelIndex&))); connect(m_Controls.treeView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnContextMenuRequested(const QPoint&))); connect(m_Tracker, SIGNAL(AboutToBeClosed(ctkXnatSession*)), this, SLOT(CleanTreeModel(ctkXnatSession*))); connect(m_Tracker, SIGNAL(Opened(ctkXnatSession*)), this, SLOT(UpdateSession(ctkXnatSession*))); m_Tracker->Open(); - ctkXnatSession* session; - - try - { - session = mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetService( - mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetServiceReference()); - } - catch (std::invalid_argument) - { - session = nullptr; - } - connect(m_Controls.treeView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(OnActivatedNode(const QModelIndex&))); connect(m_Controls.treeView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(OnXnatNodeSelected(const QModelIndex&))); connect(m_TreeModel, SIGNAL(ResourceDropped(const QList&, ctkXnatObject*, const QModelIndex&)), this, SLOT(OnUploadResource(const QList&, ctkXnatObject*, const QModelIndex&))); connect(m_Controls.btnXnatConnect, SIGNAL(clicked()), SLOT(ToggleConnection())); connect(m_Controls.btnXnatUpload, SIGNAL(clicked()), this, SLOT(OnUploadFromDataStorage())); connect(m_Controls.btnXnatDownload, SIGNAL(clicked()), this, SLOT(OnDownloadSelectedXnatFile())); connect(m_Controls.btnCreateXnatFolder, SIGNAL(clicked()), this, SLOT(OnCreateResourceFolder())); connect(m_Controls.searchField, SIGNAL(textChanged(const QString&)), this, SLOT(Search(const QString&))); } void QmitkXnatTreeBrowserView::OnCreateResourceFolder() { QModelIndex index = m_Controls.treeView->selectionModel()->currentIndex(); if(!index.isValid()) return; ctkXnatObject* parent = index.data(Qt::UserRole).value(); this->InternalAddResourceFolder(parent); OnContextMenuRefreshItem(); } void QmitkXnatTreeBrowserView::Search(const QString &toSearch) { if(m_AlreadyInSearch) return; m_AlreadyInSearch = true; m_Controls.treeView->collapseAll(); m_Controls.treeView->expandToDepth(m_Controls.searchModeBox->currentIndex()); m_Controls.treeView->clearSelection(); foreach (const QModelIndex &hidden, m_hiddenItems) { m_Controls.treeView->setRowHidden(hidden.row(),hidden.parent(),false); } m_hiddenItems.clear(); if(toSearch.isEmpty()) { m_Controls.treeView->collapseAll(); m_Controls.treeView->expandToDepth(0); m_AlreadyInSearch = false; return; } QModelIndexList items = m_Controls.treeView->model()->match( m_Controls.treeView->model()->index(0,0), Qt::DisplayRole, QVariant::fromValue(toSearch), -1, Qt::MatchContains|Qt::MatchRecursive); if(!items.isEmpty()) { foreach (const QModelIndex &match, items) { int depth = 0; QModelIndex tparent = match; while ( tparent.parent().isValid() ) { tparent = tparent.parent(); depth++; } switch (depth) { case 1: //Project Level if(m_Controls.searchModeBox->currentIndex() == ProjectLevel) { m_hiddenItems.append(match); m_Controls.treeView->setRowHidden(match.row(),match.parent(),true); } break; case 2: //Patient level if(m_Controls.searchModeBox->currentIndex() == SubjectLevel) { m_hiddenItems.append(match); m_Controls.treeView->setRowHidden(match.row(),match.parent(),true); } break; default: break; } } } m_AlreadyInSearch = false; } void QmitkXnatTreeBrowserView::OnDownloadSelectedXnatFile() { QModelIndex index = m_Controls.treeView->selectionModel()->currentIndex(); if(!index.isValid()) return; ctkXnatObject* selectedXnatObject = index.data(Qt::UserRole).value(); bool enableDownload = dynamic_cast(selectedXnatObject) != nullptr; enableDownload |= dynamic_cast(selectedXnatObject) != nullptr; if (enableDownload) { this->InternalFileDownload(index, true); } } void QmitkXnatTreeBrowserView::OnUploadFromDataStorage() { QmitkXnatUploadFromDataStorageDialog dialog; dialog.SetDataStorage(this->GetDataStorage()); int result = dialog.exec(); if (result == QDialog::Accepted) { QList nodes; nodes << dialog.GetSelectedNode().GetPointer(); QModelIndex index = m_Controls.treeView->selectionModel()->currentIndex(); if (!index.isValid()) return; ctkXnatObject* parent = m_TreeModel->xnatObject(index); this->OnUploadResource(nodes, parent, index); } } void QmitkXnatTreeBrowserView::OnXnatNodeSelected(const QModelIndex& index) { if (!index.isValid()) return; ctkXnatObject* selectedXnatObject = index.data(Qt::UserRole).value(); // enable download button bool enableDownload = dynamic_cast(selectedXnatObject) != nullptr; enableDownload |= dynamic_cast(selectedXnatObject) != nullptr; m_Controls.btnXnatDownload->setEnabled(enableDownload); // enable folder creation bool enableCreateFolder = dynamic_cast(selectedXnatObject) != nullptr; enableCreateFolder |= dynamic_cast(selectedXnatObject) != nullptr; enableCreateFolder |= dynamic_cast(selectedXnatObject) != nullptr; enableCreateFolder |= dynamic_cast(selectedXnatObject) != nullptr; m_Controls.btnCreateXnatFolder->setEnabled(enableCreateFolder); // enable upload bool enableUpload = dynamic_cast(selectedXnatObject) != nullptr; m_Controls.btnXnatUpload->setEnabled(enableUpload); } void QmitkXnatTreeBrowserView::OnActivatedNode(const QModelIndex& index) { if (!index.isValid()) return; ctkXnatObject* selectedXnatObject = index.data(Qt::UserRole).value(); bool enableDownload = dynamic_cast(selectedXnatObject) != nullptr; enableDownload |= dynamic_cast(selectedXnatObject) != nullptr; if (enableDownload) { if(!m_SilentMode) { QMessageBox msgBox; QString fname = selectedXnatObject->name() != "" ? selectedXnatObject->name() : index.data(Qt::DisplayRole).toString(); QString msg ("Do you want to download "+ fname +"?"); msgBox.setWindowTitle("MITK XNAT download"); msgBox.setText(msg); msgBox.setIcon(QMessageBox::Question); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); int result = msgBox.exec(); if (result == QMessageBox::Ok) { InternalFileDownload(index, true); } } else { InternalFileDownload(index, true); } } } void QmitkXnatTreeBrowserView::UpdateSession(ctkXnatSession* session) { if (session != 0 && session->isOpen()) { // Fill model and show in the GUI m_TreeModel->addDataModel(session->dataModel()); m_Controls.treeView->reset(); connect(session, SIGNAL(progress(QUuid,double)), this, SLOT(OnProgress(QUuid,double))); connect(session, SIGNAL(timedOut()), this, SLOT(SessionTimedOutMsg())); connect(session, SIGNAL(aboutToTimeOut()), this, SLOT(SessionTimesOutSoonMsg())); } } void QmitkXnatTreeBrowserView::CleanTreeModel(ctkXnatSession* session) { if (session != 0) { m_TreeModel->removeDataModel(session->dataModel()); m_Controls.treeView->reset(); } } void QmitkXnatTreeBrowserView::OnProgress(QUuid /*queryID*/, double progress) { if (progress > 0) { unsigned int currentProgress = progress*100; if (m_Controls.groupBox->isHidden()) { m_Controls.groupBox->show(); m_Controls.progressBar->setValue(0); } m_Controls.progressBar->setValue(currentProgress); } } void QmitkXnatTreeBrowserView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { QString downloadPath = prefs->Get("Download Path", ""); QDir downloadDir (downloadPath); if (downloadPath.length() != 0 && downloadDir.exists()) m_DownloadPath = downloadPath; m_SilentMode = prefs->GetBool("Silent Mode", false); } void QmitkXnatTreeBrowserView::InternalFileDownload(const QModelIndex& index, bool loadData) { if (!index.isValid()) return; QDir rootDownloadDir(m_DownloadPath); if(isDirWriteable(rootDownloadDir) == false) { MITK_INFO << "Download directory access permission unsufficient! " << m_DownloadPath; QMessageBox::critical(nullptr,"Download directory access permission unsufficient!", "You have no permission to write to selected download directory " + m_DownloadPath +"!\n\nChange Download Path in Settings!"); QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); _PreferencesDialog.SetSelectedPage("org.mitk.gui.qt.application.XnatConnectionPreferencePage"); _PreferencesDialog.exec(); return; } ctkXnatObject* xnatObject = m_TreeModel->xnatObject(index); if (xnatObject != nullptr) { m_Controls.progressBar->setMinimum(0); m_Controls.progressBar->setMaximum(100); // The path to the downloaded file QString filePath; QDir downloadPath (m_DownloadPath); QString serverURL = berry::Platform::GetPreferencesService()->GetSystemPreferences()->Node(VIEW_ID)->Get("Server Address", ""); bool isDICOM (false); bool filePathExists (true); // If a scan was selected, downloading the contained DICOM folder as ZIP ctkXnatScan* scan = dynamic_cast(xnatObject); if (scan != nullptr) { isDICOM = true; if (!scan->isFetched()) scan->fetch(); QList children = scan->children(); foreach (ctkXnatObject* obj, children) { if (obj->name() == "DICOM") { QString uriId = obj->resourceUri(); uriId.replace("/data/archive/projects/", ""); QString folderName = m_DownloadPath + uriId + "/"; downloadPath = folderName; filePathExists = doesDirExist(downloadPath); if(filePathExists) { try { this->InternalDICOMDownload(obj, downloadPath); } catch(const ctkRuntimeException& exc) { QmitkHttpStatusCodeHandler::HandleErrorMessage(exc.what()); return; } serverURL = obj->resourceUri(); } else { FilePathNotAvailableWarning("DICOM folder"); return; } } } } else { ctkXnatFile* file = dynamic_cast(xnatObject); if (file == nullptr) { MITK_ERROR << "Selected XNAT object not downloadable!"; return; } QString uriId = file->parent()->resourceUri(); uriId.replace("/data/archive/projects/", ""); QString folderName = m_DownloadPath + uriId + "/"; downloadPath = folderName; filePathExists = doesDirExist(downloadPath); filePath = folderName + file->name(); // Checking if the file exists already if (downloadPath.exists(file->name())) { MITK_INFO << "File '" << file->name().toStdString() << "' already exists!"; serverURL = file->parent()->resourceUri(); } else { if (file->property("collection") == QString("DICOM")) { isDICOM = true; ctkXnatObject* parent = file->parent(); QString uriId = parent->resourceUri(); uriId.replace("/data/archive/projects/", ""); QString folderName = m_DownloadPath + uriId + "/"; downloadPath = folderName; filePathExists = doesDirExist(downloadPath); if(filePathExists) { try { this->InternalDICOMDownload(parent, downloadPath); } catch(const ctkRuntimeException& exc) { QmitkHttpStatusCodeHandler::HandleErrorMessage(exc.what()); return; } } else { FilePathNotAvailableWarning(parent->name()); return; } serverURL = parent->resourceUri(); } //Normal file download, no DICOM download else { if(filePathExists) { this->SetStatusInformation("Downloading file " + file->name()); file->download(filePath); } else { MITK_INFO << "File Download Failed."; } serverURL = file->parent()->resourceUri(); // Checking if the file exists now if (downloadPath.exists(file->name())) { MITK_INFO << "Download of " << file->name().toStdString() << " completed!"; if(!m_SilentMode) { QMessageBox msgBox; msgBox.setText("Download of " + file->name() + " completed!"); msgBox.setIcon(QMessageBox::Information); msgBox.exec(); } m_Controls.groupBox->hide(); } else { if(filePathExists) { MITK_INFO << "Download of " << file->name().toStdString() << " failed!"; QMessageBox::critical(m_Controls.treeView, "Download failed!", "Download of " + file->name() + " failed!"); m_Controls.groupBox->hide(); return; } else { FilePathNotAvailableWarning(file->name()); return; } } } } } if (loadData) { QFileInfoList fileList; if (isDICOM) { fileList = downloadPath.entryInfoList(QDir::Files); } else { QFileInfo fileInfo(filePath); fileList << fileInfo; } mitk::StringProperty::Pointer xnatURL = mitk::StringProperty::New(serverURL.toStdString()); try { this->InternalOpenFiles(fileList, xnatURL); } catch(const ctkRuntimeException& exc) { QmitkHttpStatusCodeHandler::HandleErrorMessage(exc.what()); return; } } } } void QmitkXnatTreeBrowserView::InternalDICOMDownload(ctkXnatObject *obj, QDir &DICOMDirPath) { QString filePath = m_DownloadPath + obj->property("label") + ".zip"; this->SetStatusInformation("Downloading DICOM series " + obj->parent()->name()); // In case of DICOM zip download we do not know the total file size // Because of that the dowload progres cannot be calculated // Because of that we use the busy indicator of the progress bar by setting min and max to 0 m_Controls.progressBar->setMinimum(0); m_Controls.progressBar->setMaximum(0); m_Controls.progressBar->show(); obj->download(filePath); std::ifstream in(filePath.toStdString().c_str(), std::ios::binary); poco_assert(in); // decompress to XNAT_DOWNLOAD dir Poco::Zip::Decompress dec(in, Poco::Path(DICOMDirPath.path().toStdString()), true); dec.decompressAllFiles(); in.close(); QFile::remove(filePath); // Checking if the file exists now if (DICOMDirPath.exists()) { if(!m_SilentMode) { MITK_INFO << "Download of DICOM series completed!"; QMessageBox msgBox; msgBox.setText("Download of DICOM series completed!"); msgBox.setIcon(QMessageBox::Information); msgBox.exec(); m_Controls.groupBox->hide(); } } else { MITK_INFO << "Download of DICOM series failed!"; QMessageBox msgBox; msgBox.setText("Download of DICOM series failed!"); msgBox.setIcon(QMessageBox::Critical); msgBox.exec(); m_Controls.groupBox->hide(); } } void QmitkXnatTreeBrowserView::InternalOpenFiles(const QFileInfoList & fileList, mitk::StringProperty::Pointer xnatURL) { if (fileList.isEmpty()) { MITK_WARN << "No files available for loading!"; return; } mitk::IDataStorageService* dsService = m_DataStorageServiceTracker.getService(); mitk::DataStorage::Pointer dataStorage = dsService->GetDataStorage()->GetDataStorage(); QStringList list; list << fileList.at(0).absoluteFilePath(); try { mitk::DataStorage::SetOfObjects::Pointer nodes = QmitkIOUtil::Load(list, *dataStorage); if (nodes->size() == 1) { mitk::DataNode* node = nodes->at(0); node->SetProperty("xnat.url", xnatURL); } } catch (const mitk::Exception& e) { MITK_INFO << e; return; } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects( dsService->GetDataStorage()->GetDataStorage()); } void QmitkXnatTreeBrowserView::OnContextMenuDownloadFile() { QModelIndex index = m_Controls.treeView->currentIndex(); InternalFileDownload(index, false); } void QmitkXnatTreeBrowserView::OnContextMenuDownloadAndOpenFile() { QModelIndex index = m_Controls.treeView->currentIndex(); InternalFileDownload(index, true); } void QmitkXnatTreeBrowserView::OnContextMenuCreateResourceFolder() { const QModelIndex index = m_Controls.treeView->selectionModel()->currentIndex(); ctkXnatObject* parentObject = m_TreeModel->xnatObject(index); if (parentObject != nullptr) { this->InternalAddResourceFolder(parentObject); } } ctkXnatResource* QmitkXnatTreeBrowserView::InternalAddResourceFolder(ctkXnatObject *parent) { bool ok; QString folderName = QInputDialog::getText(m_Controls.treeView, tr("Create XNAT resource folder"), tr("Folder name:"), QLineEdit::Normal, tr("data"), &ok); if (ok) { if (folderName.isEmpty()) folderName = "NO LABEL"; // if called on the resource-folder level we need to provide he corresponding // parent instead of the folder ctkXnatResourceFolder* resourceFolder = dynamic_cast(parent); if (resourceFolder != nullptr) { parent = parent->parent(); } try { return parent->addResourceFolder(folderName); } catch(const ctkRuntimeException& exc) { QmitkHttpStatusCodeHandler::HandleErrorMessage(exc.what()); return nullptr; } } else { return nullptr; } } void QmitkXnatTreeBrowserView::InternalFileUpload(ctkXnatFile* file) { m_Controls.groupBox->setTitle("Uploading file..."); m_Controls.groupBox->show(); try { file->save(); MITK_INFO << "Upload of " << file->name().toStdString() << " completed!"; if(!m_SilentMode) { QMessageBox msgBox; msgBox.setText("Upload of " + file->name() + " completed!"); msgBox.setIcon(QMessageBox::Information); msgBox.show(); msgBox.exec(); } } catch (ctkXnatException &e) { QMessageBox msgbox; msgbox.setText(e.what()); msgbox.setIcon(QMessageBox::Critical); msgbox.exec(); m_Controls.progressBar->setValue(0); } m_Controls.groupBox->hide(); } void QmitkXnatTreeBrowserView::OnContextMenuUploadFile() { QString filename = QFileDialog::getOpenFileName(m_Controls.treeView, tr("Open File"), QDir::homePath()); const QModelIndex index = m_Controls.treeView->selectionModel()->currentIndex(); ctkXnatResource* resource = dynamic_cast(m_TreeModel->xnatObject(index)); if (resource != nullptr && filename.length() != 0) { ctkXnatFile* file = new ctkXnatFile(resource); file->setLocalFilePath(filename); QFileInfo fileInfo (filename); file->setName(fileInfo.fileName()); try { this->InternalFileUpload(file); } catch(const ctkRuntimeException& exc) { QmitkHttpStatusCodeHandler::HandleErrorMessage(exc.what()); return; } m_TreeModel->addChildNode(index, file); } } void QmitkXnatTreeBrowserView::OnContextMenuCopyXNATUrlToClipboard() { const QModelIndex index = m_Controls.treeView->selectionModel()->currentIndex(); ctkXnatObject* currentXnatObject = m_TreeModel->xnatObject(index); if (currentXnatObject != nullptr) { QString serverURL = berry::Platform::GetPreferencesService()->GetSystemPreferences()->Node(VIEW_ID)->Get("Server Address", ""); serverURL.append(currentXnatObject->resourceUri()); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(serverURL); } } void QmitkXnatTreeBrowserView::OnContextMenuRefreshItem() { const QModelIndex index = m_Controls.treeView->selectionModel()->currentIndex(); if (index.isValid()) { this->m_TreeModel->refresh(index); } } void QmitkXnatTreeBrowserView::OnUploadResource(const QList& droppedNodes, ctkXnatObject* parentObject, const QModelIndex& parentIndex) { if (parentObject == nullptr) return; //1. If not dropped on a resource, create a new folder //temporarily remove the annoying message box that upload was successful.. ctkXnatResource* resource = dynamic_cast(parentObject); // store original resource folder object for later use ctkXnatResourceFolder* originalResourceFolder = dynamic_cast(parentObject); if (resource == nullptr) { resource = this->InternalAddResourceFolder(parentObject); } if (resource == nullptr) { MITK_WARN << "Resource folder could not be created!"; return; } //2. Save files locally //3. Upload file mitk::DataNode* node = nullptr; foreach (node, droppedNodes) { mitk::BaseData* data = node->GetData(); if (!data) return; //We have to replace special characters due to XNAT inability to get along with them (" " is replaced by "%20", what leads to nasty behaviour!) QString fileName(QString::fromStdString(ReplaceSpecialChars(node->GetName()))); ctkXnatFile* xnatFile = new ctkXnatFile(resource); if (dynamic_cast(data)) { fileName.append(".nrrd"); } else if (dynamic_cast(data)) { fileName.append(".vtk"); } else if (dynamic_cast(data)) { fileName.append(".mps"); } else { MITK_WARN << "Could not upload file! File-type not supported"; QMessageBox msgbox; msgbox.setText("Could not upload file! File-type not supported"); msgbox.setIcon(QMessageBox::Critical); msgbox.exec(); return; } xnatFile->setName(fileName); QString xnatFolder = "XNAT_UPLOADS"; QDir dir(mitk::org_mitk_gui_qt_xnatinterface_Activator::GetContext()->getDataFile("").absoluteFilePath()); dir.mkdir(xnatFolder); fileName = dir.path().append("/" + fileName); mitk::IOUtil::Save (data, fileName.toStdString()); // TODO Check if file exists // AbstractFileReader::SetDefaultDataNodeProperties // und in die andere SetDefaultDataNodeProperties // PropertyName klein: mtime.initial + Kommentar mitk::StringProperty::Pointer orignalFilePath = mitk::StringProperty::New(); node->GetProperty(orignalFilePath, "path"); xnatFile->setLocalFilePath(fileName); try { this->InternalFileUpload(xnatFile); } catch(const ctkRuntimeException& exc) { QmitkHttpStatusCodeHandler::HandleErrorMessage(exc.what()); return; } QFile::remove(fileName); if (originalResourceFolder == nullptr) { m_TreeModel->refresh(parentIndex); } else { m_TreeModel->refresh(parentIndex.parent()); } // The filename for uploading // QFileInfo fileInfo; // if (surface) // { // // Save surface // fileName.append(".stl"); // xnatFile->setName(fileName); // dir.setPath(dir.path().append("/" + fileName)); // QString origFile = QString::fromStdString(orignalFilePath->GetValueAsString()); // origFile.append("/" + fileName); // origFile.append(".stl"); // fileInfo.setFile(origFile); // if (!fileInfo.exists()) // mitk::IOUtil::Save(surface, dir.path().toStdString()); // } // this->uploadFileToXnat(xnatFile, dir.path()); } } void QmitkXnatTreeBrowserView::OnContextMenuRequested(const QPoint & pos) { if(m_TreeModel==nullptr) { return; } QModelIndex index = m_Controls.treeView->indexAt(pos); if(index.isValid() == false) { return; } m_ContextMenu->clear(); QAction* actRefreshItem = new QAction("Refresh", m_ContextMenu); m_ContextMenu->addAction(actRefreshItem); connect(actRefreshItem, SIGNAL(triggered()), this, SLOT(OnContextMenuRefreshItem())); QAction* actGetXNATURL = new QAction("Copy XNAT URL to clipboard", m_ContextMenu); m_ContextMenu->addAction(actGetXNATURL); connect(actGetXNATURL, SIGNAL(triggered()), this, SLOT(OnContextMenuCopyXNATUrlToClipboard())); m_ContextMenu->addSeparator(); ctkXnatObject* xnatObject = m_TreeModel->xnatObject(index); bool downloadable = false; downloadable |= dynamic_cast(xnatObject)!=nullptr; downloadable |= dynamic_cast(xnatObject)!=nullptr; downloadable |= dynamic_cast(xnatObject)!=nullptr; downloadable |= dynamic_cast(xnatObject)!=nullptr; downloadable |= dynamic_cast(xnatObject)!=nullptr; downloadable |= dynamic_cast(xnatObject)!=nullptr; downloadable |= dynamic_cast(xnatObject)!=nullptr; downloadable |= dynamic_cast(xnatObject)!=nullptr; bool canHaveResourceFolder = false; canHaveResourceFolder |= dynamic_cast(xnatObject) != nullptr; canHaveResourceFolder |= dynamic_cast(xnatObject) != nullptr; canHaveResourceFolder |= dynamic_cast(xnatObject) != nullptr; canHaveResourceFolder |= dynamic_cast(xnatObject) != nullptr; bool uploadFilePossible = false; uploadFilePossible |= dynamic_cast(xnatObject) != nullptr; uploadFilePossible |= dynamic_cast(xnatObject) != nullptr; uploadFilePossible |= dynamic_cast(xnatObject) != nullptr; if (downloadable) { QAction* actDownload = new QAction("Download", m_ContextMenu); connect(actDownload, SIGNAL(triggered()), this, SLOT(OnContextMenuDownloadFile())); m_ContextMenu->addAction(actDownload); ctkXnatFile* file = dynamic_cast(xnatObject); if (file) { QAction* actView = new QAction("Download and Open", m_ContextMenu); connect(actView, SIGNAL(triggered()), this, SLOT(OnContextMenuDownloadAndOpenFile())); m_ContextMenu->addAction(actView); } } if (canHaveResourceFolder) { QAction* actCreateResource = new QAction("Add resource folder", m_ContextMenu); connect(actCreateResource, SIGNAL(triggered()), this, SLOT(OnContextMenuCreateResourceFolder())); m_ContextMenu->addAction(actCreateResource); } if (uploadFilePossible) { QAction* actUploadFile = new QAction("Upload File", m_ContextMenu); connect(actUploadFile, SIGNAL(triggered()), this, SLOT(OnContextMenuUploadFile())); m_ContextMenu->addAction(actUploadFile); } ctkXnatProject* project = dynamic_cast(xnatObject); if (project != nullptr) { QAction* actCreateSubject = new QAction("Create new subject", m_ContextMenu); m_ContextMenu->addAction(actCreateSubject); connect(actCreateSubject, SIGNAL(triggered()), this, SLOT(OnContextMenuCreateNewSubject())); } ctkXnatSubject* subject = dynamic_cast(xnatObject); if (subject != nullptr) { QAction* actCreateExperiment = new QAction("Create new experiment", m_ContextMenu); m_ContextMenu->addAction(actCreateExperiment); connect(actCreateExperiment, SIGNAL(triggered()), this, SLOT(OnContextMenuCreateNewExperiment())); } m_ContextMenu->popup(QCursor::pos()); } void QmitkXnatTreeBrowserView::CleanUp() { m_Controls.wgtExperimentInfo->hide(); m_Controls.wgtSubjectInfo->hide(); m_Controls.wgtProjectInfo->hide(); m_Controls.btnCreateXnatFolder->setEnabled(false); m_Controls.btnXnatDownload->setEnabled(false); m_Controls.btnXnatUpload->setEnabled(false); m_Controls.searchField->setEnabled(false); m_Controls.searchField->setText(""); m_Controls.searchModeBox->setEnabled(false); } std::string QmitkXnatTreeBrowserView::ReplaceSpecialChars(const std::string& input) const { QString convertedString = QString(QUrl::toPercentEncoding(QString::fromStdString(input))); return convertedString.toStdString(); } void QmitkXnatTreeBrowserView::ItemSelected(const QModelIndex& index) { //TODO: CTK seems to ignore spaces while creating the http request. This will lead to corrupted http request that will fail. QVariant variant = m_TreeModel->data(index, Qt::UserRole); if (variant.isValid()) { ctkXnatSession *session = mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetService( mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetServiceReference()); ctkXnatObject* object = variant.value(); ctkXnatProject* project = dynamic_cast(object); ctkXnatSubject* subject = dynamic_cast(object); ctkXnatExperiment* experiment = dynamic_cast(object); if (project != nullptr) { m_Controls.wgtExperimentInfo->hide(); m_Controls.wgtSubjectInfo->hide(); m_Controls.wgtProjectInfo->SetProject(project); m_Controls.wgtProjectInfo->show(); } else if (subject != nullptr) { QMap paramMap; paramMap.insert("columns", "dob,gender,handedness,weight,height"); QUuid requestID = session->httpGet(QString("%1/subjects").arg(subject->parent()->resourceUri()), paramMap); QList results = session->httpSync(requestID); foreach(const QVariantMap& propertyMap, results) { QMapIterator it(propertyMap); bool isConcretSubject = false; if (it.hasNext()) { it.next(); QVariant var = it.value(); // After CTK Change (subjectID = name) to (subjectID = ID) // CHANGE TO: if (var == subject->property("ID")) if (var == subject->property("URI").right(11)) { isConcretSubject = true; } else { isConcretSubject = false; } it.toFront(); } while (it.hasNext() && isConcretSubject) { it.next(); QString str = it.key().toLatin1().data(); QVariant var = it.value(); subject->setProperty(str, var); } } m_Controls.wgtExperimentInfo->hide(); m_Controls.wgtProjectInfo->hide(); m_Controls.wgtSubjectInfo->SetSubject(subject); m_Controls.wgtSubjectInfo->show(); } else if (experiment != nullptr) { QMap paramMap; paramMap.insert("columns", "date,time,scanner,modality"); QUuid requestID = session->httpGet(QString("%1/experiments").arg(experiment->parent()->resourceUri()), paramMap); QList results = session->httpSync(requestID); foreach(const QVariantMap& propertyMap, results) { QMapIterator it(propertyMap); bool isConcretExperiment = false; if (it.hasNext()) { it.next(); QVariant var = it.value(); if (var == experiment->property("URI")) { isConcretExperiment = true; } else { isConcretExperiment = false; } it.toFront(); } while (it.hasNext() && isConcretExperiment) { it.next(); QString str = it.key().toLatin1().data(); QVariant var = it.value(); experiment->setProperty(str, var); } } m_Controls.wgtSubjectInfo->hide(); m_Controls.wgtProjectInfo->hide(); m_Controls.wgtExperimentInfo->SetExperiment(experiment); m_Controls.wgtExperimentInfo->show(); } } } void QmitkXnatTreeBrowserView::OnContextMenuCreateNewSubject() { QModelIndex index = m_Controls.treeView->currentIndex(); QVariant variant = m_TreeModel->data(index, Qt::UserRole); if (variant.isValid()) { QmitkXnatCreateObjectDialog* dialog = new QmitkXnatCreateObjectDialog(QmitkXnatCreateObjectDialog::SpecificType::SUBJECT); if (dialog->exec() == QDialog::Accepted) { ctkXnatProject* project = dynamic_cast(variant.value()); ctkXnatSubject* subject = dynamic_cast(dialog->GetXnatObject()); subject->setParent(project); try { subject->save(); } catch(const ctkRuntimeException& exc) { //TODO: Implement isValid-flag to check if ctkRuntimeExceptio is valid http-exception. QmitkHttpStatusCodeHandler::HandleErrorMessage(exc.what()); project->remove(subject); delete subject; return; } // Get xnat session from micro service ctkXnatSession* session = mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetService( mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetServiceReference()); // Update View m_TreeModel->removeDataModel(session->dataModel()); UpdateSession(session); } } } void QmitkXnatTreeBrowserView::OnContextMenuCreateNewExperiment() { QModelIndex index = m_Controls.treeView->currentIndex(); QVariant variant = m_TreeModel->data(index, Qt::UserRole); if (variant.isValid()) { QmitkXnatCreateObjectDialog* dialog = new QmitkXnatCreateObjectDialog(QmitkXnatCreateObjectDialog::SpecificType::EXPERIMENT); if (dialog->exec() == QDialog::Accepted) { ctkXnatSubject* subject = dynamic_cast(variant.value()); ctkXnatExperiment* experiment = dynamic_cast(dialog->GetXnatObject()); experiment->setParent(subject); experiment->setProperty("xsiType", experiment->imageModality()); try { experiment->save(); } catch(const ctkRuntimeException& exc) { QmitkHttpStatusCodeHandler::HandleErrorMessage(exc.what()); subject->remove(experiment); delete experiment; return; } // Get xnat session from micro service ctkXnatSession* session = mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetService( mitk::org_mitk_gui_qt_xnatinterface_Activator::GetXnatModuleContext()->GetServiceReference()); // Update View m_TreeModel->removeDataModel(session->dataModel()); UpdateSession(session); } } } void QmitkXnatTreeBrowserView::SetStatusInformation(const QString& text) { m_Controls.groupBox->setTitle(text); m_Controls.progressBar->setValue(0); m_Controls.groupBox->show(); } void QmitkXnatTreeBrowserView::SessionTimedOutMsg() { ctkXnatSession* session = qobject_cast(QObject::sender()); if (session == nullptr) return; ctkXnatDataModel* dataModel = session->dataModel(); m_TreeModel->removeDataModel(dataModel); m_Controls.treeView->reset(); session->close(); QMessageBox::warning(m_Controls.treeView, "Session Timeout", "The session timed out."); m_Controls.btnXnatConnect->setToolTip("Connect"); m_Controls.btnXnatConnect->setIcon(QIcon(":/xnat-plugin/xnat-connect.png")); CleanUp(); } void QmitkXnatTreeBrowserView::SessionTimesOutSoonMsg() { ctkXnatSession* session = qobject_cast(QObject::sender()); if (session == nullptr) return; QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle("Session Timeout Soon"); msgBox.setText("The session will time out in 1 minute.\nDo you want to renew the session?"); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); msgBox.show(); QTimer* timer = new QTimer(this); timer->start(60000); this->connect(timer, SIGNAL(timeout()), &msgBox, SLOT(reject())); if (msgBox.exec() == QMessageBox::Yes){ session->renew(); } timer->stop(); }