$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
median_h.hh
1 // Copyright (C) 2007, 2008, 2009, 2011 EPITA Research and Development
2 // Laboratory (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 #ifndef MLN_ACCU_STAT_MEDIAN_H_HH
28 # define MLN_ACCU_STAT_MEDIAN_H_HH
29 
33 
34 # include <mln/accu/internal/base.hh>
35 # include <mln/accu/histo.hh>
36 # include <mln/value/set.hh>
37 
38 
39 namespace mln
40 {
41 
42  namespace accu
43  {
44 
45  namespace stat
46  {
47 
48  // Forward declaration.
49  template <typename V>
50  struct median_h;
51 
52  } // end of namespace mln::accu::stat
53 
54  namespace meta
55  {
56 
57  namespace stat
58  {
59 
61  struct median_h : public Meta_Accumulator< median_h >
62  {
63  template <typename V>
64  struct with
65  {
67  };
68  };
69 
70  } // end of namespace mln::accu::meta::stat
71 
72  } // end of namespace mln::accu::meta
73 
74  namespace stat
75  {
76 
81  template <typename V>
82  struct median_h : public mln::accu::internal::base< const V&, median_h<V> >
83  {
84  typedef V argument;
85 
86  median_h();
87  median_h& operator=(const median_h& rhs);
88 
91  void init();
92  void take(const argument& t);
93  void take(const median_h<V>& other);
94  void untake(const argument& t);
96 
97  unsigned card() const { return h_.sum(); }
98 
100  const argument& to_result() const;
101 
102  const accu::histo<V>& histo() const;
103 
106  bool is_valid() const;
107 
108  protected:
109 
111  const value::set<V>& s_; // derived from h_
112 
113  mutable unsigned sum_minus_, sum_plus_;
114 
115  mutable bool valid_;
116  mutable unsigned i_; // the median_h index
117  mutable argument t_; // the median_h value
118 
119  // Auxiliary methods
120  void update_() const;
121  void go_minus_() const;
122  void go_plus_() const;
123  };
124 
125 # ifndef MLN_INCLUDE_ONLY
126 
127  template <typename V>
128  inline
130  : h_(),
131  s_(h_.vset())
132  {
133  init();
134  }
135 
136  template <typename V>
137  inline
138  median_h<V>&
139  median_h<V>::operator=(const median_h<V>& rhs)
140  {
141  h_ = rhs.h_;
142  sum_minus_ = rhs.sum_minus_;
143  sum_plus_ = rhs.sum_plus_;
144  valid_ = rhs.valid_;
145  i_ = rhs.i_;
146  t_ = rhs.t_;
147 
148  return *this;
149  }
150 
151  template <typename V>
152  inline
153  void
154  median_h<V>::take(const argument& t)
155  {
156  h_.take(t);
157 
158  if (t < t_)
159  ++sum_minus_;
160  else if (t > t_)
161  ++sum_plus_;
162 
163  if (valid_)
164  valid_ = false;
165  }
166 
167  template <typename V>
168  inline
169  void
170  median_h<V>::take(const median_h<V>& other)
171  {
172  // h_
173  h_.take(other.h_);
174 
175  // sum_minus_
176  for (unsigned i = 0; i < i_; ++i)
177  sum_minus_ += other.h_[i];
178 
179  // sum_plus_
180  for (unsigned i = i_ + 1; i < h_.nvalues(); ++i)
181  sum_plus_ += other.h_[i];
182 
183  if (valid_)
184  valid_ = false;
185  }
186 
187  template <typename V>
188  inline
189  void
190  median_h<V>::untake(const argument& t)
191  {
192  mln_precondition(h_(t) != 0);
193  h_.untake(t);
194 
195  if (t < t_)
196  --sum_minus_;
197  else if (t > t_)
198  --sum_plus_;
199 
200  if (valid_)
201  valid_ = false;
202  }
203 
204  template <typename V>
205  inline
206  void
207  median_h<V>::update_() const
208  {
209  valid_ = true;
210 
211  if (h_.sum() == 0)
212  return;
213 
214  if (2 * sum_minus_ > h_.sum())
215  go_minus_();
216  else
217  if (2 * sum_plus_ > h_.sum())
218  go_plus_();
219  else
220  if (h_[i_] == 0)
221  {
222  // go to the heaviest side
223  if (sum_plus_ > sum_minus_)
224  go_plus_();
225  else
226  go_minus_(); // default when both sides are balanced
227  }
228  }
229 
230  template <typename V>
231  inline
232  void
233  median_h<V>::go_minus_() const
234  {
235  do
236  {
237  sum_plus_ += h_[i_];
238  do
239  --i_;
240  while (h_[i_] == 0);
241  sum_minus_ -= h_[i_];
242  }
243  while (2 * sum_minus_ > h_.sum());
244  t_ = s_[i_];
245  }
246 
247  template <typename V>
248  inline
249  void
250  median_h<V>::go_plus_() const
251  {
252  do
253  {
254  sum_minus_ += h_[i_];
255  do
256  ++i_;
257  while (h_[i_] == 0);
258  sum_plus_ -= h_[i_];
259  }
260  while (2 * sum_plus_ > h_.sum());
261  t_ = s_[i_];
262  }
263 
264  template <typename V>
265  inline
266  void
268  {
269  h_.init();
270  sum_minus_ = 0;
271  sum_plus_ = 0;
272  i_ = (s_.index_of(mln_max(argument))
273  - s_.index_of(mln_min(argument))) / 2;
274  t_ = s_[i_];
275  valid_ = true;
276  }
277 
278  template <typename V>
279  inline
280  const typename median_h<V>::argument&
281  median_h<V>::to_result() const
282  {
283  if (! valid_)
284  update_();
285  return t_;
286  }
287 
288  template <typename V>
289  inline
290  const accu::histo<V>&
291  median_h<V>::histo() const
292  {
293  return h_;
294  }
295 
296  template <typename V>
297  inline
298  bool
299  median_h<V>::is_valid() const
300  {
301  return true;
302  }
303 
304 # endif // ! MLN_INCLUDE_ONLY
305 
306  } // end of namespace mln::accu::stat
307 
308  } // end of namespace mln::accu
309 
310 } // end of namespace mln
311 
312 #endif // ! MLN_ACCU_STAT_MEDIAN_H_HH