16 #ifndef __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp
17 #define __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp
20 #include "itkImageRegionConstIterator.h"
21 #include "itkImageRegionConstIteratorWithIndex.h"
22 #include "itkImageRegionIterator.h"
24 #include "vnl/vnl_matrix.h"
25 #include "vnl/algo/vnl_symmetric_eigensystem.h"
31 #define IVIM_FOO -100000
36 template<
class TIn,
class TOut>
39 m_GradientDirectionContainer(nullptr),
40 m_Method(IVIM_DSTAR_FIX),
44 this->SetNumberOfRequiredInputs( 1 );
46 this->SetNumberOfRequiredOutputs( 3 );
48 this->SetNthOutput(0, outputPtr1.GetPointer());
50 this->SetNthOutput(1, outputPtr2.GetPointer());
52 this->SetNthOutput(2, outputPtr3.GetPointer());
57 template<
class TIn,
class TOut>
63 std::string gradientImageClassName(
64 this->ProcessObject::GetInput(0)->GetNameOfClass());
65 if ( strcmp(gradientImageClassName.c_str(),
"VectorImage") != 0 )
68 "There is only one Gradient image. I expect that to be a VectorImage. "
69 <<
"But its of type: " << gradientImageClassName );
74 GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin();
76 while( gdcit != this->m_GradientDirectionContainer->End() )
78 double norm = gdcit.Value().one_norm();
84 gdcit = this->m_GradientDirectionContainer->Begin();
85 while( gdcit != this->m_GradientDirectionContainer->End() )
87 if(gdcit.Value().one_norm() <= minNorm)
89 m_Snap.baselineind.push_back(gdcit.Index());
93 m_Snap.gradientind.push_back(gdcit.Index());
94 double twonorm = gdcit.Value().two_norm();
95 m_Snap.bvals.push_back( m_BValue*twonorm*twonorm );
99 if (m_Snap.gradientind.size()==0)
100 itkExceptionMacro(
"Only one b-value supplied. At least two needed for IVIM fit.");
103 m_Snap.iterated_sequence =
false;
104 if(m_Snap.baselineind.size() == m_Snap.gradientind.size())
106 int size = m_Snap.baselineind.size();
107 int sum_b = 0, sum_g = 0;
108 for(
int i=0; i<size; i++)
110 sum_b += m_Snap.baselineind.at(i) % 2;
111 sum_g += m_Snap.gradientind.at(i) % 2;
113 if( (sum_b == size || sum_b == 0)
114 && (sum_g == size || sum_g == 0) )
116 m_Snap.iterated_sequence =
true;
119 MITK_INFO <<
"Iterating b0 and diffusion weighted aquisition detected. Weighting each weighted measurement with its own b0.";
125 m_Snap.N = m_Snap.gradientind.size();
128 m_Snap.bvalues.set_size(m_Snap.N);
129 for(
int i=0; i<m_Snap.N; i++)
131 m_Snap.bvalues[i] = m_Snap.bvals.at(i);
136 std::cout <<
"ref bval: " << m_BValue <<
"; b-values: ";
137 for(
int i=0; i<m_Snap.N; i++)
139 std::cout << m_Snap.bvalues[i] <<
"; ";
141 std::cout << std::endl;
145 if(m_Method == IVIM_D_THEN_DSTAR || m_Method == IVIM_LINEAR_D_THEN_F || m_Method == IVIM_REGULARIZED)
147 for(
int i=0; i<m_Snap.N; i++)
149 if(m_Snap.bvalues[i]>m_BThres)
151 m_Snap.high_indices.push_back(i);
155 m_Snap.Nhigh = m_Snap.high_indices.size();
156 m_Snap.high_bvalues.set_size(m_Snap.Nhigh);
157 m_Snap.high_meas.set_size(m_Snap.Nhigh);
158 for(
int i=0; i<m_Snap.Nhigh; i++)
160 m_Snap.high_bvalues[i] = m_Snap.bvalues[m_Snap.high_indices.at(i)];
165 template<
class TIn,
class TOut>
169 std::vector<double> newmeas;
170 std::vector<double> newbvals;
173 for(
int i=0; i<N; i++)
177 newmeas.push_back(meas[i]);
178 newbvals.push_back(bvals[i]);
184 retval.
N = newmeas.size();
186 retval.
meas.set_size(retval.
N);
187 for(
size_t i=0; i<newmeas.size(); i++)
189 retval.
meas[i] = newmeas[i];
192 retval.
bvals.set_size(retval.
N);
193 for(
size_t i=0; i<newbvals.size(); i++)
195 retval.
bvals[i] = newbvals[i];
201 template<
class TIn,
class TOut>
208 static_cast< OutputImageType *
>(this->ProcessObject::GetPrimaryOutput());
209 ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread);
214 ImageRegionIterator< OutputImageType > oit1(dImage, outputRegionForThread);
219 ImageRegionIterator< OutputImageType > oit2(dstarImage, outputRegionForThread);
222 typedef ImageRegionConstIterator< InputImageType > InputIteratorType;
229 this->ProcessObject::GetInput(0) );
231 InputIteratorType iit(inputImagePointer, outputRegionForThread );
236 m_InternalVectorImage->SetSpacing( inputImagePointer->GetSpacing() );
237 m_InternalVectorImage->SetOrigin( inputImagePointer->GetOrigin() );
238 m_InternalVectorImage->SetDirection( inputImagePointer->GetDirection() );
239 m_InternalVectorImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() );
242 m_InitialFitImage->SetSpacing( inputImagePointer->GetSpacing() );
243 m_InitialFitImage->SetOrigin( inputImagePointer->GetOrigin() );
244 m_InitialFitImage->SetDirection( inputImagePointer->GetDirection() );
245 m_InitialFitImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() );
247 if(m_Method == IVIM_REGULARIZED)
249 m_InternalVectorImage->SetVectorLength(m_Snap.Nhigh);
250 m_InternalVectorImage->Allocate();
252 for(
int i=0; i<m_Snap.Nhigh; i++) varvec[i] =
IVIM_FOO;
253 m_InternalVectorImage->FillBuffer(varvec);
255 m_InitialFitImage->Allocate();
257 vec[0] = 0.5; vec[1] = 0.01; vec[2]=0.001;
258 m_InitialFitImage->FillBuffer(vec);
261 typedef itk::ImageRegionIterator<VectorImageType> VectorIteratorType;
262 VectorIteratorType vecit(m_InternalVectorImage, outputRegionForThread );
265 typedef itk::ImageRegionIterator<InitialFitImageType> InitIteratorType;
266 InitIteratorType initit(m_InitialFitImage, outputRegionForThread );
269 while( !iit.IsAtEnd() )
271 InputVectorType measvec = iit.Get();
273 typename NumericTraits<InputPixelType>::AccumulateType b0 = NumericTraits<InputPixelType>::Zero;
275 m_Snap.meas.set_size(m_Snap.N);
276 m_Snap.allmeas.set_size(m_Snap.N);
277 if(!m_Snap.iterated_sequence)
280 for(
unsigned int i = 0; i < m_Snap.baselineind.size(); ++i)
282 b0 += measvec[m_Snap.baselineind[i]];
284 if(m_Snap.baselineind.size())
285 b0 /= m_Snap.baselineind.size();
288 for(
int i = 0; i < m_Snap.N; ++i)
290 m_Snap.allmeas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001);
292 if(measvec[m_Snap.gradientind[i]] > m_S0Thres)
294 m_Snap.meas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001);
305 for(
int i = 0; i < m_Snap.N; ++i)
307 b0 = measvec[m_Snap.baselineind[i]];
309 m_Snap.allmeas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001);
311 if(measvec[m_Snap.gradientind[i]] > m_S0Thres)
313 m_Snap.meas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001);
324 m_Snap.currentDStar = 0;
329 case IVIM_D_THEN_DSTAR:
332 for(
int i=0; i<m_Snap.Nhigh; i++)
334 m_Snap.high_meas[i] = m_Snap.meas[m_Snap.high_indices.at(i)];
337 MeasAndBvals input = ApplyS0Threshold(m_Snap.high_meas, m_Snap.high_bvalues);
338 m_Snap.bvals1 = input.
bvals;
339 m_Snap.meas1 = input.
meas;
345 m_Snap.currentD = - log(input.
meas[0]) / input.
bvals[0];
347 m_Snap.currentDStar = 0;
356 vnl_vector< double > x_donly(2);
361 vnl_levenberg_marquardt lm_donly(f_donly);
362 lm_donly.set_f_tolerance(0.0001);
363 lm_donly.minimize(x_donly);
364 m_Snap.currentD = x_donly[0];
365 m_Snap.currentF = x_donly[1];
370 MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues);
371 m_Snap.bvals2 = input2.
bvals;
372 m_Snap.meas2 = input2.
meas;
373 if (input2.
N < 2)
break;
379 vnl_vector< double > x_dstar_only(1);
380 vnl_vector< double > fx_dstar_only(input2.
N);
382 double opt = 1111111111111111.0;
385 double min_val = .001;
386 double max_val = .15;
387 for(
int i=0; i<num_its; i++)
389 x_dstar_only[0] = min_val + i * ((max_val-min_val) / num_its);
390 f_dstar_only.
f(x_dstar_only, fx_dstar_only);
391 double err = fx_dstar_only.two_norm();
399 m_Snap.currentDStar = min_val + opt_idx * ((max_val-min_val) / num_its);
422 MeasAndBvals input = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues);
423 m_Snap.bvals1 = input.
bvals;
424 m_Snap.meas1 = input.
meas;
425 if (input.
N < 2)
break;
431 vnl_vector< double > x(2);
436 vnl_levenberg_marquardt lm(f_fixdstar);
437 lm.set_f_tolerance(0.0001);
440 m_Snap.currentF = x[0];
441 m_Snap.currentD = x[1];
442 m_Snap.currentDStar = m_DStar;
450 MeasAndBvals input = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues);
451 m_Snap.bvals1 = input.
bvals;
452 m_Snap.meas1 = input.
meas;
453 if (input.
N < 3)
break;
459 vnl_vector< double > x(3);
465 vnl_levenberg_marquardt lm(f_3param);
466 lm.set_f_tolerance(0.0001);
469 m_Snap.currentF = x[0];
470 m_Snap.currentD = x[1];
471 m_Snap.currentDStar = x[2];
476 case IVIM_LINEAR_D_THEN_F:
492 for(
int i=0; i<m_Snap.Nhigh; i++)
494 m_Snap.high_meas[i] = m_Snap.meas[m_Snap.high_indices.at(i)];
497 MeasAndBvals input = ApplyS0Threshold(m_Snap.high_meas, m_Snap.high_bvalues);
498 m_Snap.bvals1 = input.
bvals;
499 m_Snap.meas1 = input.
meas;
505 m_Snap.currentD = - log(input.
meas[0]) / input.
bvals[0];
507 m_Snap.currentDStar = 0;
512 for(
int i=0; i<input.
N; i++)
519 for(
int i=0; i<input.
N; i++)
521 bval_m += input.
bvals[i];
522 meas_m += input.
meas[i];
527 vnl_matrix<double> X(input.
N,2);
528 for(
int i=0; i<input.
N; i++)
530 X(i,0) = input.
bvals[i] - bval_m;
531 X(i,1) = input.
meas[i] - meas_m;
534 vnl_matrix<double> XX = X.transpose() * X;
535 vnl_symmetric_eigensystem<double> eigs(XX);
537 vnl_vector<double> eig;
538 if(eigs.get_eigenvalue(0) > eigs.get_eigenvalue(1))
539 eig = eigs.get_eigenvector(0);
541 eig = eigs.get_eigenvector(1);
543 m_Snap.currentF = 1 - exp( meas_m - bval_m*(eig(1)/eig(0)) );
544 m_Snap.currentD = -eig(1)/eig(0);
548 MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues);
549 m_Snap.bvals2 = input2.
bvals;
550 m_Snap.meas2 = input2.
meas;
551 if (input2.
N < 2)
break;
557 vnl_vector< double > x_dstar_only(1);
558 vnl_vector< double > fx_dstar_only(input2.
N);
560 double opt = 1111111111111111.0;
563 double min_val = .001;
564 double max_val = .15;
565 for(
int i=0; i<num_its; i++)
567 x_dstar_only[0] = min_val + i * ((max_val-min_val) / num_its);
568 f_dstar_only.
f(x_dstar_only, fx_dstar_only);
569 double err = fx_dstar_only.two_norm();
577 m_Snap.currentDStar = min_val + opt_idx * ((max_val-min_val) / num_its);
592 case IVIM_REGULARIZED:
595 for(
int i=0; i<m_Snap.Nhigh; i++)
597 m_Snap.high_meas[i] = m_Snap.meas[m_Snap.high_indices.at(i)];
600 MeasAndBvals input = ApplyS0Threshold(m_Snap.high_meas, m_Snap.high_bvalues);
602 vnl_vector< double > x_donly(2);
612 vnl_levenberg_marquardt lm_donly(f_donly);
613 lm_donly.set_f_tolerance(0.0001);
614 lm_donly.minimize(x_donly);
618 initvec[0] = x_donly[1];
619 initvec[1] = x_donly[0];
624 int N = m_Snap.high_meas.size();
626 for(
int i=0; i<N; i++)
628 vec[i] = m_Snap.high_meas[i];
638 if( vecit.GetIndex()[0] == m_CrossPosition[0]
639 && vecit.GetIndex()[0] == m_CrossPosition[1]
640 && vecit.GetIndex()[0] == m_CrossPosition[2] )
642 MeasAndBvals input = ApplyS0Threshold(m_Snap.high_meas, m_Snap.high_bvalues);
643 m_Snap.bvals1 = input.
bvals;
644 m_Snap.meas1 = input.
meas;
646 MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues);
647 m_Snap.bvals2 = input2.
bvals;
648 m_Snap.meas2 = input2.
meas;
650 m_tmp_allmeas = m_Snap.allmeas;
657 m_Snap.currentFunceiled = m_Snap.currentF;
660 oit.Set( m_Snap.currentF );
661 oit1.Set( m_Snap.currentD );
662 oit2.Set( m_Snap.currentDStar );
674 std::cout <<
"One Thread finished reconstruction" << std::endl;
678 template<
class TIn,
class TOut>
682 if(m_Method == IVIM_REGULARIZED)
685 static_cast< OutputImageType *
>(this->ProcessObject::GetPrimaryOutput());
686 ImageRegionIterator< OutputImageType > oit0(outputImage, outputImage->GetLargestPossibleRegion());
691 ImageRegionIterator< OutputImageType > oit1(dImage, dImage->GetLargestPossibleRegion());
696 ImageRegionIterator< OutputImageType > oit2(dstarImage, dstarImage->GetLargestPossibleRegion());
700 <double,double,
float> RegFitType;
702 filter->SetInput(m_InitialFitImage);
703 filter->SetReferenceImage(m_InternalVectorImage);
704 filter->SetBValues(m_Snap.high_bvalues);
705 filter->SetNumberIterations(m_NumberIterations);
706 filter->SetNumberOfThreads(1);
707 filter->SetLambda(m_Lambda);
711 ImageRegionConstIterator< RegFitType::OutputImageType > iit(outimg, outimg->GetLargestPossibleRegion());
714 while( !iit.IsAtEnd() )
716 double f = iit.Get()[0];
719 oit0.Set( myround(f * 100.0) );
720 oit1.Set( myround(iit.Get()[1] * 10000.0) );
721 oit2.Set( myround(iit.Get()[2] * 1000.0) );
726 if( iit.GetIndex()[0] == m_CrossPosition[0]
727 && iit.GetIndex()[1] == m_CrossPosition[1]
728 && iit.GetIndex()[2] == m_CrossPosition[2] )
731 m_Snap.currentD = iit.Get()[1];
732 m_Snap.currentDStar = iit.Get()[2];
733 m_Snap.allmeas = m_tmp_allmeas;
734 MITK_INFO <<
"setting " << f <<
";" << iit.Get()[1] <<
";" << iit.Get()[2];
746 template<
class TIn,
class TOut>
750 return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5);
753 template<
class TIn,
class TOut>
757 this->m_GradientDirectionContainer = gradientDirection;
758 this->m_NumberOfGradientDirections = gradientDirection->Size();
761 template<
class TIn,
class TOut>
765 Superclass::PrintSelf(os,indent);
767 if ( m_GradientDirectionContainer )
769 os << indent <<
"GradientDirectionContainer: "
770 << m_GradientDirectionContainer << std::endl;
775 "GradientDirectionContainer: (Gradient directions not set)" << std::endl;
781 #endif // __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp
VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType)
itk::SmartPointer< Self > Pointer
void set_bvalues(const vnl_vector< double > &x)
vnl_vector< double > meas
MeasAndBvals ApplyS0Threshold(vnl_vector< double > &meas, vnl_vector< double > &bvals)
#define IVIM_CEIL(val, u, o)
void PrintSelf(std::ostream &os, Indent indent) const
void SetGradientDirections(GradientDirectionContainerType *)
Superclass::OutputImageRegionType OutputImageRegionType
void AfterThreadedGenerateData()
void f(const vnl_vector< double > &x, vnl_vector< double > &fx) override
void BeforeThreadedGenerateData()
Applies a total variation denoising filter to an image.
vnl_vector< double > bvals
Image< OutputPixelType, 3 > OutputImageType
DiffusionIntravoxelIncoherentMotionReconstructionImageFilter()
void set_measurements(const vnl_vector< double > &x)
Superclass::InputImageType InputImageType
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.