lsd.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 struct valpos {
33  double val;
34  int pos;
35 };
36 
37 
38 template <typename TCost>
39 class TLSDImageCost: public TCost {
40 public:
41  typedef typename TCost::Data Data;
42  typedef typename TCost::Force Force;
43 private:
44 
45  class CRefPrepare :public mia::TFilter<void> {
46  public:
47  CRefPrepare(std::vector<double>& QtQinv, std::vector<int>& Q_mappping):
48  m_QtQinv(QtQinv),
49  m_Q_mappping(Q_mappping)
50  {
51  }
52  template <typename DataTempl>
53  void operator()(const DataTempl& ref);
54 
55  std::vector<double>& m_QtQinv;
56  std::vector<int>& m_Q_mappping;
57  };
58 
59  class RunCost : mia::TFilter<double> {
60  public:
61  typedef TFilter<double>::result_type result_type;
62  RunCost( const std::vector<double>& QtQinv, const std::vector<int>& Q_mappping);
63 
64  template <typename DataTempl>
65  double operator()(const DataTempl& ref)const;
66 
67  template <typename DataTempl>
68  double operator()(const DataTempl& ref, Force& force)const;
69  private:
70  const std::vector<double>& m_QtQinv;
71  const std::vector<int>& m_Q_mappping;
72  };
73 
74 
75 
76  virtual double do_value(const Data& a, const Data& b) const;
77 
78  virtual double do_evaluate_force(const Data& a, const Data& /*b*/, Force& force) const;
79 
80  virtual void post_set_reference(const Data& ref);
81 
82  std::vector<double> m_QtQinv;
83  std::vector<int> m_Q_mappping;
84 };
85 
86 
87 inline bool operator < (const valpos& a, const valpos& b)
88 {
89  return a.val < b.val;
90 }
91 
92 template <typename CP, typename C>
93 class TLSDImageCostPlugin: public CP {
94 public:
95  TLSDImageCostPlugin();
96  virtual TLSDImageCost<C> *do_create()const;
97  const std::string do_get_descr()const;
98 };
99 
100 template <typename TCost>
101 template <typename DataTempl>
102 void TLSDImageCost<TCost>::CRefPrepare::operator()(const DataTempl& ref)
103 {
104  size_t npixels = ref.get_size().x * ref.get_size().y;
105  std::vector<valpos> buffer(npixels);
106  m_Q_mappping.resize(npixels);
107  m_QtQinv.resize(npixels);
108 
109  int idx = 0;
110  for( auto x = ref.begin(); x != ref.end(); ++x, ++idx) {
111  double value = *x;
112  valpos vp = {value, idx};
113  buffer[idx] = vp;
114  }
115  std::sort(buffer.begin(), buffer.end());
116 
117  idx = 0;
118  auto x = buffer.begin();
119  double oldv = x->val;
120  ++x;
121  ++m_QtQinv[idx];
122 
123  // build histogram and prepare target mapping
124  m_Q_mappping[x->pos] = idx;
125 
126  while ( x != buffer.end() ) {
127  if (x->val != oldv) {
128  oldv = x->val;
129  ++idx;
130  }
131  ++m_QtQinv[idx];
132  m_Q_mappping[x->pos] = idx;
133  ++x;
134  }
135  ++idx;
136  m_QtQinv.resize(idx);
137  std::transform(m_QtQinv.begin(), m_QtQinv.end(), m_QtQinv.begin(),
138  [](double x){return 1.0 / x; });
139 }
140 
141 template <typename TCost>
142 void TLSDImageCost<TCost>::post_set_reference(const Data& ref)
143 {
144  CRefPrepare rp(m_QtQinv, m_Q_mappping);
145  mia::accumulate(rp, ref);
146 }
147 
148 
149 template <typename TCost>
150 double TLSDImageCost<TCost>::do_value(const Data& a, const Data& /*b*/) const
151 {
152  RunCost rf(m_QtQinv, m_Q_mappping);
153  return mia::filter(rf, a);
154 }
155 
156 template <typename TCost>
157 double TLSDImageCost<TCost>::do_evaluate_force(const Data& a, const Data& /*b*/, Force& force) const
158 {
159  RunCost rf(m_QtQinv, m_Q_mappping);
160  return mia::filter_and_output(rf, a, force);
161 }
162 
163 template <typename TCost>
164 TLSDImageCost<TCost>::RunCost::RunCost(const std::vector<double>& QtQinv, const std::vector<int>& Q_mappping):
165  m_QtQinv(QtQinv),
166  m_Q_mappping(Q_mappping)
167 {
168 }
169 
170 template <typename TCost>
171 template <typename DataTempl>
172 double TLSDImageCost<TCost>::RunCost::operator()(const DataTempl& a)const
173 {
174  double val1 = 0.0;
175  double val2 = 0.0;
176  std::vector<double> sums(m_QtQinv.size(), 0.0);
177 
178  auto idx = m_Q_mappping.begin();
179  for (auto ia = a.begin(); ia != a.end(); ++ia, ++idx) {
180  val1 += *ia * *ia;
181  sums[*idx] += *ia;
182  }
183 
184 
185  for(size_t i = 0; i < sums.size(); ++i)
186  val2 += sums[i] * sums[i] * m_QtQinv[i];
187 
188  return 0.5 * (val1 - val2);
189 }
190 
191 template <typename TCost>
192 template <typename DataTempl>
193 double TLSDImageCost<TCost>::RunCost::operator()(const DataTempl& a, Force& force)const
194 {
195  double value = 0.0;
196  std::vector<double> sums(m_QtQinv.size(), 0.0);
197 
198  auto idx = m_Q_mappping.begin();
199  for (auto ia = a.begin(); ia != a.end(); ++ia, ++idx) {
200  value += *ia * *ia;
201  sums[*idx] += *ia;
202  }
203 
204  auto s = sums.begin();
205  for (auto q = m_QtQinv.begin(); q != m_QtQinv.end(); ++q, ++s) {
206  value -= *q * *s * *s;
207  *s *= *q;
208  }
209 
210  auto gradient = get_gradient(a);
211  auto iforce = force.begin();
212  auto igrad = gradient.begin();
213  idx = m_Q_mappping.begin();
214  for (auto ia = a.begin(); ia != a.end(); ++ia, ++iforce, ++igrad, ++idx)
215  *iforce = *igrad * (*ia - sums[*idx]);
216 
217  return 0.5 * value;
218 
219 }
220 
221 template <typename CP, typename C>
222 TLSDImageCostPlugin<CP,C>::TLSDImageCostPlugin():
223  CP("lsd")
224 {
225 }
226 
227 template <typename CP, typename C>
228 TLSDImageCost<C> *TLSDImageCostPlugin<CP,C>::do_create()const
229 {
230  return new TLSDImageCost<C>();
231 }
232 
233 template <typename CP, typename C>
234 const std::string TLSDImageCostPlugin<CP,C>::do_get_descr()const
235 {
236  return "Least-Squares Distance measure";
237 }
238 
240 NS_END
static F::result_type filter_and_output(const F &f, const B &a, O &b)
Definition: core/filter.hh:469
The generic cost function interface.
Definition: core/cost.hh:64
#define NS_BEGIN(NS)
conveniance define to start a namespace
Definition: defines.hh:42
T Data
typedef for generic programming: The data type used by the cost function
Definition: core/cost.hh:67
bool operator<(const T2DVector< T > &a, const T2DVector< S > &b)
Definition: 2d/vector.hh:453
static F::result_type filter(const F &f, const B &b)
Definition: core/filter.hh:250
EXPORT_2D C2DFVectorfield get_gradient(const C2DImage &image)
R result_type
defines the return type of the filter function
Definition: core/filter.hh:72
static F::result_type accumulate(F &f, const B &data)
Definition: core/filter.hh:317
#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