diff --git a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp index e39f3987dd..394decf583 100644 --- a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp +++ b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp @@ -1,348 +1,356 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkStreamlineTrackingFilter_txx #define __itkStreamlineTrackingFilter_txx #include #include #include #include "itkStreamlineTrackingFilter.h" #include #include #include #define _USE_MATH_DEFINES #include namespace itk { //#define QBALL_RECON_PI M_PI template< class TTensorPixelType, class TPDPixelType> StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::StreamlineTrackingFilter(): m_FaThreshold(0.2), m_StepSize(0.2), m_MaxLength(10000), m_SeedsPerVoxel(1) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); } +template< class TTensorPixelType, + class TPDPixelType> +double StreamlineTrackingFilter< TTensorPixelType, +TPDPixelType> +::RoundToNearest(double num) { + return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); +} + template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::BeforeThreadedGenerateData() { m_FiberPolyData = FiberPolyDataType::New(); m_Points = vtkPoints::New(); m_Cells = vtkCellArray::New(); typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); m_ImageSize[0] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(0); m_ImageSize[1] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(1); m_ImageSize[2] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(2); m_PolyDataContainer = itk::VectorContainer< int, FiberPolyDataType >::New(); for (int i=0; iGetNumberOfThreads(); i++) { FiberPolyDataType poly = FiberPolyDataType::New(); m_PolyDataContainer->InsertElement(i, poly); } if (m_MaskImage.IsNull()) { itk::Vector spacing = inputImage->GetSpacing(); itk::Point origin = inputImage->GetOrigin(); itk::Matrix direction = inputImage->GetDirection(); ImageRegion<3> imageRegion = inputImage->GetLargestPossibleRegion(); // initialize crossings image m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing ); m_MaskImage->SetOrigin( origin ); m_MaskImage->SetDirection( direction ); m_MaskImage->SetRegions( imageRegion ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } std::cout << "starting streamline tracking" << std::endl; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId) { FiberPolyDataType poly = m_PolyDataContainer->GetElement(threadId); vtkSmartPointer Points = vtkPoints::New(); vtkSmartPointer Cells = vtkCellArray::New(); typedef itk::DiffusionTensor3D TensorType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typedef ImageRegionConstIterator< ItkUcharImgType > MaskIteratorType; typedef typename InputImageType::PixelType InputTensorType; typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType it(inputImage, outputRegionForThread ); MaskIteratorType mit(m_MaskImage, outputRegionForThread ); it.GoToBegin(); mit.GoToBegin(); while( !it.IsAtEnd() ) { if (mit.Value()==0) { ++mit; ++it; continue; } typename TensorType::EigenValuesArrayType eigenvalues; typename TensorType::EigenVectorsMatrixType eigenvectors; for (int s=0; s container = vtkSmartPointer::New(); std::vector< vtkIdType > pointISs; typename InputImageType::IndexType index = it.GetIndex(); itk::ContinuousIndex pos; itk::ContinuousIndex start; if (m_SeedsPerVoxel>1) { pos[0] = index[0]+(double)(rand()%99-49)/100; pos[1] = index[1]+(double)(rand()%99-49)/100; pos[2] = index[2]+(double)(rand()%99-49)/100; } else { pos[0] = index[0]; pos[1] = index[1]; pos[2] = index[2]; } start = pos; int step = 0; vnl_vector_fixed dirOld; dirOld.fill(0.0); // do forward tracking while (step < m_MaxLength) { ++step; - index[0] = round(pos[0]); - index[1] = round(pos[1]); - index[2] = round(pos[2]); + index[0] = RoundToNearest(pos[0]); + index[1] = RoundToNearest(pos[1]); + index[2] = RoundToNearest(pos[2]); if (index[0] < 0 || index[0]>=m_ImageSize[0]) break; if (index[1] < 0 || index[1]>=m_ImageSize[1]) break; if (index[2] < 0 || index[2]>=m_ImageSize[2]) break; typename InputImageType::PixelType tensor = inputImage->GetPixel(index); if(tensor.GetTrace()!=0 && tensor.GetFractionalAnisotropy()>m_FaThreshold) { tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); int eIndex = 2; if( (eigenvalues[0] >= eigenvalues[1]) && (eigenvalues[0] >= eigenvalues[2]) ) eIndex = 0; else if(eigenvalues[1] >= eigenvalues[2]) eIndex = 1; vnl_vector_fixed dir; dir[0] = eigenvectors(eIndex, 0); dir[1] = eigenvectors(eIndex, 1); dir[2] = eigenvectors(eIndex, 2); dir.normalize(); if (!dirOld.is_zero()) { float angle = dot_product(dirOld, dir); if (angle<0) dir *= -1; angle = fabs(dot_product(dirOld, dir)); if (angle<0.7) break; } dirOld = dir; dir *= m_StepSize; itk::Point worldPos; inputImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos ); vtkIdType id = Points->InsertNextPoint(worldPos.GetDataPointer()); pointISs.push_back(id); counter++; pos[0] += dir[0]; pos[1] += dir[1]; pos[2] += dir[2]; } } // insert reverse IDs while (!pointISs.empty()) { container->GetPointIds()->InsertNextId(pointISs.back()); pointISs.pop_back(); } // do backward tracking index = it.GetIndex(); pos = start; dirOld.fill(0.0); while (step < m_MaxLength) { ++step; - index[0] = round(pos[0]); - index[1] = round(pos[1]); - index[2] = round(pos[2]); + index[0] = RoundToNearest(pos[0]); + index[1] = RoundToNearest(pos[1]); + index[2] = RoundToNearest(pos[2]); if (index[0] < 0 || index[0]>=m_ImageSize[0]) break; if (index[1] < 0 || index[1]>=m_ImageSize[1]) break; if (index[2] < 0 || index[2]>=m_ImageSize[2]) break; typename InputImageType::PixelType tensor = inputImage->GetPixel(index); if(tensor.GetTrace()!=0 && tensor.GetFractionalAnisotropy()>m_FaThreshold) { tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); int eIndex = 2; if( (eigenvalues[0] >= eigenvalues[1]) && (eigenvalues[0] >= eigenvalues[2]) ) eIndex = 0; else if(eigenvalues[1] >= eigenvalues[2]) eIndex = 1; vnl_vector_fixed dir; dir[0] = eigenvectors(eIndex, 0); dir[1] = eigenvectors(eIndex, 1); dir[2] = eigenvectors(eIndex, 2); dir.normalize(); dir *= -1; // reverse direction if (!dirOld.is_zero()) { float angle = dot_product(dirOld, dir); if (angle<0) dir *= -1; angle = fabs(dot_product(dirOld, dir)); if (angle<0.7) break; } dirOld = dir; dir *= m_StepSize; itk::Point worldPos; inputImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos ); vtkIdType id = Points->InsertNextPoint(worldPos.GetDataPointer()); container->GetPointIds()->InsertNextId(id); counter++; pos[0] += dir[0]; pos[1] += dir[1]; pos[2] += dir[2]; } } if (counter>0) Cells->InsertNextCell(container); } ++mit; ++it; } poly->SetPoints(Points); poly->SetLines(Cells); std::cout << "Thread " << threadId << " finished tracking" << std::endl; } template< class TTensorPixelType, class TPDPixelType> vtkSmartPointer< vtkPolyData > StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = poly1->GetLines(); vtkSmartPointer vNewPoints = poly1->GetPoints(); vtkSmartPointer vLines = poly2->GetLines(); vLines->InitTraversal(); for( int i=0; iGetNumberOfCells(); i++ ) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(poly2->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); return vNewPolyData; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::AfterThreadedGenerateData() { MITK_INFO << "Generating polydata "; m_FiberPolyData = m_PolyDataContainer->GetElement(0); for (int i=1; iGetNumberOfThreads(); i++) { m_FiberPolyData = AddPolyData(m_FiberPolyData, m_PolyDataContainer->GetElement(i)); } MITK_INFO << "done"; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { } } #endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx diff --git a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h index d6aaa4b759..f87a66f63c 100644 --- a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h +++ b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h @@ -1,107 +1,108 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkStreamlineTrackingFilter_h_ #define __itkStreamlineTrackingFilter_h_ #include "MitkDiffusionImagingExports.h" #include #include #include #include #include #include #include #include #include namespace itk{ /** \class StreamlineTrackingFilter */ template< class TTensorPixelType, class TPDPixelType=double> class StreamlineTrackingFilter : public ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< Vector< TPDPixelType, 3 >, 3 > > { public: typedef StreamlineTrackingFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< Vector< TPDPixelType, 3 >, 3 > > Superclass; /** Method for creation through the object factory. */ itkNewMacro(Self) /** Runtime information support. */ itkTypeMacro(StreamlineTrackingFilter, ImageToImageFilter) typedef TTensorPixelType TensorComponentType; typedef TPDPixelType DirectionPixelType; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef itk::Image ItkUcharImgType; typedef vtkSmartPointer< vtkPolyData > FiberPolyDataType; itkGetMacro( FiberPolyData, FiberPolyDataType ) itkSetMacro( MaskImage, ItkUcharImgType::Pointer) itkSetMacro( SeedsPerVoxel, int) itkSetMacro( FaThreshold, float) protected: StreamlineTrackingFilter(); ~StreamlineTrackingFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; + double RoundToNearest(double num); void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, int threadId); void AfterThreadedGenerateData(); FiberPolyDataType AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2); FiberPolyDataType m_FiberPolyData; vtkSmartPointer m_Points; vtkSmartPointer m_Cells; float m_FaThreshold; float m_StepSize; int m_MaxLength; int m_SeedsPerVoxel; int m_ImageSize[3]; ItkUcharImgType::Pointer m_MaskImage; itk::VectorContainer< int, FiberPolyDataType >::Pointer m_PolyDataContainer; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkStreamlineTrackingFilter.cpp" #endif #endif //__itkStreamlineTrackingFilter_h_