$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
object_groups.hh
1 // Copyright (C) 2009, 2010, 2011, 2013 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 SCRIBO_CORE_OBJECT_GROUPS_HH
28 # define SCRIBO_CORE_OBJECT_GROUPS_HH
29 
33 
34 # include <mln/util/array.hh>
35 
36 # include <scribo/core/object_links.hh>
37 # include <scribo/core/component_set.hh>
38 
39 # include <scribo/core/group_info.hh>
40 # include <scribo/core/internal/sort_comp_ids.hh>
41 # include <scribo/core/concept/serializable.hh>
42 
43 // Not to include.
44 //#include <scribo/core/line_info.hh>
45 
46 namespace scribo
47 {
48 
49  using namespace mln;
50 
51 
52  // Forward declaration.
53  template <typename L> class object_groups;
54 
55  namespace internal
56  {
57 
58  inline
59  unsigned
60  find_root(mln::util::array<unsigned>& parent, unsigned x)
61  {
62  if (parent(x) == x)
63  return x;
64  else
65  return parent(x) = find_root(parent, parent(x));
66  }
67 
68 
70  template <typename L>
72  {
74  object_groups_data(const object_links<L>& links);
77 
78  mln::util::array<unsigned> comp_to_group_;
79  mln::util::array<group_info> group_info_;
80 
81  component_set<L> components_;
82  object_links<L> links_;
83  };
84 
85  } // end of namespace scribo::internal
86 
87 
88 
89 
93  //
94  template <typename L>
95  class object_groups : public Serializable<object_groups<L> >
96  {
98 
99  public:
100  object_groups();
101  object_groups(const object_links<L>& links);
102  // Used for incremental construction (xml loading)
103  object_groups(const object_links<L>& links,
105 
106  const component_set<L>& components() const;
107  const object_links<L>& links() const;
108 
109  bool is_valid() const;
110 
111 
112  // Return the number of groups
113  unsigned nelements() const;
114 
115 
117  const group_info& group_of(unsigned comp_id) const;
118  group_info& group_of(unsigned comp_id);
119 
122  const group_info& operator()(unsigned group_id) const;
123  group_info& operator()(unsigned group_id);
124 
125  // Map component ids to group ids.
126  const mln::util::array<unsigned>& comp_to_group() const;
127 
128  void merge(unsigned group_id_from, unsigned group_id_to);
129 
130  object_groups<L> duplicate() const;
131 
132 
133  private: // attributes
135  };
136 
137 
138  template <typename L>
139  std::ostream&
140  operator<<(std::ostream& ostr, const object_groups<L>& groups);
141 
142  template <typename L>
143  bool
144  operator==(const object_groups<L>& lhs, const object_groups<L>& rhs);
145 
146 
147 # ifndef MLN_INCLUDE_ONLY
148 
149  namespace internal
150  {
151 
152 
154  template <typename L>
155  object_groups_data<L>::object_groups_data()
156  {
157  }
158 
159 
160  template <typename L>
161  object_groups_data<L>::object_groups_data(const object_links<L>& links)
162  : comp_to_group_(unsigned(links.nelements())),
163  components_(links.components()), links_(links)
164  {
165  comp_to_group_ = links.comp_to_link();
166 
167  unsigned ngroups = 0;
168  mln::util::array<unsigned> new_id(comp_to_group_.nelements(), 0);
171  mln::util::array<unsigned> pixel_areas(1);
172 
173  // Remove potential loops in linking
174  // FIXME: we may try to avoid loops while linking...
175  {
176  mln::util::array<bool> deja_vu(comp_to_group_.nelements());
177  for_all_elements(e, comp_to_group_)
178  if (comp_to_group_(e) != e && comp_to_group_(e) != 0)
179  {
180  deja_vu.fill(false); // FIXME: ugly!
181  unsigned cur = e;
182  deja_vu(cur) = true;
183  while (comp_to_group_(cur) != cur && !deja_vu(comp_to_group_(cur)))
184  {
185  cur = comp_to_group_(cur);
186  deja_vu(cur) = true;
187  }
188  // Break the loop!
189  if (comp_to_group_(cur) != cur && deja_vu(comp_to_group_(cur)))
190  comp_to_group_(cur) = cur;
191  }
192  }
193 
194  for_all_elements(e, comp_to_group_)
195  if (comp_to_group_(e) != 0)
196  {
197  // Make sure there is no intermediate ids to reach the root.
198  // FIXME: useful?
199  unsigned e_root = internal::find_root(comp_to_group_, e);
200 
201  if (! new_id(e_root))
202  {
203  new_id(e_root) = ++ngroups;
204  comp_ids.resize(comp_ids.size() + 1);
205  bboxes.resize(bboxes.size() + 1);
206  pixel_areas.resize(pixel_areas.size() + 1, 0);
207  }
208 
209  unsigned nid = new_id(e_root);
210  comp_ids(nid).append(e);
211 
212  bboxes(nid).take(components_(e).bbox());
213  pixel_areas(nid) += components_(e).card();
214  }
215 
216  group_info_.resize(1);
217  group_info_.reserve(ngroups);
218  mln::util::array<unsigned> group_idx(ngroups + 1, 0);
219 
220  for (unsigned i = 1; i < new_id.nelements(); ++i)
221  if (new_id(i))
222  {
223  unsigned id = new_id(i);
224 
225  // Order component ids according to component localization (left
226  // to right).
227  std::sort(comp_ids(id).hook_std_vector_().begin(),
228  comp_ids(id).hook_std_vector_().end(),
229  internal::sort_comp_ids<L>(components_));
230 
231  group_idx(id) = group_info_.size();
232  group_info_.append(group_info(group_info_.size(), comp_ids(id), pixel_areas(id), bboxes(id)));
233  }
234 
235  // Update mapping comp/group with new ids. Note: group id is
236  // different from its location in group_info array during
237  // construction.
238  for (unsigned i = 0; i < comp_to_group_.nelements(); ++i)
239  comp_to_group_(i) = group_idx(new_id(comp_to_group_(i)));
240  }
241 
242  template <typename L>
243  object_groups_data<L>::object_groups_data(const object_links<L>& links,
245  : comp_to_group_(unsigned(links.nelements())), group_info_(info),
246  components_(links.components()), links_(links)
247  {
248  for_all_groups(g, group_info_)
249  for_all_elements(e, group_info_(g).component_ids())
250  comp_to_group_(group_info_(g).component_ids()(e)) = group_info_(g).id();
251  }
252 
253  } // end of namespace scribo::internal
254 
255 
256  template <typename L>
257  object_groups<L>::object_groups()
258  {
259  }
260 
261  template <typename L>
262  object_groups<L>::object_groups(const object_links<L>& links)
263  {
264  data_ = new data_t(links);
265  }
266 
267  template <typename L>
268  object_groups<L>::object_groups(const object_links<L>& links,
269  const mln::util::array<group_info>& info)
270  {
271  data_ = new data_t(links, info);
272  }
273 
274  template <typename L>
275  const component_set<L>&
277  {
278  return data_->components_;
279  }
280 
281  template <typename L>
282  const object_links<L>&
283  object_groups<L>::links() const
284  {
285  mln_assertion(data_ != 0);
286  return data_->links_;
287  }
288 
289  template <typename L>
290  bool
291  object_groups<L>::is_valid() const
292  {
293  mln_assertion(data_->components_.nelements() == data_->comp_to_group_.nelements() - 1);
294  return data_->links_.is_valid();
295  }
296 
297  template <typename L>
298  unsigned
299  object_groups<L>::nelements() const
300  {
301  return data_->group_info_.nelements();
302  }
303 
304  template <typename L>
305  const group_info&
306  object_groups<L>::group_of(unsigned comp_id) const
307  {
308  mln_precondition(comp_id < data_->comp_to_group_.nelements());
309  mln_assertion(data_->group_info_(data_->comp_to_group_(comp_id)).id()
310  == data_->comp_to_group_(comp_id));
311  return data_->group_info_(data_->comp_to_group_(comp_id));
312  }
313 
314  template <typename L>
315  group_info&
316  object_groups<L>::group_of(unsigned comp_id)
317  {
318  mln_precondition(comp_id < data_->comp_to_group_.nelements());
319  mln_assertion(data_->group_info_(data_->comp_to_group_(comp_id)).id()
320  == data_->comp_to_group_(comp_id));
321  return data_->group_info_(data_->comp_to_group_(comp_id));
322  }
323 
324  template <typename L>
326  object_groups<L>::comp_to_group() const
327  {
328  return data_->comp_to_group_;
329  }
330 
331 
332  template <typename L>
333  void
334  object_groups<L>::merge(unsigned group_id_from, unsigned group_id_to)
335  {
336  // Mark components as being part of group group_id_to.
338  comp_ids = data_->group_info_(group_id_from).component_ids();
339  for_all_elements(e, comp_ids)
340  data_->comp_to_group_(comp_ids(e)) = group_id_to;
341 
342  // Merge group info.
343  data_->group_info_(group_id_to).merge(data_->group_info_(group_id_from));
344  }
345 
346 
347  template <typename L>
348  const group_info&
349  object_groups<L>::operator()(unsigned group_id) const
350  {
351  mln_precondition(group_id < data_->group_info_.nelements());
352  return data_->group_info_(group_id);
353  }
354 
355 
356  template <typename L>
357  group_info&
358  object_groups<L>::operator()(unsigned group_id)
359  {
360  mln_precondition(group_id < data_->group_info_.nelements());
361  return data_->group_info_(group_id);
362  }
363 
364 
365  template <typename L>
366  inline
367  object_groups<L>
369  {
370  object_groups<L> output;
371  output.data_ = new data_t();
372 
373  *(output.data_.ptr_) = *(data_.ptr_);
374  return output;
375  }
376 
377  template <typename L>
378  std::ostream&
379  operator<<(std::ostream& ostr, const object_groups<L>& groups)
380  {
381  ostr << "object_groups[";
382 
383  for_all_groups(g, groups)
384  ostr << groups(g) << ", ";
385 
386  ostr << " | comp_to_group=" << groups.comp_to_group();
387 
388  ostr << "]";
389 
390  return ostr;
391  }
392 
393 
394  template <typename L>
395  bool
396  operator==(const object_groups<L>& lhs, const object_groups<L>& rhs)
397  {
398  if (! (lhs.components() == rhs.components()))
399  {
400  return false;
401  }
402 
403  if (!( lhs.comp_to_group() == rhs.comp_to_group() && lhs.nelements() == rhs.nelements()))
404  {
405  return false;
406  }
407 
408 
409  for_all_groups(g, lhs)
410  if (! (lhs(g) == rhs(g)))
411  {
412  return false;
413  }
414 
415  return true;
416  }
417 
418 # endif // ! MLN_INCLUDE_ONLY
419 
420 
421 } // end of namespace scribo
422 
423 
424 #endif // ! SCRIBO_CORE_OBJECT_GROUPS_HH