vnl_matrix<double> FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::CalcShBasis(vnl_matrix<double>& sphCoords) { int M = sphCoords.rows(); int j, m; double mag, plm; vnl_matrix<double> shBasis; shBasis.set_size(M, m_NumCoeffs); for (int p=0; p<M; p++) { j=0; for (int l=0; l<=ShOrder; l=l+2) for (m=-l; m<=l; m++) { switch (m_Toolkit) { case FSL: plm = legendre_p<double>(l,abs(m),cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial<double>(l-abs(m))/factorial<double>(l+abs(m)))*plm; if (m<0) shBasis(p,j) = sqrt(2.0)*mag*cos(fabs((double)m)*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*sphCoords(p,1)); break; case MRTRIX: plm = legendre_p<double>(l,abs(m),-cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial<double>(l-abs(m))/factorial<double>(l+abs(m)))*plm; if (m>0) shBasis(p,j) = mag*cos(m*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = mag*sin(-m*sphCoords(p,1)); break; } j++; } } return shBasis; }
void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadID ) { typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, outputRegionForThread ); OdfType odf; while( !cit.IsAtEnd() ) { typename CoefficientImageType::IndexType idx3 = cit.GetIndex(); if (m_MaskImage->GetPixel(idx3)==0) { ++cit; continue; } CoefficientPixelType c = cit.Get(); // calculate ODF double max = 0; odf.Fill(0.0); for (int i=0; i<NrOdfDirections; i++) { for (int j=0; j<m_NumCoeffs; j++) odf[i] += c[j]*m_ShBasis(i,j); if (odf[i]>max) max = odf[i]; } if (max<0.0001) { ++cit; continue; } std::vector< DirectionType > candidates, peaks, temp; peaks.clear(); max *= m_PeakThreshold; // relative threshold FindCandidatePeaks(odf, max, candidates); // find all local maxima candidates = MeanShiftClustering(candidates); // cluster maxima vnl_matrix<double> sphCoords; CreateDirMatrix(candidates, sphCoords); // convert candidate peaks to spherical angles vnl_matrix< float > shBasis; if (m_Toolkit==Toolkit::MRTRIX) shBasis = mitk::sh::CalcShBasisForDirections(ShOrder, sphCoords); else shBasis = mitk::sh::CalcShBasisForDirections(ShOrder, sphCoords, false); max = 0.0; for (unsigned int i=0; i<candidates.size(); i++) // scale peaks according to ODF value { double val = 0; for (int j=0; j<m_NumCoeffs; j++) val += c[j]*shBasis(i,j); if (val>max) max = val; peaks.push_back(candidates[i]*val); } std::sort( peaks.begin(), peaks.end(), CompareVectors ); // sort peaks // kick out directions to close to a larger direction (too far away to cluster but too close to keep) unsigned int m = peaks.size(); if ( m>m_MaxNumPeaks ) m = m_MaxNumPeaks; for (unsigned int i=0; i<m; i++) { DirectionType v1 = peaks.at(i); double val = v1.magnitude(); if (val<max*m_PeakThreshold || val<m_AbsolutePeakThreshold) break; bool flag = true; for (unsigned int j=0; j<peaks.size(); j++) if (i!=j) { DirectionType v2 = peaks.at(j); double val2 = v2.magnitude(); double angle = fabs(dot_product(v1,v2)/(val*val2)); if (angle>m_AngularThreshold && val<val2) { flag = false; break; } } if (flag) temp.push_back(v1); } peaks = temp; itk::Index<4> idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2]; // fill output image unsigned int num = peaks.size(); if ( num>m_MaxNumPeaks ) num = m_MaxNumPeaks; for (unsigned int i=0; i<num; i++) { DirectionType dir = peaks.at(i); switch (m_NormalizationMethod) { case NO_NORM: break; case SINGLE_VEC_NORM: dir.normalize(); break; case MAX_VEC_NORM: dir /= max; break; } if (m_ApplyDirectionMatrix) dir = m_MaskImage->GetDirection()*dir; if (m_FlipX) dir[0] = -dir[0]; if (m_FlipY) dir[1] = -dir[1]; if (m_FlipZ) dir[2] = -dir[2]; for (unsigned int j = 0; j<3; j++) { idx4[3] = i*3 + j; m_PeakImage->SetPixel(idx4, dir[j]); } } m_NumDirectionsImage->SetPixel(idx3, num); ++cit; } MITK_INFO << "Thread " << threadID << " finished extraction"; }