ANIMA  4.0
animaGMMT2RelaxometryEstimationImageFilter.hxx
Go to the documentation of this file.
1 #pragma once
3 
4 #include <itkImageRegionIterator.h>
5 #include <itkImageRegionConstIterator.h>
6 
7 #include <animaNLOPTOptimizers.h>
9 
10 #include <fstream>
11 #include <boost/lexical_cast.hpp>
12 #include <boost/algorithm/string.hpp>
13 
14 namespace anima
15 {
16 
17 template <class TPixelScalarType>
18 void
19 GMMT2RelaxometryEstimationImageFilter <TPixelScalarType>
20 ::SetGaussianMeans(std::string fileName)
21 {
22  std::ifstream fileIn(fileName.c_str());
23 
24  if (!fileIn.is_open())
25  {
26  std::string errorMsg = "Unable to read file: ";
27  errorMsg += fileName;
28  throw itk::ExceptionObject(__FILE__,__LINE__,errorMsg,ITK_LOCATION);
29  }
30 
31  m_GaussianMeans.clear();
32 
33  while (!fileIn.eof())
34  {
35  char tmpStr[2048];
36  fileIn.getline(tmpStr,2048);
37 
38  std::string workStr(tmpStr);
39  if (workStr == "")
40  continue;
41 
42  boost::algorithm::trim_right(workStr);
43  std::istringstream iss(workStr);
44  std::string shortStr;
45  iss >> shortStr;
46  m_GaussianMeans.push_back(boost::lexical_cast<double> (shortStr));
47  }
48 
49  fileIn.close();
50 }
51 
52 template <class TPixelScalarType>
53 void
55 ::SetGaussianVariances(std::string fileName)
56 {
57  std::ifstream fileIn(fileName.c_str());
58 
59  if (!fileIn.is_open())
60  {
61  std::string errorMsg = "Unable to read file: ";
62  errorMsg += fileName;
63  throw itk::ExceptionObject(__FILE__,__LINE__,errorMsg,ITK_LOCATION);
64  }
65 
66  m_GaussianVariances.clear();
67 
68  while (!fileIn.eof())
69  {
70  char tmpStr[2048];
71  fileIn.getline(tmpStr,2048);
72 
73  std::string workStr(tmpStr);
74  if (workStr == "")
75  continue;
76 
77  boost::algorithm::trim_right(workStr);
78  std::istringstream iss(workStr);
79  std::string shortStr;
80  iss >> shortStr;
81  m_GaussianVariances.push_back(boost::lexical_cast<double> (shortStr));
82  }
83 
84  fileIn.close();
85 }
86 
87 template <class TPixelScalarType>
88 void
90 ::BeforeThreadedGenerateData()
91 {
92  if (m_GaussianVariances.size() != 3)
93  itkExceptionMacro("Number of variance parameters has to be 3...");
94 
95  Superclass::BeforeThreadedGenerateData();
96 
97  this->GetB1OutputImage()->FillBuffer(1.0);
98 
99  m_WeightsImage = VectorOutputImageType::New();
100  m_WeightsImage->Initialize();
101  m_WeightsImage->SetRegions(this->GetInput(0)->GetLargestPossibleRegion());
102  m_WeightsImage->SetSpacing (this->GetInput(0)->GetSpacing());
103  m_WeightsImage->SetOrigin (this->GetInput(0)->GetOrigin());
104  m_WeightsImage->SetDirection (this->GetInput(0)->GetDirection());
105  m_WeightsImage->SetVectorLength(3);
106  m_WeightsImage->Allocate();
107 
108  OutputVectorType zero(3);
109  zero.Fill(0.0);
110  m_WeightsImage->FillBuffer(zero);
111 }
112 
113 template <class TPixelScalarType>
114 void
116 ::CheckComputationMask()
117 {
118  if (this->GetComputationMask())
119  return;
120 
121  typedef itk::ImageRegionConstIterator <InputImageType> IteratorType;
122  typedef itk::ImageRegionIterator <MaskImageType> MaskIteratorType;
123 
124  std::vector <IteratorType> inItrs(this->GetNumberOfIndexedInputs());
125  for (unsigned int i = 0;i < this->GetNumberOfIndexedInputs();++i)
126  inItrs[i] = IteratorType(this->GetInput(i),this->GetOutput(0)->GetLargestPossibleRegion());
127 
128  typename MaskImageType::Pointer maskImage = MaskImageType::New();
129  maskImage->Initialize();
130  maskImage->SetRegions(this->GetInput(0)->GetLargestPossibleRegion());
131  maskImage->SetSpacing (this->GetInput(0)->GetSpacing());
132  maskImage->SetOrigin (this->GetInput(0)->GetOrigin());
133  maskImage->SetDirection (this->GetInput(0)->GetDirection());
134  maskImage->Allocate();
135 
136  MaskIteratorType maskItr (maskImage,this->GetOutput(0)->GetLargestPossibleRegion());
137  while (!maskItr.IsAtEnd())
138  {
139  double averageVal = 0;
140  for (unsigned int i = 0;i < this->GetNumberOfIndexedInputs();++i)
141  averageVal += inItrs[i].Get();
142 
143  averageVal /= this->GetNumberOfIndexedInputs();
144 
145  bool maskPoint = (averageVal <= m_AverageSignalThreshold);
146 
147  if (maskPoint)
148  maskItr.Set(0);
149  else
150  maskItr.Set(1);
151 
152  for (unsigned int i = 0;i < this->GetNumberOfIndexedInputs();++i)
153  ++inItrs[i];
154 
155  ++maskItr;
156  }
157 
158  this->SetComputationMask(maskImage);
159 }
160 
161 template <class TPixelScalarType>
162 void
164 ::DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread)
165 {
166  typedef itk::ImageRegionConstIterator <InputImageType> ImageConstIteratorType;
167  typedef itk::ImageRegionIterator <InputImageType> ImageIteratorType;
168  typedef itk::ImageRegionIterator <VectorOutputImageType> VectorImageIteratorType;
169 
170  VectorImageIteratorType outWeightsIterator(this->GetWeightsImage(),outputRegionForThread);
171  ImageIteratorType outM0Iterator(this->GetM0OutputImage(),outputRegionForThread);
172  ImageIteratorType outMWFIterator(this->GetMWFOutputImage(),outputRegionForThread);
173  ImageIteratorType outB1Iterator(this->GetB1OutputImage(),outputRegionForThread);
174  ImageIteratorType outSigmaSqIterator(this->GetSigmaSquareOutputImage(),outputRegionForThread);
175 
176  unsigned int numInputs = this->GetNumberOfIndexedInputs();
177  std::vector <ImageConstIteratorType> inIterators;
178  for (unsigned int i = 0;i < numInputs;++i)
179  inIterators.push_back(ImageConstIteratorType(this->GetInput(i),outputRegionForThread));
180 
181  typedef itk::ImageRegionIterator <MaskImageType> MaskIteratorType;
182  MaskIteratorType maskItr(this->GetComputationMask(),outputRegionForThread);
183 
184  ImageIteratorType t1MapItr;
185  if (m_T1Map)
186  t1MapItr = ImageIteratorType(m_T1Map,outputRegionForThread);
187 
188  typedef anima::NLOPTOptimizers B1OptimizerType;
189  typedef anima::B1GMMRelaxometryCostFunction B1CostFunctionType;
190 
191  B1OptimizerType::ParametersType signalValues(numInputs);
192  unsigned int numberOfGaussians = m_GaussianMeans.size();
193  OutputVectorType outputT2Weights(numberOfGaussians);
194  B1OptimizerType::ParametersType t2OptimizedWeights(numberOfGaussians);
195 
196  typename B1CostFunctionType::Pointer cost = B1CostFunctionType::New();
197  cost->SetEchoSpacing(m_EchoSpacing);
198  cost->SetExcitationFlipAngle(m_T2ExcitationFlipAngle);
199 
200  unsigned int dimension = cost->GetNumberOfParameters();
201  itk::Array<double> lowerBounds(dimension);
202  itk::Array<double> upperBounds(dimension);
203  B1OptimizerType::ParametersType p(dimension);
204  lowerBounds[0] = 1.0 * m_T2FlipAngles[0];
205  upperBounds[0] = 2.0 * m_T2FlipAngles[0];
206 
207  cost->SetGaussianMeans(m_GaussianMeans);
208  cost->SetGaussianVariances(m_GaussianVariances);
209  cost->SetGaussianIntegralTolerance(m_GaussianIntegralTolerance);
210 
211  while (!maskItr.IsAtEnd())
212  {
213  outputT2Weights.Fill(0);
214 
215  if (maskItr.Get() == 0)
216  {
217  outWeightsIterator.Set(outputT2Weights);
218  outM0Iterator.Set(0);
219  outMWFIterator.Set(0.0);
220  outB1Iterator.Set(1.0);
221  outSigmaSqIterator.Set(0.0);
222 
223  ++maskItr;
224  ++outWeightsIterator;
225  ++outM0Iterator;
226  ++outMWFIterator;
227  ++outB1Iterator;
228  ++outSigmaSqIterator;
229 
230  for (unsigned int i = 0;i < numInputs;++i)
231  ++inIterators[i];
232 
233  if (m_T1Map)
234  ++t1MapItr;
235 
236  continue;
237  }
238 
239  double t1Value = 1000.0;
240  double m0Value = 0.0;
241 
242  for (unsigned int i = 0;i < numInputs;++i)
243  signalValues[i] = inIterators[i].Get();
244 
245  if (m_T1Map)
246  {
247  t1Value = t1MapItr.Get();
248  if (t1Value <= 0.0)
249  t1Value = 1000.0;
250  }
251 
252  cost->SetT1Value(t1Value);
253  cost->SetT2RelaxometrySignals(signalValues);
254 
255  B1OptimizerType::Pointer b1Optimizer = B1OptimizerType::New();
256  b1Optimizer->SetAlgorithm(NLOPT_LN_BOBYQA);
257  b1Optimizer->SetCostFunction(cost);
258  b1Optimizer->SetXTolRel(1.0e-5);
259  b1Optimizer->SetFTolRel(1.0e-7);
260  b1Optimizer->SetMaxEval(500);
261  b1Optimizer->SetVectorStorageSize(2000);
262  b1Optimizer->SetLowerBoundParameters(lowerBounds);
263  b1Optimizer->SetUpperBoundParameters(upperBounds);
264 
265  p[0] = 1.1 * m_T2FlipAngles[0];
266 
267  b1Optimizer->SetInitialPosition(p);
268  b1Optimizer->SetCostFunction(cost);
269 
270  b1Optimizer->StartOptimization();
271  p = b1Optimizer->GetCurrentPosition();
272 
273  t2OptimizedWeights = cost->GetOptimalT2Weights();
274 
275  m0Value = 0;
276  for (unsigned int i = 0;i < numberOfGaussians;++i)
277  m0Value += t2OptimizedWeights[i];
278 
279  for (unsigned int i = 0;i < numberOfGaussians;++i)
280  {
281  if (m0Value > 0.0)
282  outputT2Weights[i] = t2OptimizedWeights[i] / m0Value;
283  else
284  outputT2Weights[i] = 0.0;
285  }
286 
287  outM0Iterator.Set(m0Value);
288  outWeightsIterator.Set(outputT2Weights);
289 
290  double mwfValue = outputT2Weights[0];
291 
292  outMWFIterator.Set(mwfValue);
293 
294  double b1Value = p[0] / m_T2FlipAngles[0];
295  outB1Iterator.Set(b1Value);
296  outSigmaSqIterator.Set(cost->GetSigmaSquare());
297 
298  this->IncrementNumberOfProcessedPoints();
299  ++maskItr;
300  ++outWeightsIterator;
301  ++outM0Iterator;
302  ++outMWFIterator;
303  ++outB1Iterator;
304  ++outSigmaSqIterator;
305 
306  for (unsigned int i = 0;i < numInputs;++i)
307  ++inIterators[i];
308 
309  if (m_T1Map)
310  ++t1MapItr;
311  }
312 }
313 
314 } // end namespace anima
Cost function for estimating B1 from T2 relaxometry acquisition, following a multi-T2 EPG decay model...
Implements an ITK wrapper for the NLOPT library.