diff --git a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp index e19d7e6f62..1e4628dc1d 100644 --- a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp +++ b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp @@ -1,126 +1,272 @@ /*=================================================================== 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 __itkStreamlineTrackingFilter_txx #define __itkStreamlineTrackingFilter_txx #include <time.h> #include <stdio.h> #include <stdlib.h> #include "itkStreamlineTrackingFilter.h" #include <itkImageRegionConstIterator.h> #include <itkImageRegionConstIteratorWithIndex.h> #include <itkImageRegionIterator.h> #define _USE_MATH_DEFINES #include <math.h> namespace itk { //#define QBALL_RECON_PI M_PI template< class TTensorPixelType, class TPDPixelType> StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::StreamlineTrackingFilter(): - m_FaThres(0.2) + m_FaThreshold(0.2), + m_StepSize(0.2), + m_MaxLength(10000), + m_SeedsPerVoxel(1) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::BeforeThreadedGenerateData() { - m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New(); + m_FiberPolyData = FiberPolyDataType::New(); m_Points = vtkPoints::New(); m_Cells = vtkCellArray::New(); + + typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); + m_ImageSize[0] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(0); + m_ImageSize[1] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(1); + m_ImageSize[2] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(2); + + m_PolyDataContainer = itk::VectorContainer< int, FiberPolyDataType >::New(); + for (int i=0; i<this->GetNumberOfThreads(); i++) + { + FiberPolyDataType poly = FiberPolyDataType::New(); + m_PolyDataContainer->InsertElement(i, poly); + } + + if (m_MaskImage.IsNull()) + { + itk::Vector<double, 3> spacing = inputImage->GetSpacing(); + itk::Point<double, 3> origin = inputImage->GetOrigin(); + itk::Matrix<double, 3, 3> direction = inputImage->GetDirection(); + ImageRegion<3> imageRegion = inputImage->GetLargestPossibleRegion(); + + // initialize crossings image + m_MaskImage = ItkUcharImgType::New(); + m_MaskImage->SetSpacing( spacing ); + m_MaskImage->SetOrigin( origin ); + m_MaskImage->SetDirection( direction ); + m_MaskImage->SetRegions( imageRegion ); + m_MaskImage->Allocate(); + m_MaskImage->FillBuffer(1); + } } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - int ) + int threadId) { + FiberPolyDataType poly = m_PolyDataContainer->GetElement(threadId); + vtkSmartPointer<vtkPoints> Points = vtkPoints::New(); + vtkSmartPointer<vtkCellArray> Cells = vtkCellArray::New(); typedef itk::DiffusionTensor3D<TTensorPixelType> TensorType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; + typedef ImageRegionConstIterator< ItkUcharImgType > MaskIteratorType; typedef typename InputImageType::PixelType InputTensorType; - typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); + typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); - InputIteratorType it(inputImagePointer, outputRegionForThread ); + InputIteratorType it(inputImage, outputRegionForThread ); + MaskIteratorType mit(m_MaskImage, outputRegionForThread ); it.GoToBegin(); + mit.GoToBegin(); while( !it.IsAtEnd() ) { - InputTensorType b = it.Get(); - TensorType tensor = b.GetDataPointer(); - - - vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); + if (mit.Value()==0) + { + ++mit; + ++it; + continue; + } typename TensorType::EigenValuesArrayType eigenvalues; typename TensorType::EigenVectorsMatrixType eigenvectors; - if(tensor.GetTrace()!=0 && tensor.GetFractionalAnisotropy()>m_FaThres) + + for (int s=0; s<m_SeedsPerVoxel; s++) { + unsigned long counter = 0; + vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); typename InputImageType::IndexType index = it.GetIndex(); - tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); + itk::ContinuousIndex<double, 3> pos; + + if (m_SeedsPerVoxel>1) + { + pos[0] = index[0]+(double)(rand()%99-49)/100; + pos[1] = index[1]+(double)(rand()%99-49)/100; + pos[2] = index[2]+(double)(rand()%99-49)/100; + } + else + { + pos[0] = index[0]; + pos[1] = index[1]; + pos[2] = index[2]; + } + + int step = 0; + vnl_vector_fixed<double,3> dirOld; dirOld.fill(0.0); + while (step < m_MaxLength) + { + ++step; + + index[0] = round(pos[0]); + index[1] = round(pos[1]); + index[2] = round(pos[2]); + + if (index[0] < 0 || index[0]>=m_ImageSize[0]) + break; + if (index[1] < 0 || index[1]>=m_ImageSize[1]) + break; + if (index[2] < 0 || index[2]>=m_ImageSize[2]) + break; + + typename InputImageType::PixelType tensor = inputImage->GetPixel(index); + if(tensor.GetTrace()!=0 && tensor.GetFractionalAnisotropy()>m_FaThreshold) + { + tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); + + int eIndex = 2; + if( (eigenvalues[0] >= eigenvalues[1]) && (eigenvalues[0] >= eigenvalues[2]) ) + eIndex = 0; + else if(eigenvalues[1] >= eigenvalues[2]) + eIndex = 1; - int eIndex = 2; - if( (eigenvalues[0] >= eigenvalues[1]) && (eigenvalues[0] >= eigenvalues[2]) ) - eIndex = 0; - else if(eigenvalues[1] >= eigenvalues[2]) - eIndex = 1; + vnl_vector_fixed<double,3> dir; + dir[0] = eigenvectors(eIndex, 0); + dir[1] = eigenvectors(eIndex, 1); + dir[2] = eigenvectors(eIndex, 2); + dir.normalize(); - vnl_vector_fixed<double,3> vec; - vec[0] = eigenvectors(eIndex, 0); - vec[1] = eigenvectors(eIndex, 1); - vec[2] = eigenvectors(eIndex, 2); + if (!dirOld.is_zero()) + { + float angle = dot_product(dirOld, dir); + if (angle<0) + dir *= -1; + angle = fabs(dot_product(dirOld, dir)); + if (angle<0.7) + break; + } + dirOld = dir; - m_Cells->InsertNextCell(container); + dir *= m_StepSize; + + itk::Point<double> worldPos; + inputImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos ); + + vtkIdType id = Points->InsertNextPoint(worldPos.GetDataPointer()); + container->GetPointIds()->InsertNextId(id); + counter++; + + pos[0] += dir[0]; + pos[1] += dir[1]; + pos[2] += dir[2]; + } + } + if (counter>0) + Cells->InsertNextCell(container); } - ++it; // image iterator + ++mit; + ++it; } - std::cout << "One Thread finished tracking" << std::endl; + poly->SetPoints(Points); + poly->SetLines(Cells); + + std::cout << "Thread " << threadId << " finished tracking" << std::endl; } +template< class TTensorPixelType, + class TPDPixelType> +vtkSmartPointer< vtkPolyData > StreamlineTrackingFilter< TTensorPixelType, +TPDPixelType> +::AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2) +{ + vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New(); + vtkSmartPointer<vtkCellArray> vNewLines = poly1->GetLines(); + vtkSmartPointer<vtkPoints> vNewPoints = poly1->GetPoints(); + + vtkSmartPointer<vtkCellArray> vLines = poly2->GetLines(); + vLines->InitTraversal(); + for( int i=0; i<vLines->GetNumberOfCells(); i++ ) + { + vtkIdType numPoints(0); + vtkIdType* points(NULL); + vLines->GetNextCell ( numPoints, points ); + + vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); + for( int j=0; j<numPoints; j++) + { + vtkIdType id = vNewPoints->InsertNextPoint(poly2->GetPoint(points[j])); + container->GetPointIds()->InsertNextId(id); + } + vNewLines->InsertNextCell(container); + } + + // initialize polydata + vNewPolyData->SetPoints(vNewPoints); + vNewPolyData->SetLines(vNewLines); + + return vNewPolyData; +} template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::AfterThreadedGenerateData() { - m_FiberPolyData->SetPoints(m_Points); - m_FiberPolyData->SetLines(m_Cells); + MITK_INFO << "Generating polydata "; + m_FiberPolyData = m_PolyDataContainer->GetElement(0); + for (int i=1; i<this->GetNumberOfThreads(); i++) + { + m_FiberPolyData = AddPolyData(m_FiberPolyData, m_PolyDataContainer->GetElement(i)); + } + MITK_INFO << "done"; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { } } #endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx diff --git a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h index ae6cb4ebd8..d6aaa4b759 100644 --- a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h +++ b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h @@ -1,96 +1,107 @@ /*=================================================================== 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. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkStreamlineTrackingFilter_h_ #define __itkStreamlineTrackingFilter_h_ #include "MitkDiffusionImagingExports.h" #include <itkImageToImageFilter.h> #include <itkVectorContainer.h> #include <itkVectorImage.h> #include <itkDiffusionTensor3D.h> #include <vtkSmartPointer.h> #include <vtkPolyData.h> #include <vtkCellArray.h> #include <vtkPoints.h> #include <vtkPolyLine.h> namespace itk{ /** \class StreamlineTrackingFilter */ template< class TTensorPixelType, class TPDPixelType=double> class StreamlineTrackingFilter : public ImageToImageFilter< Image< DiffusionTensor3D<TTensorPixelType>, 3 >, Image< Vector< TPDPixelType, 3 >, 3 > > { public: typedef StreamlineTrackingFilter Self; typedef SmartPointer<Self> Pointer; typedef SmartPointer<const Self> ConstPointer; - typedef ImageToImageFilter< Image< DiffusionTensor3D<TTensorPixelType>, 3 >, - Image< Vector< TPDPixelType, 3 >, 3 > > - Superclass; + typedef ImageToImageFilter< Image< DiffusionTensor3D<TTensorPixelType>, 3 >, Image< Vector< TPDPixelType, 3 >, 3 > > Superclass; /** Method for creation through the object factory. */ itkNewMacro(Self) /** Runtime information support. */ itkTypeMacro(StreamlineTrackingFilter, ImageToImageFilter) typedef TTensorPixelType TensorComponentType; typedef TPDPixelType DirectionPixelType; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; + typedef itk::Image<unsigned char, 3> ItkUcharImgType; typedef vtkSmartPointer< vtkPolyData > FiberPolyDataType; itkGetMacro( FiberPolyData, FiberPolyDataType ) + itkSetMacro( MaskImage, ItkUcharImgType::Pointer) + itkSetMacro( SeedsPerVoxel, int) + itkSetMacro( FaThreshold, float) protected: StreamlineTrackingFilter(); ~StreamlineTrackingFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, int); + void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, int threadId); void AfterThreadedGenerateData(); + FiberPolyDataType AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2); + FiberPolyDataType m_FiberPolyData; vtkSmartPointer<vtkPoints> m_Points; vtkSmartPointer<vtkCellArray> m_Cells; - float m_FaThres; + float m_FaThreshold; + float m_StepSize; + int m_MaxLength; + int m_SeedsPerVoxel; + int m_ImageSize[3]; + ItkUcharImgType::Pointer m_MaskImage; + + itk::VectorContainer< int, FiberPolyDataType >::Pointer m_PolyDataContainer; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkStreamlineTrackingFilter.cpp" #endif #endif //__itkStreamlineTrackingFilter_h_ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake index 68930fafcd..dcdcef089d 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake @@ -1,121 +1,124 @@ set(SRC_CPP_FILES QmitkODFDetailsWidget.cpp QmitkODFRenderWidget.cpp QmitkPartialVolumeAnalysisWidget.cpp QmitkIVIMWidget.cpp QmitkTbssRoiAnalysisWidget.cpp QmitkResidualAnalysisWidget.cpp QmitkResidualViewWidget.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkQBallReconstructionView.cpp QmitkPreprocessingView.cpp QmitkDiffusionDicomImportView.cpp QmitkDiffusionQuantificationView.cpp QmitkTensorReconstructionView.cpp QmitkDiffusionImagingPublicPerspective.cpp QmitkControlVisualizationPropertiesView.cpp QmitkODFDetailsView.cpp QmitkGibbsTrackingView.cpp QmitkStochasticFiberTrackingView.cpp + QmitkStreamlineTrackingView.cpp QmitkFiberProcessingView.cpp QmitkFiberBundleDeveloperView.cpp QmitkPartialVolumeAnalysisView.cpp QmitkIVIMView.cpp QmitkTractbasedSpatialStatisticsView.cpp QmitkTbssTableModel.cpp QmitkTbssMetaTableModel.cpp QmitkTbssSkeletonizationView.cpp Connectomics/QmitkBrainNetworkAnalysisView.cpp Connectomics/QmitkNetworkHistogramCanvas.cpp ) set(UI_FILES src/internal/QmitkQBallReconstructionViewControls.ui src/internal/QmitkPreprocessingViewControls.ui src/internal/QmitkDiffusionDicomImportViewControls.ui src/internal/QmitkDiffusionQuantificationViewControls.ui src/internal/QmitkTensorReconstructionViewControls.ui src/internal/QmitkControlVisualizationPropertiesViewControls.ui src/internal/QmitkODFDetailsViewControls.ui src/internal/QmitkGibbsTrackingViewControls.ui src/internal/QmitkStochasticFiberTrackingViewControls.ui + src/internal/QmitkStreamlineTrackingViewControls.ui src/internal/QmitkFiberProcessingViewControls.ui src/internal/QmitkFiberBundleDeveloperViewControls.ui src/internal/QmitkPartialVolumeAnalysisViewControls.ui src/internal/QmitkIVIMViewControls.ui src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui src/internal/QmitkTbssSkeletonizationViewControls.ui src/internal/Connectomics/QmitkBrainNetworkAnalysisViewControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkQBallReconstructionView.h src/internal/QmitkPreprocessingView.h src/internal/QmitkDiffusionDicomImportView.h src/internal/QmitkDiffusionImagingPublicPerspective.h src/internal/QmitkDiffusionQuantificationView.h src/internal/QmitkTensorReconstructionView.h src/internal/QmitkControlVisualizationPropertiesView.h src/internal/QmitkODFDetailsView.h src/QmitkODFRenderWidget.h src/QmitkODFDetailsWidget.h src/internal/QmitkGibbsTrackingView.h src/internal/QmitkStochasticFiberTrackingView.h + src/internal/QmitkStreamlineTrackingView.h src/internal/QmitkFiberProcessingView.h src/internal/QmitkFiberBundleDeveloperView.h src/internal/QmitkPartialVolumeAnalysisView.h src/QmitkPartialVolumeAnalysisWidget.h src/internal/QmitkIVIMView.h src/internal/QmitkTractbasedSpatialStatisticsView.h src/internal/QmitkTbssSkeletonizationView.h src/QmitkTbssRoiAnalysisWidget.h src/QmitkResidualAnalysisWidget.h src/QmitkResidualViewWidget.h src/internal/Connectomics/QmitkBrainNetworkAnalysisView.h src/internal/Connectomics/QmitkNetworkHistogramCanvas.h ) set(CACHED_RESOURCE_FILES # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench plugin.xml resources/preprocessing.png resources/dwiimport.png resources/quantification.png resources/reconodf.png resources/recontensor.png resources/vizControls.png resources/OdfDetails.png resources/GibbsTracking.png resources/FiberBundleOperations.png resources/PartialVolumeAnalysis_24.png resources/IVIM_48.png resources/stochFB.png resources/tbss.png resources/QmitkBrainNetworkAnalysisViewIcon_48.png resources/arrow.png ) set(QRC_FILES # uncomment the following line if you want to use Qt resources resources/QmitkDiffusionImaging.qrc #resources/QmitkTractbasedSpatialStatisticsView.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml b/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml index e8b9846c4b..76277778da 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml @@ -1,125 +1,132 @@ <?xml version="1.0" encoding="UTF-8"?> <?BlueBerry version="0.1"?> <plugin> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.qballreconstruction" name="Q-Balls" icon="resources/reconodf.png" class="QmitkQBallReconstructionView" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.diffusiondicomimport" name="DICOM Import" class="QmitkDiffusionDicomImport" icon="resources/dwiimport.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.diffusionpreprocessing" name="Preprocessing" class="QmitkPreprocessingView" icon="resources/preprocessing.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.diffusionquantification" name="Quantification" class="QmitkDiffusionQuantificationView" icon="resources/quantification.png"/> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.tensorreconstruction" name="Tensors" icon="resources/recontensor.png" class="QmitkTensorReconstructionView" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.controlvisualizationpropertiesview" name="Visualization" icon="resources/vizControls.png" class="QmitkControlVisualizationPropertiesView" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.ivim" name="IVIM" class="QmitkIVIMView" icon="resources/IVIM_48.png" /> </extension> <extension point="org.blueberry.ui.perspectives"> <perspective id="org.mitk.perspectives.publicdiffusionimaging" name="Diffusion Imaging Public" class="QmitkDiffusionImagingPublicPerspective" icon="resources/reconodf.png"/> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.odfdetails" name="ODF Details" class="QmitkODFDetailsView" icon="resources/OdfDetails.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.gibbstracking" name="Gibbs Tracking" class="QmitkGibbsTrackingView" icon="resources/GibbsTracking.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.stochasticfibertracking" name="Stochastic Tracking" class="QmitkStochasticFiberTrackingView" icon="resources/stochFB.png" /> </extension> + <extension point="org.blueberry.ui.views"> + <view id="org.mitk.views.streamlinetracking" + name="Streamline Tracking" + class="QmitkStreamlineTrackingView" + icon="resources/stochFB.png" /> + </extension> + <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.fiberprocessing" name="Fiber Processing" class="QmitkFiberProcessingView" icon="resources/FiberBundleOperations.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.fiberbundledeveloper" name="FiberDevTool" class="QmitkFiberBundleDeveloperView" icon="resources/FiberBundleOperations.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.partialvolumeanalysisview" name="PV Analysis" class="QmitkPartialVolumeAnalysisView" icon="resources/PartialVolumeAnalysis_24.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.tbssskeletonization" name="Tbss Skeletonization" class="QmitkTbssSkeletonizationView" icon="resources/tbss.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.tractbasedspatialstatistics" name="Tract-based spatial statistics" class="QmitkTractbasedSpatialStatisticsView" icon="resources/tbss.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.brainnetworkanalysis" name="Brain Network Analysis" class="QmitkBrainNetworkAnalysisView" icon="resources/QmitkBrainNetworkAnalysisViewIcon_48.png" /> </extension> </plugin> diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp index 9344e300de..2fb8a396fd 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp @@ -1,1828 +1,1797 @@ /*=================================================================== 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 <berryISelectionService.h> #include <berryIWorkbenchWindow.h> // Qmitk #include "QmitkFiberProcessingView.h" #include <QmitkStdMultiWidget.h> // Qt #include <QMessageBox> // MITK #include <mitkNodePredicateProperty.h> #include <mitkImageCast.h> #include <mitkPointSet.h> #include <mitkPlanarCircle.h> #include <mitkPlanarPolygon.h> #include <mitkPlanarRectangle.h> #include <mitkPlanarFigureInteractor.h> #include <mitkGlobalInteraction.h> #include <mitkImageAccessByItk.h> #include <mitkDataNodeObject.h> #include <mitkDiffusionImage.h> #include <mitkTensorImage.h> // ITK #include <itkResampleImageFilter.h> #include <itkGaussianInterpolateImageFunction.h> #include <itkImageRegionIteratorWithIndex.h> #include <itkTractsToFiberEndingsImageFilter.h> #include <itkTractDensityImageFilter.h> #include <itkImageRegion.h> #include <itkTractsToRgbaImageFilter.h> #include <math.h> const std::string QmitkFiberProcessingView::VIEW_ID = "org.mitk.views.fiberprocessing"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace mitk; QmitkFiberProcessingView::QmitkFiberProcessingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_EllipseCounter(0) , m_PolygonCounter(0) , m_UpsamplingFactor(5) { } // Destructor QmitkFiberProcessingView::~QmitkFiberProcessingView() { } void QmitkFiberProcessingView::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::QmitkFiberProcessingViewControls; m_Controls->setupUi( parent ); m_Controls->doExtractFibersButton->setDisabled(true); m_Controls->PFCompoANDButton->setDisabled(true); m_Controls->PFCompoORButton->setDisabled(true); m_Controls->PFCompoNOTButton->setDisabled(true); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_RectangleButton->setVisible(false); connect( m_Controls->doExtractFibersButton, SIGNAL(clicked()), this, SLOT(DoFiberExtraction()) ); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ), this, SLOT( OnDrawCircle() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ), this, SLOT( OnDrawPolygon() ) ); connect(m_Controls->PFCompoANDButton, SIGNAL(clicked()), this, SLOT(GenerateAndComposite()) ); connect(m_Controls->PFCompoORButton, SIGNAL(clicked()), this, SLOT(GenerateOrComposite()) ); connect(m_Controls->PFCompoNOTButton, SIGNAL(clicked()), this, SLOT(GenerateNotComposite()) ); connect(m_Controls->m_JoinBundles, SIGNAL(clicked()), this, SLOT(JoinBundles()) ); connect(m_Controls->m_SubstractBundles, SIGNAL(clicked()), this, SLOT(SubstractBundles()) ); connect(m_Controls->m_GenerateRoiImage, SIGNAL(clicked()), this, SLOT(GenerateRoiImage()) ); connect(m_Controls->m_Extract3dButton, SIGNAL(clicked()), this, SLOT(Extract3d())); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ResampleFibersButton, SIGNAL(clicked()), this, SLOT(ResampleSelectedBundles()) ); connect(m_Controls->m_FaColorFibersButton, SIGNAL(clicked()), this, SLOT(DoFaColorCoding())); connect( m_Controls->m_PruneFibersButton, SIGNAL(clicked()), this, SLOT(PruneBundle()) ); connect( m_Controls->m_MirrorFibersButton, SIGNAL(clicked()), this, SLOT(MirrorFibers()) ); - connect( m_Controls->m_StreamlineTrackingButton, SIGNAL(clicked()), this, SLOT(StreamlineTrackingStart()) ); } } void QmitkFiberProcessingView::Extract3d() { std::vector<mitk::DataNode*> nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::FiberBundleX::Pointer fib = mitk::FiberBundleX::New(); mitk::Surface::Pointer roi = mitk::Surface::New(); bool fibB = false; bool roiB = false; for (int i=0; i<nodes.size(); i++) { if (dynamic_cast<mitk::FiberBundleX*>(nodes.at(i)->GetData())) { fib = dynamic_cast<mitk::FiberBundleX*>(nodes.at(i)->GetData()); fibB = true; } else if (dynamic_cast<mitk::Surface*>(nodes.at(i)->GetData())) { roi = dynamic_cast<mitk::Surface*>(nodes.at(i)->GetData()); roiB = true; } } if (!fibB) return; if (!roiB) return; vtkSmartPointer<vtkPolyData> polyRoi = roi->GetVtkPolyData(); vtkSmartPointer<vtkPolyData> polyFib = fib->GetFiberPolyData(); vtkSmartPointer<vtkSelectEnclosedPoints> selectEnclosedPoints = vtkSmartPointer<vtkSelectEnclosedPoints>::New(); selectEnclosedPoints->SetInput(polyFib); selectEnclosedPoints->SetSurface(polyRoi); selectEnclosedPoints->Update(); vtkSmartPointer<vtkPolyData> newPoly = vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkCellArray> newCellArray = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkPolyData> newPolyComplement = vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkCellArray> newCellArrayComplement = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkPoints> newPointsComplement = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray> vLines = polyFib->GetLines(); vLines->InitTraversal(); int numberOfLines = vLines->GetNumberOfCells(); // each line for (int j=0; j<numberOfLines; j++) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); bool isPassing = false; // each point of this line for (int k=0; k<numPoints; k++) { // is point inside polydata ? if (selectEnclosedPoints->IsInside(points[k])) { isPassing = true; // fill new polydata vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); for (int k=0; k<numPoints; k++) { double* point = polyFib->GetPoint(points[k]); vtkIdType pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); } newCellArray->InsertNextCell(container); break; } } if (!isPassing) { vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); for (int k=0; k<numPoints; k++) { double* point = polyFib->GetPoint(points[k]); vtkIdType pointId = newPointsComplement->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); } newCellArrayComplement->InsertNextCell(container); } } newPoly->SetPoints(newPoints); newPoly->SetLines(newCellArray); mitk::FiberBundleX::Pointer fb = mitk::FiberBundleX::New(newPoly); DataNode::Pointer newNode = DataNode::New(); newNode->SetData(fb); newNode->SetName("passing surface"); GetDefaultDataStorage()->Add(newNode); newPolyComplement->SetPoints(newPointsComplement); newPolyComplement->SetLines(newCellArrayComplement); mitk::FiberBundleX::Pointer fbComplement = mitk::FiberBundleX::New(newPolyComplement); DataNode::Pointer newNodeComplement = DataNode::New(); newNodeComplement->SetData(fbComplement); newNodeComplement->SetName("not passing surface"); GetDefaultDataStorage()->Add(newNodeComplement); } void QmitkFiberProcessingView::GenerateRoiImage(){ if (m_SelectedPF.empty()) return; mitk::Geometry3D::Pointer geometry; if (!m_SelectedFB.empty()) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.front()->GetData()); geometry = fib->GetGeometry(); } else return; mitk::Vector3D spacing = geometry->GetSpacing(); spacing /= m_UpsamplingFactor; 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<double, 3, 3> direction; itk::ImageRegion<3> imageRegion; for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction[j][i] = geometry->GetMatrixColumn(i)[j]/spacing[j]; imageRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); imageRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); imageRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); m_PlanarFigureImage = itkUCharImageType::New(); m_PlanarFigureImage->SetSpacing( spacing ); // Set the image spacing m_PlanarFigureImage->SetOrigin( newOrigin ); // Set the image origin m_PlanarFigureImage->SetDirection( direction ); // Set the image direction m_PlanarFigureImage->SetRegions( imageRegion ); m_PlanarFigureImage->Allocate(); m_PlanarFigureImage->FillBuffer( 0 ); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); for (int i=0; i<m_SelectedPF.size(); i++) CompositeExtraction(m_SelectedPF.at(i), tmpImage); DataNode::Pointer node = DataNode::New(); tmpImage = Image::New(); tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); node->SetData(tmpImage); node->SetName("ROI Image"); this->GetDefaultDataStorage()->Add(node); } void QmitkFiberProcessingView::CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image) { if (dynamic_cast<mitk::PlanarFigure*>(node.GetPointer()->GetData()) && !dynamic_cast<mitk::PlanarFigureComposite*>(node.GetPointer()->GetData())) { m_PlanarFigure = dynamic_cast<mitk::PlanarFigure*>(node.GetPointer()->GetData()); AccessFixedDimensionByItk_2( image, InternalReorientImagePlane, 3, m_PlanarFigure->GetGeometry(), -1); // itk::Image< unsigned char, 3 >::Pointer outimage = itk::Image< unsigned char, 3 >::New(); // outimage->SetSpacing( m_PlanarFigure->GetGeometry()->GetSpacing()/m_UpsamplingFactor ); // Set the image spacing // mitk::Point3D origin = m_PlanarFigure->GetGeometry()->GetOrigin(); // mitk::Point3D indexOrigin; // m_PlanarFigure->GetGeometry()->WorldToIndex(origin, indexOrigin); // indexOrigin[0] = indexOrigin[0] - .5 * (1.0-1.0/m_UpsamplingFactor); // indexOrigin[1] = indexOrigin[1] - .5 * (1.0-1.0/m_UpsamplingFactor); // indexOrigin[2] = indexOrigin[2] - .5 * (1.0-1.0/m_UpsamplingFactor); // mitk::Point3D newOrigin; // m_PlanarFigure->GetGeometry()->IndexToWorld(indexOrigin, newOrigin); // outimage->SetOrigin( newOrigin ); // Set the image origin // itk::Matrix<double, 3, 3> matrix; // for (int i=0; i<3; i++) // for (int j=0; j<3; j++) // matrix[j][i] = m_PlanarFigure->GetGeometry()->GetMatrixColumn(i)[j]/m_PlanarFigure->GetGeometry()->GetSpacing().GetElement(i); // outimage->SetDirection( matrix ); // Set the image direction // itk::ImageRegion<3> upsampledRegion; // upsampledRegion.SetSize(0, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(0)/m_PlanarFigure->GetGeometry()->GetSpacing()[0]); // upsampledRegion.SetSize(1, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(1)/m_PlanarFigure->GetGeometry()->GetSpacing()[1]); // upsampledRegion.SetSize(2, 1); // typename itk::Image< unsigned char, 3 >::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); // for (unsigned int n = 0; n < 2; n++) // { // upsampledSize[n] = upsampledSize[n] * m_UpsamplingFactor; // } // upsampledRegion.SetSize( upsampledSize ); // outimage->SetRegions( upsampledRegion ); // outimage->Allocate(); // this->m_InternalImage = mitk::Image::New(); // this->m_InternalImage->InitializeByItk( outimage.GetPointer() ); // this->m_InternalImage->SetVolume( outimage->GetBufferPointer() ); AccessFixedDimensionByItk_2( m_InternalImage, InternalCalculateMaskFromPlanarFigure, 3, 2, node->GetName() ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberProcessingView::InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ) { MITK_INFO << "InternalReorientImagePlane() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< float, VImageDimension > FloatImageType; typedef itk::ResampleImageFilter<ImageType, FloatImageType, double> ResamplerType; typename ResamplerType::Pointer resampler = ResamplerType::New(); mitk::PlaneGeometry* planegeo = dynamic_cast<mitk::PlaneGeometry*>(planegeo3D); float upsamp = m_UpsamplingFactor; float gausssigma = 0.5; // Spacing typename ResamplerType::SpacingType spacing = planegeo->GetSpacing(); spacing[0] = image->GetSpacing()[0] / upsamp; spacing[1] = image->GetSpacing()[1] / upsamp; spacing[2] = image->GetSpacing()[2]; resampler->SetOutputSpacing( spacing ); // Size typename ResamplerType::SizeType size; size[0] = planegeo->GetParametricExtentInMM(0) / spacing[0]; size[1] = planegeo->GetParametricExtentInMM(1) / spacing[1]; size[2] = 1; resampler->SetSize( size ); // Origin typename mitk::Point3D orig = planegeo->GetOrigin(); typename mitk::Point3D corrorig; planegeo3D->WorldToIndex(orig,corrorig); corrorig[0] += 0.5/upsamp; corrorig[1] += 0.5/upsamp; corrorig[2] += 0; planegeo3D->IndexToWorld(corrorig,corrorig); resampler->SetOutputOrigin(corrorig ); // Direction typename ResamplerType::DirectionType direction; typename mitk::AffineTransform3D::MatrixType matrix = planegeo->GetIndexToWorldTransform()->GetMatrix(); for(int c=0; c<matrix.ColumnDimensions; c++) { double sum = 0; for(int r=0; r<matrix.RowDimensions; r++) { sum += matrix(r,c)*matrix(r,c); } for(int r=0; r<matrix.RowDimensions; r++) { direction(r,c) = matrix(r,c)/sqrt(sum); } } resampler->SetOutputDirection( direction ); // Gaussian interpolation if(gausssigma != 0) { double sigma[3]; for( unsigned int d = 0; d < 3; d++ ) { sigma[d] = gausssigma * image->GetSpacing()[d]; } double alpha = 2.0; typedef itk::GaussianInterpolateImageFunction<ImageType, double> GaussianInterpolatorType; typename GaussianInterpolatorType::Pointer interpolator = GaussianInterpolatorType::New(); interpolator->SetInputImage( image ); interpolator->SetParameters( sigma, alpha ); resampler->SetInterpolator( interpolator ); } else { // typedef typename itk::BSplineInterpolateImageFunction<ImageType, double> // InterpolatorType; typedef typename itk::LinearInterpolateImageFunction<ImageType, double> InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetInputImage( image ); resampler->SetInterpolator( interpolator ); } // Other resampling options resampler->SetInput( image ); resampler->SetDefaultPixelValue(0); MITK_INFO << "Resampling requested image plane ... "; resampler->Update(); MITK_INFO << " ... done"; if(additionalIndex < 0) { this->m_InternalImage = mitk::Image::New(); this->m_InternalImage->InitializeByItk( resampler->GetOutput() ); this->m_InternalImage->SetVolume( resampler->GetOutput()->GetBufferPointer() ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberProcessingView::InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ) { MITK_INFO << "InternalCalculateMaskFromPlanarFigure() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::CastImageFilter< ImageType, itkUCharImageType > CastFilterType; // Generate mask image as new image with same header as input image and // initialize with "1". itkUCharImageType::Pointer newMaskImage = itkUCharImageType::New(); newMaskImage->SetSpacing( image->GetSpacing() ); // Set the image spacing newMaskImage->SetOrigin( image->GetOrigin() ); // Set the image origin newMaskImage->SetDirection( image->GetDirection() ); // Set the image direction newMaskImage->SetRegions( image->GetLargestPossibleRegion() ); newMaskImage->Allocate(); newMaskImage->FillBuffer( 1 ); // Generate VTK polygon from (closed) PlanarFigure polyline // (The polyline points are shifted by -0.5 in z-direction to make sure // that the extrusion filter, which afterwards elevates all points by +0.5 // in z-direction, creates a 3D object which is cut by the the plane z=0) const Geometry2D *planarFigureGeometry2D = m_PlanarFigure->GetGeometry2D(); const PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 ); const Geometry3D *imageGeometry3D = m_InternalImage->GetGeometry( 0 ); vtkPolyData *polyline = vtkPolyData::New(); polyline->Allocate( 1, 1 ); // Determine x- and y-dimensions depending on principal axis int i0, i1; switch ( axis ) { case 0: i0 = 1; i1 = 2; break; case 1: i0 = 0; i1 = 2; break; case 2: default: i0 = 0; i1 = 1; break; } // Create VTK polydata object of polyline contour vtkPoints *points = vtkPoints::New(); PlanarFigure::PolyLineType::const_iterator it; std::vector<vtkIdType> indices; unsigned int numberOfPoints = 0; for ( it = planarFigurePolyline.begin(); it != planarFigurePolyline.end(); ++it ) { Point3D point3D; // Convert 2D point back to the local index coordinates of the selected // image Point2D point2D = it->Point; planarFigureGeometry2D->WorldToIndex(point2D, point2D); point2D[0] -= 0.5/m_UpsamplingFactor; point2D[1] -= 0.5/m_UpsamplingFactor; planarFigureGeometry2D->IndexToWorld(point2D, point2D); planarFigureGeometry2D->Map( point2D, point3D ); // Polygons (partially) outside of the image bounds can not be processed // further due to a bug in vtkPolyDataToImageStencil if ( !imageGeometry3D->IsInside( point3D ) ) { float bounds[2] = {0,0}; bounds[0] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i0); bounds[1] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i1); imageGeometry3D->WorldToIndex( point3D, point3D ); // if (point3D[i0]<0) // point3D[i0] = 0.5; // else if (point3D[i0]>bounds[0]) // point3D[i0] = bounds[0]-0.5; // if (point3D[i1]<0) // point3D[i1] = 0.5; // else if (point3D[i1]>bounds[1]) // point3D[i1] = bounds[1]-0.5; if (point3D[i0]<0) point3D[i0] = 0.0; else if (point3D[i0]>bounds[0]) point3D[i0] = bounds[0]-0.001; if (point3D[i1]<0) point3D[i1] = 0.0; else if (point3D[i1]>bounds[1]) point3D[i1] = bounds[1]-0.001; points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } else { imageGeometry3D->WorldToIndex( point3D, point3D ); // Add point to polyline array points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } } polyline->SetPoints( points ); points->Delete(); vtkIdType *ptIds = new vtkIdType[numberOfPoints]; for ( vtkIdType i = 0; i < numberOfPoints; ++i ) { ptIds[i] = i; } polyline->InsertNextCell( VTK_POLY_LINE, numberOfPoints, ptIds ); // Extrude the generated contour polygon vtkLinearExtrusionFilter *extrudeFilter = vtkLinearExtrusionFilter::New(); extrudeFilter->SetInput( polyline ); extrudeFilter->SetScaleFactor( 1 ); extrudeFilter->SetExtrusionTypeToNormalExtrusion(); extrudeFilter->SetVector( 0.0, 0.0, 1.0 ); // Make a stencil from the extruded polygon vtkPolyDataToImageStencil *polyDataToImageStencil = vtkPolyDataToImageStencil::New(); polyDataToImageStencil->SetInput( extrudeFilter->GetOutput() ); // Export from ITK to VTK (to use a VTK filter) typedef itk::VTKImageImport< itkUCharImageType > ImageImportType; typedef itk::VTKImageExport< itkUCharImageType > ImageExportType; typename ImageExportType::Pointer itkExporter = ImageExportType::New(); itkExporter->SetInput( newMaskImage ); vtkImageImport *vtkImporter = vtkImageImport::New(); this->ConnectPipelines( itkExporter, vtkImporter ); vtkImporter->Update(); // Apply the generated image stencil to the input image vtkImageStencil *imageStencilFilter = vtkImageStencil::New(); imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() ); imageStencilFilter->SetStencil( polyDataToImageStencil->GetOutput() ); imageStencilFilter->ReverseStencilOff(); imageStencilFilter->SetBackgroundValue( 0 ); imageStencilFilter->Update(); // Export from VTK back to ITK vtkImageExport *vtkExporter = vtkImageExport::New(); vtkExporter->SetInputConnection( imageStencilFilter->GetOutputPort() ); vtkExporter->Update(); typename ImageImportType::Pointer itkImporter = ImageImportType::New(); this->ConnectPipelines( vtkExporter, itkImporter ); itkImporter->Update(); // calculate cropping bounding box m_InternalImageMask3D = itkImporter->GetOutput(); m_InternalImageMask3D->SetDirection(image->GetDirection()); itk::ImageRegionConstIterator<itkUCharImageType> itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion()); itk::ImageRegionIterator<ImageType> itimage(image, image->GetLargestPossibleRegion()); itmask = itmask.Begin(); itimage = itimage.Begin(); typename ImageType::SizeType lowersize = {{9999999999,9999999999,9999999999}}; typename ImageType::SizeType uppersize = {{0,0,0}}; while( !itmask.IsAtEnd() ) { if(itmask.Get() == 0) { itimage.Set(0); } else { typename ImageType::IndexType index = itimage.GetIndex(); typename ImageType::SizeType signedindex; signedindex[0] = index[0]; signedindex[1] = index[1]; signedindex[2] = index[2]; lowersize[0] = signedindex[0] < lowersize[0] ? signedindex[0] : lowersize[0]; lowersize[1] = signedindex[1] < lowersize[1] ? signedindex[1] : lowersize[1]; lowersize[2] = signedindex[2] < lowersize[2] ? signedindex[2] : lowersize[2]; uppersize[0] = signedindex[0] > uppersize[0] ? signedindex[0] : uppersize[0]; uppersize[1] = signedindex[1] > uppersize[1] ? signedindex[1] : uppersize[1]; uppersize[2] = signedindex[2] > uppersize[2] ? signedindex[2] : uppersize[2]; } ++itmask; ++itimage; } typename ImageType::IndexType index; index[0] = lowersize[0]; index[1] = lowersize[1]; index[2] = lowersize[2]; typename ImageType::SizeType size; size[0] = uppersize[0] - lowersize[0] + 1; size[1] = uppersize[1] - lowersize[1] + 1; size[2] = uppersize[2] - lowersize[2] + 1; itk::ImageRegion<3> cropRegion = itk::ImageRegion<3>(index, size); // crop internal mask typedef itk::RegionOfInterestImageFilter< itkUCharImageType, itkUCharImageType > ROIMaskFilterType; typename ROIMaskFilterType::Pointer roi2 = ROIMaskFilterType::New(); roi2->SetRegionOfInterest(cropRegion); roi2->SetInput(m_InternalImageMask3D); roi2->Update(); m_InternalImageMask3D = roi2->GetOutput(); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_InternalImageMask3D.GetPointer()); tmpImage->SetVolume(m_InternalImageMask3D->GetBufferPointer()); Image::Pointer tmpImage2 = Image::New(); tmpImage2->InitializeByItk(m_PlanarFigureImage.GetPointer()); const Geometry3D *pfImageGeometry3D = tmpImage2->GetGeometry( 0 ); const Geometry3D *intImageGeometry3D = tmpImage->GetGeometry( 0 ); typedef itk::ImageRegionIteratorWithIndex<itkUCharImageType> IteratorType; IteratorType imageIterator (m_InternalImageMask3D, m_InternalImageMask3D->GetRequestedRegion()); imageIterator.GoToBegin(); while ( !imageIterator.IsAtEnd() ) { unsigned char val = imageIterator.Value(); if (val>0) { itk::Index<3> index = imageIterator.GetIndex(); Point3D point; point[0] = index[0]; point[1] = index[1]; point[2] = index[2]; intImageGeometry3D->IndexToWorld(point, point); pfImageGeometry3D->WorldToIndex(point, point); point[i0] += 0.5; point[i1] += 0.5; index[0] = point[0]; index[1] = point[1]; index[2] = point[2]; if (pfImageGeometry3D->IsIndexInside(index)) m_PlanarFigureImage->SetPixel(index, 1); } ++imageIterator; } // Clean up VTK objects polyline->Delete(); extrudeFilter->Delete(); polyDataToImageStencil->Delete(); vtkImporter->Delete(); imageStencilFilter->Delete(); //vtkExporter->Delete(); // TODO: crashes when outcommented; memory leak?? delete[] ptIds; } void QmitkFiberProcessingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkFiberProcessingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } /* OnSelectionChanged is registered to SelectionService, therefore no need to implement SelectionService Listener explicitly */ void QmitkFiberProcessingView::UpdateGui() { // are fiber bundles selected? if ( m_SelectedFB.empty() ) { m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); m_Controls->m_ProcessFiberBundleButton->setEnabled(false); m_Controls->doExtractFibersButton->setEnabled(false); m_Controls->m_Extract3dButton->setEnabled(false); m_Controls->m_ResampleFibersButton->setEnabled(false); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_FaColorFibersButton->setEnabled(false); m_Controls->m_PruneFibersButton->setEnabled(false); m_Controls->m_MirrorFibersButton->setEnabled(false); } else { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); m_Controls->m_ProcessFiberBundleButton->setEnabled(true); m_Controls->m_ResampleFibersButton->setEnabled(true); m_Controls->m_PruneFibersButton->setEnabled(true); m_Controls->m_MirrorFibersButton->setEnabled(true); if (m_Surfaces.size()>0) m_Controls->m_Extract3dButton->setEnabled(true); // one bundle and one planar figure needed to extract fibers if (!m_SelectedPF.empty()) m_Controls->doExtractFibersButton->setEnabled(true); // more than two bundles needed to join/subtract if (m_SelectedFB.size() > 1) { m_Controls->m_JoinBundles->setEnabled(true); m_Controls->m_SubstractBundles->setEnabled(true); } else { m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); } if (m_SelectedImage.IsNotNull()) m_Controls->m_FaColorFibersButton->setEnabled(true); } // are planar figures selected? if ( m_SelectedPF.empty() ) { m_Controls->doExtractFibersButton->setEnabled(false); m_Controls->PFCompoANDButton->setEnabled(false); m_Controls->PFCompoORButton->setEnabled(false); m_Controls->PFCompoNOTButton->setEnabled(false); m_Controls->m_GenerateRoiImage->setEnabled(false); } else { if ( !m_SelectedFB.empty() ) m_Controls->m_GenerateRoiImage->setEnabled(true); else m_Controls->m_GenerateRoiImage->setEnabled(false); if (m_SelectedPF.size() > 1) { m_Controls->PFCompoANDButton->setEnabled(true); m_Controls->PFCompoORButton->setEnabled(true); m_Controls->PFCompoNOTButton->setEnabled(false); } else { m_Controls->PFCompoANDButton->setEnabled(false); m_Controls->PFCompoORButton->setEnabled(false); m_Controls->PFCompoNOTButton->setEnabled(true); } } - - if (m_SelectedImage.IsNotNull()) - m_Controls->m_StreamlineTrackingButton->setEnabled(true); - else - m_Controls->m_StreamlineTrackingButton->setEnabled(false); } void QmitkFiberProcessingView::OnSelectionChanged( std::vector<mitk::DataNode*> nodes ) { if ( !this->IsVisible() ) return; //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection m_SelectedFB.clear(); m_SelectedPF.clear(); m_Surfaces.clear(); m_SelectedImage = NULL; for( std::vector<mitk::DataNode*>::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( dynamic_cast<mitk::FiberBundleX*>(node->GetData()) ) m_SelectedFB.push_back(node); else if (dynamic_cast<mitk::PlanarFigure*>(node->GetData())) m_SelectedPF.push_back(node); else if (dynamic_cast<mitk::Image*>(node->GetData())) m_SelectedImage = dynamic_cast<mitk::Image*>(node->GetData()); else if (dynamic_cast<mitk::Surface*>(node->GetData())) m_Surfaces.push_back(dynamic_cast<mitk::Surface*>(node->GetData())); } UpdateGui(); GenerateStats(); } void QmitkFiberProcessingView::OnDrawPolygon() { // bool checked = m_Controls->m_PolygonButton->isChecked(); // if(!this->AssertDrawingIsPossible(checked)) // return; mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); this->AddFigureToDataStorage(figure, QString("Polygon%1").arg(++m_PolygonCounter)); MITK_INFO << "PlanarPolygon created ..."; mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast<mitk::DataNode*>(it->Value().GetPointer()); figureP = dynamic_cast<mitk::PlanarFigure*>(node->GetData()); if(figureP) { figureInteractor = dynamic_cast<mitk::PlanarFigureInteractor*>(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } } void QmitkFiberProcessingView::OnDrawCircle() { //bool checked = m_Controls->m_CircleButton->isChecked(); //if(!this->AssertDrawingIsPossible(checked)) // return; mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); this->AddFigureToDataStorage(figure, QString("Circle%1").arg(++m_EllipseCounter)); this->GetDataStorage()->Modified(); MITK_INFO << "PlanarCircle created ..."; //call mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast<mitk::DataNode*>(it->Value().GetPointer()); figureP = dynamic_cast<mitk::PlanarFigure*>(node->GetData()); if(figureP) { figureInteractor = dynamic_cast<mitk::PlanarFigureInteractor*>(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } } void QmitkFiberProcessingView::Activated() { MITK_INFO << "FB OPerations ACTIVATED()"; /* mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figure = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast<mitk::DataNode*>(it->Value().GetPointer()); figure = dynamic_cast<mitk::PlanarFigure*>(node->GetData()); if(figure) { figureInteractor = dynamic_cast<mitk::PlanarFigureInteractor*>(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } */ } void QmitkFiberProcessingView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey, mitk::BaseProperty *property ) { // initialize figure's geometry with empty geometry mitk::PlaneGeometry::Pointer emptygeometry = mitk::PlaneGeometry::New(); figure->SetGeometry2D( emptygeometry ); //set desired data to DataNode where Planarfigure is stored mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,0.0,0.0)); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true)); newNode->AddProperty( "selected", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.ishovering", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawoutline", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawquantities", mitk::BoolProperty::New(false) ); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(3.0) ); newNode->AddProperty( "planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.outline.width", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.helperline.width", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.markerline.color", mitk::ColorProperty::New(0.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.marker.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.marker.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.marker.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.line.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.outline.opacity", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.selected.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.helperline.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.marker.opacity",mitk::FloatProperty::New(2.0)); // figure drawn on the topmost layer / image newNode->SetColor(1.0,1.0,1.0); newNode->SetOpacity(0.8); GetDataStorage()->Add(newNode ); std::vector<mitk::DataNode*> selectedNodes = GetDataManagerSelection(); for(unsigned int i = 0; i < selectedNodes.size(); i++) { selectedNodes[i]->SetSelected(false); } newNode->SetSelected(true); } void QmitkFiberProcessingView::DoFiberExtraction() { if ( m_SelectedFB.empty() ){ QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; return; } for (int i=0; i<m_SelectedFB.size(); i++) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); mitk::PlanarFigure::Pointer roi = dynamic_cast<mitk::PlanarFigure*> (m_SelectedPF.at(0)->GetData()); mitk::FiberBundleX::Pointer extFB = fib->ExtractFiberSubset(roi); if (extFB->GetNumFibers()<=0) continue; mitk::DataNode::Pointer node; node = mitk::DataNode::New(); node->SetData(extFB); QString name(m_SelectedFB.at(i)->GetName().c_str()); name += "_"; name += m_SelectedPF.at(0)->GetName().c_str(); node->SetName(name.toStdString()); GetDataStorage()->Add(node); m_SelectedFB.at(i)->SetVisibility(false); } } void QmitkFiberProcessingView::GenerateAndComposite() { mitk::PlanarFigureComposite::Pointer PFCAnd = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast<mitk::PlaneGeometry*>( const_cast<mitk::Geometry2D*>(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCAnd->SetGeometry2D(currentGeometry2D); PFCAnd->setOperationType(mitk::PFCOMPOSITION_AND_OPERATION); for( std::vector<mitk::DataNode::Pointer>::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast<mitk::PlanarFigure*>( nodePF->GetData() ); PFCAnd->addPlanarFigure( tmpPF ); PFCAnd->addDataNode( nodePF ); PFCAnd->setDisplayName("AND_COMPO"); } AddCompositeToDatastorage(PFCAnd, NULL); } void QmitkFiberProcessingView::GenerateOrComposite() { mitk::PlanarFigureComposite::Pointer PFCOr = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast<mitk::PlaneGeometry*>( const_cast<mitk::Geometry2D*>(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCOr->SetGeometry2D(currentGeometry2D); PFCOr->setOperationType(mitk::PFCOMPOSITION_OR_OPERATION); for( std::vector<mitk::DataNode::Pointer>::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast<mitk::PlanarFigure*>( nodePF->GetData() ); PFCOr->addPlanarFigure( tmpPF ); PFCOr->addDataNode( nodePF ); PFCOr->setDisplayName("OR_COMPO"); } AddCompositeToDatastorage(PFCOr, NULL); } void QmitkFiberProcessingView::GenerateNotComposite() { mitk::PlanarFigureComposite::Pointer PFCNot = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast<mitk::PlaneGeometry*>( const_cast<mitk::Geometry2D*>(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCNot->SetGeometry2D(currentGeometry2D); PFCNot->setOperationType(mitk::PFCOMPOSITION_NOT_OPERATION); for( std::vector<mitk::DataNode::Pointer>::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast<mitk::PlanarFigure*>( nodePF->GetData() ); PFCNot->addPlanarFigure( tmpPF ); PFCNot->addDataNode( nodePF ); PFCNot->setDisplayName("NOT_COMPO"); } AddCompositeToDatastorage(PFCNot, NULL); } /* CLEANUP NEEDED */ void QmitkFiberProcessingView::AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer pfcomp, mitk::DataNode::Pointer parentDataNode ) { mitk::DataNode::Pointer newPFCNode; newPFCNode = mitk::DataNode::New(); newPFCNode->SetName( pfcomp->getDisplayName() ); newPFCNode->SetData(pfcomp); newPFCNode->SetVisibility(true); switch (pfcomp->getOperationType()) { case 0: { if (!parentDataNode.IsNull()) { GetDataStorage()->Add(newPFCNode, parentDataNode); } else { GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; i<pfcomp->getNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast<mitk::PlanarFigureComposite*>(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; } else { MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } MITK_INFO << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 1: { if (!parentDataNode.IsNull()) { MITK_INFO << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_INFO << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } for(int i=0; i<pfcomp->getNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast<mitk::PlanarFigureComposite*>(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } MITK_INFO << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 2: { if (!parentDataNode.IsNull()) { MITK_INFO << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_INFO << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; i<pfcomp->getNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast<mitk::PlanarFigureComposite*>(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // makeRemoveBundle new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } MITK_INFO << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } default: MITK_INFO << "we have an UNDEFINED composition... ERROR" ; break; } } void QmitkFiberProcessingView::JoinBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector<mitk::DataNode::Pointer>::const_iterator it = m_SelectedFB.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast<mitk::FiberBundleX*>((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; it!=m_SelectedFB.end(); ++it) { newBundle = newBundle->AddBundle(dynamic_cast<mitk::FiberBundleX*>((*it)->GetData())); name += "+"+QString((*it)->GetName().c_str()); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } void QmitkFiberProcessingView::SubstractBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector<mitk::DataNode::Pointer>::const_iterator it = m_SelectedFB.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast<mitk::FiberBundleX*>((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; it!=m_SelectedFB.end(); ++it) { newBundle = newBundle->SubtractBundle(dynamic_cast<mitk::FiberBundleX*>((*it)->GetData())); if (newBundle.IsNull()) break; name += "-"+QString((*it)->GetName().c_str()); } if (newBundle.IsNull()) { QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers. Did you select the fiber bundles in the correct order? X-Y is not equal to Y-X!"); return; } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } void QmitkFiberProcessingView::PruneBundle() { int minLength = this->m_Controls->m_PruneFibersSpinBox->value(); bool doneSomething = false; for (int i=0; i<m_SelectedFB.size(); i++) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); if (!fib->RemoveShortFibers(minLength)) QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); else doneSomething = true; } if (doneSomething) { GenerateStats(); RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkFiberProcessingView::GenerateStats() { if ( m_SelectedFB.empty() ) return; QString stats(""); for( int i=0; i<m_SelectedFB.size(); i++ ) { mitk::DataNode::Pointer node = m_SelectedFB[i]; if (node.IsNotNull() && dynamic_cast<mitk::FiberBundleX*>(node->GetData())) { if (i>0) stats += "\n-----------------------------\n"; stats += QString(node->GetName().c_str()) + "\n"; mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(node->GetData()); vtkSmartPointer<vtkPolyData> fiberPolyData = fib->GetFiberPolyData(); vtkSmartPointer<vtkCellArray> vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int numberOfLines = vLines->GetNumberOfCells(); stats += "Number of fibers: "+ QString::number(numberOfLines) + "\n"; float length = 0; std::vector<float> lengths; for (int i=0; i<numberOfLines; i++) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); float l=0; for (unsigned int j=0; j<numPoints-1; j++) { itk::Point<double> p1; itk::Point<double> p2; fiberPolyData->GetPoint(points[j], p1.GetDataPointer()); fiberPolyData->GetPoint(points[j+1], p2.GetDataPointer()); float dist = p1.EuclideanDistanceTo(p2); length += dist; l += dist; } itk::Point<double> p2; fiberPolyData->GetPoint(points[numPoints-1], p2.GetDataPointer()); lengths.push_back(l); } std::sort(lengths.begin(), lengths.end()); if (numberOfLines>0) length /= numberOfLines; float dev=0; int count = 0; vLines->InitTraversal(); for (int i=0; i<numberOfLines; i++) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); float l=0; for (unsigned int j=0; j<numPoints-1; j++) { itk::Point<double> p1; itk::Point<double> p2; fiberPolyData->GetPoint(points[j], p1.GetDataPointer()); fiberPolyData->GetPoint(points[j+1], p2.GetDataPointer()); float dist = p1.EuclideanDistanceTo(p2); l += dist; } dev += (length-l)*(length-l); count++; } if (numberOfLines>1) dev /= (numberOfLines-1); else dev = 0; stats += "Min. length: "+ QString::number(lengths.front(),'f',1) + " mm\n"; stats += "Max. length: "+ QString::number(lengths.back(),'f',1) + " mm\n"; stats += "Mean length: "+ QString::number(length,'f',1) + " mm\n"; stats += "Median length: "+ QString::number(lengths.at(lengths.size()/2),'f',1) + " mm\n"; stats += "Standard deviation: "+ QString::number(sqrt(dev),'f',1) + " mm\n"; } } this->m_Controls->m_StatsTextEdit->setText(stats); } void QmitkFiberProcessingView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( int i=0; i<m_SelectedFB.size(); i++ ) { mitk::DataNode::Pointer node = m_SelectedFB[i]; if (node.IsNotNull() && dynamic_cast<mitk::FiberBundleX*>(node->GetData())) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = NULL; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, true); name += "_envelope"; break; case 2: newNode = GenerateColorHeatmap(fib); break; case 3: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 4: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer<vtkPolyData> fiberPolyData = fib->GetFiberPolyData(); vtkSmartPointer<vtkCellArray> vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; i<numFibers; i++ ) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); if (numPoints>0) { double* point = fiberPolyData->GetPoint(points[0]); itk::Point<float,3> itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = fiberPolyData->GetPoint(points[numPoints-1]); itk::Point<float,3> itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib) { typedef unsigned char OutPixType; typedef itk::Image<OutPixType,3> OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetInvertImage(m_Controls->m_InvertCheckbox->isChecked()); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->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); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib) { typedef itk::RGBAPixel<unsigned char> OutPixType; typedef itk::Image<OutPixType, 3> OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image<unsigned char, 3>::Pointer itkImage = itk::Image<unsigned char, 3>::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image<OutPixType,3> OutType; OutType::Pointer outImg = generator->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); return node; } // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary) { typedef float OutPixType; typedef itk::Image<OutPixType, 3> OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetInvertImage(m_Controls->m_InvertCheckbox->isChecked()); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image<OutPixType,3> OutType; OutType::Pointer outImg = generator->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); return node; } void QmitkFiberProcessingView::ResampleSelectedBundles() { int factor = this->m_Controls->m_ResampleFibersSpinBox->value(); for (int i=0; i<m_SelectedFB.size(); i++) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); fib->DoFiberSmoothing(factor); } GenerateStats(); RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::MirrorFibers() { unsigned int axis = this->m_Controls->m_AxisSelectionBox->currentIndex(); for (int i=0; i<m_SelectedFB.size(); i++) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); fib->MirrorFibers(axis); } GenerateStats(); RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::DoFaColorCoding() { if (m_SelectedImage.IsNull()) return; for( int i=0; i<m_SelectedFB.size(); i++ ) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); fib->SetFAMap(m_SelectedImage); fib->SetColorCoding(mitk::FiberBundleX::COLORCODING_FA_BASED); fib->DoColorCodingFaBased(); } if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } - -void QmitkFiberProcessingView::StreamlineTrackingStart() -{ - if (m_SelectedImage.IsNull()) - return; - - if (!dynamic_cast<mitk::TensorImage*>(m_SelectedImage.GetPointer())) - return; - mitk::TensorImage::Pointer tensorimage = dynamic_cast<mitk::TensorImage*>(m_SelectedImage.GetPointer()); - - MITK_INFO << "tensor image found"; - - typedef itk::Image< itk::DiffusionTensor3D<float>, 3> TensorImageType; - typedef mitk::ImageToItk<TensorImageType> CastType; - - CastType::Pointer caster = CastType::New(); - caster->SetInput(tensorimage); - caster->Update(); - TensorImageType::Pointer image = caster->GetOutput(); - - typedef itk::StreamlineTrackingFilter< float > FilterType; - FilterType::Pointer filter = FilterType::New(); - filter->SetInput(image); - filter->Update(); -} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h index 966e845995..db1daf65c2 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h @@ -1,200 +1,199 @@ /*=================================================================== 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 QmitkFiberProcessingView_h #define QmitkFiberProcessingView_h #include <QmitkFunctionality.h> #include "ui_QmitkFiberProcessingViewControls.h" #include <mitkDataStorage.h> #include <mitkDataStorageSelection.h> #include <mitkPlanarFigure.h> #include <mitkPlanarFigureComposite.h> #include <mitkFiberBundleX.h> #include <mitkDataNode.h> #include <mitkSurface.h> #include <itkImage.h> #include <itkCastImageFilter.h> #include <itkVTKImageImport.h> #include <itkVTKImageExport.h> #include <itkRegionOfInterestImageFilter.h> #include <vtkLinearExtrusionFilter.h> #include <vtkPolyDataToImageStencil.h> #include <vtkSelectEnclosedPoints.h> #include <vtkImageImport.h> #include <vtkImageExport.h> #include <vtkImageStencil.h> #include <vtkSmartPointer.h> #include <vtkSelection.h> #include <vtkSelectionNode.h> #include <vtkExtractSelectedThresholds.h> #include <vtkFloatArray.h> #include <mitkUnstructuredGrid.h> #include <vtkXMLUnstructuredGridWriter.h> #include <itkTimeProbe.h> #include <itkStreamlineTrackingFilter.h> /*! \brief QmitkFiberProcessingView \warning View to process fiber bundles. Supplies methods to extract fibers from the bundle, join and subtract bundles, generate images from the selected bundle and much more. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkFiberProcessingView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: typedef itk::Image< unsigned char, 3 > itkUCharImageType; typedef itk::Image< float, 3 > itkFloatImageType; static const std::string VIEW_ID; QmitkFiberProcessingView(); virtual ~QmitkFiberProcessingView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void Activated(); protected slots: void OnDrawCircle(); void OnDrawPolygon(); void DoFiberExtraction(); void GenerateAndComposite(); void GenerateOrComposite(); void GenerateNotComposite(); void PruneBundle(); void MirrorFibers(); void JoinBundles(); void SubstractBundles(); void GenerateRoiImage(); void ProcessSelectedBundles(); void ResampleSelectedBundles(); void DoFaColorCoding(); void Extract3d(); - void StreamlineTrackingStart(); virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector<mitk::DataNode*> nodes ); Ui::QmitkFiberProcessingViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; /** Connection from VTK to ITK */ template <typename VTK_Exporter, typename ITK_Importer> void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template <typename ITK_Exporter, typename VTK_Importer> void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ); void GenerateStats(); void UpdateGui(); berry::ISelectionListener::Pointer m_SelListener; berry::IStructuredSelection::ConstPointer m_CurrentSelection; private: int m_EllipseCounter; int m_PolygonCounter; //contains the selected FiberBundles std::vector<mitk::DataNode::Pointer> m_SelectedFB; //contains the selected PlanarFigures std::vector<mitk::DataNode::Pointer> m_SelectedPF; mitk::Image::Pointer m_SelectedImage; mitk::Image::Pointer m_InternalImage; mitk::PlanarFigure::Pointer m_PlanarFigure; float m_UpsamplingFactor; itkUCharImageType::Pointer m_InternalImageMask3D; itkUCharImageType::Pointer m_PlanarFigureImage; std::vector<mitk::Surface::Pointer> m_Surfaces; void AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer, mitk::DataNode::Pointer); void debugPFComposition(mitk::PlanarFigureComposite::Pointer , int ); void CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image); mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary); mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib); }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui index d70f0b051b..34374ce3c9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,820 +1,790 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>QmitkFiberProcessingViewControls</class> <widget class="QWidget" name="QmitkFiberProcessingViewControls"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>665</width> <height>671</height> </rect> </property> <property name="windowTitle"> <string>Form</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>9</number> </property> <property name="topMargin"> <number>3</number> </property> <property name="rightMargin"> <number>9</number> </property> <property name="bottomMargin"> <number>3</number> </property> <item> <widget class="QGroupBox" name="groupBox"> <property name="title"> <string>Fiber Bundle Modification</string> </property> <layout class="QGridLayout" name="gridLayout_4"> <item row="0" column="0"> <widget class="QFrame" name="m_PlanarFigureButtonsFrame"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>200</width> <height>0</height> </size> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>60</height> </size> </property> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout"> <property name="margin"> <number>0</number> </property> <item row="0" column="0"> <widget class="QPushButton" name="m_CircleButton"> <property name="maximumSize"> <size> <width>30</width> <height>30</height> </size> </property> <property name="toolTip"> <string>Draw circular ROI. Select reference fiber bundle to execute.</string> </property> <property name="text"> <string/> </property> <property name="icon"> <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> <normaloff>:/QmitkDiffusionImaging/circle.png</normaloff>:/QmitkDiffusionImaging/circle.png</iconset> </property> <property name="iconSize"> <size> <width>32</width> <height>32</height> </size> </property> <property name="checkable"> <bool>false</bool> </property> <property name="flat"> <bool>true</bool> </property> </widget> </item> <item row="0" column="1"> <widget class="QPushButton" name="m_RectangleButton"> <property name="maximumSize"> <size> <width>30</width> <height>30</height> </size> </property> <property name="toolTip"> <string>Draw rectangular ROI. Select reference fiber bundle to execute.</string> </property> <property name="text"> <string/> </property> <property name="icon"> <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> <normaloff>:/QmitkDiffusionImaging/rectangle.png</normaloff>:/QmitkDiffusionImaging/rectangle.png</iconset> </property> <property name="iconSize"> <size> <width>32</width> <height>32</height> </size> </property> <property name="checkable"> <bool>true</bool> </property> <property name="flat"> <bool>true</bool> </property> </widget> </item> <item row="0" column="2"> <widget class="QPushButton" name="m_PolygonButton"> <property name="maximumSize"> <size> <width>30</width> <height>30</height> </size> </property> <property name="toolTip"> <string>Draw polygonal ROI. Select reference fiber bundle to execute.</string> </property> <property name="text"> <string/> </property> <property name="icon"> <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> <normaloff>:/QmitkDiffusionImaging/polygon.png</normaloff>:/QmitkDiffusionImaging/polygon.png</iconset> </property> <property name="iconSize"> <size> <width>32</width> <height>32</height> </size> </property> <property name="checkable"> <bool>true</bool> </property> <property name="flat"> <bool>true</bool> </property> </widget> </item> <item row="0" column="3"> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> </layout> </widget> </item> <item row="2" column="0"> <widget class="QFrame" name="frame_2"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout_3"> <property name="margin"> <number>0</number> </property> <item row="0" column="0"> <widget class="QCommandLinkButton" name="doExtractFibersButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute.</string> </property> <property name="text"> <string>Extract</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QCommandLinkButton" name="m_SubstractBundles"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute.</string> </property> <property name="text"> <string>Substract</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QCommandLinkButton" name="m_JoinBundles"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Merge selected fiber bundles. Select at least two fiber bundles to execute.</string> </property> <property name="text"> <string>Join</string> </property> </widget> </item> <item row="0" column="2"> <spacer name="horizontalSpacer_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item row="0" column="1"> <widget class="QCommandLinkButton" name="m_Extract3dButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Extract fibers passing through selected surface mesh. Select surface mesh and fiber bundle to execute.</string> </property> <property name="text"> <string>Extract 3D</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QCommandLinkButton" name="m_GenerateRoiImage"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image.</string> </property> <property name="text"> <string>ROI Image</string> </property> </widget> </item> </layout> </widget> </item> <item row="1" column="0"> <widget class="QFrame" name="m_PlanarFigureButtonsFrame_2"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>200</width> <height>0</height> </size> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>60</height> </size> </property> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout_5"> <property name="margin"> <number>0</number> </property> <item row="0" column="3"> <spacer name="horizontalSpacer_3"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item row="0" column="0"> <widget class="QCommandLinkButton" name="PFCompoANDButton"> <property name="enabled"> <bool>false</bool> </property> <property name="maximumSize"> <size> <width>60</width> <height>16777215</height> </size> </property> <property name="toolTip"> <string>Create AND composition with selected ROIs.</string> </property> <property name="text"> <string>AND</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QCommandLinkButton" name="PFCompoORButton"> <property name="enabled"> <bool>false</bool> </property> <property name="maximumSize"> <size> <width>60</width> <height>16777215</height> </size> </property> <property name="toolTip"> <string>Create OR composition with selected ROIs.</string> </property> <property name="text"> <string>OR</string> </property> </widget> </item> <item row="0" column="2"> <widget class="QCommandLinkButton" name="PFCompoNOTButton"> <property name="enabled"> <bool>false</bool> </property> <property name="maximumSize"> <size> <width>60</width> <height>16777215</height> </size> </property> <property name="toolTip"> <string>Create NOT composition from selected ROI.</string> </property> <property name="text"> <string>NOT</string> </property> </widget> </item> </layout> </widget> </item> </layout> </widget> </item> <item> <widget class="QGroupBox" name="groupBox_2"> <property name="title"> <string>Fiber Bundle Processing</string> </property> <layout class="QFormLayout" name="formLayout"> <property name="fieldGrowthPolicy"> <enum>QFormLayout::AllNonFixedFieldsGrow</enum> </property> <item row="0" column="0"> <widget class="QComboBox" name="m_GenerationBox"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <item> <property name="text"> <string>Tract Density Image (TDI)</string> </property> </item> <item> <property name="text"> <string>Binary Envelope</string> </property> </item> <item> <property name="text"> <string>Fiber Bundle Image</string> </property> </item> <item> <property name="text"> <string>Fiber Endings Image</string> </property> </item> <item> <property name="text"> <string>Fiber Endings Pointset</string> </property> </item> </widget> </item> <item row="0" column="1"> <widget class="QSpinBox" name="m_UpsamplingSpinBox"> <property name="toolTip"> <string>Upsampling factor</string> </property> <property name="minimum"> <number>1</number> </property> <property name="maximum"> <number>10</number> </property> <property name="value"> <number>2</number> </property> </widget> </item> <item row="1" column="0"> <widget class="QCommandLinkButton" name="m_ProcessFiberBundleButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Perform selected operation on all selected fiber bundles.</string> </property> <property name="text"> <string>Generate</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QCheckBox" name="m_InvertCheckbox"> <property name="toolTip"> <string>If selected operation generates an image, the inverse image is returned.</string> </property> <property name="text"> <string>Invert</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QCommandLinkButton" name="m_ResampleFibersButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Resample fibers using a Kochanek spline interpolation.</string> </property> <property name="text"> <string>Smooth Fibers</string> </property> </widget> </item> <item row="2" column="1"> <widget class="QSpinBox" name="m_ResampleFibersSpinBox"> <property name="toolTip"> <string>Points per cm</string> </property> <property name="minimum"> <number>1</number> </property> <property name="maximum"> <number>50</number> </property> <property name="value"> <number>10</number> </property> </widget> </item> <item row="3" column="0"> <widget class="QCommandLinkButton" name="m_PruneFibersButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Remove fibers shorten than the specified length (in mm).</string> </property> <property name="text"> <string>Prune Bundle</string> </property> </widget> </item> <item row="3" column="1"> <widget class="QSpinBox" name="m_PruneFibersSpinBox"> <property name="toolTip"> <string>Minimum fiber length in mm</string> </property> <property name="minimum"> <number>0</number> </property> <property name="maximum"> <number>1000</number> </property> <property name="value"> <number>20</number> </property> </widget> </item> <item row="4" column="0"> <widget class="QCommandLinkButton" name="m_MirrorFibersButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Mirror fibers around specified axis.</string> </property> <property name="text"> <string>Mirror Fibers</string> </property> </widget> </item> <item row="5" column="0"> <widget class="QCommandLinkButton" name="m_FaColorFibersButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Apply float image values (0-1) as color coding to the selected fiber bundle.</string> </property> <property name="text"> <string>Color By Scalar Map</string> </property> </widget> </item> <item row="4" column="1"> <widget class="QComboBox" name="m_AxisSelectionBox"> <property name="currentIndex"> <number>0</number> </property> <property name="maxVisibleItems"> <number>3</number> </property> <property name="maxCount"> <number>3</number> </property> <item> <property name="text"> <string>x - Axis</string> </property> </item> <item> <property name="text"> <string>y - Axis</string> </property> </item> <item> <property name="text"> <string>z - Axis</string> </property> </item> </widget> </item> </layout> </widget> </item> <item> <widget class="QGroupBox" name="groupBox_3"> <property name="title"> <string>Fiber Bundle Statistics</string> </property> <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> <widget class="QTextEdit" name="m_StatsTextEdit"> <property name="font"> <font> <family>Courier 10 Pitch</family> </font> </property> <property name="acceptDrops"> <bool>false</bool> </property> <property name="readOnly"> <bool>true</bool> </property> </widget> </item> </layout> </widget> </item> - <item> - <widget class="QCommandLinkButton" name="m_StreamlineTrackingButton"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>200</width> - <height>16777215</height> - </size> - </property> - <property name="font"> - <font> - <pointsize>11</pointsize> - </font> - </property> - <property name="toolTip"> - <string>Apply float image values (0-1) as color coding to the selected fiber bundle.</string> - </property> - <property name="text"> - <string>Streamline Tracking</string> - </property> - </widget> - </item> <item> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>40</height> </size> </property> </spacer> </item> </layout> </widget> <resources> <include location="../../resources/QmitkDiffusionImaging.qrc"/> </resources> <connections/> </ui> diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui index b99d3213ef..de4d981ce9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui @@ -1,1045 +1,1045 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>QmitkGibbsTrackingViewControls</class> <widget class="QWidget" name="QmitkGibbsTrackingViewControls"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>463</width> <height>1011</height> </rect> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>0</width> <height>0</height> </size> </property> <property name="windowTitle"> <string>QmitkTemplate</string> </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>9</number> </property> <property name="topMargin"> <number>3</number> </property> <property name="rightMargin"> <number>9</number> </property> <property name="bottomMargin"> <number>3</number> </property> <item> <widget class="QGroupBox" name="m_DataFrame"> <property name="title"> <string>Data</string> </property> <layout class="QGridLayout" name="gridLayout_4"> <item row="0" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>Q-Ball Image:</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QLabel" name="m_QballImageLabel"> <property name="toolTip"> <string>Mandatory input</string> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Mask Image:</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QLabel" name="m_MaskImageLabel"> <property name="toolTip"> <string>Optional input to limit the algorithms search space.</string> </property> <property name="text"> <string>-</string> </property> </widget> </item> </layout> </widget> </item> <item> <widget class="QGroupBox" name="m_ParametersFrame"> <property name="title"> <string>Parameters</string> </property> <layout class="QGridLayout" name="gridLayout_5"> <property name="bottomMargin"> <number>0</number> </property> <item row="0" column="0"> <widget class="QLabel" name="m_IterationsLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Iterations: 10^7</string> </property> </widget> </item> <item row="0" column="2"> <widget class="QSlider" name="m_IterationsSlider"> <property name="toolTip"> <string>Specify number of iterations for the tracking algorithm.</string> </property> <property name="maximum"> <number>10</number> </property> <property name="value"> <number>6</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::TicksBelow</enum> </property> </widget> </item> <item row="2" column="0"> <widget class="QCheckBox" name="m_VisualizationCheckbox"> <property name="enabled"> <bool>true</bool> </property> <property name="toolTip"> <string>Activate continuous visualization of intermediate results.</string> </property> <property name="text"> <string>Visualize Tractography</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="2" column="2"> <widget class="QToolButton" name="m_VisualizeOnceButton"> <property name="toolTip"> <string>Visualize intermediate result.</string> </property> <property name="text"> <string/> </property> <property name="icon"> <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> <normaloff>:/QmitkDiffusionImaging/Refresh_48.png</normaloff>:/QmitkDiffusionImaging/Refresh_48.png</iconset> </property> <property name="checkable"> <bool>true</bool> </property> </widget> </item> <item row="3" column="0"> <widget class="QCheckBox" name="m_AdvancedSettingsCheckbox"> <property name="text"> <string>Advanced Settings</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="m_CurvatureThresholdLabel_3"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Output File:</string> </property> </widget> </item> <item row="1" column="2"> <widget class="QFrame" name="frame_2"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Plain</enum> </property> <property name="lineWidth"> <number>0</number> </property> <layout class="QGridLayout" name="gridLayout"> <property name="margin"> <number>0</number> </property> <property name="spacing"> <number>0</number> </property> <item row="0" column="1"> <widget class="QToolButton" name="m_OutputFileButton"> <property name="toolTip"> <string>Select output file name and folder.</string> </property> <property name="text"> <string>...</string> </property> </widget> </item> <item row="0" column="0"> <widget class="QLineEdit" name="m_OutputFileLabel"> <property name="text"> <string>N/A</string> </property> <property name="readOnly"> <bool>true</bool> </property> </widget> </item> </layout> </widget> </item> </layout> </widget> </item> <item> <widget class="QFrame" name="m_AdvancedFrame"> <property name="enabled"> <bool>true</bool> </property> <property name="frameShape"> <enum>QFrame::StyledPanel</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout_2"> <property name="leftMargin"> <number>9</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>9</number> </property> <property name="bottomMargin"> <number>0</number> </property> <property name="spacing"> <number>4</number> </property> <item row="1" column="1"> <widget class="QLabel" name="m_ParticleLengthLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>auto</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="2" column="1"> <widget class="QLabel" name="m_ParticleWidthLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>auto</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="2" column="2"> <widget class="QSlider" name="m_ParticleWidthSlider"> <property name="toolTip"> <string>auto = 0.5 * min. spacing; sigma</string> </property> <property name="maximum"> <number>100</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="3" column="1"> <widget class="QLabel" name="m_ParticleWeightLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>auto</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="3" column="2"> <widget class="QSlider" name="m_ParticleWeightSlider"> <property name="toolTip"> <string>automatic estimation from gfa map and q-ball data.</string> </property> <property name="minimum"> <number>0</number> </property> <property name="maximum"> <number>1000</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>0</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="invertedControls"> <bool>true</bool> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="4" column="1"> <widget class="QLabel" name="m_StartTempLabel"> <property name="text"> <string>0.1</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="4" column="2"> <widget class="QSlider" name="m_StartTempSlider"> <property name="minimum"> <number>1</number> </property> <property name="maximum"> <number>100</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>10</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="invertedAppearance"> <bool>false</bool> </property> <property name="invertedControls"> <bool>false</bool> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="5" column="1"> <widget class="QLabel" name="m_EndTempLabel"> <property name="text"> <string>0.001</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="5" column="2"> <widget class="QSlider" name="m_EndTempSlider"> <property name="minimum"> <number>1</number> </property> <property name="maximum"> <number>99</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>10</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="6" column="1"> <widget class="QLabel" name="m_InExBalanceLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>0</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="6" column="2"> <widget class="QSlider" name="m_InExBalanceSlider"> <property name="toolTip"> <string>IE Bias < 0 < EE Bias</string> </property> <property name="minimum"> <number>-50</number> </property> <property name="maximum"> <number>50</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="7" column="1"> <widget class="QLabel" name="m_FiberLengthLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>40mm</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="7" column="2"> <widget class="QSlider" name="m_FiberLengthSlider"> <property name="toolTip"> <string>Only fibers longer than specified are accepted.</string> </property> <property name="maximum"> - <number>100</number> + <number>500</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>40</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="m_ParticleLengthLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Particle Length:</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="m_ParticleWidthLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Particle Width:</string> </property> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="m_ParticleWeightLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Particle Weight:</string> </property> </widget> </item> <item row="4" column="0"> <widget class="QLabel" name="m_StartTempLabel_2"> <property name="text"> <string>Start Temperature:</string> </property> </widget> </item> <item row="5" column="0"> <widget class="QLabel" name="m_EndTempLabel_2"> <property name="text"> <string>End Temperature:</string> </property> </widget> </item> <item row="6" column="0"> <widget class="QLabel" name="m_InExBalanceLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Balance In/Ex Energy:</string> </property> </widget> </item> <item row="7" column="0"> <widget class="QLabel" name="m_FiberLengthLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Min. Fiber Length:</string> </property> </widget> </item> <item row="10" column="0"> <widget class="QCheckBox" name="m_MeanSubtractionCheckbox"> <property name="enabled"> <bool>true</bool> </property> <property name="toolTip"> <string>Use mean subtracted ODFs (recommended).</string> </property> <property name="text"> <string>Subtract ODF Mean</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="10" column="1"> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Fixed</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>60</width> <height>20</height> </size> </property> </spacer> </item> <item row="8" column="0"> <widget class="QLabel" name="m_CurvatureThresholdLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Curvature Threshold:</string> </property> </widget> </item> <item row="8" column="1"> <widget class="QLabel" name="m_CurvatureThresholdLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>45°</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="8" column="2"> <widget class="QSlider" name="m_CurvatureThresholdSlider"> <property name="toolTip"> <string>Allow only fiber curvature values smaller than the selected threshold.</string> </property> <property name="maximum"> <number>180</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>45</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="1" column="2"> <widget class="QSlider" name="m_ParticleLengthSlider"> <property name="toolTip"> <string>auto = 1.5 * min. spacing; l</string> </property> <property name="maximum"> <number>100</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> </layout> </widget> </item> <item> <widget class="QFrame" name="frame_3"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Plain</enum> </property> <property name="lineWidth"> <number>0</number> </property> <layout class="QGridLayout" name="gridLayout_7"> <property name="margin"> <number>0</number> </property> <property name="spacing"> <number>0</number> </property> <item row="0" column="0"> <widget class="QCommandLinkButton" name="m_SaveTrackingParameters"> <property name="enabled"> <bool>true</bool> </property> <property name="toolTip"> <string>Save current parameters as xml (.gtp)</string> </property> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> </property> <property name="text"> <string>Save Parameters</string> </property> <property name="icon"> <iconset resource="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"> <normaloff>:/qmitk/btnMoveDown.png</normaloff>:/qmitk/btnMoveDown.png</iconset> </property> </widget> </item> <item row="0" column="1"> <widget class="QCommandLinkButton" name="m_LoadTrackingParameters"> <property name="enabled"> <bool>true</bool> </property> <property name="toolTip"> <string>Load parameters from xml file (.gtp)</string> </property> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> </property> <property name="text"> <string>Load Parameters</string> </property> <property name="icon"> <iconset resource="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"> <normaloff>:/qmitk/btnMoveUp.png</normaloff>:/qmitk/btnMoveUp.png</iconset> </property> </widget> </item> <item row="1" column="0"> <widget class="QCommandLinkButton" name="m_TrackingStart"> <property name="enabled"> <bool>false</bool> </property> <property name="toolTip"> <string>No Q-Ball image selected.</string> </property> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> </property> <property name="text"> <string>Start Tractography</string> </property> <property name="icon"> <iconset resource="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"> <normaloff>:/qmitk/play.xpm</normaloff>:/qmitk/play.xpm</iconset> </property> </widget> </item> <item row="1" column="1"> <widget class="QCommandLinkButton" name="m_TrackingStop"> <property name="enabled"> <bool>false</bool> </property> <property name="toolTip"> <string/> </property> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> </property> <property name="text"> <string>Stop Tractography</string> </property> <property name="icon"> <iconset resource="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"> <normaloff>:/qmitk/stop.xpm</normaloff>:/qmitk/stop.xpm</iconset> </property> </widget> </item> </layout> </widget> </item> <item> <widget class="QGroupBox" name="groupBox_4"> <property name="title"> <string>Monitor</string> </property> <layout class="QGridLayout" name="gridLayout_6"> <item row="0" column="0"> <widget class="QLabel" name="label_23"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Progress:</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QLabel" name="m_CurrentStepLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="label_21"> <property name="toolTip"> <string comment="Will only be updated if tracking is visualized" extracomment="Will only be updated if tracking is visualized">Will only be updated if tracking is visualized</string> </property> <property name="statusTip"> <string>Will only be updated if tracking is visualized</string> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Accepted Fibers:</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="label_24"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Connections:</string> </property> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="label_25"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Particles:</string> </property> </widget> </item> <item row="4" column="0"> <widget class="QLabel" name="label_27"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Proposal Acceptance Rate:</string> </property> </widget> </item> <item row="5" column="0"> <widget class="QLabel" name="label_26"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Tracking Time:</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QLabel" name="m_AcceptedFibersLabel"> <property name="toolTip"> <string>Will only be updated if tracking is visualized</string> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="2" column="1"> <widget class="QLabel" name="m_NumConnectionsLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="3" column="1"> <widget class="QLabel" name="m_NumParticlesLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="4" column="1"> <widget class="QLabel" name="m_ProposalAcceptance"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="5" column="1"> <widget class="QLabel" name="m_TrackingTimeLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> </layout> </widget> </item> <item> <spacer name="spacer1"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>0</width> <height>0</height> </size> </property> </spacer> </item> </layout> </widget> <layoutdefault spacing="6" margin="11"/> <resources> <include location="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"/> <include location="../../resources/QmitkDiffusionImaging.qrc"/> </resources> <connections/> </ui> diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp new file mode 100644 index 0000000000..fe502112c6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp @@ -0,0 +1,197 @@ +/*=================================================================== + +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 <berryISelectionService.h> +#include <berryIWorkbenchWindow.h> +#include <berryIStructuredSelection.h> + +// Qmitk +#include "QmitkStreamlineTrackingView.h" +#include "QmitkStdMultiWidget.h" + +// Qt +#include <QMessageBox> + +// MITK +#include <mitkImageToItk.h> +#include <mitkFiberBundleX.h> + +// VTK +#include <vtkPolyData.h> +#include <vtkPoints.h> +#include <vtkCellArray.h> +#include <vtkSmartPointer.h> +#include <vtkPolyLine.h> +#include <vtkCellData.h> + + +const std::string QmitkStreamlineTrackingView::VIEW_ID = "org.mitk.views.streamlinetracking"; +const std::string id_DataManager = "org.mitk.views.datamanager"; +using namespace berry; + +QmitkStreamlineTrackingView::QmitkStreamlineTrackingView() + : QmitkFunctionality() + , m_Controls( 0 ) + , m_MultiWidget( NULL ) + , m_TensorImage( NULL ) + , m_SeedRoi( NULL ) +{ +} + +// Destructor +QmitkStreamlineTrackingView::~QmitkStreamlineTrackingView() +{ + +} + +void QmitkStreamlineTrackingView::CreateQtPartControl( QWidget *parent ) +{ + if ( !m_Controls ) + { + // create GUI widgets from the Qt Designer's .ui file + m_Controls = new Ui::QmitkStreamlineTrackingViewControls; + m_Controls->setupUi( parent ); + + connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); + connect( m_Controls->m_SeedsPerVoxelSlider, SIGNAL(valueChanged(int)), this, SLOT(OnSeedsPerVoxelChanged(int)) ); + connect( m_Controls->m_MinTractLengthSlider, SIGNAL(valueChanged(int)), this, SLOT(OnMinTractLengthChanged(int)) ); + connect( m_Controls->m_FaThresholdSlider, SIGNAL(valueChanged(int)), this, SLOT(OnFaThresholdChanged(int)) ); + } +} + +void QmitkStreamlineTrackingView::OnSeedsPerVoxelChanged(int value) +{ + m_Controls->m_SeedsPerVoxelLabel->setText(QString("Seeds per Voxel: ")+QString::number(value)); +} + +void QmitkStreamlineTrackingView::OnMinTractLengthChanged(int value) +{ + m_Controls->m_MinTractLengthLabel->setText(QString("Min. Tract Length: ")+QString::number(value)+QString("mm")); +} + +void QmitkStreamlineTrackingView::OnFaThresholdChanged(int value) +{ + m_Controls->m_FaThresholdLabel->setText(QString("FA Threshold: ")+QString::number((float)value/100)); +} + +void QmitkStreamlineTrackingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) +{ + m_MultiWidget = &stdMultiWidget; +} + + +void QmitkStreamlineTrackingView::StdMultiWidgetNotAvailable() +{ + m_MultiWidget = NULL; +} + +void QmitkStreamlineTrackingView::OnSelectionChanged( std::vector<mitk::DataNode*> nodes ) +{ + m_TensorImageNode = NULL; + m_TensorImage = NULL; + m_SeedRoi = NULL; + m_Controls->m_TensorImageLabel->setText("-"); + m_Controls->m_RoiImageLabel->setText("-"); + + if(nodes.empty()) + return; + + for( std::vector<mitk::DataNode*>::iterator it = nodes.begin(); it != nodes.end(); ++it ) + { + mitk::DataNode::Pointer node = *it; + + if( node.IsNotNull() && dynamic_cast<mitk::Image*>(node->GetData()) ) + { + if( dynamic_cast<mitk::TensorImage*>(node->GetData()) ) + { + m_TensorImageNode = node; + m_TensorImage = dynamic_cast<mitk::TensorImage*>(node->GetData()); + m_Controls->m_TensorImageLabel->setText(node->GetName().c_str()); + } + else + { + bool isBinary = false; + node->GetPropertyValue<bool>("binary", isBinary); + if (isBinary) + { + m_SeedRoi = dynamic_cast<mitk::Image*>(node->GetData()); + m_Controls->m_RoiImageLabel->setText(node->GetName().c_str()); + } + } + } + } + + if(m_TensorImage.IsNotNull()) + m_Controls->commandLinkButton->setEnabled(true); + else + m_Controls->commandLinkButton->setEnabled(false); +} + + + +void QmitkStreamlineTrackingView::DoFiberTracking() +{ + if (m_TensorImage.IsNull()) + return; + + typedef itk::Image< itk::DiffusionTensor3D<float>, 3> TensorImageType; + typedef mitk::ImageToItk<TensorImageType> CastType; + typedef mitk::ImageToItk<ItkUCharImageType> CastType2; + + CastType::Pointer caster = CastType::New(); + caster->SetInput(m_TensorImage); + caster->Update(); + TensorImageType::Pointer image = caster->GetOutput(); + + typedef itk::StreamlineTrackingFilter< float > FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(image); + filter->SetSeedsPerVoxel(m_Controls->m_SeedsPerVoxelSlider->value()); + filter->SetFaThreshold((float)m_Controls->m_FaThresholdSlider->value()/100); + + if (m_SeedRoi.IsNotNull()) + { + CastType2::Pointer caster2 = CastType2::New(); + caster2->SetInput(m_SeedRoi); + caster2->Update(); + ItkUCharImageType::Pointer mask = caster2->GetOutput(); + filter->SetMaskImage(mask); + } + + filter->Update(); + + vtkSmartPointer<vtkPolyData> fiberBundle = filter->GetFiberPolyData(); + if ( fiberBundle->GetNumberOfLines()==0 ) + return; + mitk::FiberBundleX::Pointer fib = mitk::FiberBundleX::New(fiberBundle); + + fib->RemoveShortFibers(m_Controls->m_MinTractLengthSlider->value()); + + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(fib); + + QString name(m_TensorImageNode->GetName().c_str()); + name += "_FiberBundle"; + node->SetName(name.toStdString()); + + node->SetVisibility(true); + + GetDataStorage()->Add(node); +} + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h new file mode 100644 index 0000000000..3c436283e3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h @@ -0,0 +1,87 @@ +/*=================================================================== + +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 QmitkStreamlineTrackingView_h +#define QmitkStreamlineTrackingView_h + +#include <QmitkFunctionality.h> + +#include "ui_QmitkStreamlineTrackingViewControls.h" + +#include <mitkTensorImage.h> +#include <mitkDataStorage.h> +#include <mitkImage.h> +#include <itkImage.h> +#include <itkStreamlineTrackingFilter.h> + + +/*! +\brief QmitkStreamlineTrackingView + +\warning Implements standard streamline tracking as proposed by Mori et al. 1999 "Three-Dimensional Tracking of Axonal Projections in the Brain by Magnetic Resonance Imaging" + +\sa QmitkFunctionality +\ingroup Functionalities +*/ +class QmitkStreamlineTrackingView : public QmitkFunctionality +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + typedef itk::Image< unsigned char, 3 > ItkUCharImageType; + + QmitkStreamlineTrackingView(); + virtual ~QmitkStreamlineTrackingView(); + + virtual void CreateQtPartControl(QWidget *parent); + + virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); + virtual void StdMultiWidgetNotAvailable(); + + protected slots: + + void DoFiberTracking(); + +protected: + + /// \brief called by QmitkFunctionality when DataManager's selection has changed + virtual void OnSelectionChanged( std::vector<mitk::DataNode*> nodes ); + Ui::QmitkStreamlineTrackingViewControls* m_Controls; + QmitkStdMultiWidget* m_MultiWidget; + +protected slots: + + void OnSeedsPerVoxelChanged(int value); + void OnMinTractLengthChanged(int value); + void OnFaThresholdChanged(int value); + +private: + + mitk::Image::Pointer m_SeedRoi; + mitk::TensorImage::Pointer m_TensorImage; + mitk::DataNode::Pointer m_TensorImageNode; + +}; + + + +#endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui new file mode 100644 index 0000000000..5a90ff232e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui @@ -0,0 +1,212 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>QmitkStreamlineTrackingViewControls</class> + <widget class="QWidget" name="QmitkStreamlineTrackingViewControls"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>480</width> + <height>553</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="windowTitle"> + <string>QmitkTemplate</string> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <property name="topMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Data</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Tensor Image:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="m_TensorImageLabel"> + <property name="text"> + <string>-</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Seed ROI Image:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="m_RoiImageLabel"> + <property name="text"> + <string>-</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="3" column="0"> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Parameters</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="3" column="0"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="m_SeedsPerVoxelLabel"> + <property name="toolTip"> + <string>Number of tracts started in each voxel of the seed ROI.</string> + </property> + <property name="text"> + <string>Seeds per Voxel: 1</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSlider" name="m_MinTractLengthSlider"> + <property name="toolTip"> + <string>Minimum tract length in mm.</string> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>500</number> + </property> + <property name="value"> + <number>40</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSlider" name="m_SeedsPerVoxelSlider"> + <property name="toolTip"> + <string>Number of tracts started in each voxel of the seed ROI.</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="m_MinTractLengthLabel"> + <property name="toolTip"> + <string>Minimum tract length in mm.</string> + </property> + <property name="text"> + <string>Min. Tract Length: 40mm</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="m_FaThresholdLabel"> + <property name="toolTip"> + <string>Minimum tract length in mm.</string> + </property> + <property name="text"> + <string>FA Threshold: 0.2</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSlider" name="m_FaThresholdSlider"> + <property name="toolTip"> + <string>Fractional Anisotropy Threshold</string> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="value"> + <number>20</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="4" column="0"> + <widget class="QCommandLinkButton" name="commandLinkButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Start Tracking</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <spacer name="spacer1"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>220</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11"/> + <tabstops> + <tabstop>commandLinkButton</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp index 50f76f44a1..de283acb87 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp @@ -1,71 +1,73 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +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 +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 "mitkPluginActivator.h" #include <QtPlugin> #include "src/internal/QmitkDiffusionImagingPublicPerspective.h" #include "src/internal/QmitkQBallReconstructionView.h" #include "src/internal/QmitkPreprocessingView.h" #include "src/internal/QmitkDiffusionDicomImportView.h" #include "src/internal/QmitkDiffusionQuantificationView.h" #include "src/internal/QmitkTensorReconstructionView.h" #include "src/internal/QmitkControlVisualizationPropertiesView.h" #include "src/internal/QmitkODFDetailsView.h" #include "src/internal/QmitkGibbsTrackingView.h" #include "src/internal/QmitkStochasticFiberTrackingView.h" #include "src/internal/QmitkFiberProcessingView.h" #include "src/internal/QmitkFiberBundleDeveloperView.h" #include "src/internal/QmitkPartialVolumeAnalysisView.h" #include "src/internal/QmitkIVIMView.h" #include "src/internal/QmitkTractbasedSpatialStatisticsView.h" #include "src/internal/QmitkTbssSkeletonizationView.h" +#include "src/internal/QmitkStreamlineTrackingView.h" #include "src/internal/Connectomics/QmitkBrainNetworkAnalysisView.h" namespace mitk { void PluginActivator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionImagingPublicPerspective, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkQBallReconstructionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkPreprocessingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionDicomImport, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionQuantificationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTensorReconstructionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkControlVisualizationPropertiesView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkODFDetailsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkGibbsTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkStochasticFiberTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberProcessingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberBundleDeveloperView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkPartialVolumeAnalysisView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkIVIMView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTractbasedSpatialStatisticsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTbssSkeletonizationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkBrainNetworkAnalysisView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkStreamlineTrackingView, context) } void PluginActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) } } Q_EXPORT_PLUGIN2(org_mitk_gui_qt_diffusionimaging, mitk::PluginActivator) diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp index e03ad86c59..c476b26af0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp @@ -1,56 +1,60 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +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 +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 "QmitkDIAppFiberTractographyPerspective.h" #include "berryIViewLayout.h" void QmitkDIAppFiberTractographyPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// std::string editorArea = layout->GetEditorArea(); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .2f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneView("org.mitk.views.imagenavigator", false, berry::IPageLayout::BOTTOM, .4f, "org.mbi.diffusionimaginginternal.leftcontrols"); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.gibbstracking"); berry::IViewLayout::Pointer lo = layout->GetViewLayout("org.mitk.views.gibbstracking"); lo->SetCloseable(false); left->AddView("org.mitk.views.stochasticfibertracking"); lo = layout->GetViewLayout("org.mitk.views.stochasticfibertracking"); lo->SetCloseable(false); + left->AddView("org.mitk.views.streamlinetracking"); + lo = layout->GetViewLayout("org.mitk.views.streamlinetracking"); + lo->SetCloseable(false); + left->AddView("org.mitk.views.fiberprocessing"); lo = layout->GetViewLayout("org.mitk.views.fiberprocessing"); lo->SetCloseable(false); }