ssd.hh
Go to the documentation of this file.
1 /* -*- mia-c++ -*-
2  *
3  * This file is part of MIA - a toolbox for medical image analysis
4  * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
5  *
6  * MIA is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with MIA; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include <mia/core/filter.hh>
22 #include <mia/core/msgstream.hh>
23 #include <mia/core/parameter.hh>
25 
26 #include <numeric>
27 #include <limits>
28 
29 NS_BEGIN(NS)
30 
31 
37 template <typename TCost>
38 class TSSDCost: public TCost {
39 public:
40  typedef typename TCost::Data Data;
41  typedef typename TCost::Force Force;
42 
43  TSSDCost();
44  TSSDCost(bool normalize, float automask_thresh);
45 private:
46  virtual double do_value(const Data& a, const Data& b) const;
47  virtual double do_evaluate_force(const Data& a, const Data& b, Force& force) const;
48  bool m_normalize;
49  float m_automask_thresh;
50 };
51 
52 
53 struct FEvalSSD : public mia::TFilter<double> {
54  FEvalSSD(bool normalize, float automask_thresh):
55  m_normalize(normalize), m_automask_thresh(automask_thresh){}
56 
57  template <typename T, typename R>
58  struct SQD {
59  double operator ()(T a, R b) const {
60  double d = (double)a - (double)b;
61  return d * d;
62  }
63  };
64 
65  template <typename T, typename R>
66  FEvalSSD::result_type operator () (const T& a, const R& b) const {
67  double scale = m_normalize ? 0.5 / a.size() : 0.5;
68  if (m_automask_thresh == 0.0f)
69  return scale * inner_product(a.begin(), a.end(), b.begin(), 0.0, ::std::plus<double>(),
70  SQD<typename T::value_type , typename R::value_type >());
71  else {
72  auto ia = a.begin();
73  auto ib = b.begin();
74  auto ie = a.end();
75  long n = 0;
76  double sum = 0.0;
77  while (ia != ie) {
78  if (*ia > m_automask_thresh) {
79  double d = (double)*ia - (double)*ib;
80  sum += d*d;
81  ++n;
82  }
83  ++ia; ++ib;
84  }
85  // high penalty if the mask don't overlap at all
86  return n > 0 ? 0.5 * sum / n : std::numeric_limits<float>::max();
87  }
88  }
89  bool m_normalize;
90  float m_automask_thresh;
91 };
92 
93 
94 template <typename TCost>
95 TSSDCost<TCost>::TSSDCost():
96  m_normalize(true),
97  m_automask_thresh(0.0)
98 {
99  this->add(::mia::property_gradient);
100 }
101 
102 template <typename TCost>
103 TSSDCost<TCost>::TSSDCost(bool normalize, float automask_thresh):
104  m_normalize(normalize),
105  m_automask_thresh(automask_thresh)
106 {
107  this->add(::mia::property_gradient);
108 }
109 
110 template <typename TCost>
111 double TSSDCost<TCost>::do_value(const Data& a, const Data& b) const
112 {
113  FEvalSSD essd(m_normalize, m_automask_thresh);
114  return filter(essd, a, b);
115 }
116 
117 template <typename Force>
118 struct FEvalForce: public mia::TFilter<float> {
119  FEvalForce(Force& force, bool normalize, float automask_thresh):
120  m_force(force),
121  m_normalize(normalize),
122  m_automask_thresh(automask_thresh)
123  {
124  }
125  template <typename T, typename R>
126  float operator ()( const T& a, const R& b) const {
127  Force gradient = get_gradient(a);
128  float cost = 0.0;
129  auto ai = a.begin();
130  auto bi = b.begin();
131  auto fi = m_force.begin();
132  auto gi = gradient.begin();
133 
134  if (m_automask_thresh == 0.0f) {
135  float scale = m_normalize ? 1.0 / a.size() : 1.0;
136 
137  for (size_t i = 0; i < a.size(); ++i, ++ai, ++bi, ++fi, ++gi) {
138  float delta = float(*ai) - float(*bi);
139  *fi = *gi * delta * scale;
140  cost += delta * delta * scale;
141  }
142  return 0.5 * cost;
143  }else{
144  long n = 0;
145  for (size_t i = 0; i < a.size(); ++i, ++ai, ++bi, ++fi, ++gi) {
146  if (*ai > m_automask_thresh) {
147  float delta = float(*ai) - float(*bi);
148  *fi = *gi * delta;
149  cost += delta * delta;
150  ++n;
151  }
152  }
153  if ( n > 0) {
154  float scale = 1.0f / n;
155  transform(m_force.begin(), m_force.end(), m_force.begin(),
156  [scale](const typename Force::value_type& x){return scale * x;});
157  return 0.5 * cost *scale;
158  }else{
159  return std::numeric_limits<float>::max();
160  }
161  }
162  }
163 private:
164  Force& m_force;
165  bool m_normalize;
166  float m_automask_thresh;
167 };
168 
169 
173 template <typename TCost>
174 double TSSDCost<TCost>::do_evaluate_force(const Data& a, const Data& b, Force& force) const
175 {
176  assert(a.get_size() == b.get_size());
177  assert(a.get_size() == force.get_size());
178  FEvalForce<Force> ef(force, m_normalize, m_automask_thresh);
179  return filter(ef, a, b);
180 }
181 
182 
188 template <typename CP, typename C>
189 class TSSDCostPlugin: public CP {
190 public:
191  TSSDCostPlugin();
192  C *do_create()const;
193 private:
194  bool m_normalize;
195  float m_automask_thresh;
196 };
197 
198 
202 template <typename CP, typename C>
203 TSSDCostPlugin<CP,C>::TSSDCostPlugin():
204  CP("ssd"),
205  m_normalize(false),
206  m_automask_thresh(0)
207 {
208  TRACE("TSSDCostPlugin<CP,C>::TSSDCostPlugin()");
209  this->add_property(::mia::property_gradient);
210  this->add_parameter("norm", new mia::CBoolParameter(m_normalize, false,
211  "Set whether the metric should be normalized by the number of image pixels")
212  );
213  this->add_parameter("autothresh", mia::make_ci_param(m_automask_thresh, 0.0f, 1000.0f, false,
214  "Use automatic masking of the moving image by only takeing "
215  "intensity values into accound that are larger than the given threshold"));
216 
217 }
218 
222 template <typename CP, typename C>
223 C *TSSDCostPlugin<CP,C>::do_create() const
224 {
225  return new TSSDCost<C>(m_normalize, m_automask_thresh);
226 }
227 
229 NS_END
The generic cost function interface.
Definition: core/cost.hh:64
#define NS_BEGIN(NS)
conveniance define to start a namespace
Definition: defines.hh:42
CTParameter< bool > CBoolParameter
boolean parameter
Definition: parameter.hh:553
T Data
typedef for generic programming: The data type used by the cost function
Definition: core/cost.hh:67
std::shared_ptr< Image > normalize(const Image &image)
a normalizer for image intensities
Definition: normalize.hh:131
static F::result_type filter(const F &f, const B &b)
Definition: core/filter.hh:250
EXPORT_2D C2DFVectorfield get_gradient(const C2DImage &image)
#define TRACE(DOMAIN)
Definition: msgstream.hh:201
EXPORT_CORE const char * property_gradient
constant defining the gradient property
CParameter * make_ci_param(T &value, S1 lower_bound, S2 upper_bound, bool required, const char *descr)
Definition: parameter.hh:326
#define NS_END
conveniance define to end a namespace
Definition: defines.hh:45
V Force
typedef for generic programming: The gradient forca type create by the cost function ...
Definition: core/cost.hh:70