17 #ifndef __itkMLBSTrackingFilter_txx
18 #define __itkMLBSTrackingFilter_txx
25 #include <itkImageRegionConstIterator.h>
26 #include <itkImageRegionConstIteratorWithIndex.h>
27 #include <itkImageRegionIterator.h>
28 #include <itkImageFileWriter.h>
30 #define _USE_MATH_DEFINES
35 template<
int ShOrder,
int NumImageFeatures >
38 : m_PauseTracking(false)
39 , m_AbortTracking(false)
40 , m_FiberPolyData(NULL)
43 , m_AngularThreshold(0.7)
46 , m_MinTractLength(20.0)
47 , m_MaxTractLength(400.0)
49 , m_RandomSampling(false)
50 , m_SamplingDistance(-1)
51 , m_NumberOfSamples(50)
52 , m_StoppingRegions(NULL)
55 , m_AposterioriCurvCheck(false)
56 , m_RemoveWmEndFibers(false)
60 this->SetNumberOfRequiredInputs(1);
63 template<
int ShOrder,
int NumImageFeatures >
66 return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5);
69 template<
int ShOrder,
int NumImageFeatures >
73 m_ForestHandler.InitForTracking();
79 std::vector< double > m_ImageSpacing; m_ImageSpacing.resize(3);
80 m_ImageSpacing[0] = m_InputImage->GetSpacing()[0];
81 m_ImageSpacing[1] = m_InputImage->GetSpacing()[1];
82 m_ImageSpacing[2] = m_InputImage->GetSpacing()[2];
85 if(m_ImageSpacing[0]<m_ImageSpacing[1] && m_ImageSpacing[0]<m_ImageSpacing[2])
86 minSpacing = m_ImageSpacing[0];
87 else if (m_ImageSpacing[1] < m_ImageSpacing[2])
88 minSpacing = m_ImageSpacing[1];
90 minSpacing = m_ImageSpacing[2];
92 m_StepSize *= minSpacing;
94 m_StepSize = 0.5*minSpacing;
96 m_SamplingDistance *= minSpacing;
98 m_SamplingDistance = minSpacing*0.5;
100 m_PolyDataContainer.clear();
101 for (
unsigned int i=0; i<this->GetNumberOfThreads(); i++)
104 m_PolyDataContainer.push_back(poly);
107 if (m_StoppingRegions.IsNull())
110 m_StoppingRegions->SetSpacing( m_InputImage->GetSpacing() );
111 m_StoppingRegions->SetOrigin( m_InputImage->GetOrigin() );
112 m_StoppingRegions->SetDirection( m_InputImage->GetDirection() );
113 m_StoppingRegions->SetRegions( m_InputImage->GetLargestPossibleRegion() );
114 m_StoppingRegions->Allocate();
115 m_StoppingRegions->FillBuffer(0);
118 if (m_SeedImage.IsNull())
121 m_SeedImage->SetSpacing( m_InputImage->GetSpacing() );
122 m_SeedImage->SetOrigin( m_InputImage->GetOrigin() );
123 m_SeedImage->SetDirection( m_InputImage->GetDirection() );
124 m_SeedImage->SetRegions( m_InputImage->GetLargestPossibleRegion() );
125 m_SeedImage->Allocate();
126 m_SeedImage->FillBuffer(1);
129 if (m_MaskImage.IsNull())
133 m_MaskImage->SetSpacing( m_InputImage->GetSpacing() );
134 m_MaskImage->SetOrigin( m_InputImage->GetOrigin() );
135 m_MaskImage->SetDirection( m_InputImage->GetDirection() );
136 m_MaskImage->SetRegions( m_InputImage->GetLargestPossibleRegion() );
137 m_MaskImage->Allocate();
138 m_MaskImage->FillBuffer(1);
141 std::cout <<
"MLBSTrackingFilter: using mask image" << std::endl;
143 if (m_AngularThreshold<0.0)
144 m_AngularThreshold = 0.5*minSpacing;
145 m_BuildFibersReady = 0;
146 m_BuildFibersFinished =
false;
148 m_Tractogram.clear();
151 m_StartTime = std::chrono::system_clock::now();
153 std::cout <<
"MLBSTrackingFilter: Angular threshold: " << m_AngularThreshold << std::endl;
154 std::cout <<
"MLBSTrackingFilter: Stepsize: " << m_StepSize <<
" mm" << std::endl;
155 std::cout <<
"MLBSTrackingFilter: Seeds per voxel: " << m_SeedsPerVoxel << std::endl;
156 std::cout <<
"MLBSTrackingFilter: Max. sampling distance: " << m_SamplingDistance <<
" mm" << std::endl;
157 std::cout <<
"MLBSTrackingFilter: Number of samples: " << m_NumberOfSamples << std::endl;
158 std::cout <<
"MLBSTrackingFilter: Max. tract length: " << m_MaxTractLength <<
" mm" << std::endl;
159 std::cout <<
"MLBSTrackingFilter: Min. tract length: " << m_MinTractLength <<
" mm" << std::endl;
160 std::cout <<
"MLBSTrackingFilter: Starting streamline tracking using " << this->GetNumberOfThreads() <<
" threads." << std::endl;
163 template<
int ShOrder,
int NumImageFeatures >
175 template<
int ShOrder,
int NumImageFeatures >
179 typename FeatureImageType::IndexType idx;
180 m_InputImage->TransformPhysicalPointToIndex(pos, idx);
181 if (!m_InputImage->GetLargestPossibleRegion().IsInside(idx) || m_MaskImage->GetPixel(idx)==0)
187 template<
int ShOrder,
int NumImageFeatures >
190 return (
double)(rand()%((int)(10000*(max-min))) + 10000*
min)/10000;
193 template<
int ShOrder,
int NumImageFeatures >
198 m_SamplingPointset->Clear();
199 m_AlternativePointset->Clear();
201 vnl_vector_fixed<double,3> direction; direction.fill(0);
203 ItkUcharImgType::IndexType idx;
204 m_StoppingRegions->TransformPhysicalPointToIndex(pos, idx);
205 if (m_StoppingRegions->GetLargestPossibleRegion().IsInside(idx) && m_StoppingRegions->GetPixel(idx)>0)
208 if (m_MaskImage.IsNotNull() && ((m_MaskImage->GetLargestPossibleRegion().IsInside(idx) && m_MaskImage->GetPixel(idx)<=0) || !m_MaskImage->GetLargestPossibleRegion().IsInside(idx)) )
211 if (olddir.magnitude()>0)
216 if (IsValidPosition(pos))
218 direction = m_ForestHandler.Classify(pos, candidates, olddir, m_AngularThreshold, w, m_MaskImage);
223 itk::Point<double, 3> sample_pos;
224 int alternatives = 1;
225 for (
int i=0; i<m_NumberOfSamples; i++)
227 vnl_vector_fixed<double,3> d;
229 if (m_RandomSampling)
231 d[0] = GetRandDouble();
232 d[1] = GetRandDouble();
233 d[2] = GetRandDouble();
235 d *= GetRandDouble(0,m_SamplingDistance);
242 sample_pos[0] = pos[0] + d[0];
243 sample_pos[1] = pos[1] + d[1];
244 sample_pos[2] = pos[2] + d[2];
246 m_SamplingPointset->InsertPoint(i, sample_pos);
249 vnl_vector_fixed<double,3> tempDir; tempDir.fill(0.0);
250 if (IsValidPosition(sample_pos))
251 tempDir = m_ForestHandler.Classify(sample_pos, candidates, olddir, m_AngularThreshold, w, m_MaskImage);
252 if (candidates>0 && tempDir.magnitude()>0.001)
254 direction += tempDir*w;
256 else if (m_AvoidStop && candidates==0 && olddir.magnitude()>0)
258 double dot = dot_product(d, olddir);
260 d = -d + 2*dot*olddir;
265 sample_pos[0] = pos[0] + d[0];
266 sample_pos[1] = pos[1] + d[1];
267 sample_pos[2] = pos[2] + d[2];
269 m_AlternativePointset->InsertPoint(alternatives, sample_pos);
272 vnl_vector_fixed<double,3> tempDir; tempDir.fill(0.0);
273 if (IsValidPosition(sample_pos))
274 tempDir = m_ForestHandler.Classify(sample_pos, candidates, olddir, m_AngularThreshold, w, m_MaskImage);
276 if (candidates>0 && tempDir.magnitude()>0.001)
279 direction += tempDir*w;
284 if (direction.magnitude()>0.001)
286 direction.normalize();
287 olddir[0] = direction[0];
288 olddir[1] = direction[1];
289 olddir[2] = direction[2];
297 template<
int ShOrder,
int NumImageFeatures >
300 vnl_vector_fixed<double,3> dirOld = dir;
303 for (
int step=0; step< m_MaxLength/2; step++)
307 CalculateNewPosition(pos, dir);
316 tractLength += m_StepSize;
318 fib->push_front(pos);
322 if (m_AposterioriCurvCheck)
324 int curv = CheckCurvature(fib, front);
327 tractLength -= m_StepSize*curv;
340 if (tractLength>m_MaxTractLength)
346 m_BuildFibersReady++;
347 m_Tractogram.push_back(*fib);
355 dir = GetNewDirection(pos, dirOld);
357 while (m_PauseTracking){}
359 if (dir.magnitude()<0.0001)
365 template<
int ShOrder,
int NumImageFeatures >
368 double m_Distance = 5;
373 std::vector< vnl_vector_fixed< float, 3 > > vectors;
374 vnl_vector_fixed< float, 3 > meanV; meanV.fill(0);
380 while(dist<m_Distance && c<fib->size()-1)
382 itk::Point<double> p1 = fib->at(c);
383 itk::Point<double> p2 = fib->at(c+1);
385 vnl_vector_fixed< float, 3 > v;
389 dist += v.magnitude();
391 vectors.push_back(v);
400 while(dist<m_Distance && c>0)
402 itk::Point<double> p1 = fib->at(c);
403 itk::Point<double> p2 = fib->at(c-1);
405 vnl_vector_fixed< float, 3 > v;
409 dist += v.magnitude();
411 vectors.push_back(v);
412 if (c==fib->size()-1)
419 for (
int c=0; c<vectors.size(); c++)
421 double angle = dot_product(meanV, vectors.at(c));
426 dev += acos(angle)*180/
M_PI;
428 if (vectors.size()>0)
429 dev /= vectors.size();
434 return vectors.size();
437 template<
int ShOrder,
int NumImageFeatures >
443 typedef ImageRegionConstIterator< ItkUcharImgType > MaskIteratorType;
444 MaskIteratorType sit(m_SeedImage, regionForThread );
445 MaskIteratorType mit(m_MaskImage, regionForThread );
449 itk::Point<double> worldPos;
450 while( !sit.IsAtEnd() )
452 if (sit.Value()==0 || mit.Value()==0)
459 for (
int s=0; s<m_SeedsPerVoxel; s++)
462 double tractLength = 0;
463 typename FeatureImageType::IndexType index = sit.GetIndex();
464 itk::ContinuousIndex<double, 3> start;
465 unsigned int counter = 0;
467 if (m_SeedsPerVoxel>1)
469 start[0] = index[0]+GetRandDouble(-0.5, 0.5);
470 start[1] = index[1]+GetRandDouble(-0.5, 0.5);
471 start[2] = index[2]+GetRandDouble(-0.5, 0.5);
481 m_SeedImage->TransformContinuousIndexToPhysicalPoint( start, worldPos );
486 vnl_vector_fixed<double,3> dirOld; dirOld.fill(0.0);
487 vnl_vector_fixed<double,3> dir; dir.fill(0.0);
488 if (IsValidPosition(worldPos))
489 dir = m_ForestHandler.Classify(worldPos, candidates, dirOld, 0, prob, m_MaskImage);
490 if (dir.magnitude()<0.0001)
494 tractLength = FollowStreamline(worldPos, dir, &fib, 0,
false);
495 fib.push_front(worldPos);
497 if (m_RemoveWmEndFibers)
499 itk::Point<double> check = fib.back();
501 vnl_vector_fixed<double,3> check2 = GetNewDirection(check, dirOld);
502 if (check2.magnitude()>0.001)
504 MITK_INFO <<
"Detected WM ending. Discarding fiber.";
510 tractLength = FollowStreamline(worldPos, -dir, &fib, tractLength,
true);
511 counter = fib.size();
513 if (m_RemoveWmEndFibers)
515 itk::Point<double> check = fib.front();
517 vnl_vector_fixed<double,3> check2 = GetNewDirection(check, dirOld);
518 if (check2.magnitude()>0.001)
520 MITK_INFO <<
"Detected WM ending. Discarding fiber.";
525 if (tractLength<m_MinTractLength || counter<2)
529 m_Tractogram.push_back(fib);
541 std::cout <<
"Thread " << threadId <<
" finished tracking" << std::endl;
544 template<
int ShOrder,
int NumImageFeatures >
547 if (m_BuildFibersReady<m_Threads && check)
554 for (
int i=0; i<m_Tractogram.size(); i++)
558 for (FiberType::iterator it = fib.begin(); it!=fib.end(); ++it)
560 vtkIdType
id = vNewPoints->InsertNextPoint((*it).GetDataPointer());
561 container->GetPointIds()->InsertNextId(
id);
563 vNewLines->InsertNextCell(container);
567 for (
int i=0; i<m_BuildFibersReady; i++)
568 m_Tractogram.pop_back();
569 m_BuildFibersReady = 0;
571 m_FiberPolyData->SetPoints(vNewPoints);
572 m_FiberPolyData->SetLines(vNewLines);
573 m_BuildFibersFinished =
true;
576 template<
int ShOrder,
int NumImageFeatures >
583 m_EndTime = std::chrono::system_clock::now();
584 std::chrono::hours hh = std::chrono::duration_cast<std::chrono::hours>(m_EndTime - m_StartTime);
585 std::chrono::minutes mm = std::chrono::duration_cast<std::chrono::minutes>(m_EndTime - m_StartTime);
586 std::chrono::seconds ss = std::chrono::duration_cast<std::chrono::seconds>(m_EndTime - m_StartTime);
589 MITK_INFO <<
"Tracking took " << hh.count() <<
"h, " << mm.count() <<
"m and " << ss.count() <<
"s";
594 #endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx
Superclass::InputImageRegionType InputImageRegionType
double FollowStreamline(itk::Point< double, 3 > pos, vnl_vector_fixed< double, 3 > dir, FiberType *fib, double tractLength, bool front)
Start streamline in one direction.
double GetRandDouble(double min=-1, double max=1)
void ThreadedGenerateData(const InputImageRegionType &outputRegionForThread, ThreadIdType threadId) override
vtkSmartPointer< vtkPolyData > PolyDataType
void CalculateNewPosition(itk::Point< double, 3 > &pos, vnl_vector_fixed< double, 3 > &dir)
Calculate next integration step.
int CheckCurvature(FiberType *fib, bool front)
bool IsValidPosition(itk::Point< double, 3 > &pos)
Are we outside of the mask image?
vnl_vector_fixed< double, 3 > GetNewDirection(itk::Point< double, 3 > &pos, vnl_vector_fixed< double, 3 > &olddir)
Determine new direction by sample voting at the current position taking the last progression directio...
Represents an ODF for Q-Ball imaging.
static vnl_vector_fixed< double, 3 > GetDirection(int i)
void AfterThreadedGenerateData() override
std::deque< itk::Point< double > > FiberType
void BuildFibers(bool check)
Superclass::InputImageType InputImageType
MITKCORE_EXPORT const ScalarType eps
void BeforeThreadedGenerateData() override
double RoundToNearest(double num)
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.