16 #ifndef __itkFiniteDiffOdfMaximaExtractionFilter_cpp
17 #define __itkFiniteDiffOdfMaximaExtractionFilter_cpp
20 #include <itkImageRegionConstIterator.h>
21 #include <itkImageRegionConstIteratorWithIndex.h>
22 #include <itkImageRegionIterator.h>
23 #include <vnl/vnl_vector.h>
25 #include <itkContinuousIndex.h>
27 #include <vtkSmartPointer.h>
28 #include <vtkPolyData.h>
29 #include <vtkCellArray.h>
30 #include <vtkPoints.h>
31 #include <vtkPolyLine.h>
33 #include <boost/math/special_functions.hpp>
34 #include <boost/progress.hpp>
42 static bool CompareVectors(
const vnl_vector_fixed< double, 3 >& v1,
const vnl_vector_fixed< double, 3 >& v2)
44 return (v1.magnitude()>v2.magnitude());
47 template<
class PixelType,
int ShOrder,
int NrOdfDirections >
48 FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections>
49 ::FiniteDiffOdfMaximaExtractionFilter()
50 : m_NormalizationMethod(MAX_VEC_NORM)
52 , m_PeakThreshold(0.4)
53 , m_AbsolutePeakThreshold(0)
54 , m_ClusteringThreshold(0.9)
55 , m_AngularThreshold(0.7)
56 , m_NumCoeffs((ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder)
59 this->SetNumberOfRequiredInputs(1);
62 template<
class PixelType,
int ShOrder,
int NrOdfDirections >
69 vnl_vector_fixed< bool, NrOdfDirections > used; used.fill(
false);
71 for (
int i=0; i<NrOdfDirections; i++)
76 double val = odf.GetElement(i);
77 if (val>thr && val*gfa>m_AbsolutePeakThreshold)
81 for (
unsigned int j=0; j<neighbours.size(); j++)
82 if (val<=odf.GetElement(neighbours.at(j)))
91 for (
unsigned int j=0; j<neighbours.size(); j++)
92 used[neighbours.at(j)] =
true;
98 template<
class PixelType,
int ShOrder,
int NrOdfDirections >
101 std::vector< DirectionType > outDirs;
106 std::vector< int > touched;
109 touched.resize(inDirs.size(), 0);
111 currentMean = inDirs[0];
119 while ((currentMean-oldMean).magnitude()>0.0001)
122 oldMean = currentMean;
123 workingMean = oldMean;
124 workingMean.normalize();
125 currentMean.fill(0.0);
126 for (
unsigned int i=0; i<inDirs.size(); i++)
128 angle = dot_product(workingMean, inDirs[i]);
129 if (angle>=m_ClusteringThreshold)
131 currentMean += inDirs[i];
135 else if (-angle>=m_ClusteringThreshold)
137 currentMean -= inDirs[i];
147 float mag = currentMean.magnitude();
151 outDirs.push_back(currentMean);
157 for (
unsigned int i=0; i<touched.size(); i++)
160 currentMean = inDirs[i];
165 if (inDirs.size()==outDirs.size())
170 return MeanShiftClustering(outDirs);
173 template<
class PixelType,
int ShOrder,
int NrOdfDirections >
178 itk::Vector<double,3> spacing = ShCoeffImage->GetSpacing();
179 double minSpacing = spacing[0];
180 if (spacing[1]<minSpacing)
181 minSpacing = spacing[1];
182 if (spacing[2]<minSpacing)
183 minSpacing = spacing[2];
186 itk::Matrix<double, 3, 3> direction = ShCoeffImage->GetDirection();
187 ImageRegion<3> imageRegion = ShCoeffImage->GetLargestPossibleRegion();
189 if (m_MaskImage.IsNotNull())
191 origin = m_MaskImage->GetOrigin();
192 direction = m_MaskImage->GetDirection();
193 imageRegion = m_MaskImage->GetLargestPossibleRegion();
197 for (
unsigned int i=0; i<m_MaxNumPeaks; i++)
199 itk::Vector< float, 3 > nullVec; nullVec.Fill(0.0);
201 img->SetSpacing( spacing );
202 img->SetOrigin( origin );
203 img->SetDirection( direction );
204 img->SetRegions( imageRegion );
206 img->FillBuffer(nullVec);
207 m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), img);
209 if (m_MaskImage.IsNull())
212 m_MaskImage->SetSpacing( spacing );
213 m_MaskImage->SetOrigin( origin );
214 m_MaskImage->SetDirection( direction );
215 m_MaskImage->SetRegions( imageRegion );
216 m_MaskImage->Allocate();
217 m_MaskImage->FillBuffer(1);
220 m_NumDirectionsImage->SetSpacing( spacing );
221 m_NumDirectionsImage->SetOrigin( origin );
222 m_NumDirectionsImage->SetDirection( direction );
223 m_NumDirectionsImage->SetRegions( imageRegion );
224 m_NumDirectionsImage->Allocate();
225 m_NumDirectionsImage->FillBuffer(0);
227 this->SetNumberOfIndexedOutputs(m_MaxNumPeaks);
231 vnl_matrix_fixed<double, 3, NrOdfDirections>* directions = odf.
GetDirections();
232 vnl_matrix< double > sphCoords;
233 std::vector< DirectionType > dirs;
234 for (
int i=0; i<NrOdfDirections; i++)
235 dirs.push_back(directions->get_column(i));
236 Cart2Sph(dirs, sphCoords);
237 m_ShBasis = CalcShBasis(sphCoords);
239 MITK_INFO <<
"Starting finite differences maximum extraction";
240 MITK_INFO <<
"ODF sampling points: " << NrOdfDirections;
242 MITK_INFO <<
"Maximum peaks: " << m_MaxNumPeaks;
243 MITK_INFO <<
"Relative threshold: " << m_PeakThreshold;
244 MITK_INFO <<
"Absolute threshold: " << m_AbsolutePeakThreshold;
245 MITK_INFO <<
"Clustering threshold: " << m_ClusteringThreshold;
246 MITK_INFO <<
"Angular threshold: " << m_AngularThreshold;
249 template<
class PixelType,
int ShOrder,
int NrOdfDirections >
258 ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, ShCoeffImage->GetLargestPossibleRegion() );
261 double minSpacing = spacing[0];
262 if (spacing[1]<minSpacing)
263 minSpacing = spacing[1];
264 if (spacing[2]<minSpacing)
265 minSpacing = spacing[2];
267 int maxProgress = ShCoeffImage->GetLargestPossibleRegion().GetSize()[0]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[1]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[2];
268 boost::progress_display disp(maxProgress);
270 while( !cit.IsAtEnd() )
274 typename CoefficientImageType::IndexType index = cit.GetIndex();
275 if (m_MaskImage->GetPixel(index)==0)
281 for (
unsigned int i=0; i<m_DirectionImageContainer->Size(); i++)
284 itk::Vector< float, 3 > pixel = img->GetPixel(index);
285 DirectionType dir; dir[0] = pixel[0]; dir[1] = pixel[1]; dir[2] = pixel[2];
288 itk::ContinuousIndex<double, 3> center;
289 center[0] = index[0];
290 center[1] = index[1];
291 center[2] = index[2];
292 itk::Point<double> worldCenter;
293 m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter );
295 itk::Point<double> worldStart;
296 worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing;
297 worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing;
298 worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing;
299 vtkIdType
id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer());
300 container->GetPointIds()->InsertNextId(
id);
301 itk::Point<double> worldEnd;
302 worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing;
303 worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing;
304 worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing;
305 id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer());
306 container->GetPointIds()->InsertNextId(
id);
307 m_VtkCellArray->InsertNextCell(container);
313 directionsPolyData->SetPoints(m_VtkPoints);
314 directionsPolyData->SetLines(m_VtkCellArray);
317 for (
unsigned int i=0; i<m_DirectionImageContainer->Size(); i++)
320 this->SetNthOutput(i, img);
324 template<
class PixelType,
int ShOrder,
int NrOdfDirections >
330 ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, outputRegionForThread );
333 while( !cit.IsAtEnd() )
335 typename CoefficientImageType::IndexType index = cit.GetIndex();
336 if (m_MaskImage->GetPixel(index)==0)
347 for (
int i=0; i<NrOdfDirections; i++)
349 for (
int j=0; j<m_NumCoeffs; j++)
350 odf[i] += c[j]*m_ShBasis(i,j);
360 std::vector< DirectionType > candidates, peaks, temp;
362 max *= m_PeakThreshold;
363 FindCandidatePeaks(odf, max, candidates);
364 candidates = MeanShiftClustering(candidates);
366 vnl_matrix< double > shBasis, sphCoords;
367 Cart2Sph(candidates, sphCoords);
368 shBasis = CalcShBasis(sphCoords);
370 for (
unsigned int i=0; i<candidates.size(); i++)
373 for (
int j=0; j<m_NumCoeffs; j++)
374 val += c[j]*shBasis(i,j);
377 peaks.push_back(candidates[i]*val);
382 unsigned int m = peaks.size();
383 if ( m>m_DirectionImageContainer->Size() )
384 m = m_DirectionImageContainer->Size();
385 for (
unsigned int i=0; i<m; i++)
388 double val = v1.magnitude();
389 if (val<max*m_PeakThreshold || val<m_AbsolutePeakThreshold)
393 for (
unsigned int j=0; j<peaks.size(); j++)
397 double val2 = v2.magnitude();
398 double angle = fabs(dot_product(v1,v2)/(val*val2));
399 if (angle>m_AngularThreshold && val<val2)
412 unsigned int num = peaks.size();
413 if ( num>m_DirectionImageContainer->Size() )
414 num = m_DirectionImageContainer->Size();
415 for (
unsigned int i=0; i<num; i++)
417 vnl_vector<double> dir = peaks.at(i);
421 switch (m_NormalizationMethod)
425 case SINGLE_VEC_NORM:
433 dir = m_MaskImage->GetDirection()*dir;
442 itk::Vector< float, 3 > pixel;
443 pixel.SetElement(0, dir[0]);
444 pixel.SetElement(1, dir[1]);
445 pixel.SetElement(2, dir[2]);
446 img->SetPixel(index, pixel);
448 m_NumDirectionsImage->SetPixel(index, num);
451 MITK_INFO <<
"Thread " << threadID <<
" finished extraction";
455 template<
class PixelType,
int ShOrder,
int NrOdfDirections >
457 ::Cart2Sph(
const std::vector< DirectionType >& dir, vnl_matrix<double>& sphCoords)
459 sphCoords.set_size(dir.size(), 2);
461 for (
unsigned int i=0; i<dir.size(); i++)
463 double mag = dir[i].magnitude();
467 sphCoords(i,0) =
M_PI/2;
468 sphCoords(i,1) =
M_PI/2;
472 sphCoords(i,0) = acos(dir[i](2)/mag);
473 sphCoords(i,1) = atan2(dir[i](1), dir[i](0));
479 template<
class PixelType,
int ShOrder,
int NrOdfDirections >
483 int M = sphCoords.rows();
484 int j, m;
double mag, plm;
485 vnl_matrix<double> shBasis;
486 shBasis.set_size(M, m_NumCoeffs);
488 for (
int p=0; p<M; p++)
491 for (
int l=0; l<=ShOrder; l=l+2)
492 for (m=-l; m<=l; m++)
497 plm = legendre_p<double>(l,abs(m),cos(sphCoords(p,0)));
498 mag = sqrt((
double)(2*l+1)/(4.0*
M_PI)*factorial<double>(l-abs(m))/factorial<double>(l+abs(m)))*plm;
501 shBasis(p,j) = sqrt(2.0)*mag*cos(fabs((
double)m)*sphCoords(p,1));
505 shBasis(p,j) = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*sphCoords(p,1));
509 plm = legendre_p<double>(l,abs(m),-cos(sphCoords(p,0)));
510 mag = sqrt((
double)(2*l+1)/(4.0*
M_PI)*factorial<double>(l-abs(m))/factorial<double>(l+abs(m)))*plm;
512 shBasis(p,j) = mag*cos(m*sphCoords(p,1));
516 shBasis(p,j) = mag*sin(-m*sphCoords(p,1));
528 #endif // __itkFiniteDiffOdfMaximaExtractionFilter_cpp
itk::SmartPointer< Self > Pointer
static DirectionsType * GetDirections()
Represents an ODF for Q-Ball imaging.
static vnl_vector_fixed< double, 3 > GetDirection(int i)
static std::vector< int > GetNeighbors(int idx)
static bool CompareVectors(const vnl_vector_fixed< double, 3 > &v1, const vnl_vector_fixed< double, 3 > &v2)
TComponent GetGeneralizedFractionalAnisotropy() const
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.