Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
itkShortestPathCostFunctionLiveWire.txx
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #ifndef __itkShortestPathCostFunctionLiveWire_txx
14 #define __itkShortestPathCostFunctionLiveWire_txx
15 
16 #include "itkShortestPathCostFunctionLiveWire.h"
17 
18 #include <cmath>
19 
20 #include <itkCannyEdgeDetectionImageFilter.h>
21 #include <itkCastImageFilter.h>
22 #include <itkGradientImageFilter.h>
23 #include <itkGradientMagnitudeImageFilter.h>
24 #include <itkLaplacianImageFilter.h>
25 #include <itkStatisticsImageFilter.h>
26 #include <itkZeroCrossingImageFilter.h>
27 
28 namespace itk
29 {
30  // Constructor
31  template <class TInputImageType>
32  ShortestPathCostFunctionLiveWire<TInputImageType>::ShortestPathCostFunctionLiveWire(): m_MinCosts(0.0), m_UseRepulsivePoints(false), m_GradientMax(0.0), m_Initialized(false), m_UseCostMap(false), m_MaxMapCosts(-1.0)
33  {
34  }
35 
36  template <class TInputImageType>
37  void ShortestPathCostFunctionLiveWire<TInputImageType>::AddRepulsivePoint(const IndexType &index)
38  {
39  this->m_MaskImage->SetPixel(index, 255);
40  m_UseRepulsivePoints = true;
41  }
42 
43  template <class TInputImageType>
44  void ShortestPathCostFunctionLiveWire<TInputImageType>::RemoveRepulsivePoint(const IndexType &index)
45  {
46  this->m_MaskImage->SetPixel(index, 0);
47  }
48 
49  template <class TInputImageType>
50  void ShortestPathCostFunctionLiveWire<TInputImageType>::SetImage(const TInputImageType *_arg)
51  {
52  if (this->m_Image != _arg)
53  {
54  this->m_Image = _arg;
55 
56  // initialize mask image
57  this->m_MaskImage = UnsignedCharImageType::New();
58  this->m_MaskImage->SetRegions(this->m_Image->GetLargestPossibleRegion());
59  this->m_MaskImage->SetOrigin(this->m_Image->GetOrigin());
60  this->m_MaskImage->SetSpacing(this->m_Image->GetSpacing());
61  this->m_MaskImage->SetDirection(this->m_Image->GetDirection());
62  this->m_MaskImage->Allocate();
63  this->m_MaskImage->FillBuffer(0);
64 
65  this->Modified();
66  this->m_Initialized = false;
67  }
68  }
69 
70  template <class TInputImageType>
71  void ShortestPathCostFunctionLiveWire<TInputImageType>::ClearRepulsivePoints()
72  {
73  m_UseRepulsivePoints = false;
74  this->m_MaskImage->FillBuffer(0);
75  }
76 
77  template <class TInputImageType>
78  double ShortestPathCostFunctionLiveWire<TInputImageType>::GetCost(IndexType p1, IndexType p2)
79  {
80  // local component costs
81  // weights
82  double w1;
83  double w2;
84  double w3;
85  double costs = 0.0;
86 
87  // if we are on the mask, return asap
88  if (m_UseRepulsivePoints)
89  {
90  if ((this->m_MaskImage->GetPixel(p1) != 0) || (this->m_MaskImage->GetPixel(p2) != 0))
91  return 1000;
92  }
93 
94  double gradientX, gradientY;
95  gradientX = gradientY = 0.0;
96 
97  double gradientCost;
98 
99  double gradientMagnitude;
100 
101  // Gradient Magnitude costs
102  gradientMagnitude = this->m_GradientMagnitudeImage->GetPixel(p2);
103  gradientX = m_GradientImage->GetPixel(p2)[0];
104  gradientY = m_GradientImage->GetPixel(p2)[1];
105 
106  if (m_UseCostMap && !m_CostMap.empty())
107  {
108  std::map<int, int>::iterator end = m_CostMap.end();
109  std::map<int, int>::iterator last = --(m_CostMap.end());
110 
111  // current position
112  std::map<int, int>::iterator x;
113  // std::map< int, int >::key_type keyOfX = static_cast<std::map< int, int >::key_type>(gradientMagnitude * 1000);
114  int keyOfX = static_cast<int>(gradientMagnitude /* ShortestPathCostFunctionLiveWire::MAPSCALEFACTOR*/);
115  x = m_CostMap.find(keyOfX);
116 
117  std::map<int, int>::iterator left2;
118  std::map<int, int>::iterator left1;
119  std::map<int, int>::iterator right1;
120  std::map<int, int>::iterator right2;
121 
122  if (x == end)
123  { // x can also be == end if the key is not in the map but between two other keys
124  // search next key within map from x upwards
125  right1 = m_CostMap.lower_bound(keyOfX);
126  }
127  else
128  {
129  right1 = x;
130  }
131 
132  if (right1 == end || right1 == last)
133  {
134  right2 = end;
135  }
136  else //( right1 != (end-1) )
137  {
138  auto temp = right1;
139  right2 = ++right1; // rght1 + 1
140  right1 = temp;
141  }
142 
143  if (right1 == m_CostMap.begin())
144  {
145  left1 = end;
146  left2 = end;
147  }
148  else if (right1 == (++(m_CostMap.begin())))
149  {
150  auto temp = right1;
151  left1 = --right1; // rght1 - 1
152  right1 = temp;
153  left2 = end;
154  }
155  else
156  {
157  auto temp = right1;
158  left1 = --right1; // rght1 - 1
159  left2 = --right1; // rght1 - 2
160  right1 = temp;
161  }
162 
163  double partRight1, partRight2, partLeft1, partLeft2;
164  partRight1 = partRight2 = partLeft1 = partLeft2 = 0.0;
165 
166  /*
167  f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 )
168 
169  gaussian approximation
170 
171  where
172  v(bin) is the value in the map
173  k(bin) is the key
174  */
175 
176  if (left2 != end)
177  {
178  partLeft2 = ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(keyOfX, left2->first, left2->second);
179  }
180 
181  if (left1 != end)
182  {
183  partLeft1 = ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(keyOfX, left1->first, left1->second);
184  }
185 
186  if (right1 != end)
187  {
188  partRight1 = ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(keyOfX, right1->first, right1->second);
189  }
190 
191  if (right2 != end)
192  {
193  partRight2 = ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(keyOfX, right2->first, right2->second);
194  }
195 
196  if (m_MaxMapCosts > 0.0)
197  {
198  gradientCost = 1.0 - ((partRight1 + partRight2 + partLeft1 + partLeft2) / m_MaxMapCosts);
199  }
200  else
201  { // use linear mapping
202  gradientCost = 1.0 - (gradientMagnitude / m_GradientMax);
203  }
204  }
205  else
206  { // use linear mapping
207  // value between 0 (good) and 1 (bad)
208  gradientCost = 1.0 - (gradientMagnitude / m_GradientMax);
209  }
210 
211  // Laplacian zero crossing costs
212  // f(p) = 0; if I(p)=0
213  // or 1; if I(p)!=0
214  double laplacianCost;
215  typename Superclass::PixelType laplaceImageValue;
216 
217  laplaceImageValue = m_EdgeImage->GetPixel(p2);
218 
219  if (laplaceImageValue < 0 || laplaceImageValue > 0)
220  {
221  laplacianCost = 1.0;
222  }
223  else
224  {
225  laplacianCost = 0.0;
226  }
227 
228  // gradient vector at p1
229  double nGradientAtP1[2];
230  nGradientAtP1[0] = gradientX; // previously computed for gradient magnitude
231  nGradientAtP1[1] = gradientY;
232 
233  // gradient direction unit vector of p1
234  nGradientAtP1[0] /= gradientMagnitude;
235  nGradientAtP1[1] /= gradientMagnitude;
236  //-------
237 
238  // gradient vector at p1
239  double nGradientAtP2[2];
240 
241  nGradientAtP2[0] = m_GradientImage->GetPixel(p2)[0];
242  nGradientAtP2[1] = m_GradientImage->GetPixel(p2)[1];
243 
244  nGradientAtP2[0] /= m_GradientMagnitudeImage->GetPixel(p2);
245  nGradientAtP2[1] /= m_GradientMagnitudeImage->GetPixel(p2);
246 
247  double scalarProduct = (nGradientAtP1[0] * nGradientAtP2[0]) + (nGradientAtP1[1] * nGradientAtP2[1]);
248  if (std::abs(scalarProduct) >= 1.0)
249  {
250  // this should probably not happen; make sure the input for acos is valid
251  scalarProduct = 0.999999999;
252  }
253 
254  double gradientDirectionCost = acos(scalarProduct) / 3.14159265;
255 
256  if (this->m_UseCostMap)
257  {
258  w1 = 0.43;
259  w2 = 0.43;
260  w3 = 0.14;
261  }
262  else
263  {
264  w1 = 0.10;
265  w2 = 0.85;
266  w3 = 0.05;
267  }
268  costs = w1 * laplacianCost + w2 * gradientCost + w3 * gradientDirectionCost;
269 
270  // scale by euclidian distance
271  double costScale;
272  if (p1[0] == p2[0] || p1[1] == p2[1])
273  {
274  // horizontal or vertical neighbor
275  costScale = 1.0;
276  }
277  else
278  {
279  // diagonal neighbor
280  costScale = sqrt(2.0);
281  }
282 
283  costs *= costScale;
284 
285  return costs;
286  }
287 
288  template <class TInputImageType>
289  double ShortestPathCostFunctionLiveWire<TInputImageType>::GetMinCost()
290  {
291  return m_MinCosts;
292  }
293 
294  template <class TInputImageType>
295  void ShortestPathCostFunctionLiveWire<TInputImageType>::Initialize()
296  {
297  if (!m_Initialized)
298  {
299  typedef itk::CastImageFilter<TInputImageType, FloatImageType> CastFilterType;
300  typename CastFilterType::Pointer castFilter = CastFilterType::New();
301  castFilter->SetInput(this->m_Image);
302 
303  // init gradient magnitude image
304  typedef itk::GradientMagnitudeImageFilter<FloatImageType, FloatImageType> GradientMagnitudeFilterType;
305  typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New();
306  gradientFilter->SetInput(castFilter->GetOutput());
307  // gradientFilter->SetNumberOfThreads(4);
308  // gradientFilter->GetOutput()->SetRequestedRegion(m_RequestedRegion);
309 
310  gradientFilter->Update();
311  this->m_GradientMagnitudeImage = gradientFilter->GetOutput();
312 
313  typedef itk::StatisticsImageFilter<FloatImageType> StatisticsImageFilterType;
314  typename StatisticsImageFilterType::Pointer statisticsImageFilter = StatisticsImageFilterType::New();
315  statisticsImageFilter->SetInput(this->m_GradientMagnitudeImage);
316  statisticsImageFilter->Update();
317 
318  m_GradientMax = statisticsImageFilter->GetMaximum();
319 
320  typedef itk::GradientImageFilter<FloatImageType> GradientFilterType;
321 
322  typename GradientFilterType::Pointer filter = GradientFilterType::New();
323  // sigma is specified in millimeters
324  // filter->SetSigma( 1.5 );
325  filter->SetInput(castFilter->GetOutput());
326  filter->Update();
327 
328  m_GradientImage = filter->GetOutput();
329 
330  // init zero crossings
331  // typedef itk::ZeroCrossingImageFilter< TInputImageType, UnsignedCharImageType > ZeroCrossingImageFilterType;
332  // ZeroCrossingImageFilterType::Pointer zeroCrossingImageFilter = ZeroCrossingImageFilterType::New();
333  // zeroCrossingImageFilter->SetInput(this->m_Image);
334  // zeroCrossingImageFilter->SetBackgroundValue(1);
335  // zeroCrossingImageFilter->SetForegroundValue(0);
336  // zeroCrossingImageFilter->SetNumberOfThreads(4);
337  // zeroCrossingImageFilter->Update();
338 
339  // m_EdgeImage = zeroCrossingImageFilter->GetOutput();
340 
341  // cast image to float to apply canny edge dection filter
342  /*typedef itk::CastImageFilter< TInputImageType, FloatImageType > CastFilterType;
343  CastFilterType::Pointer castFilter = CastFilterType::New();
344  castFilter->SetInput(this->m_Image);*/
345 
346  // typedef itk::LaplacianImageFilter<FloatImageType, FloatImageType > filterType;
347  // filterType::Pointer laplacianFilter = filterType::New();
348  // laplacianFilter->SetInput( castFilter->GetOutput() ); // NOTE: input image type must be double or float
349  // laplacianFilter->Update();
350 
351  // m_EdgeImage = laplacianFilter->GetOutput();
352 
353  // init canny edge detection
354  typedef itk::CannyEdgeDetectionImageFilter<FloatImageType, FloatImageType> CannyEdgeDetectionImageFilterType;
355  typename CannyEdgeDetectionImageFilterType::Pointer cannyEdgeDetectionfilter =
356  CannyEdgeDetectionImageFilterType::New();
357  cannyEdgeDetectionfilter->SetInput(castFilter->GetOutput());
358  cannyEdgeDetectionfilter->SetUpperThreshold(30);
359  cannyEdgeDetectionfilter->SetLowerThreshold(15);
360  cannyEdgeDetectionfilter->SetVariance(4);
361  cannyEdgeDetectionfilter->SetMaximumError(.01f);
362 
363  cannyEdgeDetectionfilter->Update();
364  m_EdgeImage = cannyEdgeDetectionfilter->GetOutput();
365 
366  // set minCosts
367  m_MinCosts = 0.0; // The lower, the more thouroughly! 0 = dijkstra. If estimate costs are lower than actual costs
368  // everything is fine. If estimation is higher than actual costs, you might not get the shortest
369  // but a different path.
370 
371  m_Initialized = true;
372  }
373 
374  // check start/end point value
375  startValue = this->m_Image->GetPixel(this->m_StartIndex);
376  endValue = this->m_Image->GetPixel(this->m_EndIndex);
377  }
378 
379  template <class TInputImageType>
380  double ShortestPathCostFunctionLiveWire<TInputImageType>::SigmoidFunction(
381  double I, double max, double min, double alpha, double beta)
382  {
383  // Using the SIgmoid formula from ITK Software Guide 6.3.2 Non Linear Mappings
384  double Exponent = -1 * ((I - beta) / alpha);
385  double Factor = 1 / (1 + exp(Exponent));
386  double newI = (max - min) * Factor + min;
387 
388  return newI;
389  }
390 
391  template <class TInputImageType>
392  double ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(double x, double xOfGaussian, double yOfGaussian)
393  {
394  return yOfGaussian * exp(-0.5 * pow((x - xOfGaussian), 2));
395  }
396 
397 } // end namespace itk
398 
399 #endif // __itkShortestPathCostFunctionLiveWire_txx