diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h index 0641de02ce..33aba1ef2b 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h @@ -1,102 +1,103 @@ /*=================================================================== 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 __itkDiffusionTensorPrincipalDirectionImageFilter_h_ #define __itkDiffusionTensorPrincipalDirectionImageFilter_h_ #include #include #include #include #include #include #include #include #include namespace itk{ /** \brief Extracts principal eigenvectors of the input tensors */ -template< class TTensorPixelType, class TPDPixelType=float> -class DiffusionTensorPrincipalDirectionImageFilter : - public ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< Vector< TPDPixelType, 3 >, 3 > > +template< class TTensorPixelType> +class DiffusionTensorPrincipalDirectionImageFilter : public ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< unsigned char, 3 > > { public: typedef DiffusionTensorPrincipalDirectionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; - typedef ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< Vector< TPDPixelType, 3 >, 3 > > + typedef ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< unsigned char, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionTensorPrincipalDirectionImageFilter, 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 ItkUcharImgType; typedef vnl_vector_fixed< double, 3 > DirectionType; + typedef Image< float, 4 > PeakImageType; void SetImage( const InputImageType *image ); // input itkSetMacro( MaskImage, ItkUcharImgType::Pointer) itkSetMacro( NormalizeVectors, bool) + itkSetMacro( UsePolarCoordinates, bool) // output itkGetMacro( OutputFiberBundle, mitk::FiberBundle::Pointer) - itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer) + itkGetMacro( PeakImage, PeakImageType::Pointer) protected: DiffusionTensorPrincipalDirectionImageFilter(); ~DiffusionTensorPrincipalDirectionImageFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType ); void AfterThreadedGenerateData(); private: bool m_NormalizeVectors; ///< Normalizes the output vector to length 1 - mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< Vector field representation of the output vectors - ItkUcharImgType::Pointer m_NumDirectionsImage; ///< Image containing the number of fiber directions per voxel + mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< Vector field representation of the output vectors ItkUcharImgType::Pointer m_MaskImage; ///< Extraction is only performed inside of the binary mask + PeakImageType::Pointer m_PeakImage; float m_MaxEigenvalue; + bool m_UsePolarCoordinates; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionTensorPrincipalDirectionImageFilter.txx" #endif #endif //__itkDiffusionTensorPrincipalDirectionImageFilter_h_ diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx index e7abe7c63a..76f2f3abbf 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx @@ -1,235 +1,280 @@ /*=================================================================== 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 __itkDiffusionTensorPrincipalDirectionImageFilter_txx #define __itkDiffusionTensorPrincipalDirectionImageFilter_txx #include #include #include #include "itkDiffusionTensorPrincipalDirectionImageFilter.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include "itkArray.h" #include "vnl/vnl_vector.h" #include #include #include #include #include #include #define _USE_MATH_DEFINES #include namespace itk { //#define QBALL_RECON_PI M_PI -template< class TTensorPixelType, class TPDPixelType> -DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType, -TPDPixelType> -::DiffusionTensorPrincipalDirectionImageFilter() +template< class TTensorPixelType> +DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType>::DiffusionTensorPrincipalDirectionImageFilter() : m_NormalizeVectors(true) , m_MaxEigenvalue(0.0) + , m_UsePolarCoordinates(false) { this->SetNumberOfRequiredInputs( 1 ); } -template< class TTensorPixelType, - class TPDPixelType> -void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType, -TPDPixelType> -::BeforeThreadedGenerateData() +template< class TTensorPixelType> +void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType>::BeforeThreadedGenerateData() { typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); - Vector spacing = inputImagePointer->GetSpacing(); - mitk::Point3D origin = inputImagePointer->GetOrigin(); - itk::Matrix direction = inputImagePointer->GetDirection(); - ImageRegion<3> imageRegion = inputImagePointer->GetLargestPossibleRegion(); + Vector spacing3 = inputImagePointer->GetSpacing(); + mitk::Point3D origin3 = inputImagePointer->GetOrigin(); + itk::Matrix direction3 = inputImagePointer->GetDirection(); + ImageRegion<3> imageRegion3 = inputImagePointer->GetLargestPossibleRegion(); if (m_MaskImage.IsNull()) { m_MaskImage = ItkUcharImgType::New(); - m_MaskImage->SetSpacing( spacing ); - m_MaskImage->SetOrigin( origin ); - m_MaskImage->SetDirection( direction ); - m_MaskImage->SetRegions( imageRegion ); + m_MaskImage->SetSpacing( spacing3 ); + m_MaskImage->SetOrigin( origin3 ); + m_MaskImage->SetDirection( direction3 ); + m_MaskImage->SetRegions( imageRegion3 ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } - m_NumDirectionsImage = ItkUcharImgType::New(); - m_NumDirectionsImage->SetSpacing( spacing ); - m_NumDirectionsImage->SetOrigin( origin ); - m_NumDirectionsImage->SetDirection( direction ); - m_NumDirectionsImage->SetRegions( imageRegion ); - m_NumDirectionsImage->Allocate(); - m_NumDirectionsImage->FillBuffer(0); - - itk::Vector< TPDPixelType, 3 > nullVec; nullVec.Fill(0.0); + typename OutputImageType::Pointer outputImage = OutputImageType::New(); - outputImage->SetSpacing( spacing ); - outputImage->SetOrigin( origin ); - outputImage->SetDirection( direction ); - outputImage->SetRegions( imageRegion ); + outputImage->SetSpacing( spacing3 ); + outputImage->SetOrigin( origin3 ); + outputImage->SetDirection( direction3 ); + outputImage->SetRegions( imageRegion3 ); outputImage->Allocate(); - outputImage->FillBuffer(nullVec); + outputImage->FillBuffer(0); this->SetNthOutput(0, outputImage); + + + itk::Vector spacing4; + itk::Point origin4; + itk::Matrix direction4; + itk::ImageRegion<4> imageRegion4; + + spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; + origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin3[3] = 0; + for (int r=0; r<3; r++) + for (int c=0; c<3; c++) + direction4[r][c] = direction3[r][c]; + direction4[3][3] = 1; + imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); + imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); + imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); + imageRegion4.SetSize(3, 3); + + m_PeakImage = PeakImageType::New(); + m_PeakImage->SetSpacing( spacing4 ); + m_PeakImage->SetOrigin( origin4 ); + m_PeakImage->SetDirection( direction4 ); + m_PeakImage->SetRegions( imageRegion4 ); + m_PeakImage->Allocate(); + m_PeakImage->FillBuffer(0.0); } -template< class TTensorPixelType, - class TPDPixelType> -void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType, -TPDPixelType> +template< class TTensorPixelType> +void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType> ::AfterThreadedGenerateData() { vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); - typename OutputImageType::Pointer directionImage = static_cast< OutputImageType* >( this->ProcessObject::GetPrimaryOutput() ); - ImageRegionConstIterator< OutputImageType > it(directionImage, directionImage->GetLargestPossibleRegion() ); + typename OutputImageType::Pointer numDirImage = static_cast< OutputImageType* >( this->ProcessObject::GetPrimaryOutput() ); + ImageRegionConstIterator< OutputImageType > it(numDirImage, numDirImage->GetLargestPossibleRegion() ); - mitk::Vector3D spacing = directionImage->GetSpacing(); + mitk::Vector3D spacing = numDirImage->GetSpacing(); double minSpacing = spacing[0]; if (spacing[1]GetPixel(index)==0) { ++it; continue; } - itk::Vector< float, 3 > pixel = directionImage->GetPixel(index); - DirectionType dir; dir[0] = pixel[0]; dir[1] = pixel[1]; dir[2] = pixel[2]; - - if (!m_NormalizeVectors && m_MaxEigenvalue>0) + typename PeakImageType::IndexType peakIndex; + peakIndex[0] = it.GetIndex()[0]; + peakIndex[1] = it.GetIndex()[1]; + peakIndex[2] = it.GetIndex()[2]; + DirectionType dir; + peakIndex[3] = 0; + dir[0] = m_PeakImage->GetPixel(peakIndex); + peakIndex[3] = 1; + dir[1] = m_PeakImage->GetPixel(peakIndex); + peakIndex[3] = 2; + dir[2] = m_PeakImage->GetPixel(peakIndex); + + if (!m_NormalizeVectors && m_MaxEigenvalue>0 && !m_UsePolarCoordinates) dir /= m_MaxEigenvalue; vtkSmartPointer container = vtkSmartPointer::New(); itk::ContinuousIndex center; center[0] = index[0]; center[1] = index[1]; center[2] = index[2]; itk::Point worldCenter; - directionImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); + numDirImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); itk::Point worldStart; worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing; worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing; worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing; vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); container->GetPointIds()->InsertNextId(id); itk::Point worldEnd; worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing; worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing; worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing; id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); container->GetPointIds()->InsertNextId(id); m_VtkCellArray->InsertNextCell(container); ++it; } vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); directionsPolyData->SetPoints(m_VtkPoints); directionsPolyData->SetLines(m_VtkCellArray); m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); } -template< class TTensorPixelType, - class TPDPixelType> -void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType, -TPDPixelType> +template< class TTensorPixelType> +void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType> ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) { typedef itk::DiffusionTensor3D TensorType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); - ImageRegionIterator< OutputImageType > outIt(outputImage, outputRegionForThread); - InputIteratorType inIt(inputImagePointer, outputRegionForThread ); - ImageRegionIterator< ItkUcharImgType > nIt(m_NumDirectionsImage, outputRegionForThread ); + ImageRegionIterator< OutputImageType > numDirectionsIterator(outputImage, outputRegionForThread); + InputIteratorType tensorIterator(inputImagePointer, outputRegionForThread ); - while( !inIt.IsAtEnd() ) + while( !tensorIterator.IsAtEnd() ) { - typename InputImageType::IndexType index = inIt.GetIndex(); + typename InputImageType::IndexType index = tensorIterator.GetIndex(); if (m_MaskImage->GetPixel(index)==0) { - ++inIt; - ++nIt; - ++outIt; + ++tensorIterator; + ++numDirectionsIterator; continue; } - typename InputImageType::PixelType b = inIt.Get(); + typename InputImageType::PixelType b = tensorIterator.Get(); TensorType tensor = b.GetDataPointer(); - typename OutputImageType::PixelType dir; + typename PeakImageType::IndexType peakIndex; + peakIndex[0] = tensorIterator.GetIndex()[0]; + peakIndex[1] = tensorIterator.GetIndex()[1]; + peakIndex[2] = tensorIterator.GetIndex()[2]; + typename TensorType::EigenValuesArrayType eigenvalues; typename TensorType::EigenVectorsMatrixType eigenvectors; if(tensor.GetTrace()!=0) { tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); - vnl_vector_fixed vec; + vnl_vector_fixed vec; vec[0] = eigenvectors(2,0); vec[1] = eigenvectors(2,1); vec[2] = eigenvectors(2,2); if (!m_NormalizeVectors) vec *= eigenvalues[2]; if (eigenvalues[2]>m_MaxEigenvalue) m_MaxEigenvalue = eigenvalues[2]; - dir[0] = (TPDPixelType)vec[0]; - dir[1] = (TPDPixelType)vec[1]; - dir[2] = (TPDPixelType)vec[2]; - - outIt.Set( dir ); - m_NumDirectionsImage->SetPixel(index, 1); + vnl_vector_fixed out; + if (m_UsePolarCoordinates) + { + if(vec[0] || vec[1] || vec[2]) + { + out[0] = sqrt( vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] ); + out[1] = atan2( vec[1], vec[0] ); + out[2] = 0.5*M_PI - atan( vec[2] / sqrt( vec[0] * vec[0] + vec[1] * vec[1] ) ); + + if(out[1]>M_PI) + { + out[1] = out[1] - M_PI; + } + } + else + { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + } + else + { + out = vec; + } + + peakIndex[3] = 0; + m_PeakImage->SetPixel(peakIndex, out[0]); + peakIndex[3] = 1; + m_PeakImage->SetPixel(peakIndex, out[1]); + peakIndex[3] = 2; + m_PeakImage->SetPixel(peakIndex, out[2]); + + numDirectionsIterator.Set( 1 ); } - ++outIt; - ++inIt; - ++nIt; + ++numDirectionsIterator; + ++tensorIterator; } std::cout << "One Thread finished extraction" << std::endl; } -template< class TTensorPixelType, - class TPDPixelType> -void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType, -TPDPixelType> +template< class TTensorPixelType> +void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { } } #endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h index ad6c92e33f..6c52c16b05 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h @@ -1,154 +1,151 @@ /*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkDiffusionTensor3DReconstructionImageFilter.h,v $ Language: C++ Date: $Date: 2006-03-27 17:01:06 $ Version: $Revision: 1.12 $ Copyright (c) Insight Software Consortium. All rights reserved. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __itkFiniteDiffOdfMaximaExtractionFilter_h_ #define __itkFiniteDiffOdfMaximaExtractionFilter_h_ #include "itkImageToImageFilter.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" #include #include namespace itk{ /** * \brief Extract ODF peaks by searching all local maxima on a densely sampled ODF und clustering these maxima to get the underlying fiber direction. * NrOdfDirections: number of sampling points on the ODF surface (about 20000 is a good value) */ template< class PixelType, int ShOrder, int NrOdfDirections > class FiniteDiffOdfMaximaExtractionFilter : public ImageToImageFilter< Image< Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 >, Image< unsigned char, 3 > > { public: enum Toolkit { ///< SH coefficient convention (depends on toolkit) FSL, MRTRIX }; enum NormalizationMethods { NO_NORM, ///< no length normalization of the output peaks SINGLE_VEC_NORM, ///< normalize the single peaks to length 1 MAX_VEC_NORM ///< normalize all peaks according to their length in comparison to the largest peak (0-1) }; typedef FiniteDiffOdfMaximaExtractionFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 >, Image< unsigned char, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(FiniteDiffOdfMaximaExtractionFilter, ImageToImageFilter) typedef typename Superclass::InputImageType CoefficientImageType; typedef typename CoefficientImageType::RegionType CoefficientImageRegionType; typedef typename CoefficientImageType::PixelType CoefficientPixelType; - typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; - typedef typename Superclass::InputImageRegionType InputImageRegionType; - typedef Image< float, 4 > PeakImageType; typedef OrientationDistributionFunction OdfType; typedef itk::Image ItkUcharImgType; typedef vnl_vector_fixed< double, 3 > DirectionType; // input itkSetMacro( MaxNumPeaks, unsigned int) ///< maximum number of peaks per voxel. if more peaks are detected, only the largest are kept. itkSetMacro( PeakThreshold, double) ///< threshold on the peak length relative to the largest peak inside the current voxel itkSetMacro( AbsolutePeakThreshold, double) ///< hard threshold on the peak length of all local maxima itkSetMacro( ClusteringThreshold, double) ///< directions closer together than the specified angular threshold will be clustered (in rad) itkSetMacro( AngularThreshold, double) ///< directions closer together than the specified threshold that remain after clustering are discarded (largest is kept) (in rad) itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< only voxels inside the binary mask are processed itkSetMacro( NormalizationMethod, NormalizationMethods) ///< normalization method of ODF peaks itkSetMacro( FlipX, bool) ///< flip peaks in x direction itkSetMacro( FlipY, bool) ///< flip peaks in y direction itkSetMacro( FlipZ, bool) ///< flip peaks in z direction itkSetMacro( ApplyDirectionMatrix, bool) // output itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer ) itkGetMacro( PeakImage, PeakImageType::Pointer ) itkGetMacro( OutputFiberBundle, mitk::FiberBundle::Pointer) ///< vector field (peak sizes rescaled for visualization purposes) itkSetMacro( Toolkit, Toolkit) ///< define SH coefficient convention (depends on toolkit) itkGetMacro( Toolkit, Toolkit) ///< SH coefficient convention (depends on toolkit) protected: FiniteDiffOdfMaximaExtractionFilter(); ~FiniteDiffOdfMaximaExtractionFilter(){} void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadID ); void AfterThreadedGenerateData(); /** Extract all local maxima from the densely sampled ODF surface. Thresholding possible. **/ void FindCandidatePeaks(OdfType& odf, double odfMax, std::vector< DirectionType >& inDirs); /** Cluster input directions within a certain angular threshold **/ std::vector< DirectionType > MeanShiftClustering(std::vector< DirectionType >& inDirs); /** Convert cartesian to spherical coordinates **/ void Cart2Sph(const std::vector< DirectionType >& dir, vnl_matrix& sphCoords); /** Calculate spherical harmonic basis of the defined order **/ vnl_matrix CalcShBasis(vnl_matrix& sphCoords); private: NormalizationMethods m_NormalizationMethod; ///< normalization method of ODF peaks unsigned int m_MaxNumPeaks; ///< maximum number of peaks per voxel. if more peaks are detected, only the largest are kept. double m_PeakThreshold; ///< threshold on the peak length relative to the largest peak inside the current voxel double m_AbsolutePeakThreshold;///< hard threshold on the peak length of all local maxima vnl_matrix< double > m_ShBasis; ///< container for evaluated SH base functions double m_ClusteringThreshold; ///< directions closer together than the specified angular threshold will be clustered (in rad) double m_AngularThreshold; ///< directions closer together than the specified threshold that remain after clustering are discarded (largest is kept) (in rad) const int m_NumCoeffs; ///< number of spherical harmonics coefficients mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< vector field (peak sizes rescaled for visualization purposes) PeakImageType::Pointer m_PeakImage; ItkUcharImgType::Pointer m_NumDirectionsImage; ///< number of peaks per voxel ItkUcharImgType::Pointer m_MaskImage; ///< only voxels inside the binary mask are processed Toolkit m_Toolkit; bool m_FlipX; bool m_FlipY; bool m_FlipZ; bool m_ApplyDirectionMatrix; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFiniteDiffOdfMaximaExtractionFilter.cpp" #endif #endif //__itkFiniteDiffOdfMaximaExtractionFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/TrackingHandlers/mitkTrackingHandlerPeaks.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/TrackingHandlers/mitkTrackingHandlerPeaks.cpp index cc6846cf1f..01f07fb4ad 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/TrackingHandlers/mitkTrackingHandlerPeaks.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/TrackingHandlers/mitkTrackingHandlerPeaks.cpp @@ -1,270 +1,271 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTrackingHandlerPeaks.h" namespace mitk { TrackingHandlerPeaks::TrackingHandlerPeaks() : m_PeakThreshold(0.1) + , m_ApplyDirectionMatrix(false) { } TrackingHandlerPeaks::~TrackingHandlerPeaks() { } void TrackingHandlerPeaks::InitForTracking() { MITK_INFO << "Initializing peak tracker."; itk::Vector spacing4 = m_PeakImage->GetSpacing(); itk::Point origin4 = m_PeakImage->GetOrigin(); itk::Matrix direction4 = m_PeakImage->GetDirection(); itk::ImageRegion<4> imageRegion4 = m_PeakImage->GetLargestPossibleRegion(); spacing3[0] = spacing4[0]; spacing3[1] = spacing4[1]; spacing3[2] = spacing4[2]; origin3[0] = origin4[0]; origin3[1] = origin4[1]; origin3[2] = origin4[2]; for (int r=0; r<3; r++) for (int c=0; c<3; c++) { direction3[r][c] = direction4[r][c]; m_FloatImageRotation[r][c] = direction4[r][c]; } imageRegion3.SetSize(0, imageRegion4.GetSize()[0]); imageRegion3.SetSize(1, imageRegion4.GetSize()[1]); imageRegion3.SetSize(2, imageRegion4.GetSize()[2]); m_DummyImage = ItkUcharImgType::New(); m_DummyImage->SetSpacing( spacing3 ); m_DummyImage->SetOrigin( origin3 ); m_DummyImage->SetDirection( direction3 ); m_DummyImage->SetRegions( imageRegion3 ); m_DummyImage->Allocate(); m_DummyImage->FillBuffer(0.0); m_NumDirs = imageRegion4.GetSize(3)/3; } vnl_vector_fixed TrackingHandlerPeaks::GetMatchingDirection(itk::Index<3> idx3, vnl_vector_fixed& oldDir) { vnl_vector_fixed out_dir; out_dir.fill(0); float angle = 0; float mag = oldDir.magnitude(); if (magmitk::eps) { oldDir[0] = out_dir[0]; oldDir[1] = out_dir[1]; oldDir[2] = out_dir[2]; break; } } // if you didn't find a non-zero random direction, take first non-zero direction you find for (int i=0; imitk::eps) { oldDir[0] = out_dir[0]; oldDir[1] = out_dir[1]; oldDir[2] = out_dir[2]; break; } } } else { for (int i=0; i dir = GetDirection(idx3, i); mag = dir.magnitude(); if (mag>mitk::eps) dir.normalize(); float a = dot_product(dir, oldDir); if (fabs(a)>angle) { angle = fabs(a); if (a<0) out_dir = -dir; else out_dir = dir; out_dir *= mag; out_dir *= angle; // shrink contribution of direction if is less parallel to previous direction } } } return out_dir; } vnl_vector_fixed TrackingHandlerPeaks::GetDirection(itk::Index<3> idx3, int dirIdx) { vnl_vector_fixed dir; dir.fill(0.0); if ( !m_DummyImage->GetLargestPossibleRegion().IsInside(idx3) ) return dir; PeakImgType::IndexType idx4; idx4.SetElement(0,idx3[0]); idx4.SetElement(1,idx3[1]); idx4.SetElement(2,idx3[2]); for (int k=0; k<3; k++) { idx4.SetElement(3, dirIdx*3 + k); dir[k] = m_PeakImage->GetPixel(idx4); } if (m_FlipX) dir[0] *= -1; if (m_FlipY) dir[1] *= -1; if (m_FlipZ) dir[2] *= -1; if (m_ApplyDirectionMatrix) dir = m_FloatImageRotation*dir; return dir; } vnl_vector_fixed TrackingHandlerPeaks::GetDirection(itk::Point itkP, bool interpolate, vnl_vector_fixed oldDir){ // transform physical point to index coordinates itk::Index<3> idx3; itk::ContinuousIndex< float, 3> cIdx; m_DummyImage->TransformPhysicalPointToIndex(itkP, idx3); m_DummyImage->TransformPhysicalPointToContinuousIndex(itkP, cIdx); vnl_vector_fixed dir; dir.fill(0.0); if ( !m_DummyImage->GetLargestPossibleRegion().IsInside(idx3) ) return dir; if (interpolate) { float frac_x = cIdx[0] - idx3[0]; float frac_y = cIdx[1] - idx3[1]; float frac_z = cIdx[2] - idx3[2]; if (frac_x<0) { idx3[0] -= 1; frac_x += 1; } if (frac_y<0) { idx3[1] -= 1; frac_y += 1; } if (frac_z<0) { idx3[2] -= 1; frac_z += 1; } frac_x = 1-frac_x; frac_y = 1-frac_y; frac_z = 1-frac_z; // int coordinates inside image? if (idx3[0] >= 0 && idx3[0] < m_DummyImage->GetLargestPossibleRegion().GetSize(0)-1 && idx3[1] >= 0 && idx3[1] < m_DummyImage->GetLargestPossibleRegion().GetSize(1)-1 && idx3[2] >= 0 && idx3[2] < m_DummyImage->GetLargestPossibleRegion().GetSize(2)-1) { // trilinear interpolation vnl_vector_fixed interpWeights; interpWeights[0] = ( frac_x)*( frac_y)*( frac_z); interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z); interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z); interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z); interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z); interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z); interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z); interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z); dir = GetMatchingDirection(idx3, oldDir) * interpWeights[0]; itk::Index<3> tmpIdx = idx3; tmpIdx[0]++; dir += GetMatchingDirection(tmpIdx, oldDir) * interpWeights[1]; tmpIdx = idx3; tmpIdx[1]++; dir += GetMatchingDirection(tmpIdx, oldDir) * interpWeights[2]; tmpIdx = idx3; tmpIdx[2]++; dir += GetMatchingDirection(tmpIdx, oldDir) * interpWeights[3]; tmpIdx = idx3; tmpIdx[0]++; tmpIdx[1]++; dir += GetMatchingDirection(tmpIdx, oldDir) * interpWeights[4]; tmpIdx = idx3; tmpIdx[1]++; tmpIdx[2]++; dir += GetMatchingDirection(tmpIdx, oldDir) * interpWeights[5]; tmpIdx = idx3; tmpIdx[2]++; tmpIdx[0]++; dir += GetMatchingDirection(tmpIdx, oldDir) * interpWeights[6]; tmpIdx = idx3; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; dir += GetMatchingDirection(tmpIdx, oldDir) * interpWeights[7]; } } else dir = GetMatchingDirection(idx3, oldDir); return dir; } vnl_vector_fixed TrackingHandlerPeaks::ProposeDirection(itk::Point& pos, std::deque >& olddirs, itk::Index<3>& oldIndex) { // CHECK: wann wird wo normalisiert vnl_vector_fixed output_direction; output_direction.fill(0); itk::Index<3> index; m_DummyImage->TransformPhysicalPointToIndex(pos, index); vnl_vector_fixed oldDir = olddirs.back(); float old_mag = oldDir.magnitude(); if (!m_Interpolate && oldIndex==index) return oldDir; output_direction = GetDirection(pos, m_Interpolate, oldDir); float mag = output_direction.magnitude(); if (mag>=m_PeakThreshold) { output_direction.normalize(); float a = 1; if (old_mag>0.5) a = dot_product(output_direction, oldDir); if (a>m_AngularThreshold) output_direction *= mag; else output_direction.fill(0); } else output_direction.fill(0); return output_direction; } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionView.cpp index 9913249b5e..40761f52e4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionView.cpp @@ -1,476 +1,477 @@ /*=================================================================== 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. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include #include // Blueberry #include #include // Qmitk #include "QmitkOdfMaximaExtractionView.h" // MITK #include #include #include #include #include // ITK #include #include #include #include #include #include #include #include #include #include #include #include // Qt #include const std::string QmitkOdfMaximaExtractionView::VIEW_ID = "org.mitk.views.odfmaximaextractionview"; using namespace mitk; QmitkOdfMaximaExtractionView::QmitkOdfMaximaExtractionView() : m_Controls(nullptr) { } // Destructor QmitkOdfMaximaExtractionView::~QmitkOdfMaximaExtractionView() { } void QmitkOdfMaximaExtractionView::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::QmitkOdfMaximaExtractionViewControls; m_Controls->setupUi(parent); connect((QObject*)m_Controls->m_StartPeakExtractionButton, SIGNAL(clicked()), (QObject*) this, SLOT(StartPeakExtraction())); connect((QObject*)m_Controls->m_ImportShCoeffs, SIGNAL(clicked()), (QObject*) this, SLOT(ConvertShCoeffs())); m_Controls->m_MaskBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateNot::Pointer isDwi = mitk::NodePredicateNot::New(mitk::NodePredicateIsDWI::New()); mitk::NodePredicateNot::Pointer isQbi = mitk::NodePredicateNot::New(mitk::NodePredicateDataType::New("QBallImage")); mitk::NodePredicateAnd::Pointer unwanted = mitk::NodePredicateAnd::New(isQbi, isDwi); mitk::NodePredicateDimension::Pointer dim3 = mitk::NodePredicateDimension::New(3); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); m_Controls->m_MaskBox->SetPredicate(mitk::NodePredicateAnd::New(mitk::NodePredicateAnd::New(unwanted, dim3), isBinaryPredicate)); m_Controls->m_ImageBox->SetPredicate(mitk::NodePredicateAnd::New(mitk::NodePredicateAnd::New(unwanted, isMitkImage), mitk::NodePredicateNot::New(isBinaryPredicate))); m_Controls->m_MaskBox->SetZeroEntryText("--"); m_Controls->m_ImageBox->SetZeroEntryText("--"); connect( (QObject*)(m_Controls->m_ImageBox), SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnImageSelectionChanged()) ); m_Controls->m_StartPeakExtractionButton->setVisible(false); m_Controls->m_ImportShCoeffs->setVisible(false); } } void QmitkOdfMaximaExtractionView::SetFocus() { } void QmitkOdfMaximaExtractionView::StartPeakExtraction() { if (dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()) != nullptr) { StartTensorPeakExtraction(dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData())); } else { StartMaximaExtraction(dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData())); } } template void QmitkOdfMaximaExtractionView::TemplatedConvertShCoeffs(mitk::Image* mitkImg) { typedef itk::ShCoefficientImageImporter< float, shOrder > FilterType; typedef mitk::ImageToItk< itk::Image< float, 4 > > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImg); caster->Update(); typename FilterType::Pointer filter = FilterType::New(); switch (m_Controls->m_ToolkitBox->currentIndex()) { case 0: filter->SetToolkit(FilterType::FSL); break; case 1: filter->SetToolkit(FilterType::MRTRIX); break; default: filter->SetToolkit(FilterType::FSL); } filter->SetInputImage(caster->GetOutput()); filter->GenerateData(); typename FilterType::QballImageType::Pointer itkQbi = filter->GetQballImage(); typename FilterType::CoefficientImageType::Pointer itkCi = filter->GetCoefficientImage(); { mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(itkCi.GetPointer()); img->SetVolume(itkCi->GetBufferPointer()); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_ShCoefficientImage_Imported"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); } { mitk::QBallImage::Pointer img = mitk::QBallImage::New(); img->InitializeByItk(itkQbi.GetPointer()); img->SetVolume(itkQbi->GetBufferPointer()); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_OdfImage_Imported"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); } } void QmitkOdfMaximaExtractionView::ConvertShCoeffs() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNull()) return; Image::Pointer mitkImg = dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); if (mitkImg->GetDimension() != 4 && mitkImg->GetLargestPossibleRegion().GetSize()[3]<6) { MITK_INFO << "wrong image type (need 4 dimensions)"; return; } int nrCoeffs = mitkImg->GetLargestPossibleRegion().GetSize()[3]; // // solve bx² + cx + d = 0 = shOrder² + 2*shOrder + 2-2*neededCoeffs; // int c = 3, d = 2 - 2 * nrCoeffs; // double D = c*c - 4 * d; // int shOrder; // if (D>0) // { // shOrder = (-c + sqrt(D)) / 2.0; // if (shOrder<0) // shOrder = (-c - sqrt(D)) / 2.0; // } // else if (D == 0) // shOrder = -c / 2.0; switch (nrCoeffs) { case 6: TemplatedConvertShCoeffs<2>(mitkImg); break; case 15: TemplatedConvertShCoeffs<4>(mitkImg); break; case 28: TemplatedConvertShCoeffs<6>(mitkImg); break; case 45: TemplatedConvertShCoeffs<8>(mitkImg); break; case 66: TemplatedConvertShCoeffs<10>(mitkImg); break; case 91: TemplatedConvertShCoeffs<12>(mitkImg); break; default : QMessageBox::warning(NULL, "Error", "Only spherical harmonics orders 2-12 are supported.", QMessageBox::Ok); } } void QmitkOdfMaximaExtractionView::StartTensorPeakExtraction(mitk::TensorImage* img) { - typedef itk::DiffusionTensorPrincipalDirectionImageFilter< float, float > MaximaExtractionFilterType; + typedef itk::DiffusionTensorPrincipalDirectionImageFilter< float > MaximaExtractionFilterType; MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); + filter->SetUsePolarCoordinates(false); mitk::BaseGeometry::Pointer geometry; try{ ItkTensorImage::Pointer itkImage = ItkTensorImage::New(); CastToItkImage(img, itkImage); filter->SetInput(itkImage); geometry = img->GetGeometry(); } catch (itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); QMessageBox::warning(NULL, "Wrong pixel type", "Could not perform Tensor Principal Direction Extraction due to Image has wrong pixel type.", QMessageBox::Ok); return; } if (m_Controls->m_MaskBox->GetSelectedNode().IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_Controls->m_MaskBox->GetSelectedNode()->GetData()); CastToItkImage(mitkMaskImg, itkMaskImage); filter->SetMaskImage(itkMaskImage); } if (m_Controls->m_NormalizationBox->currentIndex() == 0) filter->SetNormalizeVectors(false); filter->Update(); if (m_Controls->m_OutputDirectionImagesBox->isChecked()) { - MaximaExtractionFilterType::OutputImageType::Pointer itkImg = filter->GetOutput(); + MaximaExtractionFilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); mitk::Image::Pointer img = mitk::Image::New(); - img->InitializeByItk(itkImg.GetPointer()); - img->SetVolume(itkImg->GetBufferPointer()); + CastToMitkImage(itkImg, img); + DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_PrincipalDirection"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); } if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { - ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); + ItkUcharImgType::Pointer numDirImage = filter->GetOutput(); mitk::Image::Pointer image2 = mitk::Image::New(); image2->InitializeByItk(numDirImage.GetPointer()); image2->SetVolume(numDirImage->GetBufferPointer()); DataNode::Pointer node2 = DataNode::New(); node2->SetData(image2); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_NumDirections"; node2->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node2, m_Controls->m_ImageBox->GetSelectedNode()); } if (m_Controls->m_OutputVectorFieldBox->isChecked()) { mitk::Vector3D outImageSpacing = geometry->GetSpacing(); float minSpacing = 1; if (outImageSpacing[0]GetOutputFiberBundle(); // directions->SetGeometry(geometry); DataNode::Pointer node = DataNode::New(); node->SetData(directions); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_VectorField"; node->SetName(name.toStdString().c_str()); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(minSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); } } template void QmitkOdfMaximaExtractionView::StartMaximaExtraction(Image *image) { typedef itk::FiniteDiffOdfMaximaExtractionFilter< float, shOrder, 20242 > MaximaExtractionFilterType; typename MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); switch (m_Controls->m_ToolkitBox->currentIndex()) { case 0: filter->SetToolkit(MaximaExtractionFilterType::FSL); break; case 1: filter->SetToolkit(MaximaExtractionFilterType::MRTRIX); break; default: filter->SetToolkit(MaximaExtractionFilterType::FSL); } mitk::BaseGeometry::Pointer geometry; try{ typedef ImageToItk< typename MaximaExtractionFilterType::CoefficientImageType > CasterType; typename CasterType::Pointer caster = CasterType::New(); caster->SetInput(image); caster->Update(); filter->SetInput(caster->GetOutput()); geometry = image->GetGeometry(); } catch (itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); QMessageBox::warning(NULL, "Wrong pixel type", "Could not perform Finite Differences Extraction due to Image has wrong pixel type.", QMessageBox::Ok); return; } filter->SetAngularThreshold(cos((float)m_Controls->m_AngularThreshold->value()*M_PI / 180)); filter->SetClusteringThreshold(cos((float)m_Controls->m_ClusteringAngleBox->value()*M_PI / 180)); filter->SetMaxNumPeaks(m_Controls->m_MaxNumPeaksBox->value()); filter->SetPeakThreshold(m_Controls->m_PeakThresholdBox->value()); filter->SetAbsolutePeakThreshold(m_Controls->m_AbsoluteThresholdBox->value()); if (m_Controls->m_MaskBox->GetSelectedNode().IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_Controls->m_MaskBox->GetSelectedNode()->GetData()); CastToItkImage(mitkMaskImg, itkMaskImage); filter->SetMaskImage(itkMaskImage); } switch (m_Controls->m_NormalizationBox->currentIndex()) { case 0: filter->SetNormalizationMethod(MaximaExtractionFilterType::NO_NORM); break; case 1: filter->SetNormalizationMethod(MaximaExtractionFilterType::MAX_VEC_NORM); break; case 2: filter->SetNormalizationMethod(MaximaExtractionFilterType::SINGLE_VEC_NORM); break; } filter->Update(); if (m_Controls->m_OutputDirectionImagesBox->isChecked()) { typename MaximaExtractionFilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); mitk::Image::Pointer img = mitk::Image::New(); CastToMitkImage(itkImg, img); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_PEAKS"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); } if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); mitk::Image::Pointer image2 = mitk::Image::New(); CastToMitkImage(numDirImage, image2); DataNode::Pointer node2 = DataNode::New(); node2->SetData(image2); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_NUM_DIRECTIONS"; node2->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node2, m_Controls->m_ImageBox->GetSelectedNode()); } if (m_Controls->m_OutputVectorFieldBox->isChecked()) { mitk::Vector3D outImageSpacing = geometry->GetSpacing(); float minSpacing = 1; if (outImageSpacing[0]GetOutputFiberBundle(); // directions->SetGeometry(geometry); DataNode::Pointer node = DataNode::New(); node->SetData(directions); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_VECTOR_FIELD"; node->SetName(name.toStdString().c_str()); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(minSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); } } void QmitkOdfMaximaExtractionView::StartMaximaExtraction(Image* img) { mitk::PixelType pixT = img->GetPixelType(); switch (pixT.GetNumberOfComponents()) { case 6: StartMaximaExtraction<2>(img); break; case 15: StartMaximaExtraction<4>(img); break; case 28: StartMaximaExtraction<6>(img); break; case 45: StartMaximaExtraction<8>(img); break; case 66: StartMaximaExtraction<10>(img); break; case 91: StartMaximaExtraction<12>(img); break; default : QMessageBox::warning(NULL, "Error", "Only spherical harmonics orders 2-12 are supported.", QMessageBox::Ok); } } void QmitkOdfMaximaExtractionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) { (void) nodes; this->OnImageSelectionChanged(); } void QmitkOdfMaximaExtractionView::OnImageSelectionChanged() { m_Controls->m_StartPeakExtractionButton->setVisible(false); m_Controls->m_ImportShCoeffs->setVisible(false); mitk::DataNode::Pointer node = m_Controls->m_ImageBox->GetSelectedNode(); if (node.IsNull()) return; Image::Pointer img = dynamic_cast(node->GetData()); if (img->GetDimension()==4) m_Controls->m_ImportShCoeffs->setVisible(true); else m_Controls->m_StartPeakExtractionButton->setVisible(true); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp index 94669f7a42..da58bdca81 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.cpp @@ -1,2169 +1,2161 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPartialVolumeAnalysisView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "QmitkSliderNavigatorWidget.h" #include #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" #include "mitkImageTimeSelector.h" #include "mitkProperties.h" #include "mitkProgressBar.h" #include "mitkImageCast.h" #include "mitkImageToItk.h" #include "mitkITKImageImport.h" #include "mitkDataNodeObject.h" #include "mitkNodePredicateData.h" #include "mitkPlanarFigureInteractor.h" #include "mitkTensorImage.h" #include "mitkPlanarCircle.h" #include "mitkPlanarRectangle.h" #include "mitkPlanarPolygon.h" #include "mitkPartialVolumeAnalysisClusteringCalculator.h" #include "usModuleRegistry.h" #include #include "itkTensorDerivedMeasurementsFilter.h" #include "itkDiffusionTensor3D.h" #include "itkCartesianToPolarVectorImageFilter.h" #include "itkPolarToCartesianVectorImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkMaskImageFilter.h" #include "itkCastImageFilter.h" #include "itkImageMomentsCalculator.h" #include #include #include #include #include #define _USE_MATH_DEFINES #include #define PVA_PI M_PI const std::string QmitkPartialVolumeAnalysisView::VIEW_ID = "org.mitk.views.partialvolumeanalysisview"; class QmitkRequestStatisticsUpdateEvent : public QEvent { public: enum Type { StatisticsUpdateRequest = QEvent::MaxUser - 1025 }; QmitkRequestStatisticsUpdateEvent() : QEvent( (QEvent::Type) StatisticsUpdateRequest ) {}; }; typedef itk::Image ImageType; typedef itk::Image FloatImageType; typedef itk::Image, 3> VectorImageType; inline bool my_isnan(float x) { volatile float d = x; if(d!=d) return true; if(d==d) return false; return d != d; } QmitkPartialVolumeAnalysisView::QmitkPartialVolumeAnalysisView(QObject * /*parent*/, const char * /*name*/) : QmitkAbstractView(), m_Controls( NULL ), m_TimeStepperAdapter( NULL ), m_MeasurementInfoRenderer(0), m_MeasurementInfoAnnotation(0), m_SelectedImageNodes( ), m_SelectedImage( NULL ), m_SelectedMaskNode( NULL ), m_SelectedImageMask( NULL ), m_SelectedPlanarFigureNodes(0), m_SelectedPlanarFigure( NULL ), m_IsTensorImage(false), m_FAImage(0), m_RDImage(0), m_ADImage(0), m_MDImage(0), m_CAImage(0), // m_DirectionImage(0), m_DirectionComp1Image(0), m_DirectionComp2Image(0), m_AngularErrorImage(0), m_SelectedRenderWindow(NULL), m_LastRenderWindow(NULL), m_ImageObserverTag( -1 ), m_ImageMaskObserverTag( -1 ), m_PlanarFigureObserverTag( -1 ), m_CurrentStatisticsValid( false ), m_StatisticsUpdatePending( false ), m_GaussianSigmaChangedSliding(false), m_NumberBinsSliding(false), m_UpsamplingChangedSliding(false), m_ClusteringResult(NULL), m_EllipseCounter(0), m_RectangleCounter(0), m_PolygonCounter(0), m_CurrentFigureNodeInitialized(false), m_QuantifyClass(2), m_IconTexOFF(new QIcon(":/QmitkPartialVolumeAnalysisView/texIntOFFIcon.png")), m_IconTexON(new QIcon(":/QmitkPartialVolumeAnalysisView/texIntONIcon.png")), m_TexIsOn(true), m_Visible(false) { } QmitkPartialVolumeAnalysisView::~QmitkPartialVolumeAnalysisView() { if ( m_SelectedImage.IsNotNull() ) m_SelectedImage->RemoveObserver( m_ImageObserverTag ); if ( m_SelectedImageMask.IsNotNull() ) m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); if ( m_SelectedPlanarFigure.IsNotNull() ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); } this->GetDataStorage()->AddNodeEvent -= mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage ); m_SelectedPlanarFigureNodes->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedPlanarFigureNodes->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedPlanarFigureNodes->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedImageNodes->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedImageNodes->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); } void QmitkPartialVolumeAnalysisView::CreateQtPartControl(QWidget *parent) { if (m_Controls == NULL) { m_Controls = new Ui::QmitkPartialVolumeAnalysisViewControls; m_Controls->setupUi(parent); this->CreateConnections(); } SetHistogramVisibility(); m_Controls->m_TextureIntON->setIcon(*m_IconTexON); m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); vtkTextProperty *textProp = vtkTextProperty::New(); textProp->SetColor(1.0, 1.0, 1.0); m_MeasurementInfoAnnotation = vtkCornerAnnotation::New(); m_MeasurementInfoAnnotation->SetMaximumFontSize(12); m_MeasurementInfoAnnotation->SetTextProperty(textProp); m_MeasurementInfoRenderer = vtkRenderer::New(); m_MeasurementInfoRenderer->AddActor(m_MeasurementInfoAnnotation); m_SelectedPlanarFigureNodes = mitk::DataStorageSelection::New(this->GetDataStorage(), false); m_SelectedPlanarFigureNodes->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedPlanarFigureNodes->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedPlanarFigureNodes->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes = mitk::DataStorageSelection::New(this->GetDataStorage(), false); m_SelectedImageNodes->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedImageNodes->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); this->GetDataStorage()->AddNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage ) ); Select(NULL,true,true); SetAdvancedVisibility(); } void QmitkPartialVolumeAnalysisView::SetFocus() { m_Controls->m_CircleButton->setFocus(); } void QmitkPartialVolumeAnalysisView::SetHistogramVisibility() { m_Controls->m_HistogramWidget->setVisible(m_Controls->m_DisplayHistogramCheckbox->isChecked()); } void QmitkPartialVolumeAnalysisView::SetAdvancedVisibility() { m_Controls->frame_7->setVisible(m_Controls->m_AdvancedCheckbox->isChecked()); } void QmitkPartialVolumeAnalysisView::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_DisplayHistogramCheckbox, SIGNAL( clicked() ) , this, SLOT( SetHistogramVisibility() ) ); connect( m_Controls->m_AdvancedCheckbox, SIGNAL( clicked() ) , this, SLOT( SetAdvancedVisibility() ) ); connect( m_Controls->m_NumberBinsSlider, SIGNAL( sliderReleased () ), this, SLOT( NumberBinsReleasedSlider( ) ) ); connect( m_Controls->m_UpsamplingSlider, SIGNAL( sliderReleased( ) ), this, SLOT( UpsamplingReleasedSlider( ) ) ); connect( m_Controls->m_GaussianSigmaSlider, SIGNAL( sliderReleased( ) ), this, SLOT( GaussianSigmaReleasedSlider( ) ) ); connect( m_Controls->m_SimilarAnglesSlider, SIGNAL( sliderReleased( ) ), this, SLOT( SimilarAnglesReleasedSlider( ) ) ); connect( m_Controls->m_NumberBinsSlider, SIGNAL( valueChanged (int) ), this, SLOT( NumberBinsChangedSlider( int ) ) ); connect( m_Controls->m_UpsamplingSlider, SIGNAL( valueChanged( int ) ), this, SLOT( UpsamplingChangedSlider( int ) ) ); connect( m_Controls->m_GaussianSigmaSlider, SIGNAL( valueChanged( int ) ), this, SLOT( GaussianSigmaChangedSlider( int ) ) ); connect( m_Controls->m_SimilarAnglesSlider, SIGNAL( valueChanged( int ) ), this, SLOT( SimilarAnglesChangedSlider(int) ) ); connect( m_Controls->m_OpacitySlider, SIGNAL( valueChanged( int ) ), this, SLOT( OpacityChangedSlider(int) ) ); connect( (QObject*)(m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(ToClipBoard())); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawEllipseTriggered() ) ); connect( m_Controls->m_RectangleButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawRectangleTriggered() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawPolygonTriggered() ) ); connect( m_Controls->m_GreenRadio, SIGNAL( clicked(bool) ) , this, SLOT( GreenRadio(bool) ) ); connect( m_Controls->m_PartialVolumeRadio, SIGNAL( clicked(bool) ) , this, SLOT( PartialVolumeRadio(bool) ) ); connect( m_Controls->m_BlueRadio, SIGNAL( clicked(bool) ) , this, SLOT( BlueRadio(bool) ) ); connect( m_Controls->m_AllRadio, SIGNAL( clicked(bool) ) , this, SLOT( AllRadio(bool) ) ); connect( m_Controls->m_EstimateCircle, SIGNAL( clicked() ) , this, SLOT( EstimateCircle() ) ); connect( (QObject*)(m_Controls->m_TextureIntON), SIGNAL(clicked()), this, SLOT(TextIntON()) ); connect( m_Controls->m_ExportClusteringResultsButton, SIGNAL(clicked()), this, SLOT(ExportClusteringResults())); } } void QmitkPartialVolumeAnalysisView::ExportClusteringResults() { if (m_ClusteringResult.IsNull() || m_SelectedImage.IsNull()) return; mitk::BaseGeometry* geometry = m_SelectedImage->GetGeometry(); itk::Image< short, 3>::Pointer referenceImage = itk::Image< short, 3>::New(); itk::Vector newSpacing = geometry->GetSpacing(); mitk::Point3D newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); newOrigin[0] += bounds.GetElement(0); newOrigin[1] += bounds.GetElement(2); newOrigin[2] += bounds.GetElement(4); itk::Matrix newDirection; itk::ImageRegion<3> imageRegion; for (int i=0; i<3; i++) for (int j=0; j<3; j++) newDirection[j][i] = geometry->GetMatrixColumn(i)[j]/newSpacing[j]; imageRegion.SetSize(0, geometry->GetExtent(0)); imageRegion.SetSize(1, geometry->GetExtent(1)); imageRegion.SetSize(2, geometry->GetExtent(2)); // apply new image parameters referenceImage->SetSpacing( newSpacing ); referenceImage->SetOrigin( newOrigin ); referenceImage->SetDirection( newDirection ); referenceImage->SetRegions( imageRegion ); referenceImage->Allocate(); typedef itk::Image< float, 3 > OutType; mitk::Image::Pointer mitkInImage = dynamic_cast(m_ClusteringResult->GetData()); typedef itk::Image< itk::RGBAPixel, 3 > ItkRgbaImageType; typedef mitk::ImageToItk< ItkRgbaImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkInImage); caster->Update(); ItkRgbaImageType::Pointer itkInImage = caster->GetOutput(); typedef itk::ExtractChannelFromRgbaImageFilter< itk::Image< short, 3>, OutType > ExtractionFilterType; ExtractionFilterType::Pointer filter = ExtractionFilterType::New(); filter->SetInput(itkInImage); filter->SetChannel(ExtractionFilterType::ALPHA); filter->SetReferenceImage(referenceImage); filter->Update(); OutType::Pointer outImg = filter->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); node->SetName("Clustering Result"); GetDataStorage()->Add(node); } void QmitkPartialVolumeAnalysisView::EstimateCircle() { typedef itk::Image SegImageType; SegImageType::Pointer mask_itk = SegImageType::New(); typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(m_SelectedImageMask); caster->Update(); typedef itk::ImageMomentsCalculator< SegImageType > MomentsType; MomentsType::Pointer momentsCalc = MomentsType::New(); momentsCalc->SetImage(caster->GetOutput()); momentsCalc->Compute(); MomentsType::VectorType cog = momentsCalc->GetCenterOfGravity(); MomentsType::MatrixType axes = momentsCalc->GetPrincipalAxes(); MomentsType::VectorType moments = momentsCalc->GetPrincipalMoments(); // moments-coord conversion // third coordinate min oder max? // max-min = extent MomentsType::AffineTransformPointer trafo = momentsCalc->GetPhysicalAxesToPrincipalAxesTransform(); itk::ImageRegionIterator itimage(caster->GetOutput(), caster->GetOutput()->GetLargestPossibleRegion()); itimage = itimage.Begin(); double max = -9999999999.0; double min = 9999999999.0; while( !itimage.IsAtEnd() ) { if(itimage.Get()) { ImageType::IndexType index = itimage.GetIndex(); itk::Point point; caster->GetOutput()->TransformIndexToPhysicalPoint(index,point); itk::Point newPoint; newPoint = trafo->TransformPoint(point); if(newPoint[2]max) max = newPoint[2]; } ++itimage; } double extent = max - min; MITK_DEBUG << "EXTENT = " << extent; mitk::Point3D origin; mitk::Vector3D right, bottom, normal; double factor = 1000.0; mitk::FillVector3D(origin, cog[0]-factor*axes[1][0]-factor*axes[2][0], cog[1]-factor*axes[1][1]-factor*axes[2][1], cog[2]-factor*axes[1][2]-factor*axes[2][2]); // mitk::FillVector3D(normal, axis[0][0],axis[0][1],axis[0][2]); mitk::FillVector3D(bottom, 2*factor*axes[1][0], 2*factor*axes[1][1], 2*factor*axes[1][2]); mitk::FillVector3D(right, 2*factor*axes[2][0], 2*factor*axes[2][1], 2*factor*axes[2][2]); mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); planegeometry->InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector()); planegeometry->SetOrigin(origin); double len1 = sqrt(axes[1][0]*axes[1][0] + axes[1][1]*axes[1][1] + axes[1][2]*axes[1][2]); double len2 = sqrt(axes[2][0]*axes[2][0] + axes[2][1]*axes[2][1] + axes[2][2]*axes[2][2]); mitk::Point2D point1; point1[0] = factor*len1; point1[1] = factor*len2; mitk::Point2D point2; point2[0] = factor*len1+extent*.5; point2[1] = factor*len2; mitk::PlanarCircle::Pointer circle = mitk::PlanarCircle::New(); circle->SetPlaneGeometry(planegeometry); circle->PlaceFigure( point1 ); circle->SetControlPoint(0,point1); circle->SetControlPoint(1,point2); //circle->SetCurrentControlPoint( point2 ); mitk::PlanarFigure::PolyLineType polyline = circle->GetPolyLine( 0 ); MITK_DEBUG << "SIZE of planar figure polyline: " << polyline.size(); AddFigureToDataStorage(circle, "Circle"); } bool QmitkPartialVolumeAnalysisView::AssertDrawingIsPossible(bool checked) { if (m_SelectedImageNodes->GetNode().IsNull()) { checked = false; this->HandleException("Please select an image!", dynamic_cast(this->parent()), true); return false; } //this->GetRenderWindowPart(OPEN)->EnableSlicingPlanes(false); return checked; } void QmitkPartialVolumeAnalysisView::ActionDrawEllipseTriggered() { bool checked = m_Controls->m_CircleButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); // using PV_ prefix for planar figures from this view // to distinguish them from that ones created throught the measurement view this->AddFigureToDataStorage(figure, QString("PV_Circle%1").arg(++m_EllipseCounter)); MITK_DEBUG << "PlanarCircle created ..."; } void QmitkPartialVolumeAnalysisView::ActionDrawRectangleTriggered() { bool checked = m_Controls->m_RectangleButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarRectangle::Pointer figure = mitk::PlanarRectangle::New(); // using PV_ prefix for planar figures from this view // to distinguish them from that ones created throught the measurement view this->AddFigureToDataStorage(figure, QString("PV_Rectangle%1").arg(++m_RectangleCounter)); MITK_DEBUG << "PlanarRectangle created ..."; } void QmitkPartialVolumeAnalysisView::ActionDrawPolygonTriggered() { bool checked = m_Controls->m_PolygonButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); // using PV_ prefix for planar figures from this view // to distinguish them from that ones created throught the measurement view this->AddFigureToDataStorage(figure, QString("PV_Polygon%1").arg(++m_PolygonCounter)); MITK_DEBUG << "PlanarPolygon created ..."; } void QmitkPartialVolumeAnalysisView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey, mitk::BaseProperty *property ) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); // Add custom property, if available if ( (propertyKey != NULL) && (property != NULL) ) { newNode->AddProperty( propertyKey, property ); } // figure drawn on the topmost layer / image this->GetDataStorage()->Add(newNode, m_SelectedImageNodes->GetNode() ); QList selectedNodes = this->GetDataManagerSelection(); for(unsigned int i = 0; i < selectedNodes.size(); i++) { selectedNodes[i]->SetSelected(false); } std::vector selectedPFNodes = m_SelectedPlanarFigureNodes->GetNodes(); for(unsigned int i = 0; i < selectedPFNodes.size(); i++) { selectedPFNodes[i]->SetSelected(false); } newNode->SetSelected(true); Select(newNode); } void QmitkPartialVolumeAnalysisView::PlanarFigureInitialized() { if(m_SelectedPlanarFigureNodes->GetNode().IsNull()) return; m_CurrentFigureNodeInitialized = true; this->Select(m_SelectedPlanarFigureNodes->GetNode()); m_Controls->m_CircleButton->setChecked(false); m_Controls->m_RectangleButton->setChecked(false); m_Controls->m_PolygonButton->setChecked(false); //this->GetRenderWindowPart(OPEN)->EnableSlicingPlanes(true); this->RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::PlanarFigureFocus(mitk::DataNode* node) { mitk::PlanarFigure* _PlanarFigure = 0; _PlanarFigure = dynamic_cast (node->GetData()); if (_PlanarFigure) { FindRenderWindow(node); const mitk::PlaneGeometry* _PlaneGeometry = _PlanarFigure->GetPlaneGeometry(); // make node visible if (m_SelectedRenderWindow) { mitk::Point3D centerP = _PlaneGeometry->GetOrigin(); m_SelectedRenderWindow->GetSliceNavigationController()->ReorientSlices( centerP, _PlaneGeometry->GetNormal()); m_SelectedRenderWindow->GetSliceNavigationController()->SelectSliceByPoint( centerP); } } } void QmitkPartialVolumeAnalysisView::FindRenderWindow(mitk::DataNode* node) { if (node && dynamic_cast (node->GetData())) { m_SelectedRenderWindow = 0; bool PlanarFigureInitializedWindow = false; foreach(QmitkRenderWindow * window, this->GetRenderWindowPart()->GetQmitkRenderWindows().values()) { if (!m_SelectedRenderWindow && node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, window->GetRenderer())) { m_SelectedRenderWindow = window; } } } } void QmitkPartialVolumeAnalysisView::OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) { m_Controls->m_InputData->setTitle("Please Select Input Data"); if (!m_Visible) return; if ( nodes.empty() ) { if (m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } Select(NULL, true, true); } for (int i=0; iRemoveOrphanImages(); bool somethingChanged = false; if(node.IsNull()) { somethingChanged = true; if(clearMaskOnFirstArgNULL) { if ( (m_SelectedImageMask.IsNotNull()) && (m_ImageMaskObserverTag >= 0) ) { m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); m_ImageMaskObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_PlanarFigureObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_PlanarFigureObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_InitializedObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); m_InitializedObserverTag = -1; } m_SelectedPlanarFigure = NULL; m_SelectedPlanarFigureNodes->RemoveAllNodes(); m_CurrentFigureNodeInitialized = false; m_SelectedRenderWindow = 0; m_SelectedMaskNode = NULL; m_SelectedImageMask = NULL; } if(clearImageOnFirstArgNULL) { if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } m_SelectedImageNodes->RemoveAllNodes(); m_SelectedImage = NULL; m_IsTensorImage = false; m_FAImage = NULL; m_RDImage = NULL; m_ADImage = NULL; m_MDImage = NULL; m_CAImage = NULL; m_DirectionComp1Image = NULL; m_DirectionComp2Image = NULL; m_AngularErrorImage = NULL; m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); } } else { typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer changeListener; changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::RequestStatisticsUpdate ); // Get selected element mitk::TensorImage *selectedTensorImage = dynamic_cast< mitk::TensorImage * >( node->GetData() ); mitk::Image *selectedImage = dynamic_cast< mitk::Image * >( node->GetData() ); mitk::PlanarFigure *selectedPlanar = dynamic_cast< mitk::PlanarFigure * >( node->GetData() ); bool isMask = false; bool isImage = false; bool isPlanar = false; bool isTensorImage = false; if (selectedTensorImage != NULL) { isTensorImage = true; } else if(selectedImage != NULL) { node->GetPropertyValue("binary", isMask); isImage = !isMask; } else if ( (selectedPlanar != NULL) ) { isPlanar = true; } // image if(isImage && selectedImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } *m_SelectedImageNodes = node; m_SelectedImage = selectedImage; m_IsTensorImage = false; m_FAImage = NULL; m_RDImage = NULL; m_ADImage = NULL; m_MDImage = NULL; m_CAImage = NULL; m_DirectionComp1Image = NULL; m_DirectionComp2Image = NULL; m_AngularErrorImage = NULL; // Add change listeners to selected objects m_ImageObserverTag = m_SelectedImage->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); m_Controls->m_SelectedImageLabel->setText( m_SelectedImageNodes->GetNode()->GetName().c_str() ); } } //planar if(isPlanar) { if(selectedPlanar != m_SelectedPlanarFigure.GetPointer()) { MITK_DEBUG << "Planar selection changed"; somethingChanged = true; // Possibly previous change listeners if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_PlanarFigureObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_PlanarFigureObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_InitializedObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); m_InitializedObserverTag = -1; } m_SelectedPlanarFigure = selectedPlanar; *m_SelectedPlanarFigureNodes = node; m_CurrentFigureNodeInitialized = selectedPlanar->IsPlaced(); m_SelectedMaskNode = NULL; m_SelectedImageMask = NULL; m_PlanarFigureObserverTag = m_SelectedPlanarFigure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), changeListener ); if(!m_CurrentFigureNodeInitialized) { typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer initializationCommand; initializationCommand = ITKCommandType::New(); // set the callback function of the member command initializationCommand->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::PlanarFigureInitialized ); // add an observer m_InitializedObserverTag = selectedPlanar->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); } m_Controls->m_SelectedMaskLabel->setText( m_SelectedPlanarFigureNodes->GetNode()->GetName().c_str() ); PlanarFigureFocus(node); } } //mask this->m_Controls->m_EstimateCircle->setEnabled(isMask && selectedImage->GetDimension()==3); if(isMask && selectedImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImageMask.IsNotNull()) && (m_ImageMaskObserverTag >= 0) ) { m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); m_ImageMaskObserverTag = -1; } m_SelectedMaskNode = node; m_SelectedImageMask = selectedImage; m_SelectedPlanarFigure = NULL; m_SelectedPlanarFigureNodes->RemoveAllNodes(); m_ImageMaskObserverTag = m_SelectedImageMask->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SelectedMaskLabel->setText( m_SelectedMaskNode->GetName().c_str() ); } } //tensor image if(isTensorImage && selectedTensorImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } *m_SelectedImageNodes = node; m_SelectedImage = selectedImage; m_IsTensorImage = true; ExtractTensorImages(selectedImage); // Add change listeners to selected objects m_ImageObserverTag = m_SelectedImage->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SimilarAnglesFrame->setVisible(true); m_Controls->m_SimilarAnglesLabel->setVisible(true); m_Controls->m_SelectedImageLabel->setText( m_SelectedImageNodes->GetNode()->GetName().c_str() ); } } } if(somethingChanged) { this->SetMeasurementInfoToRenderWindow(""); if(m_SelectedPlanarFigure.IsNull() && m_SelectedImageMask.IsNull() ) { m_Controls->m_SelectedMaskLabel->setText("mandatory"); m_Controls->m_ResampleOptionsFrame->setEnabled(false); m_Controls->m_HistogramWidget->setEnabled(false); m_Controls->m_ClassSelector->setEnabled(false); m_Controls->m_DisplayHistogramCheckbox->setEnabled(false); m_Controls->m_AdvancedCheckbox->setEnabled(false); m_Controls->frame_7->setEnabled(false); } else { m_Controls->m_ResampleOptionsFrame->setEnabled(true); m_Controls->m_HistogramWidget->setEnabled(true); m_Controls->m_ClassSelector->setEnabled(true); m_Controls->m_DisplayHistogramCheckbox->setEnabled(true); m_Controls->m_AdvancedCheckbox->setEnabled(true); m_Controls->frame_7->setEnabled(true); } // Clear statistics / histogram GUI if nothing is selected if ( m_SelectedImage.IsNull() ) { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_OpacityFrame->setEnabled(false); m_Controls->m_SelectedImageLabel->setText("mandatory"); } else { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); m_Controls->m_OpacityFrame->setEnabled(true); } if( !m_Visible || m_SelectedImage.IsNull() || (m_SelectedPlanarFigure.IsNull() && m_SelectedImageMask.IsNull()) ) { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; } else { m_Controls->m_InputData->setTitle("Input Data"); this->RequestStatisticsUpdate(); } } } void QmitkPartialVolumeAnalysisView::ShowClusteringResults() { typedef itk::Image MaskImageType; mitk::Image::Pointer mask = 0; MaskImageType::Pointer itkmask = 0; if(m_IsTensorImage && m_Controls->m_SimilarAnglesSlider->value() != 0) { typedef itk::Image AngularErrorImageType; typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(m_AngularErrorImage); caster->Update(); typedef itk::BinaryThresholdImageFilter< AngularErrorImageType, MaskImageType > ThreshType; ThreshType::Pointer thresh = ThreshType::New(); thresh->SetUpperThreshold((90-m_Controls->m_SimilarAnglesSlider->value())*(PVA_PI/180.0)); thresh->SetInsideValue(1.0); thresh->SetInput(caster->GetOutput()); thresh->Update(); itkmask = thresh->GetOutput(); mask = mitk::Image::New(); mask->InitializeByItk(itkmask.GetPointer()); mask->SetVolume(itkmask->GetBufferPointer()); // GetDataStorage()->Remove(m_newnode); // m_newnode = mitk::DataNode::New(); // m_newnode->SetData(mask); // m_newnode->SetName("masking node"); // m_newnode->SetIntProperty( "layer", 1002 ); // GetDataStorage()->Add(m_newnode, m_SelectedImageNodes->GetNode()); } mitk::Image::Pointer clusteredImage; ClusteringType::Pointer clusterer = ClusteringType::New(); if(m_QuantifyClass==3) { if(m_IsTensorImage) { double *green_fa, *green_rd, *green_ad, *green_md; //double *greengray_fa, *greengray_rd, *greengray_ad, *greengray_md; double *gray_fa, *gray_rd, *gray_ad, *gray_md; //double *redgray_fa, *redgray_rd, *redgray_ad, *redgray_md; double *red_fa, *red_rd, *red_ad, *red_md; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(0); mitk::Image::ConstPointer imgToCluster = tmpImg; red_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(3); mitk::Image::ConstPointer imgToCluster3 = tmpImg; red_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(4); mitk::Image::ConstPointer imgToCluster4 = tmpImg; red_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(5); mitk::Image::ConstPointer imgToCluster5 = tmpImg; red_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->b, mask); // clipboard QString clipboardText("FA\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText = clipboardText .arg(red_fa[0]).arg(red_fa[1]) .arg(gray_fa[0]).arg(gray_fa[1]) .arg(green_fa[0]).arg(green_fa[1]); QString clipboardText3("RD\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText3 = clipboardText3 .arg(red_rd[0]).arg(red_rd[1]) .arg(gray_rd[0]).arg(gray_rd[1]) .arg(green_rd[0]).arg(green_rd[1]); QString clipboardText4("AD\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText4 = clipboardText4 .arg(red_ad[0]).arg(red_ad[1]) .arg(gray_ad[0]).arg(gray_ad[1]) .arg(green_ad[0]).arg(green_ad[1]); QString clipboardText5("MD\t%1\t%2\t\t%3\t%4\t\t%5\t%6"); clipboardText5 = clipboardText5 .arg(red_md[0]).arg(red_md[1]) .arg(gray_md[0]).arg(gray_md[1]) .arg(green_md[0]).arg(green_md[1]); QApplication::clipboard()->setText(clipboardText+clipboardText3+clipboardText4+clipboardText5, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("%1 %2 %3 \n"); plainInfoText = plainInfoText .arg("Red ", 20) .arg("Gray ", 20) .arg("Green", 20); QString plainInfoText0("FA:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText0 = plainInfoText0 .arg(red_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(red_fa[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(gray_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(gray_fa[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(green_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(green_fa[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText3("RDx10³:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText3 = plainInfoText3 .arg(1000.0 * red_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_rd[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_rd[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_rd[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText4("ADx10³:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText4 = plainInfoText4 .arg(1000.0 * red_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_ad[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_ad[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_ad[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText5("MDx10³:%1 ± %2%3 ± %4%5 ± %6"); plainInfoText5 = plainInfoText5 .arg(1000.0 * red_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_md[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_md[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_md[1], -10, 'g', 2, QLatin1Char( ' ' )); this->SetMeasurementInfoToRenderWindow(plainInfoText+plainInfoText0+plainInfoText3+plainInfoText4+plainInfoText5); } else { double* green; double* gray; double* red; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; red = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->r); green = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->g); gray = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->b); // clipboard QString clipboardText("%1\t%2\t\t%3\t%4\t\t%5\t%6"); clipboardText = clipboardText.arg(red[0]).arg(red[1]) .arg(gray[0]).arg(gray[1]) .arg(green[0]).arg(green[1]); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("Red: %1 ± %2\nGray: %3 ± %4\nGreen: %5 ± %6"); plainInfoText = plainInfoText.arg(red[0]).arg(red[1]) .arg(gray[0]).arg(gray[1]) .arg(green[0]).arg(green[1]); this->SetMeasurementInfoToRenderWindow(plainInfoText); } clusteredImage = m_CurrentRGBClusteringResults->rgb; } else { if(m_IsTensorImage) { double *red_fa, *red_rd, *red_ad, *red_md; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(0); mitk::Image::ConstPointer imgToCluster = tmpImg; red_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(3); mitk::Image::ConstPointer imgToCluster3 = tmpImg; red_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(4); mitk::Image::ConstPointer imgToCluster4 = tmpImg; red_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(5); mitk::Image::ConstPointer imgToCluster5 = tmpImg; red_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentPerformClusteringResults->clusteredImage, mask); // clipboard QString clipboardText("FA\t%1\t%2\t"); clipboardText = clipboardText .arg(red_fa[0]).arg(red_fa[1]); QString clipboardText3("RD\t%1\t%2\t"); clipboardText3 = clipboardText3 .arg(red_rd[0]).arg(red_rd[1]); QString clipboardText4("AD\t%1\t%2\t"); clipboardText4 = clipboardText4 .arg(red_ad[0]).arg(red_ad[1]); QString clipboardText5("MD\t%1\t%2\t"); clipboardText5 = clipboardText5 .arg(red_md[0]).arg(red_md[1]); QApplication::clipboard()->setText(clipboardText+clipboardText3+clipboardText4+clipboardText5, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("%1 \n"); plainInfoText = plainInfoText .arg("Red ", 20); QString plainInfoText0("FA:%1 ± %2\n"); plainInfoText0 = plainInfoText0 .arg(red_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(red_fa[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText3("RDx10³:%1 ± %2\n"); plainInfoText3 = plainInfoText3 .arg(1000.0 * red_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_rd[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText4("ADx10³:%1 ± %2\n"); plainInfoText4 = plainInfoText4 .arg(1000.0 * red_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_ad[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText5("MDx10³:%1 ± %2"); plainInfoText5 = plainInfoText5 .arg(1000.0 * red_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_md[1], -10, 'g', 2, QLatin1Char( ' ' )); this->SetMeasurementInfoToRenderWindow(plainInfoText+plainInfoText0+plainInfoText3+plainInfoText4+plainInfoText5); } else { double* quant; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; quant = clusterer->PerformQuantification(imgToCluster, m_CurrentPerformClusteringResults->clusteredImage); // clipboard QString clipboardText("%1\t%2"); clipboardText = clipboardText.arg(quant[0]).arg(quant[1]); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("Measurement: %1 ± %2"); plainInfoText = plainInfoText.arg(quant[0]).arg(quant[1]); this->SetMeasurementInfoToRenderWindow(plainInfoText); } clusteredImage = m_CurrentPerformClusteringResults->displayImage; } if(mask.IsNotNull()) { typedef itk::Image,3> RGBImageType; typedef mitk::ImageToItk ClusterCasterType; ClusterCasterType::Pointer clCaster = ClusterCasterType::New(); clCaster->SetInput(clusteredImage); clCaster->Update(); clCaster->GetOutput(); typedef itk::MaskImageFilter< RGBImageType, MaskImageType, RGBImageType > MaskType; MaskType::Pointer masker = MaskType::New(); masker->SetInput1(clCaster->GetOutput()); masker->SetInput2(itkmask); masker->Update(); clusteredImage = mitk::Image::New(); clusteredImage->InitializeByItk(masker->GetOutput()); clusteredImage->SetVolume(masker->GetOutput()->GetBufferPointer()); } if(m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); } m_ClusteringResult = mitk::DataNode::New(); m_ClusteringResult->SetBoolProperty("helper object", true); m_ClusteringResult->SetIntProperty( "layer", 1000 ); m_ClusteringResult->SetBoolProperty("texture interpolation", m_TexIsOn); m_ClusteringResult->SetData(clusteredImage); m_ClusteringResult->SetName("Clusterprobs"); this->GetDataStorage()->Add(m_ClusteringResult, m_SelectedImageNodes->GetNode()); if(m_SelectedPlanarFigure.IsNotNull() && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { m_SelectedPlanarFigureNodes->GetNode()->SetIntProperty( "layer", 1001 ); } this->RequestRenderWindowUpdate(); } void QmitkPartialVolumeAnalysisView::UpdateStatistics() { if(!m_CurrentFigureNodeInitialized && m_SelectedPlanarFigure.IsNotNull()) { MITK_DEBUG << "Selected planar figure not initialized. No stats calculation performed."; return; } // Remove any cached images that are no longer referenced elsewhere this->RemoveOrphanImages(); if ( m_SelectedImage.IsNotNull() ) { // Check if a the selected image is a multi-channel image. If yes, statistics // cannot be calculated currently. if ( !m_IsTensorImage && m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 ) { QMessageBox::information( NULL, "Warning", "Non-tensor multi-component images not supported."); m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; return; } m_CurrentStatisticsCalculator = NULL; if(!m_IsTensorImage) { // Retrieve HistogramStatisticsCalculator from has map (or create a new one // for this image if non-existant) PartialVolumeAnalysisMapType::iterator it = m_PartialVolumeAnalysisMap.find( m_SelectedImage ); if ( it != m_PartialVolumeAnalysisMap.end() ) { m_CurrentStatisticsCalculator = it->second; } } if(m_CurrentStatisticsCalculator.IsNull()) { m_CurrentStatisticsCalculator = mitk::PartialVolumeAnalysisHistogramCalculator::New(); m_CurrentStatisticsCalculator->SetPlanarFigureThickness(m_Controls->m_PlanarFiguresThickness->value()); if(m_IsTensorImage) { m_CurrentStatisticsCalculator->SetImage( m_CAImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_FAImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_DirectionComp1Image ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_DirectionComp2Image ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_RDImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_ADImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_MDImage ); } else { m_CurrentStatisticsCalculator->SetImage( m_SelectedImage ); } m_PartialVolumeAnalysisMap[m_SelectedImage] = m_CurrentStatisticsCalculator; MITK_DEBUG << "Creating StatisticsCalculator"; } std::string maskName; std::string maskType; unsigned int maskDimension; if ( m_SelectedImageMask.IsNotNull() ) { mitk::PixelType pixelType = m_SelectedImageMask->GetPixelType(); MITK_DEBUG << pixelType.GetPixelTypeAsString(); if(pixelType.GetComponentTypeAsString() == "char") { MITK_DEBUG << "Pixel type is char instead of uchar"; return; } if(pixelType.GetBitsPerComponent() == 16) { //convert from ushort to uchar typedef itk::Image UCharImageType; UCharImageType::Pointer charImage; if(pixelType.GetComponentTypeAsString() == "short" ) { typedef itk::Image ShortImageType; ShortImageType::Pointer shortImage; mitk::CastToItkImage( m_SelectedImageMask, shortImage ); typedef itk::ImageDuplicator< ShortImageType > DuplicatorType; DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage( shortImage ); duplicator->Update(); typedef itk::CastImageFilter ImageCasterType; ImageCasterType::Pointer caster = ImageCasterType::New(); caster->SetInput( duplicator->GetOutput() ); caster->Update(); charImage = caster->GetOutput(); } else { typedef itk::Image UShortImageType; UShortImageType::Pointer shortImage; mitk::CastToItkImage( m_SelectedImageMask, shortImage ); typedef itk::ImageDuplicator< UShortImageType > DuplicatorType; DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage( shortImage ); duplicator->Update(); typedef itk::CastImageFilter ImageCasterType; ImageCasterType::Pointer caster = ImageCasterType::New(); caster->SetInput( duplicator->GetOutput() ); caster->Update(); charImage = caster->GetOutput(); } m_SelectedImageMask = nullptr; m_SelectedImageMask = mitk::Image::New(); m_SelectedImageMask->InitializeByItk( charImage.GetPointer() ); m_SelectedImageMask->SetVolume( charImage->GetBufferPointer() ); mitk::CastToMitkImage(charImage, m_SelectedImageMask); } m_CurrentStatisticsCalculator->SetImageMask( m_SelectedImageMask ); m_CurrentStatisticsCalculator->SetMaskingModeToImage(); maskName = m_SelectedMaskNode->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); maskDimension = 3; std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); } else if ( m_SelectedPlanarFigure.IsNotNull() && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { m_CurrentStatisticsCalculator->SetPlanarFigure( m_SelectedPlanarFigure ); m_CurrentStatisticsCalculator->SetMaskingModeToPlanarFigure(); maskName = m_SelectedPlanarFigureNodes->GetNode()->GetName(); maskType = m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; } else { m_CurrentStatisticsCalculator->SetMaskingModeToNone(); maskName = "-"; maskType = ""; maskDimension = 0; } bool statisticsChanged = false; bool statisticsCalculationSuccessful = false; // Initialize progress bar mitk::ProgressBar::GetInstance()->AddStepsToDo( 100 ); // Install listener for progress events and initialize progress bar typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer progressListener; progressListener = ITKCommandType::New(); progressListener->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::UpdateProgressBar ); unsigned long progressObserverTag = m_CurrentStatisticsCalculator ->AddObserver( itk::ProgressEvent(), progressListener ); ClusteringType::ParamsType *cparams = 0; ClusteringType::ClusterResultType *cresult = 0; ClusteringType::HistType *chist = 0; try { m_CurrentStatisticsCalculator->SetNumberOfBins(m_Controls->m_NumberBins->text().toInt()); m_CurrentStatisticsCalculator->SetUpsamplingFactor(m_Controls->m_Upsampling->text().toDouble()); m_CurrentStatisticsCalculator->SetGaussianSigma(m_Controls->m_GaussianSigma->text().toDouble()); // Compute statistics statisticsChanged = m_CurrentStatisticsCalculator->ComputeStatistics( ); mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; if(imgToCluster.IsNotNull()) { // perform clustering const HistogramType *histogram = m_CurrentStatisticsCalculator->GetHistogram( ); if(histogram != NULL) { ClusteringType::Pointer clusterer = ClusteringType::New(); clusterer->SetStepsNumIntegration(200); clusterer->SetMaxIt(1000); mitk::Image::Pointer pFiberImg; if(m_QuantifyClass==3) { if(m_Controls->m_Quantiles->isChecked()) { m_CurrentRGBClusteringResults = clusterer->PerformRGBQuantiles(imgToCluster, histogram, m_Controls->m_q1->value(),m_Controls->m_q2->value()); } else { m_CurrentRGBClusteringResults = clusterer->PerformRGBClustering(imgToCluster, histogram); } pFiberImg = m_CurrentRGBClusteringResults->rgbChannels->r; cparams = m_CurrentRGBClusteringResults->params; cresult = m_CurrentRGBClusteringResults->result; chist = m_CurrentRGBClusteringResults->hist; } else { if(m_Controls->m_Quantiles->isChecked()) { m_CurrentPerformClusteringResults = clusterer->PerformQuantiles(imgToCluster, histogram, m_Controls->m_q1->value(),m_Controls->m_q2->value()); } else { m_CurrentPerformClusteringResults = clusterer->PerformClustering(imgToCluster, histogram, m_QuantifyClass); } pFiberImg = m_CurrentPerformClusteringResults->clusteredImage; cparams = m_CurrentPerformClusteringResults->params; cresult = m_CurrentPerformClusteringResults->result; chist = m_CurrentPerformClusteringResults->hist; } if(m_IsTensorImage) { m_AngularErrorImage = clusterer->CaculateAngularErrorImage( m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(1), m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(2), pFiberImg); // GetDataStorage()->Remove(m_newnode2); // m_newnode2 = mitk::DataNode::New(); // m_newnode2->SetData(m_AngularErrorImage); // m_newnode2->SetName(("AngularError")); // m_newnode2->SetIntProperty( "layer", 1003 ); // GetDataStorage()->Add(m_newnode2, m_SelectedImageNodes->GetNode()); // newnode = mitk::DataNode::New(); // newnode->SetData(m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(1)); // newnode->SetName(("Comp1")); // GetDataStorage()->Add(newnode, m_SelectedImageNodes->GetNode()); // newnode = mitk::DataNode::New(); // newnode->SetData(m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(2)); // newnode->SetName(("Comp2")); // GetDataStorage()->Add(newnode, m_SelectedImageNodes->GetNode()); } ShowClusteringResults(); } } statisticsCalculationSuccessful = true; } catch ( const std::runtime_error &e ) { QMessageBox::information( NULL, "Warning", e.what()); } catch ( const std::exception &e ) { MITK_ERROR << "Caught exception: " << e.what(); QMessageBox::information( NULL, "Warning", e.what()); } m_CurrentStatisticsCalculator->RemoveObserver( progressObserverTag ); // Make sure that progress bar closes mitk::ProgressBar::GetInstance()->Progress( 100 ); if ( statisticsCalculationSuccessful ) { if ( statisticsChanged ) { // Do not show any error messages m_CurrentStatisticsValid = true; } // m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); m_Controls->m_HistogramWidget->SetParameters( cparams, cresult, chist ); // m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); } else { m_Controls->m_SelectedMaskLabel->setText("mandatory"); // Clear statistics and histogram m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; // If a (non-closed) PlanarFigure is selected, display a line profile widget if ( m_SelectedPlanarFigure.IsNotNull() ) { // TODO: enable line profile widget //m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 1 ); //m_Controls->m_LineProfileWidget->SetImage( m_SelectedImage ); //m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); //m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); } } } } void QmitkPartialVolumeAnalysisView::SetMeasurementInfoToRenderWindow(const QString& text) { FindRenderWindow(m_SelectedPlanarFigureNodes->GetNode()); if(m_LastRenderWindow != m_SelectedRenderWindow) { if(m_LastRenderWindow) { QObject::disconnect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) , this, SLOT( OnRenderWindowDelete(QObject*) ) ); } m_LastRenderWindow = m_SelectedRenderWindow; if(m_LastRenderWindow) { QObject::connect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) , this, SLOT( OnRenderWindowDelete(QObject*) ) ); } } if(m_LastRenderWindow && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { if (!text.isEmpty()) { m_MeasurementInfoAnnotation->SetText(1, text.toLatin1().data()); mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->InsertForegroundRenderer( m_MeasurementInfoRenderer, true); } else { if (mitk::VtkLayerController::GetInstance( m_LastRenderWindow->GetRenderWindow()) ->IsRendererInserted( m_MeasurementInfoRenderer)) mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->RemoveRenderer( m_MeasurementInfoRenderer); } } else { mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); if ( renderWindowPart == nullptr ) { return; } if (!text.isEmpty()) { m_MeasurementInfoAnnotation->SetText(1, text.toLatin1().data()); mitk::VtkLayerController::GetInstance(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderWindow())->InsertForegroundRenderer( m_MeasurementInfoRenderer, true); } else { if (mitk::VtkLayerController::GetInstance( renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderWindow()) ->IsRendererInserted( m_MeasurementInfoRenderer)) mitk::VtkLayerController::GetInstance(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderWindow())->RemoveRenderer( m_MeasurementInfoRenderer); } } } void QmitkPartialVolumeAnalysisView::UpdateProgressBar() { mitk::ProgressBar::GetInstance()->Progress(); } void QmitkPartialVolumeAnalysisView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { QApplication::postEvent( this, new QmitkRequestStatisticsUpdateEvent ); m_StatisticsUpdatePending = true; } } void QmitkPartialVolumeAnalysisView::RemoveOrphanImages() { PartialVolumeAnalysisMapType::iterator it = m_PartialVolumeAnalysisMap.begin(); while ( it != m_PartialVolumeAnalysisMap.end() ) { mitk::Image *image = it->first; mitk::PartialVolumeAnalysisHistogramCalculator *calculator = it->second; ++it; mitk::NodePredicateData::Pointer hasImage = mitk::NodePredicateData::New( image ); if ( this->GetDataStorage()->GetNode( hasImage ) == NULL ) { if ( m_SelectedImage == image ) { m_SelectedImage = NULL; m_SelectedImageNodes->RemoveAllNodes(); } if ( m_CurrentStatisticsCalculator == calculator ) { m_CurrentStatisticsCalculator = NULL; } m_PartialVolumeAnalysisMap.erase( image ); it = m_PartialVolumeAnalysisMap.begin(); } } } void QmitkPartialVolumeAnalysisView::ExtractTensorImages( mitk::Image::Pointer tensorimage) { typedef itk::Image< itk::DiffusionTensor3D, 3> TensorImageType; typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(tensorimage); caster->Update(); TensorImageType::Pointer image = caster->GetOutput(); typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer fa = measurementsCalculator->GetOutput(); m_FAImage = mitk::Image::New(); m_FAImage->InitializeByItk(fa.GetPointer()); m_FAImage->SetVolume(fa->GetBufferPointer()); // mitk::DataNode::Pointer node = mitk::DataNode::New(); // node->SetData(m_FAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::CA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer ca = measurementsCalculator->GetOutput(); m_CAImage = mitk::Image::New(); m_CAImage->InitializeByItk(ca.GetPointer()); m_CAImage->SetVolume(ca->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::RD); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer rd = measurementsCalculator->GetOutput(); m_RDImage = mitk::Image::New(); m_RDImage->InitializeByItk(rd.GetPointer()); m_RDImage->SetVolume(rd->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::AD); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer ad = measurementsCalculator->GetOutput(); m_ADImage = mitk::Image::New(); m_ADImage->InitializeByItk(ad.GetPointer()); m_ADImage->SetVolume(ad->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::RA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer md = measurementsCalculator->GetOutput(); m_MDImage = mitk::Image::New(); m_MDImage->InitializeByItk(md.GetPointer()); m_MDImage->SetVolume(md->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDataStorage()->Add(node); - typedef DirectionsFilterType::OutputImageType DirImageType; + typedef DirectionsFilterType::PeakImageType DirImageType; DirectionsFilterType::Pointer dirFilter = DirectionsFilterType::New(); dirFilter->SetInput(image ); + dirFilter->SetUsePolarCoordinates(true); dirFilter->Update(); + ItkUcharImgType::Pointer numDirImage = dirFilter->GetOutput(); + DirImageType::Pointer dirImage = dirFilter->GetPeakImage(); - itk::ImageRegionIterator - itd(dirFilter->GetOutput(), dirFilter->GetOutput()->GetLargestPossibleRegion()); + itk::ImageRegionIterator itd(dirImage, dirImage->GetLargestPossibleRegion()); itd = itd.Begin(); while( !itd.IsAtEnd() ) { DirImageType::PixelType direction = itd.Get(); - direction[0] = fabs(direction[0]); - direction[1] = fabs(direction[1]); - direction[2] = fabs(direction[2]); + direction = fabs(direction); itd.Set(direction); ++itd; } - typedef itk::CartesianToPolarVectorImageFilter< - DirImageType, DirImageType, true> C2PFilterType; - C2PFilterType::Pointer cpFilter = C2PFilterType::New(); - cpFilter->SetInput(dirFilter->GetOutput()); - cpFilter->Update(); - DirImageType::Pointer dir = cpFilter->GetOutput(); - typedef itk::Image CompImageType; CompImageType::Pointer comp1 = CompImageType::New(); - comp1->SetSpacing( dir->GetSpacing() ); // Set the image spacing - comp1->SetOrigin( dir->GetOrigin() ); // Set the image origin - comp1->SetDirection( dir->GetDirection() ); // Set the image direction - comp1->SetRegions( dir->GetLargestPossibleRegion() ); + comp1->SetSpacing( numDirImage->GetSpacing() ); // Set the image spacing + comp1->SetOrigin( numDirImage->GetOrigin() ); // Set the image origin + comp1->SetDirection( numDirImage->GetDirection() ); // Set the image direction + comp1->SetRegions( numDirImage->GetLargestPossibleRegion() ); comp1->Allocate(); CompImageType::Pointer comp2 = CompImageType::New(); - comp2->SetSpacing( dir->GetSpacing() ); // Set the image spacing - comp2->SetOrigin( dir->GetOrigin() ); // Set the image origin - comp2->SetDirection( dir->GetDirection() ); // Set the image direction - comp2->SetRegions( dir->GetLargestPossibleRegion() ); + comp2->SetSpacing( numDirImage->GetSpacing() ); // Set the image spacing + comp2->SetOrigin( numDirImage->GetOrigin() ); // Set the image origin + comp2->SetDirection( numDirImage->GetDirection() ); // Set the image direction + comp2->SetRegions( numDirImage->GetLargestPossibleRegion() ); comp2->Allocate(); - itk::ImageRegionConstIterator - it(dir, dir->GetLargestPossibleRegion()); - - itk::ImageRegionIterator - it1(comp1, comp1->GetLargestPossibleRegion()); + itk::ImageRegionIterator it1(comp1, comp1->GetLargestPossibleRegion()); + itk::ImageRegionIterator it2(comp2, comp2->GetLargestPossibleRegion()); - itk::ImageRegionIterator - it2(comp2, comp2->GetLargestPossibleRegion()); - - it = it.Begin(); it1 = it1.Begin(); it2 = it2.Begin(); - while( !it.IsAtEnd() ) + while( !it2.IsAtEnd() ) { - it1.Set(it.Get()[1]); - it2.Set(it.Get()[2]); - ++it; + DirImageType::IndexType peakIndex; + peakIndex[0] = it1.GetIndex()[0]; + peakIndex[1] = it1.GetIndex()[1]; + peakIndex[2] = it1.GetIndex()[2]; + peakIndex[3] = 1; + + it1.Set(dirImage->GetPixel(peakIndex)); + peakIndex[3] = 2; + it2.Set(dirImage->GetPixel(peakIndex)); ++it1; ++it2; } m_DirectionComp1Image = mitk::Image::New(); m_DirectionComp1Image->InitializeByItk(comp1.GetPointer()); m_DirectionComp1Image->SetVolume(comp1->GetBufferPointer()); m_DirectionComp2Image = mitk::Image::New(); m_DirectionComp2Image->InitializeByItk(comp2.GetPointer()); m_DirectionComp2Image->SetVolume(comp2->GetBufferPointer()); } void QmitkPartialVolumeAnalysisView::OnRenderWindowDelete(QObject * obj) { if(obj == m_LastRenderWindow) m_LastRenderWindow = 0; if(obj == m_SelectedRenderWindow) m_SelectedRenderWindow = 0; } bool QmitkPartialVolumeAnalysisView::event( QEvent *event ) { if ( event->type() == (QEvent::Type) QmitkRequestStatisticsUpdateEvent::StatisticsUpdateRequest ) { // Update statistics m_StatisticsUpdatePending = false; this->UpdateStatistics(); return true; } return false; } void QmitkPartialVolumeAnalysisView::Activated() { mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigure* figure = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; // finally add all nodes to the model for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figure = dynamic_cast(node->GetData()); if(figure) { figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( node ); } } } } void QmitkPartialVolumeAnalysisView::Deactivated() { } void QmitkPartialVolumeAnalysisView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer reference) { this->SetMeasurementInfoToRenderWindow(""); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigure* figure = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; // finally add all nodes to the model for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figure = dynamic_cast(node->GetData()); if(figure) { figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor) figureInteractor->SetDataNode( NULL ); } } } void QmitkPartialVolumeAnalysisView::Hidden() { if (m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } Select(NULL, true, true); m_Visible = false; } void QmitkPartialVolumeAnalysisView::Visible() { m_Visible = true; berry::IWorkbenchPart::Pointer bla; if (!this->GetCurrentSelection().empty()) { this->OnSelectionChanged(bla, this->GetCurrentSelection()); } else { this->OnSelectionChanged(bla, this->GetDataManagerSelection()); } } void QmitkPartialVolumeAnalysisView::GreenRadio(bool checked) { if(checked) { m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 0; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::PartialVolumeRadio(bool checked) { if(checked) { m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 1; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::BlueRadio(bool checked) { if(checked) { m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 2; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::AllRadio(bool checked) { if(checked) { m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(false); } m_QuantifyClass = 3; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::NumberBinsChangedSlider(int v ) { m_Controls->m_NumberBins->setText(QString("%1").arg(m_Controls->m_NumberBinsSlider->value()*5.0)); } void QmitkPartialVolumeAnalysisView::UpsamplingChangedSlider( int v) { m_Controls->m_Upsampling->setText(QString("%1").arg(m_Controls->m_UpsamplingSlider->value()/10.0)); } void QmitkPartialVolumeAnalysisView::GaussianSigmaChangedSlider(int v ) { m_Controls->m_GaussianSigma->setText(QString("%1").arg(m_Controls->m_GaussianSigmaSlider->value()/100.0)); } void QmitkPartialVolumeAnalysisView::SimilarAnglesChangedSlider(int v ) { m_Controls->m_SimilarAngles->setText(QString("%1°").arg(90-m_Controls->m_SimilarAnglesSlider->value())); ShowClusteringResults(); } void QmitkPartialVolumeAnalysisView::OpacityChangedSlider(int v ) { if(m_SelectedImageNodes->GetNode().IsNotNull()) { float opacImag = 1.0f-(v-5)/5.0f; opacImag = opacImag < 0 ? 0 : opacImag; m_SelectedImageNodes->GetNode()->SetFloatProperty("opacity", opacImag); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } if(m_ClusteringResult.IsNotNull()) { float opacClust = v/5.0f; opacClust = opacClust > 1 ? 1 : opacClust; m_ClusteringResult->SetFloatProperty("opacity", opacClust); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkPartialVolumeAnalysisView::NumberBinsReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::UpsamplingReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::GaussianSigmaReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::SimilarAnglesReleasedSlider( ) { } void QmitkPartialVolumeAnalysisView::ToClipBoard() { std::vector* > vals = m_Controls->m_HistogramWidget->m_Vals; QString clipboardText; for (std::vector* >::iterator it = vals.begin(); it != vals.end(); ++it) { for (std::vector::iterator it2 = (**it).begin(); it2 != (**it).end(); ++it2) { clipboardText.append(QString("%1 \t").arg(*it2)); } clipboardText.append(QString("\n")); } QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); } void QmitkPartialVolumeAnalysisView::PropertyChanged(const mitk::DataNode* /*node*/, const mitk::BaseProperty* /*prop*/) { } void QmitkPartialVolumeAnalysisView::NodeChanged(const mitk::DataNode* /*node*/) { } void QmitkPartialVolumeAnalysisView::NodeRemoved(const mitk::DataNode* node) { if (dynamic_cast(node->GetData())) this->GetDataStorage()->Remove(m_ClusteringResult); if( node == m_SelectedPlanarFigureNodes->GetNode().GetPointer() || node == m_SelectedMaskNode.GetPointer() ) { this->Select(NULL,true,false); SetMeasurementInfoToRenderWindow(""); } if( node == m_SelectedImageNodes->GetNode().GetPointer() ) { this->Select(NULL,false,true); SetMeasurementInfoToRenderWindow(""); } } void QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage(const mitk::DataNode* node) { if(!m_Visible) return; mitk::DataNode* nonConstNode = const_cast(node); mitk::PlanarFigure* figure = dynamic_cast(nonConstNode->GetData()); if(figure) { // set interactor for new node (if not already set) mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( nonConstNode ); } // remove uninitialized old planars if( m_SelectedPlanarFigureNodes->GetNode().IsNotNull() && m_CurrentFigureNodeInitialized == false ) { this->GetDataStorage()->Remove(m_SelectedPlanarFigureNodes->GetNode()); } } } void QmitkPartialVolumeAnalysisView::TextIntON() { if(m_ClusteringResult.IsNotNull()) { if(m_TexIsOn) { m_Controls->m_TextureIntON->setIcon(*m_IconTexOFF); } else { m_Controls->m_TextureIntON->setIcon(*m_IconTexON); } m_ClusteringResult->SetBoolProperty("texture interpolation", !m_TexIsOn); m_TexIsOn = !m_TexIsOn; this->RequestRenderWindowUpdate(); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.h index 75b9d2443b..293fd5eeec 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisView.h @@ -1,272 +1,273 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #if !defined(QmitkPartialVolumeAnalysisView_H__INCLUDED) #define QmitkPartialVolumeAnalysisView_H__INCLUDED #include "ui_QmitkPartialVolumeAnalysisViewControls.h" #include #include #include // berry #include #include // itk #include #include #include // qmitk #include "QmitkStepperAdapter.h" #include "QmitkRenderWindow.h" // mitk #include "mitkPartialVolumeAnalysisHistogramCalculator.h" #include "mitkPlanarLine.h" #include #include "mitkDataStorageSelection.h" #include // vtk #include #include #include //#include "itkProcessObject.h" /*! \brief QmitkPartialVolumeAnalysis */ class QmitkPartialVolumeAnalysisView : public QmitkAbstractView, public mitk::IZombieViewPart//, public itk::ProcessObject { Q_OBJECT public: /*! \ Convenient typedefs */ - typedef mitk::DataStorage::SetOfObjects ConstVector; - typedef ConstVector::ConstPointer ConstVectorPointer; - typedef ConstVector::ConstIterator ConstVectorIterator; - typedef mitk::PartialVolumeAnalysisHistogramCalculator HistogramCalculatorType; - typedef HistogramCalculatorType::HistogramType HistogramType; - typedef mitk::PartialVolumeAnalysisClusteringCalculator ClusteringType; - typedef itk::DiffusionTensorPrincipalDirectionImageFilter DirectionsFilterType; + typedef mitk::DataStorage::SetOfObjects ConstVector; + typedef ConstVector::ConstPointer ConstVectorPointer; + typedef ConstVector::ConstIterator ConstVectorIterator; + typedef mitk::PartialVolumeAnalysisHistogramCalculator HistogramCalculatorType; + typedef HistogramCalculatorType::HistogramType HistogramType; + typedef mitk::PartialVolumeAnalysisClusteringCalculator ClusteringType; + typedef itk::DiffusionTensorPrincipalDirectionImageFilter DirectionsFilterType; + typedef itk::Image ItkUcharImgType; /*! \brief default constructor */ QmitkPartialVolumeAnalysisView(QObject *parent=0, const char *name=0); /*! \brief default destructor */ virtual ~QmitkPartialVolumeAnalysisView(); /*! \brief method for creating the widget containing the application controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget *parent) override; /*! \brief method for creating the connections of main and control widget */ virtual void CreateConnections(); virtual bool event( QEvent *event ) override; virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; virtual void Activated() override; virtual void Deactivated() override; virtual void ActivatedZombieView(berry::IWorkbenchPartReference::Pointer reference) override; virtual void Hidden() override; virtual void Visible() override; virtual void SetFocus() override; bool AssertDrawingIsPossible(bool checked); virtual void NodeChanged(const mitk::DataNode* node) override; virtual void PropertyChanged(const mitk::DataNode* node, const mitk::BaseProperty* prop); virtual void NodeRemoved(const mitk::DataNode* node) override; virtual void NodeAddedInDataStorage(const mitk::DataNode* node); virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); void PlanarFigureInitialized(); void PlanarFigureFocus(mitk::DataNode* node); void ShowClusteringResults(); static const std::string VIEW_ID; protected slots: void EstimateCircle(); void SetHistogramVisibility(); void SetAdvancedVisibility(); void NumberBinsChangedSlider(int v ); void UpsamplingChangedSlider( int v ); void GaussianSigmaChangedSlider( int v ); void SimilarAnglesChangedSlider(int v ); void OpacityChangedSlider(int v ); void NumberBinsReleasedSlider( ); void UpsamplingReleasedSlider( ); void GaussianSigmaReleasedSlider( ); void SimilarAnglesReleasedSlider( ); void ActionDrawEllipseTriggered(); void ActionDrawRectangleTriggered(); void ActionDrawPolygonTriggered(); void ToClipBoard(); void GreenRadio(bool checked); void PartialVolumeRadio(bool checked); void BlueRadio(bool checked); void AllRadio(bool checked); void OnRenderWindowDelete(QObject * obj); void TextIntON(); void ExportClusteringResults(); protected: /** \brief Issues a request to update statistics by sending an event to the * Qt event processing queue. * * Statistics update should only be executed after program execution returns * to the Qt main loop. This mechanism also prevents multiple execution of * updates where only one is required.*/ void RequestStatisticsUpdate(); /** \brief Recalculate statistics for currently selected image and mask and * update the GUI. */ void UpdateStatistics(); /** \brief Listener for progress events to update progress bar. */ void UpdateProgressBar(); /** \brief Removes any cached images which are no longer referenced elsewhere. */ void RemoveOrphanImages(); void Select( mitk::DataNode::Pointer node, bool clearMaskOnFirstArgNULL=false, bool clearImageOnFirstArgNULL=false ); void SetMeasurementInfoToRenderWindow(const QString& text); void FindRenderWindow(mitk::DataNode* node); void ExtractTensorImages( mitk::Image::Pointer tensorimage); typedef std::map< mitk::Image *, mitk::PartialVolumeAnalysisHistogramCalculator::Pointer > PartialVolumeAnalysisMapType; /*! * controls containing sliders for scrolling through the slices */ Ui::QmitkPartialVolumeAnalysisViewControls *m_Controls; QmitkStepperAdapter* m_TimeStepperAdapter; unsigned int m_CurrentTime; QString m_Clipboard; // result text rendering vtkRenderer * m_MeasurementInfoRenderer; vtkCornerAnnotation *m_MeasurementInfoAnnotation; // Image and mask data mitk::DataStorageSelection::Pointer m_SelectedImageNodes; mitk::Image::Pointer m_SelectedImage; mitk::DataNode::Pointer m_SelectedMaskNode; mitk::Image::Pointer m_SelectedImageMask; mitk::DataStorageSelection::Pointer m_SelectedPlanarFigureNodes; mitk::PlanarFigure::Pointer m_SelectedPlanarFigure; bool m_IsTensorImage; mitk::Image::Pointer m_FAImage; mitk::Image::Pointer m_CAImage; mitk::Image::Pointer m_RDImage; mitk::Image::Pointer m_ADImage; mitk::Image::Pointer m_MDImage; // mitk::Image::Pointer m_DirectionImage; mitk::Image::Pointer m_DirectionComp1Image; mitk::Image::Pointer m_DirectionComp2Image; mitk::Image::Pointer m_AngularErrorImage; QmitkRenderWindow* m_SelectedRenderWindow; QmitkRenderWindow* m_LastRenderWindow; long m_ImageObserverTag; long m_ImageMaskObserverTag; long m_PlanarFigureObserverTag; // Hash map for associating one image statistics calculator with each iamge // (so that previously calculated histograms / statistics can be recovered // if a recalculation is not required) PartialVolumeAnalysisMapType m_PartialVolumeAnalysisMap; HistogramCalculatorType::Pointer m_CurrentStatisticsCalculator; bool m_CurrentStatisticsValid; bool m_StatisticsUpdatePending; bool m_GaussianSigmaChangedSliding; bool m_NumberBinsSliding; bool m_UpsamplingChangedSliding; bool m_Visible; mitk::DataNode::Pointer m_ClusteringResult; int m_EllipseCounter; int m_RectangleCounter; int m_PolygonCounter; unsigned int m_InitializedObserverTag; bool m_CurrentFigureNodeInitialized; int m_QuantifyClass; ClusteringType::HelperStructPerformRGBClusteringRetval* m_CurrentRGBClusteringResults; ClusteringType::HelperStructPerformClusteringRetval *m_CurrentPerformClusteringResults; // mitk::DataNode::Pointer m_newnode; // mitk::DataNode::Pointer m_newnode2; QIcon* m_IconTexOFF; QIcon* m_IconTexON; bool m_TexIsOn; }; #endif // !defined(QmitkPartialVolumeAnalysis_H__INCLUDED) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp index 61c6f5ecfe..363710f564 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp @@ -1,408 +1,406 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include #include // Qmitk #include "QmitkStreamlineTrackingView.h" #include "QmitkStdMultiWidget.h" // Qt #include // MITK #include #include #include #include #include #include #include #include #include // VTK #include #include #include #include #include #include #include #include const std::string QmitkStreamlineTrackingView::VIEW_ID = "org.mitk.views.streamlinetracking"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; QmitkStreamlineTrackingView::QmitkStreamlineTrackingView() : m_Controls(nullptr) { } // 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 ); m_Controls->m_FaImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_SeedImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_StopImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TissueImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New( isBinaryPredicate ); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New( isImagePredicate, isNotBinaryPredicate ); mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); m_Controls->m_FaImageBox->SetPredicate( mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, dimensionPredicate) ); m_Controls->m_FaImageBox->SetZeroEntryText("--"); m_Controls->m_SeedImageBox->SetPredicate( mitk::NodePredicateAnd::New(isBinaryPredicate, dimensionPredicate) ); m_Controls->m_SeedImageBox->SetZeroEntryText("--"); m_Controls->m_MaskImageBox->SetPredicate( mitk::NodePredicateAnd::New(isBinaryPredicate, dimensionPredicate) ); m_Controls->m_MaskImageBox->SetZeroEntryText("--"); m_Controls->m_StopImageBox->SetPredicate( mitk::NodePredicateAnd::New(isBinaryPredicate, dimensionPredicate) ); m_Controls->m_StopImageBox->SetZeroEntryText("--"); m_Controls->m_TissueImageBox->SetPredicate( mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, dimensionPredicate) ); m_Controls->m_TissueImageBox->SetZeroEntryText("--"); connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); connect( m_Controls->m_TissueImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()) ); } UpdateGui(); } void QmitkStreamlineTrackingView::SetFocus() { } void QmitkStreamlineTrackingView::OnSelectionChanged( berry::IWorkbenchPart::Pointer part, const QList& nodes ) { m_InputImageNodes.clear(); m_InputImages.clear(); for( auto node : nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { if( dynamic_cast(node->GetData()) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); } else if ( dynamic_cast(node->GetData()) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); } else { mitk::Image* img = dynamic_cast(node->GetData()); if (img!=nullptr) { int dim = img->GetDimension(); unsigned int* dimensions = img->GetDimensions(); if (dim==4 && dimensions[3]%3==0) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); } } } } } UpdateGui(); } void QmitkStreamlineTrackingView::UpdateGui() { m_Controls->m_TensorImageLabel->setText("mandatory"); m_Controls->m_fBox->setVisible(false); m_Controls->m_fLabel->setVisible(false); m_Controls->m_gBox->setVisible(false); m_Controls->m_gLabel->setVisible(false); m_Controls->m_FaImageBox->setVisible(false); m_Controls->mFaImageLabel->setVisible(false); m_Controls->m_NormalizeODFsBox->setVisible(false); if (m_Controls->m_TissueImageBox->GetSelectedNode().IsNotNull()) m_Controls->m_SeedGmBox->setVisible(true); else m_Controls->m_SeedGmBox->setVisible(false); if(!m_InputImageNodes.empty()) { if (m_InputImageNodes.size()>1) m_Controls->m_TensorImageLabel->setText(m_InputImageNodes.size()+" images selected"); else m_Controls->m_TensorImageLabel->setText(m_InputImageNodes.at(0)->GetName().c_str()); m_Controls->m_InputData->setTitle("Input Data"); m_Controls->commandLinkButton->setEnabled(true); if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { m_Controls->m_fBox->setVisible(true); m_Controls->m_fLabel->setVisible(true); m_Controls->m_gBox->setVisible(true); m_Controls->m_gLabel->setVisible(true); m_Controls->mFaImageLabel->setVisible(true); m_Controls->m_FaImageBox->setVisible(true); if (m_Controls->m_ModeBox->currentIndex()==1) m_Controls->m_NormalizeODFsBox->setVisible(true); } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { m_Controls->mFaImageLabel->setVisible(true); m_Controls->m_FaImageBox->setVisible(true); m_Controls->m_NormalizeODFsBox->setVisible(true); } else { } } else { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->commandLinkButton->setEnabled(false); } } void QmitkStreamlineTrackingView::DoFiberTracking() { if (m_InputImages.empty()) return; mitk::TrackingDataHandler* trackingHandler; if( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { typedef itk::Image< itk::DiffusionTensor3D, 3> TensorImageType; typedef mitk::ImageToItk CasterType; if (m_Controls->m_ModeBox->currentIndex()==1) { if (m_InputImages.size()>1) { QMessageBox::information(nullptr, "Information", "Probabilistic tensor tractography is only implemented for single-tensor mode!"); return; } QMessageBox::information(nullptr, "Information", "Internally calculating ODF from tensor image and performing probabilistic ODF tractography. Please keep the state of the ODF normalization box (see advanced parameters) in mind. TEND parameters are ignored."); TensorImageType::Pointer itkImg = TensorImageType::New(); mitk::CastToItkImage(m_InputImages.at(0), itkImg); typedef itk::TensorImageToQBallImageFilter< float, float > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkImg ); filter->Update(); typedef mitk::ImageToItk< mitk::TrackingHandlerOdf::ItkOdfImageType > CasterType; trackingHandler = new mitk::TrackingHandlerOdf(); dynamic_cast(trackingHandler)->SetOdfImage(filter->GetOutput()); dynamic_cast(trackingHandler)->SetGfaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(trackingHandler)->SetMinMaxNormalize(m_Controls->m_NormalizeODFsBox->isChecked()); dynamic_cast(trackingHandler)->SetOdfPower(1); if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(trackingHandler)->SetGfaImage(itkImg); } } else { trackingHandler = new mitk::TrackingHandlerTensor(); for (int i=0; i<(int)m_InputImages.size(); i++) { TensorImageType::Pointer itkImg = TensorImageType::New(); mitk::CastToItkImage(m_InputImages.at(i), itkImg); dynamic_cast(trackingHandler)->AddTensorImage(itkImg); } if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(trackingHandler)->SetFaImage(itkImg); } dynamic_cast(trackingHandler)->SetFaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(trackingHandler)->SetF((float)m_Controls->m_fBox->value()); dynamic_cast(trackingHandler)->SetG((float)m_Controls->m_gBox->value()); } } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { typedef mitk::ImageToItk< mitk::TrackingHandlerOdf::ItkOdfImageType > CasterType; trackingHandler = new mitk::TrackingHandlerOdf(); mitk::TrackingHandlerOdf::ItkOdfImageType::Pointer itkImg = mitk::TrackingHandlerOdf::ItkOdfImageType::New(); mitk::CastToItkImage(m_InputImages.at(0), itkImg); dynamic_cast(trackingHandler)->SetOdfImage(itkImg); dynamic_cast(trackingHandler)->SetGfaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(trackingHandler)->SetMinMaxNormalize(m_Controls->m_NormalizeODFsBox->isChecked()); if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(trackingHandler)->SetGfaImage(itkImg); } } else { if (m_Controls->m_ModeBox->currentIndex()==1) { QMessageBox::information(nullptr, "Information", "Probabilstic tractography is only implementedfor ODF images."); return; } try { typedef mitk::ImageToItk< mitk::TrackingHandlerPeaks::PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(m_InputImages.at(0)); caster->Update(); mitk::TrackingHandlerPeaks::PeakImgType::Pointer itkImg = caster->GetOutput(); - trackingHandler = new mitk::TrackingHandlerPeaks(); - dynamic_cast(trackingHandler)->SetPeakImage(itkImg); dynamic_cast(trackingHandler)->SetPeakThreshold(m_Controls->m_ScalarThresholdBox->value()); } catch(...) { return; } } trackingHandler->SetFlipX(m_Controls->m_FlipXBox->isChecked()); trackingHandler->SetFlipY(m_Controls->m_FlipYBox->isChecked()); trackingHandler->SetFlipZ(m_Controls->m_FlipZBox->isChecked()); trackingHandler->SetInterpolate(m_Controls->m_InterpolationBox->isChecked()); switch (m_Controls->m_ModeBox->currentIndex()) { case 0: trackingHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); break; case 1: trackingHandler->SetMode(mitk::TrackingDataHandler::MODE::PROBABILISTIC); break; default: trackingHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); } typedef itk::StreamlineTrackingFilter TrackerType; TrackerType::Pointer tracker = TrackerType::New(); if (m_Controls->m_SeedImageBox->GetSelectedNode().IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_SeedImageBox->GetSelectedNode()->GetData()), mask); tracker->SetSeedImage(mask); } if (m_Controls->m_MaskImageBox->GetSelectedNode().IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_MaskImageBox->GetSelectedNode()->GetData()), mask); tracker->SetMaskImage(mask); } if (m_Controls->m_StopImageBox->GetSelectedNode().IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_StopImageBox->GetSelectedNode()->GetData()), mask); tracker->SetStoppingRegions(mask); } if (m_Controls->m_TissueImageBox->GetSelectedNode().IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_TissueImageBox->GetSelectedNode()->GetData()), mask); tracker->SetTissueImage(mask); tracker->SetSeedOnlyGm(m_Controls->m_SeedGmBox->isChecked()); } tracker->SetSeedsPerVoxel(m_Controls->m_SeedsPerVoxelBox->value()); tracker->SetStepSize(m_Controls->m_StepSizeBox->value()); //tracker->SetSamplingDistance(0.7); tracker->SetUseStopVotes(false); tracker->SetOnlyForwardSamples(false); tracker->SetAposterioriCurvCheck(false); tracker->SetMaxNumTracts(m_Controls->m_NumFibersBox->value()); tracker->SetNumberOfSamples(m_Controls->m_NumSamplesBox->value()); tracker->SetTrackingHandler(trackingHandler); tracker->SetAngularThreshold(m_Controls->m_AngularThresholdBox->value()); tracker->SetMinTractLength(m_Controls->m_MinTractLengthBox->value()); tracker->Update(); + delete trackingHandler; + vtkSmartPointer fiberBundle = tracker->GetFiberPolyData(); if ( fiberBundle->GetNumberOfLines()==0 ) { QMessageBox warnBox; warnBox.setWindowTitle("Warning"); warnBox.setText("No fiberbundle was generated!"); warnBox.setDetailedText("No fibers were generated using the parameters: \n\n" + m_Controls->m_FaThresholdLabel->text() + "\n" + m_Controls->m_AngularThresholdLabel->text() + "\n" + m_Controls->m_fLabel->text() + "\n" + m_Controls->m_gLabel->text() + "\n" + m_Controls->m_StepsizeLabel->text() + "\n" + m_Controls->m_MinTractLengthLabel->text() + "\n" + m_Controls->m_SeedsPerVoxelLabel->text() + "\n\nPlease check your parametersettings."); warnBox.setIcon(QMessageBox::Warning); warnBox.exec(); return; } mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(fiberBundle); fib->SetReferenceGeometry(dynamic_cast(m_InputImageNodes.at(0)->GetData())->GetGeometry()); if (m_Controls->m_ResampleFibersBox->isChecked()) fib->Compress(m_Controls->m_FiberErrorBox->value()); fib->ColorFibersByOrientation(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(fib); QString name("FiberBundle_"); name += m_InputImageNodes.at(0)->GetName().c_str(); name += "_Streamline"; node->SetName(name.toStdString()); node->SetVisibility(true); GetDataStorage()->Add(node, m_InputImageNodes.at(0)); - - delete trackingHandler; }