
* scribo/core/group_info.hh, * scribo/core/internal/sort_comp_ids.hh: New. * scribo/core/object_groups.hh, * scribo/core/object_links.hh: Improve API. * scribo/core/line_info.hh, * scribo/core/line_set.hh, * scribo/debug/decision_image.hh, * scribo/estim/object_groups_mean_width.hh, * scribo/filter/object_groups_mean_width.hh, * scribo/filter/object_groups_size_ratio.hh, * scribo/filter/object_groups_small.hh, * scribo/filter/object_groups_with_holes.hh, * scribo/filter/object_links_bbox_overlap.hh, * scribo/filter/object_links_bbox_ratio.hh, * scribo/filter/object_links_non_aligned_simple.hh, * scribo/primitive/group/from_double_link_any.hh, * scribo/primitive/group/from_single_link.hh, * scribo/primitive/internal/is_link_valid.hh, * scribo/primitive/link/internal/link_functor_base.hh, * scribo/primitive/link/internal/link_several_dmax_base.hh, * scribo/primitive/link/merge_double_link.hh, * scribo/primitive/link/merge_double_link_closest_aligned.hh, * tests/filter/object_groups_mean_width.cc, * tests/filter/object_groups_size_ratio.cc, * tests/filter/object_groups_small.cc, * tests/filter/object_groups_with_holes.cc: Update code to take API changes into account. --- scribo/ChangeLog | 34 +++ scribo/scribo/core/group_info.hh | 184 ++++++++++++++++ .../sort_comp_ids.hh} | 57 +++--- scribo/scribo/core/line_info.hh | 140 ++++++++----- scribo/scribo/core/line_set.hh | 66 ++++--- scribo/scribo/core/object_groups.hh | 228 +++++++++++++++----- scribo/scribo/core/object_links.hh | 81 ++++++- scribo/scribo/debug/decision_image.hh | 8 +- scribo/scribo/estim/object_groups_mean_width.hh | 21 +-- scribo/scribo/filter/object_groups_mean_width.hh | 10 +- scribo/scribo/filter/object_groups_size_ratio.hh | 16 +- scribo/scribo/filter/object_groups_small.hh | 36 +--- scribo/scribo/filter/object_groups_with_holes.hh | 2 +- scribo/scribo/filter/object_links_bbox_overlap.hh | 6 +- scribo/scribo/filter/object_links_bbox_ratio.hh | 10 +- .../filter/object_links_non_aligned_simple.hh | 6 +- .../scribo/primitive/group/from_double_link_any.hh | 57 ++++-- scribo/scribo/primitive/group/from_single_link.hh | 13 -- scribo/scribo/primitive/internal/is_link_valid.hh | 12 +- .../primitive/link/internal/link_functor_base.hh | 2 +- .../link/internal/link_several_dmax_base.hh | 10 +- scribo/scribo/primitive/link/merge_double_link.hh | 17 +- .../link/merge_double_link_closest_aligned.hh | 6 +- scribo/tests/filter/object_groups_mean_width.cc | 11 +- scribo/tests/filter/object_groups_size_ratio.cc | 10 +- scribo/tests/filter/object_groups_small.cc | 28 +-- scribo/tests/filter/object_groups_with_holes.cc | 10 +- 27 files changed, 743 insertions(+), 338 deletions(-) create mode 100644 scribo/scribo/core/group_info.hh copy scribo/scribo/core/{component_features_data.hh => internal/sort_comp_ids.hh} (59%) diff --git a/scribo/ChangeLog b/scribo/ChangeLog index 8d95b3a..7bbfb9e 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,3 +1,37 @@ +2011-05-03 Guillaume Lazzara <lazzara@fidji.lrde.epita.fr> + + Improve object_groups and object_links API. + + * scribo/core/group_info.hh, + * scribo/core/internal/sort_comp_ids.hh: New. + + * scribo/core/object_groups.hh, + * scribo/core/object_links.hh: Improve API. + + * scribo/core/line_info.hh, + * scribo/core/line_set.hh, + * scribo/debug/decision_image.hh, + * scribo/estim/object_groups_mean_width.hh, + * scribo/filter/object_groups_mean_width.hh, + * scribo/filter/object_groups_size_ratio.hh, + * scribo/filter/object_groups_small.hh, + * scribo/filter/object_groups_with_holes.hh, + * scribo/filter/object_links_bbox_overlap.hh, + * scribo/filter/object_links_bbox_ratio.hh, + * scribo/filter/object_links_non_aligned_simple.hh, + * scribo/primitive/group/from_double_link_any.hh, + * scribo/primitive/group/from_single_link.hh, + * scribo/primitive/internal/is_link_valid.hh, + * scribo/primitive/link/internal/link_functor_base.hh, + * scribo/primitive/link/internal/link_several_dmax_base.hh, + * scribo/primitive/link/merge_double_link.hh, + * scribo/primitive/link/merge_double_link_closest_aligned.hh, + * tests/filter/object_groups_mean_width.cc, + * tests/filter/object_groups_size_ratio.cc, + * tests/filter/object_groups_small.cc, + * tests/filter/object_groups_with_holes.cc: Update code to take + API changes into account. + 2011-04-07 Guillaume Lazzara <z@lrde.epita.fr> Add test data in EXTRA_DIST. diff --git a/scribo/scribo/core/group_info.hh b/scribo/scribo/core/group_info.hh new file mode 100644 index 0000000..19a8ecc --- /dev/null +++ b/scribo/scribo/core/group_info.hh @@ -0,0 +1,184 @@ +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_CORE_GROUP_INFO_HH +# define SCRIBO_CORE_GROUP_INFO_HH + +/// \file +/// +/// \brief Object groups representation. + +# include <mln/util/array.hh> + +# include <scribo/core/object_links.hh> +# include <scribo/core/component_set.hh> + +# include <scribo/core/internal/sort_comp_ids.hh> +# include <scribo/core/concept/serializable.hh> + + +namespace scribo +{ + + using namespace mln; + + class group_info + { + public: + group_info(); + group_info(unsigned id, const mln::util::array<component_id_t>& comps, + unsigned pixel_area, const box2d& bbox); + // used for incremental construction (xml loading). + group_info(unsigned id, unsigned pixel_area, const box2d& bbox, + bool valid = false); + + const mln::util::array<component_id_t>& component_ids() const; + + // Used for incremental construction (xml loading) + mln::util::array<component_id_t>& component_ids_(); + + bool is_valid() const; + void invalidate(); + + unsigned card() const; + unsigned id() const; + unsigned pixel_area() const; + const box2d& bbox() const; + + private: + unsigned id_; + mln::util::array<component_id_t> comps_; + bool valid_; + unsigned pixel_area_; + box2d bbox_; + }; + + bool operator==(const group_info& lhs, const group_info& rhs); + +# ifndef MLN_INCLUDE_ONLY + + + group_info::group_info() + : valid_(false) + { + } + + group_info::group_info(unsigned id, const mln::util::array<component_id_t>& comps, + unsigned pixel_area, const box2d& bbox) + : id_(id), comps_(comps), valid_(true), + pixel_area_(pixel_area), bbox_(bbox) + { + } + + group_info::group_info(unsigned id, unsigned pixel_area, const box2d& bbox, bool valid) + : id_(id), valid_(valid), + pixel_area_(pixel_area), bbox_(bbox) + { + } + + const mln::util::array<component_id_t>& + group_info::component_ids() const + { + return comps_; + } + + mln::util::array<component_id_t>& + group_info::component_ids_() + { + return comps_; + } + + bool group_info::is_valid() const + { + return valid_; + } + + void + group_info::invalidate() + { + valid_ = false; + } + + unsigned + group_info::card() const + { + return comps_.nelements(); + } + + unsigned + group_info::id() const + { + return id_; + } + + unsigned + group_info::pixel_area() const + { + return pixel_area_; + } + + const box2d& + group_info::bbox() const + { + return bbox_; + } + + inline + std::ostream& + operator<<(std::ostream& ostr, const group_info& group_info) + { + ostr << "group_info["; + + ostr << "id=" << group_info.id() << ", " + << "valid=" << group_info.is_valid() << ", " + << "pixel_area=" << group_info.pixel_area() << ", " + << "bbox=" << group_info.bbox() << ", " + << "component_ids=" << group_info.component_ids(); + + ostr << "]"; + + return ostr; + } + + inline + bool + operator==(const group_info& lhs, const group_info& rhs) + { + return + lhs.id() == rhs.id() + && lhs.component_ids() == rhs.component_ids() + && lhs.is_valid() == rhs.is_valid() + && lhs.pixel_area() == rhs.pixel_area() + && lhs.bbox() == rhs.bbox(); + } + + +# endif // ! MLN_INCLUDE_ONLY + + +} // end of namespace scribo + + +#endif // ! SCRIBO_CORE_GROUP_INFO_HH diff --git a/scribo/scribo/core/component_features_data.hh b/scribo/scribo/core/internal/sort_comp_ids.hh similarity index 59% copy from scribo/scribo/core/component_features_data.hh copy to scribo/scribo/core/internal/sort_comp_ids.hh index 07b3e4a..83cd507 100644 --- a/scribo/scribo/core/component_features_data.hh +++ b/scribo/scribo/core/internal/sort_comp_ids.hh @@ -23,54 +23,55 @@ // exception does not however invalidate any other reasons why the // executable file might be covered by the GNU General Public License. -#ifndef SCRIBO_CORE_COMPONENT_FEATURES_DATA_HH -# define SCRIBO_CORE_COMPONENT_FEATURES_DATA_HH +#ifndef SCRIBO_CORE_INTERNAL_SORT_COMP_IDS_HH +# define SCRIBO_CORE_INTERNAL_SORT_COMP_IDS_HH /// \file /// -/// \brief Component features data structure. +/// Functor ordering Components by location, from left to right. -# include <scribo/core/def/color_type.hh> +# include <scribo/core/component_set.hh> + namespace scribo { - struct component_features_data + namespace internal { - component_features_data(); - - bool valid; - scribo::def::color_type color; - float boldness; - }; + template <typename L> + struct sort_comp_ids + { + sort_comp_ids(const component_set<L>& comp_set); + bool operator()(const component_id_t& l, const component_id_t& r) const; - std::ostream& - operator<<(std::ostream& ostr, const component_features_data& data); + component_set<L> comps_; + }; # ifndef MLN_INCLUDE_ONLY - component_features_data::component_features_data() - : valid(false) - { - } + template <typename L> + sort_comp_ids<L>::sort_comp_ids(const component_set<L>& comp_set) + : comps_(comp_set) + { + } - inline - std::ostream& - operator<<(std::ostream& ostr, const component_features_data& data) - { - return ostr << "features[" - << "valid=" << data.valid - << ", color=" << data.color - << ", boldness=" << data.boldness - << "]" << std::endl; - } + template <typename L> + bool + sort_comp_ids<L>::operator()(const component_id_t& l, + const component_id_t& r) const + { + return comps_(l).bbox().pmin().col() < comps_(r).bbox().pmin().col() + && comps_(l).bbox().pmax().col() < comps_(r).bbox().pmax().col(); + } # endif // ! MLN_INCLUDE_ONLY + } // end of namespace scribo::internal + } // end of namespace scribo -#endif // ! SCRIBO_CORE_COMPONENT_FEATURES_DATA_HH +#endif // ! SCRIBO_CORE_INTERNAL_SORT_COMP_IDS_HH diff --git a/scribo/scribo/core/line_info.hh b/scribo/scribo/core/line_info.hh index e925db7..b8a8be3 100644 --- a/scribo/scribo/core/line_info.hh +++ b/scribo/scribo/core/line_info.hh @@ -54,9 +54,11 @@ # include <scribo/core/tag/component.hh> # include <scribo/core/tag/line.hh> +# include <scribo/core/object_groups.hh> # include <scribo/core/line_set.hh> # include <scribo/core/component_set.hh> +# include <scribo/core/internal/sort_comp_ids.hh> # include <scribo/core/concept/serializable.hh> @@ -79,14 +81,16 @@ namespace scribo { line_info_data(); line_info_data(const line_set<L>& holder, - const mln::util::array<component_id_t>& comps); - + const group_info& group); + // Used for incremental construction (xml loading) + line_info_data(const line_set<L>& holder, + const mln::util::array<component_id_t>& component_ids); bool hidden_; line::Tag tag_; mln::box2d bbox_; mln::box2d ebbox_; - mln::util::array<component_id_t> components_; + mln::util::array<component_id_t> component_ids_; // The number of pixels used for line characters. unsigned pixel_area_; @@ -138,21 +142,11 @@ namespace scribo // Line set holding this element. line_set<L> holder_; - }; - - - // Functor used to sort components ids. - // Order by location from left to right. - template <typename L> - struct sort_comp_ids - { - sort_comp_ids(const component_set<L>& comp_set); - bool operator()(const component_id_t& l, const component_id_t& r) const; + private: + void init_(); - component_set<L> comps_; }; - } // end of namespace scribo::internal @@ -176,7 +170,7 @@ namespace scribo line_info(const line_set<L>& holder, const line_id_t& id, - const mln::util::array<component_id_t>& comps); + const group_info& group); /// The line id of the target instance is preserved if it is valid. line_info(const line_info<L>& other); @@ -317,6 +311,10 @@ namespace scribo std::ostream& operator<<(std::ostream& ostr, const line_info<L>& info); + template <typename L> + bool + operator==(const line_info<L>& lhs, const line_info<L>& rhs); + # ifndef MLN_INCLUDE_ONLY @@ -365,13 +363,28 @@ namespace scribo hidden_ = false; } + template <typename L> + line_info_data<L>::line_info_data(const line_set<L>& holder, + const group_info& group) + : hidden_(false), tag_(line::None), component_ids_(group.component_ids()), + type_(line::Undefined), holder_(holder) + { + init_(); + } template <typename L> line_info_data<L>::line_info_data(const line_set<L>& holder, - const mln::util::array<component_id_t>& comps) - : hidden_(false), tag_(line::None), components_(comps), + const mln::util::array<component_id_t>& component_ids) + : hidden_(false), tag_(line::None), component_ids_(component_ids), type_(line::Undefined), holder_(holder) { + init_(); + } + + template <typename L> + void + line_info_data<L>::init_() + { // FIXME: set valid information for these attributes in // force_stats_update. word_space_ = 0; @@ -384,26 +397,6 @@ namespace scribo indented_ = false; } - - - // sort_comp_ids functor - - template <typename L> - sort_comp_ids<L>::sort_comp_ids(const component_set<L>& comp_set) - : comps_(comp_set) - { - } - - - template <typename L> - bool - sort_comp_ids<L>::operator()(const component_id_t& l, - const component_id_t& r) const - { - return comps_(l).bbox().pmin().col() < comps_(r).bbox().pmin().col() - && comps_(l).bbox().pmax().col() < comps_(r).bbox().pmax().col(); - } - } // end of namespace scribo::internal @@ -480,10 +473,10 @@ namespace scribo template <typename L> line_info<L>::line_info(const line_set<L>& holder, const line_id_t& id, - const mln::util::array<component_id_t>& comps) + const group_info& group) : id_(id) { - data_ = new data_t(holder, comps); + data_ = new data_t(holder, group); force_stats_update(); } @@ -540,7 +533,7 @@ namespace scribo const mln::util::array<typename line_info<L>::component_id_t>& line_info<L>::component_ids() const { - return data_->components_; + return data_->component_ids_; } @@ -548,7 +541,7 @@ namespace scribo unsigned line_info<L>::card() const { - return data_->components_.size(); + return data_->component_ids_.size(); } @@ -691,9 +684,9 @@ namespace scribo void line_info<L>::update_components_type(component::Type type) { - for_all_elements(i, data_->components_) + for_all_elements(i, data_->component_ids_) { - unsigned c = data_->components_[i]; + unsigned c = data_->component_ids_[i]; data_->holder_.components_()(c).update_type(type); } } @@ -954,7 +947,7 @@ namespace scribo // Update bbox and ebbox update_bbox_and_ebox(other); - data_->components_.append(other.component_ids()); + data_->component_ids_.append(other.component_ids()); } @@ -1006,9 +999,9 @@ namespace scribo // Workaround to avoid overflow with int_u<12> in median accumulators. // // FIXME: not optimal... - for_all_elements(i, data_->components_) + for_all_elements(i, data_->component_ids_) { - unsigned c = data_->components_(i); + unsigned c = data_->component_ids_(i); // Ignore punctuation for stats computation but not for bbox // computation. @@ -1020,9 +1013,9 @@ namespace scribo unsigned used_comps = 0; - for_all_elements(i, data_->components_) + for_all_elements(i, data_->component_ids_) { - unsigned c = data_->components_(i); + unsigned c = data_->component_ids_(i); pixel_area += comp_set(c).card(); @@ -1111,8 +1104,8 @@ namespace scribo // Order component ids according to component localization (left // to right). - std::sort(data_->components_.hook_std_vector_().begin(), - data_->components_.hook_std_vector_().end(), + std::sort(data_->component_ids_.hook_std_vector_().begin(), + data_->component_ids_.hook_std_vector_().end(), internal::sort_comp_ids<L>(comp_set)); // Boldness @@ -1142,8 +1135,8 @@ namespace scribo // Char width if (card() == 2) - data_->char_width_ = (comp_set(data_->components_[0]).bbox().width() - + comp_set(data_->components_[1]).bbox().width()) / 2; + data_->char_width_ = (comp_set(data_->component_ids_[0]).bbox().width() + + comp_set(data_->component_ids_[1]).bbox().width()) / 2; else data_->char_width_ = char_width.to_result(); @@ -1218,6 +1211,47 @@ namespace scribo } + template <typename L> + bool + operator==(const line_info<L>& lhs, const line_info<L>& rhs) + { + if (! lhs.is_valid() && ! rhs.is_valid()) + return true; + + return + lhs.is_valid() == rhs.is_valid() + && lhs.id() == rhs.id() + && lhs.pixel_area() == rhs.pixel_area() + && lhs.tag() == rhs.tag() + && lhs.type() == rhs.type() + && lhs.bbox() == rhs.bbox() + && lhs.ebbox() == rhs.ebbox() + && lhs.boldness() == rhs.boldness() + && lhs.boldness_reliability() == rhs.boldness_reliability() + && lhs.color() == rhs.color() + && lhs.color_reliability() == rhs.color_reliability() + && lhs.component_ids() == rhs.component_ids() + && lhs.baseline() == rhs.baseline() + && lhs.meanline() == rhs.meanline() + && lhs.ascent() == rhs.ascent() + && lhs.descent() == rhs.descent() + && lhs.x_height() == rhs.x_height() + && lhs.d_height() == rhs.d_height() + && lhs.a_height() == rhs.a_height() + && lhs.char_space() == rhs.char_space() + && lhs.char_width() == rhs.char_width() + && lhs.word_space() == rhs.word_space() + && lhs.reading_orientation() == rhs.reading_orientation() + && lhs.type() == rhs.type() + && lhs.reverse_video() == rhs.reverse_video() + && lhs.orientation() == rhs.orientation() + && lhs.reading_orientation() == rhs.reading_orientation() + && lhs.indented() == rhs.indented() + && lhs.is_hidden() == rhs.is_hidden() + && lhs.text() == rhs.text() + && lhs.html_text() == rhs.html_text(); + } + # endif// ! MLN_INCLUDE_ONLY diff --git a/scribo/scribo/core/line_set.hh b/scribo/scribo/core/line_set.hh index f1e443b..db987e6 100644 --- a/scribo/scribo/core/line_set.hh +++ b/scribo/scribo/core/line_set.hh @@ -123,6 +123,9 @@ namespace scribo /// Return line information for a given line id \p id. const line_info<L>& operator()(const line_id_t& id) const; + /// Return all the line information. + const mln::util::array<line_info<L> >& infos() const; + /// Update tag of lines set to 'false' in \p f with \p tag. template <typename F> void update_tags(const mln::Function_v2b<F>& f, line::Tag tag); @@ -166,7 +169,6 @@ namespace scribo void update_line_data_(const mln::util::array<line_info<L> >& line_data); - private: /// Duplicate the underlying image and create a new line_set. void init_(const line_set<L>& model); @@ -174,6 +176,11 @@ namespace scribo mln::util::tracked_ptr< internal::line_set_data<L> > data_; }; + + template <typename L> + bool + operator==(const line_set<L>& lhs, const line_set<L>& rhs); + template <typename L> std::ostream& operator<<(std::ostream& ostr, const line_set<L>& lines); @@ -260,38 +267,14 @@ namespace scribo { data_ = new internal::line_set_data<L>(groups); - typedef mln_site(L) P; - - mln_value(L) n_groups = groups.nelements() - 1; - mln::fun::i2v::array<mln_value(L)> - packed_groups = mln::make::relabelfun(groups.comp_to_group(), - n_groups, n_groups); - - // FIXME: object_groups should store the relation 'group -> comp'. - mln::util::array< mln::util::array<component_id_t> > - group_to_comps(value::next(n_groups)); - - - // 1st pass - Compute data. - for_all_comps(i, data_->components_) - if (data_->components_(i).is_valid()) - { - unsigned group_id = packed_groups(i); - if (group_id != 0) // Is this component part of a group? - { - // Component id. - group_to_comps(group_id).append(i); - } - } - // 2nd pass - Store data. - data_->infos_.reserve(group_to_comps.size()); + data_->infos_.reserve(groups.nelements()); data_->infos_.append(line_info<L>()); // line with id 0 is invalid. - for_all_groups(i, group_to_comps) + for_all_groups(i, groups) { // Add line info. - line_info<L> info(*this, i, group_to_comps(i)); + line_info<L> info(*this, i, groups(i)); data_->infos_.append(info); } } @@ -339,6 +322,13 @@ namespace scribo } template <typename L> + const mln::util::array<line_info<L> >& + line_set<L>::infos() const + { + return this->data_->infos_; + } + + template <typename L> template <typename F> inline void @@ -437,6 +427,26 @@ namespace scribo data_ = new internal::line_set_data<L>(set.infos_(), set.groups()); } + template <typename L> + bool + operator==(const line_set<L>& lhs, const line_set<L>& rhs) + { + if (! (lhs.groups() == rhs.groups() && lhs.nelements() == rhs.nelements())) + { + std::cout << "line.group" << std::endl; + return false; + } + + for_all_lines(l, lhs) + if ( ! (lhs(l) != rhs(l))) + { + std::cout << "line.info" << std::endl; + return false; + } + + return true; + } + template <typename L> diff --git a/scribo/scribo/core/object_groups.hh b/scribo/scribo/core/object_groups.hh index 2a4b0b1..1cc8815 100644 --- a/scribo/scribo/core/object_groups.hh +++ b/scribo/scribo/core/object_groups.hh @@ -36,8 +36,13 @@ # include <scribo/core/object_links.hh> # include <scribo/core/component_set.hh> +# include <scribo/core/group_info.hh> +# include <scribo/core/internal/sort_comp_ids.hh> # include <scribo/core/concept/serializable.hh> +// Not to include. +//#include <scribo/core/line_info.hh> + namespace scribo { @@ -47,7 +52,6 @@ namespace scribo // Forward declaration. template <typename L> class object_groups; - namespace internal { /// Data structure for \c scribo::object_groups<I>. @@ -56,9 +60,12 @@ namespace scribo { object_groups_data(); object_groups_data(const object_links<L>& links); - object_groups_data(const object_links<L>& links, unsigned value); + object_groups_data(const object_links<L>& links, + const mln::util::array<group_info>& info); mln::util::array<unsigned> comp_to_group_; + mln::util::array<group_info> group_info_; + component_set<L> components_; object_links<L> links_; }; @@ -78,26 +85,34 @@ namespace scribo public: object_groups(); object_groups(const object_links<L>& links); - object_groups(const object_links<L>& links, unsigned value); + // Used for incremental construction (xml loading) + object_groups(const object_links<L>& links, + const mln::util::array<group_info>& info); const component_set<L>& components() const; const object_links<L>& links() const; - void init_(const object_links<L>& links); - bool is_valid() const; - bool is_valid(unsigned comp_id) const; + + // Return the number of groups unsigned nelements() const; - unsigned& operator()(unsigned comp_id); - const unsigned& operator()(unsigned comp_id) const; + /// Return the group id of the component \p comp_id. + const group_info& group_of(unsigned comp_id) const; + group_info& group_of(unsigned comp_id); + + /// Return group info data for group with id \p group_id. + /// Valid id starts from 1. + const group_info& operator()(unsigned group_id) const; + group_info& operator()(unsigned group_id); + + // Map component ids to group ids. const mln::util::array<unsigned>& comp_to_group() const; object_groups<L> duplicate() const; - void init(); private: // attributes mln::util::tracked_ptr<data_t> data_; @@ -108,6 +123,10 @@ namespace scribo std::ostream& operator<<(std::ostream& ostr, const object_groups<L>& groups); + template <typename L> + bool + operator==(const object_groups<L>& lhs, const object_groups<L>& rhs); + # ifndef MLN_INCLUDE_ONLY @@ -127,17 +146,93 @@ namespace scribo : comp_to_group_(unsigned(links.nelements())), components_(links.components()), links_(links) { - }; - + comp_to_group_ = links.comp_to_link(); + + unsigned ngroups = 0; + util::array<unsigned> new_id(comp_to_group_.nelements(), 0); + mln::util::array<mln::util::array<component_id_t> > comp_ids(1); + mln::util::array<accu::shape::bbox<mln_site(L)> > bboxes(1); + mln::util::array<unsigned> pixel_areas(1); + + // Remove potential loops in linking + // FIXME: we may try to avoid loops while linking... + { + util::array<bool> deja_vu(comp_to_group_.nelements()); + for_all_elements(e, comp_to_group_) + if (comp_to_group_(e) != e && comp_to_group_(e) != 0) + { + deja_vu.fill(false); // FIXME: ugly! + unsigned cur = e; + deja_vu(cur) = true; + while (comp_to_group_(cur) != cur && !deja_vu(comp_to_group_(cur))) + { + cur = comp_to_group_(cur); + deja_vu(cur) = true; + } + // Break the loop! + if (comp_to_group_(cur) != cur && deja_vu(comp_to_group_(cur))) + comp_to_group_(cur) = cur; + } + } + + for_all_elements(e, comp_to_group_) + if (comp_to_group_(e) != 0) + { + // Make sure there is no intermediate ids to reach the root. + // FIXME: useful? + unsigned e_root = internal::find_root(comp_to_group_, e); + + if (! new_id(e_root)) + { + new_id(e_root) = ++ngroups; + comp_ids.resize(comp_ids.size() + 1); + bboxes.resize(bboxes.size() + 1); + pixel_areas.resize(pixel_areas.size() + 1, 0); + } + + unsigned nid = new_id(e_root); + comp_ids(nid).append(e); + + bboxes(nid).take(components_(e).bbox()); + pixel_areas(nid) += components_(e).card(); + } + + group_info_.resize(1); + group_info_.reserve(ngroups); + util::array<unsigned> group_idx(ngroups + 1, 0); + + for (unsigned i = 1; i < new_id.nelements(); ++i) + if (new_id(i)) + { + unsigned id = new_id(i); + + // Order component ids according to component localization (left + // to right). + std::sort(comp_ids(id).hook_std_vector_().begin(), + comp_ids(id).hook_std_vector_().end(), + internal::sort_comp_ids<L>(components_)); + + group_idx(id) = group_info_.size(); + group_info_.append(group_info(group_info_.size(), comp_ids(id), pixel_areas(id), bboxes(id))); + } + + // Update mapping comp/group with new ids. Note: group id is + // different from its location in group_info array during + // construction. + for (unsigned i = 0; i < comp_to_group_.nelements(); ++i) + comp_to_group_(i) = group_idx(new_id(comp_to_group_(i))); + } template <typename L> object_groups_data<L>::object_groups_data(const object_links<L>& links, - unsigned value) - : comp_to_group_(unsigned(links.nelements()), value), + const mln::util::array<group_info>& info) + : comp_to_group_(unsigned(links.nelements())), group_info_(info), components_(links.components()), links_(links) { - }; - + for_all_groups(g, group_info_) + for_all_elements(e, group_info_(g).component_ids()) + comp_to_group_(group_info_(g).component_ids()(e)) = group_info_(g).id(); + } } // end of namespace scribo::internal @@ -154,9 +249,10 @@ namespace scribo } template <typename L> - object_groups<L>::object_groups(const object_links<L>& links, unsigned value) + object_groups<L>::object_groups(const object_links<L>& links, + const mln::util::array<group_info>& info) { - data_ = new data_t(links, value); + data_ = new data_t(links, info); } template <typename L> @@ -175,60 +271,66 @@ namespace scribo } template <typename L> - void - object_groups<L>::init_(const object_links<L>& links) - { - mln_assertion(data_ != 0); - data_->comp_to_group_ = links.comp_to_link(); - } - - template <typename L> bool object_groups<L>::is_valid() const { - mln_assertion(data_->components_.nelements() == (nelements() - 1)); + mln_assertion(data_->components_.nelements() == data_->comp_to_group_.nelements() - 1); return data_->links_.is_valid(); } template <typename L> - bool - object_groups<L>::is_valid(unsigned comp_id) const + unsigned + object_groups<L>::nelements() const { - mln_assertion(is_valid()); - mln_assertion(comp_id < data_->links_.nelements()); - return data_->links_(comp_id) != 0; + return data_->group_info_.nelements(); } template <typename L> - unsigned - object_groups<L>::nelements() const + const group_info& + object_groups<L>::group_of(unsigned comp_id) const { - return data_->comp_to_group_.nelements(); + mln_precondition(comp_id < data_->comp_to_group_.nelements()); + mln_assertion(data_->group_info_(data_->comp_to_group_(comp_id)).id() + == data_->comp_to_group_(comp_id)); + return data_->group_info_(data_->comp_to_group_(comp_id)); } + template <typename L> + group_info& + object_groups<L>::group_of(unsigned comp_id) + { + mln_precondition(comp_id < data_->comp_to_group_.nelements()); + mln_assertion(data_->group_info_(data_->comp_to_group_(comp_id)).id() + == data_->comp_to_group_(comp_id)); + return data_->group_info_(data_->comp_to_group_(comp_id)); + } template <typename L> - unsigned& - object_groups<L>::operator()(unsigned comp_id) + const util::array<unsigned>& + object_groups<L>::comp_to_group() const { - return data_->comp_to_group_(comp_id); + return data_->comp_to_group_; } template <typename L> - const unsigned& - object_groups<L>::operator()(unsigned comp_id) const + const group_info& + object_groups<L>::operator()(unsigned group_id) const { - return data_->comp_to_group_(comp_id); + mln_precondition(group_id < data_->group_info_.nelements()); + return data_->group_info_(group_id); } + template <typename L> - const mln::util::array<unsigned>& - object_groups<L>::comp_to_group() const + group_info& + object_groups<L>::operator()(unsigned group_id) { - return data_->comp_to_group_; + mln_precondition(group_id < data_->group_info_.nelements()); + return data_->group_info_(group_id); } + template <typename L> inline object_groups<L> @@ -242,22 +344,15 @@ namespace scribo } template <typename L> - void - object_groups<L>::init() - { - for (unsigned i = 0; i < nelements(); ++i) - data_->comp_to_group_(i) = i; - } - - - template <typename L> std::ostream& operator<<(std::ostream& ostr, const object_groups<L>& groups) { ostr << "object_groups["; for_all_groups(g, groups) - ostr << g << "->" << groups.comp_to_group()[g] << ", "; + ostr << groups(g) << ", "; + + ostr << " | comp_to_group=" << groups.comp_to_group(); ostr << "]"; @@ -265,6 +360,33 @@ namespace scribo } + template <typename L> + bool + operator==(const object_groups<L>& lhs, const object_groups<L>& rhs) + { + if (! (lhs.components() == rhs.components())) + { + std::cout << "group.comp" << std::endl; + return false; + } + + if (!( lhs.comp_to_group() == rhs.comp_to_group() && lhs.nelements() == rhs.nelements())) + { + std::cout << "group.comp_to_group" << std::endl; + return false; + } + + + for_all_groups(g, lhs) + if (! (lhs(g) == rhs(g))) + { + std::cout << "group.info" << std::endl; + return false; + } + + return true; + } + # endif // ! MLN_INCLUDE_ONLY diff --git a/scribo/scribo/core/object_links.hh b/scribo/scribo/core/object_links.hh index 1fbcd5a..386de41 100644 --- a/scribo/scribo/core/object_links.hh +++ b/scribo/scribo/core/object_links.hh @@ -39,7 +39,6 @@ # include <scribo/core/concept/serializable.hh> - namespace scribo { @@ -51,6 +50,18 @@ namespace scribo namespace internal { + + inline + unsigned + find_root(mln::util::array<unsigned>& parent, unsigned x) + { + if (parent(x) == x) + return x; + else + return parent(x) = find_root(parent, parent(x)); + } + + /// Data structure for \c scribo::object_links<I>. template <typename L> struct object_links_data @@ -83,13 +94,36 @@ namespace scribo const component_set<L>& components() const; + /// Return True if this object_links structure is correctly + /// constructed. bool is_valid() const; - bool is_valid(unsigned comp_id) const; + + /// Return True if component \p comp_id can be linked to another + /// component. + bool has_linking_enabled(unsigned comp_id) const; + + /// Return True if component \p comp_id has a link starting from + /// itself to another one. + bool is_linked(unsigned comp_id) const; unsigned nelements() const; - unsigned& operator()(unsigned comp_id); + /// Link related methods. + /// \{ + /// Set link between component \p from_id and \p to_id. + void update(unsigned from_id, unsigned to_id); + + /// Reset link for component with id \p id. This component can be + /// linked later. + void clear(unsigned id); + + /// Do not allow component with id \p id to be linked to anyother + /// ones. + void disable_linking(unsigned id); + + /// Get link id for component \p comp_id. const unsigned& operator()(unsigned comp_id) const; + /// \} const mln::util::array<unsigned>& comp_to_link() const; @@ -183,13 +217,25 @@ namespace scribo template <typename L> bool - object_links<L>::is_valid(unsigned comp_id) const + object_links<L>::has_linking_enabled(unsigned comp_id) const { mln_precondition(is_valid()); mln_precondition(comp_id < data_->comp_to_link_.nelements()); + return data_->comp_to_link_(comp_id) != 0; } + template <typename L> + bool + object_links<L>::is_linked(unsigned comp_id) const + { + mln_precondition(is_valid()); + mln_precondition(comp_id < data_->comp_to_link_.nelements()); + + return has_linking_enabled(comp_id) + && data_->comp_to_link_(comp_id) != comp_id; + } + template <typename L> unsigned @@ -200,20 +246,32 @@ namespace scribo template <typename L> - unsigned& - object_links<L>::operator()(unsigned comp_id) + const unsigned& + object_links<L>::operator()(unsigned comp_id) const { return data_->comp_to_link_(comp_id); } + template <typename L> + void + object_links<L>::update(unsigned from_id, unsigned to_id) + { + data_->comp_to_link_(from_id) = to_id; + } template <typename L> - const unsigned& - object_links<L>::operator()(unsigned comp_id) const + void + object_links<L>::clear(unsigned id) { - return data_->comp_to_link_(comp_id); + data_->comp_to_link_(id) = id; } + template <typename L> + void + object_links<L>::disable_linking(unsigned id) + { + data_->comp_to_link_(id) = 0; + } template <typename L> const mln::util::array<unsigned>& @@ -222,16 +280,15 @@ namespace scribo return data_->comp_to_link_; } - template <typename L> void object_links<L>::init() { for (unsigned i = 0; i < nelements(); ++i) if (data_->components_(i).tag() == component::Ignored) - data_->comp_to_link_(i) = 0; + disable_linking(i); else - data_->comp_to_link_(i) = i; + clear(i); } template <typename L> diff --git a/scribo/scribo/debug/decision_image.hh b/scribo/scribo/debug/decision_image.hh index aa1a188..ff298e6 100644 --- a/scribo/scribo/debug/decision_image.hh +++ b/scribo/scribo/debug/decision_image.hh @@ -1,5 +1,5 @@ -// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory -// (LRDE) +// Copyright (C) 2009, 2010, 2011 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of Olena. // @@ -150,10 +150,10 @@ namespace scribo for_all_comps(i, comps) mln::draw::box(decision_image, comps(i).bbox(), literal::blue); - for (unsigned i = 1; i < links.nelements(); ++i) + for_all_links(i, links) { - if (links(i) != i) + if (links.is_linked(i)) { mln_site(L) p1 = primitive::link::internal::compute_anchor(comps, i, anchor), diff --git a/scribo/scribo/estim/object_groups_mean_width.hh b/scribo/scribo/estim/object_groups_mean_width.hh index c74137a..65d843c 100644 --- a/scribo/scribo/estim/object_groups_mean_width.hh +++ b/scribo/scribo/estim/object_groups_mean_width.hh @@ -72,24 +72,17 @@ namespace scribo const component_set<L>& components = groups.components(); - //FIXME: remove when object_groups will store the number of - //elements per group. - mln::util::array<unsigned> group_card(groups.nelements(), 0.0); - mln::util::array<float> output(groups.nelements(), 0.0); - for_all_comps(i, components) - if (components(i).is_valid()) - { - output(groups(i)) += components(i).bbox().width(); - ++group_card(groups(i)); - } + for_all_groups(g, groups) + for_all_elements(e, groups(g).component_ids()) + output(g) += components(groups(g).component_ids()(e)).bbox().width(); output(0) = 0; - for_all_groups(i, output) - if (components(i).is_valid()) - output(i) /= static_cast<float>(group_card(i)); + for_all_groups(g, groups) + if (groups(g).is_valid()) + output(g) /= groups(g).card(); else - output(i) = 0; + output(g) = 0; trace::exiting("scribo::estim::object_groups_mean_width"); return output; diff --git a/scribo/scribo/filter/object_groups_mean_width.hh b/scribo/scribo/filter/object_groups_mean_width.hh index 0668205..b9c7b8a 100644 --- a/scribo/scribo/filter/object_groups_mean_width.hh +++ b/scribo/scribo/filter/object_groups_mean_width.hh @@ -77,11 +77,11 @@ namespace scribo group_width = estim::object_groups_mean_width(groups); object_groups<L> output = groups.duplicate(); - output(0) = 0; - for (unsigned i = 1; i < output.nelements(); ++i) - if (groups.components()(i).is_valid() - && group_width[groups(i)] < width) - output(i) = 0; + + for_all_groups(g, groups) + if (groups(g).is_valid() + && group_width[g] < width) + output(g).invalidate(); trace::exiting("scribo::filter::object_groups_mean_width"); return output; diff --git a/scribo/scribo/filter/object_groups_size_ratio.hh b/scribo/scribo/filter/object_groups_size_ratio.hh index 01676c4..6f2e33e 100644 --- a/scribo/scribo/filter/object_groups_size_ratio.hh +++ b/scribo/scribo/filter/object_groups_size_ratio.hh @@ -65,29 +65,23 @@ namespace scribo const component_set<L>& comps = groups.components(); - // FIXME: estimating the group size should be removed once - // available in the object_group structure. // Counting the number of objects per group with a size ratio > // max_ratio. mln::util::array<unsigned> - group_size(groups.nelements(), 0), invalid_object_in_group(groups.nelements(), 0); for_all_comps(i, comps) { if ((comps(i).bbox().height() / comps(i).bbox().width()) >= max_size_ratio) - ++invalid_object_in_group(groups(i)); - - ++group_size(groups(i)); + ++invalid_object_in_group(groups.group_of(i).id()); } object_groups<L> output(groups); - output(0) = 0; - for (unsigned i = 1; i < output.nelements(); ++i) - if ((invalid_object_in_group(groups(i)) / static_cast<float>(group_size(groups(i)))) >= max_invalid_ratio_per_group - || !comps(i).is_valid()) - output(i) = 0; + for_all_groups(g, groups) + if ((invalid_object_in_group(g) / static_cast<float>(groups(g).card())) >= max_invalid_ratio_per_group + || !groups(g).is_valid()) + output(g).invalidate(); trace::exiting("scribo::filter::object_groups_size_ratio"); return output; diff --git a/scribo/scribo/filter/object_groups_small.hh b/scribo/scribo/filter/object_groups_small.hh index 8dd244c..dd92852 100644 --- a/scribo/scribo/filter/object_groups_small.hh +++ b/scribo/scribo/filter/object_groups_small.hh @@ -50,7 +50,6 @@ namespace scribo \param[in] groups Information about object groups. \param[in] n_links The minimum number of links per group. - \param[out] group_size Return the group sizes _before_ filtering. \return A copy of object group in which small groups have been removed. @@ -58,13 +57,6 @@ namespace scribo template <typename L> object_groups<L> object_groups_small(const object_groups<L>& groups, - unsigned n_links, - mln::util::array<unsigned>& group_size); - - // \overload - template <typename L> - object_groups<L> - object_groups_small(const object_groups<L>& groups, unsigned n_links); @@ -76,42 +68,22 @@ namespace scribo inline object_groups<L> object_groups_small(const object_groups<L>& groups, - unsigned n_links, - mln::util::array<unsigned>& group_size) + unsigned n_links) { trace::entering("scribo::filter::object_groups_small"); mln_precondition(groups.is_valid()); - // Counting the number of objects per group. - group_size = mln::util::array<unsigned>(groups.nelements(), 0); - for_all_groups(i, group_size) - ++group_size[groups(i)]; - object_groups<L> output = groups.duplicate(); - output(0) = 0; + for_all_groups(i, output) - if (group_size[groups(i)] < n_links - || !groups.components()(i).is_valid()) - output(i) = 0; + if (output(i).is_valid() && output(i).card() < n_links) + output(i).invalidate(); trace::exiting("scribo::filter::object_groups_small"); return output; } - - template <typename L> - inline - object_groups<L> - object_groups_small(const object_groups<L>& groups, - unsigned n_links) - { - mln::util::array<unsigned> group_size; - return object_groups_small(groups, n_links, group_size); - } - - - # endif // ! MLN_INCLUDE_ONLY } // end of namespace scribo::filter diff --git a/scribo/scribo/filter/object_groups_with_holes.hh b/scribo/scribo/filter/object_groups_with_holes.hh index b86b10e..a59beec 100644 --- a/scribo/scribo/filter/object_groups_with_holes.hh +++ b/scribo/scribo/filter/object_groups_with_holes.hh @@ -298,7 +298,7 @@ namespace scribo object_groups<L> output = groups.duplicate(); for_all_groups(c, groups) if (! to_keep(group_2_comp(c))) - output(c) = 0; + output(c).invalidate(); trace::exiting("scribo::filter::impl::generic::object_groups_with_holes"); return output; diff --git a/scribo/scribo/filter/object_links_bbox_overlap.hh b/scribo/scribo/filter/object_links_bbox_overlap.hh index 995ad68..3bf3c50 100644 --- a/scribo/scribo/filter/object_links_bbox_overlap.hh +++ b/scribo/scribo/filter/object_links_bbox_overlap.hh @@ -1,5 +1,5 @@ -// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory -// (LRDE) +// Copyright (C) 2009, 2010, 2011 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of Olena. // @@ -109,7 +109,7 @@ namespace scribo if (ratio_i >= max_overlap_ratio || ratio_link_i >= max_overlap_ratio) - output(i) = i; + output.clear(i); } trace::exiting("scribo::filter::object_links_bbox_overlap"); diff --git a/scribo/scribo/filter/object_links_bbox_ratio.hh b/scribo/scribo/filter/object_links_bbox_ratio.hh index 5318b57..d6c9286 100644 --- a/scribo/scribo/filter/object_links_bbox_ratio.hh +++ b/scribo/scribo/filter/object_links_bbox_ratio.hh @@ -1,5 +1,5 @@ -// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory -// (LRDE) +// Copyright (C) 2009, 2010, 2011 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of Olena. // @@ -78,10 +78,10 @@ namespace scribo mln_precondition(links.is_valid()); const component_set<L>& components = links.components(); - object_links<L> output = links.duplicate(); + for_all_links(i, links) - if (links(i) && links(i) != i) + if (links.is_linked(i)) { float lmin = components(i).bbox().pmax()[dim] @@ -93,7 +93,7 @@ namespace scribo std::swap(lmin, lmax); if ((lmax/ lmin) > max_ratio) - output(i) = i; + output.clear(i); } trace::exiting("scribo::filter::object_links_bbox_ratio"); diff --git a/scribo/scribo/filter/object_links_non_aligned_simple.hh b/scribo/scribo/filter/object_links_non_aligned_simple.hh index 5abf598..f8db5cf 100644 --- a/scribo/scribo/filter/object_links_non_aligned_simple.hh +++ b/scribo/scribo/filter/object_links_non_aligned_simple.hh @@ -1,5 +1,5 @@ -// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory -// (LRDE) +// Copyright (C) 2009, 2010, 2011 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of Olena. // @@ -112,7 +112,7 @@ namespace scribo if (!::scribo::filter::internal::component_aligned_rad(comps, i, links(i), anchor, max_alpha_rad)) - output(i) = i; + output.clear(i); trace::exiting("scribo::filter::object_links_non_aligned_simple"); diff --git a/scribo/scribo/primitive/group/from_double_link_any.hh b/scribo/scribo/primitive/group/from_double_link_any.hh index b3bd82a..7ed15e2 100644 --- a/scribo/scribo/primitive/group/from_double_link_any.hh +++ b/scribo/scribo/primitive/group/from_double_link_any.hh @@ -1,4 +1,5 @@ -// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -42,6 +43,7 @@ # include <scribo/core/macros.hh> +# include <scribo/core/object_links.hh> # include <scribo/core/object_groups.hh> # include <scribo/core/component_set.hh> # include <scribo/primitive/internal/find_root.hh> @@ -73,6 +75,21 @@ namespace scribo # ifndef MLN_INCLUDE_ONLY + namespace internal + { + + template <typename L> + util::array<unsigned> make_parent(const object_links<L>& link) + { + mln::util::array<unsigned> parent = link.comp_to_link(); + for_all_links(l, link) + parent(l) = scribo::internal::find_root(parent, l); + + return parent; + } + + } // end of namespace scribo::primitive::group::internal + template <typename L> inline @@ -82,40 +99,46 @@ namespace scribo { trace::entering("scribo::primitive::group::from_double_link_any"); - object_groups<L> parent(left_link); - parent.init(); + object_links<L> merged_link(left_link.components()); + merged_link.init(); + + util::array<unsigned> lparent = internal::make_parent(left_link); + util::array<unsigned> rparent = internal::make_parent(right_link); - for_all_comps(i, left_link.components()) + for_all_links(i, merged_link) { + // Looking for new left link unsigned - pi = internal::find_root(parent, i), - pli = internal::find_root(parent, left_link(i)); + pi = scribo::internal::find_root(lparent, i), + pli = scribo::internal::find_root(lparent, left_link(i)); if (pi != pli) { - if (pli < pi) - parent(pli) = pi; + merged_link.update(i, left_link(i)); + if (pi < pli) + lparent(pli) = pi; else - parent(pi) = pli; + lparent(pi) = pli; } - pi = internal::find_root(parent, i); - unsigned pri = internal::find_root(parent, right_link(i)); + // Looking for new right link + pi = scribo::internal::find_root(lparent, i); + unsigned pri = scribo::internal::find_root(rparent, right_link(i)); if (pi != pri) { - if (pri < pi) - parent(pri) = pi; + merged_link.update(i, right_link(i)); + if (pi < pli) + lparent(pli) = pi; else - parent(pi) = pri; + lparent(pi) = pli; } } - for_all_groups(g, parent) - internal::find_root(parent, g); + object_groups<L> output(merged_link); trace::exiting("scribo::primitive::group::from_double_link_any"); - return parent; + return output; } diff --git a/scribo/scribo/primitive/group/from_single_link.hh b/scribo/scribo/primitive/group/from_single_link.hh index 05efdc7..0a2cca3 100644 --- a/scribo/scribo/primitive/group/from_single_link.hh +++ b/scribo/scribo/primitive/group/from_single_link.hh @@ -82,19 +82,6 @@ namespace scribo mln_precondition(links.is_valid()); object_groups<L> parent(links); - parent.init_(links); - - for_all_groups(i, parent) - if (!links.components()(i).is_valid()) - parent(i) = 0; - else - ::scribo::primitive::internal::find_root(parent, i); - - - // FIXME: useful? - // Make sure the root is propagated. - for_all_groups(g, parent) - internal::find_root(parent, g); trace::exiting("scribo::primitive::group::from_single_link"); return parent; diff --git a/scribo/scribo/primitive/internal/is_link_valid.hh b/scribo/scribo/primitive/internal/is_link_valid.hh index b18e55c..30823cb 100644 --- a/scribo/scribo/primitive/internal/is_link_valid.hh +++ b/scribo/scribo/primitive/internal/is_link_valid.hh @@ -1,5 +1,5 @@ -// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory -// (LRDE) +// Copyright (C) 2009, 2010, 2011 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of Olena. // @@ -51,9 +51,8 @@ namespace scribo /// \param[in] i The component id. /// /// \return True if the link is between the \p i-th component - /// and it neighbor is validated. template <typename L> - mln::util::couple<bool,unsigned> + bool is_link_valid(const object_links<L>& left_link, const object_links<L>& right_link, unsigned i); @@ -61,13 +60,12 @@ namespace scribo # ifndef MLN_INCLUDE_ONLY template <typename L> - mln::util::couple<bool,unsigned> + bool is_link_valid(const object_links<L>& left_link, const object_links<L>& right_link, unsigned i) { - bool b = (right_link(left_link(i)) == i && left_link(i) != i); - return mln::make::couple(b, left_link(i)); + return left_link.is_linked(i) && right_link(left_link(i)) == i; } # endif // ! MLN_INCLUDE_ONLY diff --git a/scribo/scribo/primitive/link/internal/link_functor_base.hh b/scribo/scribo/primitive/link/internal/link_functor_base.hh index 11066c5..a509126 100644 --- a/scribo/scribo/primitive/link/internal/link_functor_base.hh +++ b/scribo/scribo/primitive/link/internal/link_functor_base.hh @@ -477,7 +477,7 @@ namespace scribo { (void) start_point; (void) anchor; - this->links_(current_object) = this->labeled_image_(p); + this->links_.update(current_object, this->labeled_image_(p)); } diff --git a/scribo/scribo/primitive/link/internal/link_several_dmax_base.hh b/scribo/scribo/primitive/link/internal/link_several_dmax_base.hh index 422eed9..08681c7 100644 --- a/scribo/scribo/primitive/link/internal/link_several_dmax_base.hh +++ b/scribo/scribo/primitive/link/internal/link_several_dmax_base.hh @@ -1,5 +1,5 @@ -// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory -// (LRDE) +// Copyright (C) 2009, 2010, 2011 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of Olena. // @@ -248,15 +248,15 @@ namespace scribo if (nratio == 1) { - this->links_(current_object) - = labeled_image_(potential_links_(id_max_ratio).second()); + this->links_.update(current_object, + labeled_image_(potential_links_(id_max_ratio).second())); return potential_links_(id_max_ratio); } } - this->links_(current_object) = current_object; + this->links_.clear(current_object); return mln::make::couple(anchor::Invalid, P()); } diff --git a/scribo/scribo/primitive/link/merge_double_link.hh b/scribo/scribo/primitive/link/merge_double_link.hh index e58c1ab..2416a77 100644 --- a/scribo/scribo/primitive/link/merge_double_link.hh +++ b/scribo/scribo/primitive/link/merge_double_link.hh @@ -93,19 +93,20 @@ namespace scribo const component_set<L>& components = left_link.components(); - object_links<L> merge = left_link.duplicate(); + object_links<L> merge(components); + merge.init(); - for_all_ncomponents(i, components.nelements()) + for_all_comps(i, components) { if (components(i).tag() == component::Ignored) - merge(i) = 0; + merge.disable_linking(i); else { - mln::util::couple<bool, unsigned> - nbh = primitive::internal::is_link_valid(left_link, - right_link, i); - if (!nbh.first()) - merge(i) = i; + if (primitive::internal::is_link_valid(left_link, + right_link, i)) + merge.update(i, left_link(i)); + else + merge.clear(i); } } diff --git a/scribo/scribo/primitive/link/merge_double_link_closest_aligned.hh b/scribo/scribo/primitive/link/merge_double_link_closest_aligned.hh index 6c6e67f..d80fe85 100644 --- a/scribo/scribo/primitive/link/merge_double_link_closest_aligned.hh +++ b/scribo/scribo/primitive/link/merge_double_link_closest_aligned.hh @@ -129,14 +129,12 @@ namespace scribo if (right(left(l)) == left(l)) { - output(left(l)) = l; - //output.update_link(left(l), l); + output.update(left(l), l); } else if ((dh < align_data(left(l)).first() * 0.66f) || (alpha < align_data(left(l)).second())) { - output(left(l)) = l; - //output.update_link(left(l), l); + output.update(left(l), l); align_data(left(l)).first() = dh; align_data(left(l)).second() = alpha; } diff --git a/scribo/tests/filter/object_groups_mean_width.cc b/scribo/tests/filter/object_groups_mean_width.cc index 81da661..751649d 100644 --- a/scribo/tests/filter/object_groups_mean_width.cc +++ b/scribo/tests/filter/object_groups_mean_width.cc @@ -45,8 +45,8 @@ int main() std::string img = SCRIBO_IMG_DIR "/the_valleys.pbm"; - const unsigned ref[] = { 0, 1, 7, 3, 4, 3, 3, 7, 7, 3, 3, 3, 3 }; - const unsigned filtered_ref[] = { 0, 0, 7, 3, 0, 3, 3, 7, 7, 3, 3, 3, 3 }; + const bool ref[] = { false, true, true, true, true }; + const unsigned filtered_ref[] = { false, false, true, false, true }; image2d<bool> input; io::pbm::load(input, img.c_str()); @@ -61,12 +61,13 @@ int main() object_groups<L> groups = primitive::group::from_single_link(links); + mln_assertion(groups.nelements() == 5); for_all_groups(g, groups) - mln_assertion(groups(g) == ref[g]); + mln_assertion(groups(g).is_valid() == ref[g]); groups = filter::object_groups_mean_width(groups, 10); + mln_assertion(groups.nelements() == 5); for_all_groups(g, groups) - mln_assertion(groups(g) == filtered_ref[g]); - + mln_assertion(groups(g).is_valid() == filtered_ref[g]); } diff --git a/scribo/tests/filter/object_groups_size_ratio.cc b/scribo/tests/filter/object_groups_size_ratio.cc index 90e353a..4051c71 100644 --- a/scribo/tests/filter/object_groups_size_ratio.cc +++ b/scribo/tests/filter/object_groups_size_ratio.cc @@ -45,8 +45,8 @@ int main() std::string img = SCRIBO_IMG_DIR "/the_valleys.pbm"; - const unsigned ref[] = { 0, 1, 7, 3, 4, 3, 3, 7, 7, 3, 3, 3, 3 }; - const unsigned filtered_ref[] = { 0, 1, 0, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3 }; + const bool ref[] = { false, true, true, true, true }; + const bool filtered_ref[] = { false, true, true, false, false }; image2d<bool> input; io::pbm::load(input, img.c_str()); @@ -61,11 +61,13 @@ int main() object_groups<L> groups = primitive::group::from_single_link(links); + mln_assertion(groups.nelements() == 5); for_all_groups(g, groups) - mln_assertion(groups(g) == ref[g]); + mln_assertion(groups(g).is_valid() == ref[g]); groups = filter::object_groups_size_ratio(groups, 1.2, 0.3); + mln_assertion(groups.nelements() == 5); for_all_groups(g, groups) - mln_assertion(groups(g) == filtered_ref[g]); + mln_assertion(groups(g).is_valid() == filtered_ref[g]); } diff --git a/scribo/tests/filter/object_groups_small.cc b/scribo/tests/filter/object_groups_small.cc index 165634d..9812b70 100644 --- a/scribo/tests/filter/object_groups_small.cc +++ b/scribo/tests/filter/object_groups_small.cc @@ -45,9 +45,9 @@ int main() std::string img = SCRIBO_IMG_DIR "/the_valleys.pbm"; - const unsigned ref[] = { 0, 1, 7, 3, 4, 3, 3, 7, 7, 3, 3, 3, 3 }; - const unsigned filtered_ref[] = { 0, 0, 0, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3 }; - const unsigned size_ref[] = { 0, 1, 0, 7, 1, 0, 0, 3, 0, 0, 0, 0, 0 }; + const bool ref[] = { false, true, true, true, true }; + const bool filtered_ref[] = { false, false, true, false, false }; + const unsigned size_ref[] = { 0, 1, 7, 1, 3 }; image2d<bool> input; @@ -63,25 +63,17 @@ int main() object_groups<L> groups = primitive::group::from_single_link(links); + mln_assertion(groups.nelements() == 5); for_all_groups(g, groups) - mln_assertion(groups(g) == ref[g]); + mln_assertion(groups(g).is_valid() == ref[g]); - { - object_groups<L> groups2 = filter::object_groups_small(groups, 4); - - for_all_groups(g, groups2) - mln_assertion(groups2(g) == filtered_ref[g]); - } + object_groups<L> groups2 = filter::object_groups_small(groups, 4); + for_all_groups(g, groups2) { - mln::util::array<unsigned> group_size; - object_groups<L> groups2 = filter::object_groups_small(groups, 4, group_size); - - for_all_groups(g, groups2) - { - mln_assertion(groups2(g) == filtered_ref[g]); - mln_assertion(group_size(g) == size_ref[g]); - } + mln_assertion(groups2(g).is_valid() == filtered_ref[g]); + mln_assertion(groups2(g).card() == size_ref[g]); } + } diff --git a/scribo/tests/filter/object_groups_with_holes.cc b/scribo/tests/filter/object_groups_with_holes.cc index 3b5b29f..72f8464 100644 --- a/scribo/tests/filter/object_groups_with_holes.cc +++ b/scribo/tests/filter/object_groups_with_holes.cc @@ -45,8 +45,8 @@ int main() std::string img = SCRIBO_IMG_DIR "/the_valleys.pbm"; - const unsigned ref[] = { 0, 1, 7, 3, 4, 3, 3, 7, 7, 3, 3, 3, 3 }; - const unsigned filtered_ref[] = { 0, 0, 7, 3, 0, 3, 3, 7, 7, 3, 3, 3, 3 }; + const bool ref[] = { false, true, true, true, true }; + const bool filtered_ref[] = { 0, false, true, true, false }; image2d<bool> input; io::pbm::load(input, img.c_str()); @@ -61,11 +61,13 @@ int main() object_groups<L> groups = primitive::group::from_single_link(links); + mln_assertion(groups.nelements() == 5); for_all_groups(g, groups) - mln_assertion(groups(g) == ref[g]); + mln_assertion(groups(g).is_valid() == ref[g]); groups = filter::object_groups_with_holes(groups, 3); + mln_assertion(groups.nelements() == 5); for_all_groups(g, groups) - mln_assertion(groups(g) == filtered_ref[g]); + mln_assertion(groups(g).is_valid() == filtered_ref[g]); } -- 1.5.6.5