last-svn-commit-808-g3f14376 New non-text components extraction routine.

* scribo/make/text_blocks_image.hh, * scribo/make/text_components_image.hh, * scribo/primitive/extract/internal/union.hh: New. * scribo/primitive/extract/non_text.hh: New implementation. * scribo/primitive/extract/non_text_kmean.hh: New. Old implementatino is saved here. --- scribo/ChangeLog | 13 + scribo/scribo/make/text_blocks_image.hh | 136 ++++++++ scribo/scribo/make/text_components_image.hh | 101 ++++++ scribo/scribo/primitive/extract/internal/union.hh | 246 +++++++++++++ scribo/scribo/primitive/extract/non_text.hh | 366 ++++++++++++++------ .../extract/{non_text.hh => non_text_kmean.hh} | 17 +- 6 files changed, 761 insertions(+), 118 deletions(-) create mode 100644 scribo/scribo/make/text_blocks_image.hh create mode 100644 scribo/scribo/make/text_components_image.hh create mode 100644 scribo/scribo/primitive/extract/internal/union.hh copy scribo/scribo/primitive/extract/{non_text.hh => non_text_kmean.hh} (91%) diff --git a/scribo/ChangeLog b/scribo/ChangeLog index 43041fe..32dda87 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,5 +1,18 @@ 2011-03-14 Guillaume Lazzara <z@lrde.epita.fr> + New non-text components extraction routine. + + * scribo/make/text_blocks_image.hh, + * scribo/make/text_components_image.hh, + * scribo/primitive/extract/internal/union.hh: New. + + * scribo/primitive/extract/non_text.hh: New implementation. + + * scribo/primitive/extract/non_text_kmean.hh: New. Old + implementatino is saved here. + +2011-03-14 Guillaume Lazzara <z@lrde.epita.fr> + Introduce result image output. * scribo/fun/v2v/highlight.hh, diff --git a/scribo/scribo/make/text_blocks_image.hh b/scribo/scribo/make/text_blocks_image.hh new file mode 100644 index 0000000..fbc16df --- /dev/null +++ b/scribo/scribo/make/text_blocks_image.hh @@ -0,0 +1,136 @@ +// 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_MAKE_TEXT_BLOCKS_IMAGE_HH +# define SCRIBO_MAKE_TEXT_BLOCKS_IMAGE_HH + +/// \file +/// +/// \brief Create a mask of paragraph blocks. + +# include <mln/core/image/image2d.hh> +# include <mln/draw/box_plain.hh> + +# include <scribo/core/document.hh> +# include <scribo/core/paragraph_set.hh> +# include <scribo/core/line_info.hh> + + +namespace scribo +{ + + namespace make + { + using namespace mln; + + + /// \brief Create a mask of paragraph blocks. + /*! + \pre \p doc has_text() methods MUST return True. + */ + template <typename L> + mln_ch_value(L,bool) + text_blocks_image(const document<L>& doc, unsigned min_nlines); + + + # ifndef MLN_INCLUDE_ONLY + + template <typename L> + mln_ch_value(L,bool) + text_blocks_image(const document<L>& doc, unsigned min_nlines) + { + trace::entering("scribo::make::text_blocks_image"); + + mln_precondition(doc.is_open()); + + image2d<bool> output; + initialize(output, doc.image()); + data::fill(output, false); + + // image2d<value::int_u8> log; + // initialize(log, output); + // data::fill(log, 0); + + if (doc.has_text()) + { + const paragraph_set<L>& parset = doc.paragraphs(); + for_all_paragraphs(p, parset) + if (parset(p).nlines() >= min_nlines) + { + box2d last_box; + + // For each line in this paragraph. + for_all_elements(l, parset(p).line_ids()) + { + const line_info<L>& + line = parset.lines()(parset(p).line_ids()(l)); + + // Avoid invalid case: + // + // ======= + // ====== + if (last_box.is_valid() + && last_box.pmax().row() < line.bbox().pmin().row() + && last_box.pmin().col() < line.bbox().pmax().col()) + { + point2d + pmin(std::min(last_box.pmax().row(), + line.bbox().pmin().row()), + std::max(last_box.pmin().col(), + line.bbox().pmin().col())), + pmax(std::max(last_box.pmax().row(), + line.bbox().pmin().row()), + std::min(last_box.pmax().col(), + line.bbox().pmax().col())); + + box2d new_box(pmin, pmax); + mln::draw::box_plain(output, new_box, true); + // mln::draw::box_plain(log, new_box, 1); + + // mln::io::pgm::save(log, mln::debug::filename("log.pgm", i++)); + } + + mln::draw::box_plain(output, line.bbox(), true); + // mln::draw::box_plain(log, line.bbox(), 255); + // mln::io::pgm::save(log, mln::debug::filename("log.pgm", i++)); + last_box = line.bbox(); + } + } + } + + + trace::exiting("scribo::make::text_blocks_image"); + return output; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace scribo::make + +} // end of namespace scribo + + + +#endif // ! SCRIBO_MAKE_TEXT_BLOCKS_IMAGE_HH diff --git a/scribo/scribo/make/text_components_image.hh b/scribo/scribo/make/text_components_image.hh new file mode 100644 index 0000000..e7c892e --- /dev/null +++ b/scribo/scribo/make/text_components_image.hh @@ -0,0 +1,101 @@ +// 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_MAKE_TEXT_COMPONENTS_IMAGE_HH +# define SCRIBO_MAKE_TEXT_COMPONENTS_IMAGE_HH + +/// \file +/// +/// Create a binary image with text components only. + +#include <mln/pw/all.hh> +#include <mln/core/image/dmorph/image_if.hh> +#include <mln/util/array.hh> +#include <mln/data/fill.hh> + +#include <scribo/core/document.hh> +#include <scribo/core/line_set.hh> + + +namespace scribo +{ + + namespace make + { + using namespace mln; + + + /// \brief Create a binary image with text components only. + /*! + \pre \p doc has_text() methods MUST return True. + */ + template <typename L> + mln_ch_value(L,bool) + text_components_image(const document<L>& doc); + + +# ifndef MLN_INCLUDE_ONLY + + template <typename L> + mln_ch_value(L,bool) + text_components_image(const document<L>& doc) + { + trace::entering("scribo::make::text_components_image"); + + mln_precondition(doc.is_open()); + + mln_ch_value(L,bool) output; + initialize(output, doc.image()); + data::fill(output, false); + + if (doc.has_text()) + { + const scribo::line_set<L>& lines = doc.lines(); + for_all_lines(l, doc.lines()) + if (lines(l).is_textline()) + { + const util::array<component_id_t>& + comp_ids = lines(l).component_ids(); + const L& lbl = lines.components().labeled_image(); + for_all_elements(c, comp_ids) + data::fill((output | lines.components()(comp_ids(c)).bbox()).rw(), + ((doc.binary_image() | lines.components()(comp_ids(c)).bbox()) + | (pw::value(lbl) == comp_ids(c)))); + } + } + + trace::exiting("scribo::make::text_components_image"); + return output; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace scribo::make + +} // end of namespace scribo + + + +#endif // ! SCRIBO_MAKE_TEXT_COMPONENTS_IMAGE_HH diff --git a/scribo/scribo/primitive/extract/internal/union.hh b/scribo/scribo/primitive/extract/internal/union.hh new file mode 100644 index 0000000..509a7e4 --- /dev/null +++ b/scribo/scribo/primitive/extract/internal/union.hh @@ -0,0 +1,246 @@ +// 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. + +/// \file +/// +/// \brief Various utilities for image extraction +/// +/// \fixme To be cleanup + +#ifndef SCRIBO_PRIMITIVE_EXTRACT_INTERNAL_UNION_HH +# define SCRIBO_PRIMITIVE_EXTRACT_INTERNAL_UNION_HH + +# include <mln/core/image/image2d.hh> +# include <mln/border/fill.hh> + + +namespace scribo +{ + + namespace primitive + { + + namespace extract + { + + namespace internal + { + + using namespace mln; + + + unsigned find_root(image2d<unsigned>& parent, unsigned x); + + + void union_find(const image2d<bool>& input, bool lab, + image2d<unsigned>& parent, image2d<unsigned>& area, + unsigned& max_area); + + +# ifndef MLN_INCLUDE_ONLY + + inline + unsigned find_root(image2d<unsigned>& parent, unsigned x) + { + if (parent.element(x) == x) + return x; + return parent.element(x) = find_root(parent, parent.element(x)); + } + + + inline + void union_find(const image2d<bool>& input, + bool lab, + // output: + image2d<unsigned>& parent, + image2d<unsigned>& area, + unsigned& max_area) + { + const unsigned nrows = input.nrows(), ncols = input.ncols(); + + unsigned op, on, delta = input.delta_index(dpoint2d(1, 0)); + + data::fill(parent, 0); + max_area = 0; + + { + + // row == 0 and col == 0 + + op = input.index_of_point(point2d(0,0)); + if (input.element(op) == lab) + { + area.element(op) = 1; + parent.element(op) = op; + } + + + // row = 0 + + for (unsigned col = 1; col < ncols; ++col) + { + on = op; + ++op; + + if (input.element(op) != lab) + continue; + + if (input.element(on) == lab) + { + unsigned& par_p = parent.element(op); + par_p = find_root(parent, on); + ++area.element(par_p); + if (area.element(par_p) > max_area) + max_area = area.element(par_p); + } + else + { + area.element(op) = 1; + parent.element(op) = op; + } + + } + } + + + for (unsigned row = 1; row < nrows; ++row) + { + + { + // col == 0 + + op = input.index_of_point(point2d(row, 0)); + on = op - delta; + + if (input.element(op) == lab) + { + if (input.element(on) == lab) + { + unsigned& par_p = parent.element(op); + par_p = find_root(parent, on); + ++area.element(par_p); + if (area.element(par_p) > max_area) + max_area = area.element(par_p); + } + else + { + area.element(op) = 1; + parent.element(op) = op; + } + } + + } + + for (unsigned col = 1; col < ncols; ++col) + { + ++op; + ++on; + + if (input.element(op) != lab) + continue; + + bool merge_ = false; + + // up + + if (input.element(on) == lab) + { + unsigned& par_p = parent.element(op); + par_p = find_root(parent, on); + ++area.element(par_p); + if (area.element(par_p) > max_area) + max_area = area.element(par_p); + merge_ = true; + } + + + // left + + unsigned ol = op - 1; + + if (input.element(ol) == lab) + { + if (merge_) + { + if (input.element(on - 1) != lab) // not already merged + { + unsigned r_op = parent.element(op), r_ol = find_root(parent, ol); + if (r_op != r_ol) + { + // do-union + if (r_op < r_ol) + { + parent.element(r_ol) = r_op; + area.element(r_op) += area.element(r_ol); + if (area.element(r_op) > max_area) + max_area = area.element(r_op); + } + else + { + parent.element(r_op) = r_ol; + area.element(r_ol) += area.element(r_op); + if (area.element(r_ol) > max_area) + max_area = area.element(r_ol); + } + } + } + } // end of "if (merge) + else + { + unsigned& par_p = parent.element(op); + par_p = find_root(parent, ol); + ++area.element(par_p); + if (area.element(par_p) > max_area) + max_area = area.element(par_p); + merge_ = true; + } + } + + + // finalization + + if (merge_ == false) + { + parent.element(op) = op; + area.element(op) = 1; + } + + } + } + + } // end of 'union_find' + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace scribo::primivite::extract::internal + + } // end of namespace scribo::primitive::extract + + } // end of namespace scribo::primitive + +} // end of namespace scribo + + +#endif // ! SCRIBO_PRIMITIVE_EXTRACT_INTERNAL_UNION_HH diff --git a/scribo/scribo/primitive/extract/non_text.hh b/scribo/scribo/primitive/extract/non_text.hh index 8528782..a456270 100644 --- a/scribo/scribo/primitive/extract/non_text.hh +++ b/scribo/scribo/primitive/extract/non_text.hh @@ -1,4 +1,4 @@ -// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory +// Copyright (C) 2011 EPITA Research and Development Laboratory // (LRDE) // // This file is part of Olena. @@ -33,30 +33,19 @@ #ifndef SCRIBO_PRIMITIVE_EXTRACT_NON_TEXT_HH # define SCRIBO_PRIMITIVE_EXTRACT_NON_TEXT_HH -# include <mln/core/image/image2d.hh> -# include <mln/core/alias/neighb2d.hh> -# include <mln/data/fill.hh> -# include <mln/util/array.hh> -# include <mln/labeling/compute.hh> -# include <mln/labeling/relabel.hh> -# include <mln/accu/math/count.hh> -# include <mln/pw/all.hh> +# include <mln/morpho/elementary/dilation.hh> -# include <mln/draw/box_plain.hh> -# include <mln/value/label_8.hh> -# include <mln/value/rgb.hh> -# include <mln/value/rgb8.hh> +# include <scribo/make/text_components_image.hh> +# include <scribo/make/text_blocks_image.hh> -# include <scribo/core/macros.hh> -# include <scribo/core/component_set.hh> -# include <scribo/core/document.hh> -# include <scribo/core/line_set.hh> -# include <scribo/core/def/lbl_type.hh> -# include <scribo/filter/objects_small.hh> +# include <scribo/primitive/extract/internal/union.hh> +# include <scribo/debug/logger.hh> + +//DEBUG +#include <mln/util/timer.hh> +#include <mln/io/pbm/save.hh> -# include <mln/clustering/kmean_rgb.hh> -# include <mln/fun/v2v/rgb8_to_rgbn.hh> namespace scribo { @@ -69,10 +58,24 @@ namespace scribo using namespace mln; + /*! \brief Extract non text components. + + This method takes text localization into account and tries to + learn the background colors to deduce the relevant non text + components. + + \param[in] doc A document structure. Its must have paragraph + information. + + \param[in] nlines The number of lines needed in a paragraph to + consider the latter during the background color learning. + - template <typename L, typename I> + \return A component set of non text components. + */ + template <typename L> component_set<L> - non_text(const document<L>& doc, const Image<I>& input); + non_text(const document<L>& doc, unsigned nlines); # ifndef MLN_INCLUDE_ONLY @@ -82,133 +85,276 @@ namespace scribo { template <typename L> - struct order_bbox + image2d<bool> + learn(const document<L>& doc, + const image2d<bool>& txt, + const image2d<bool>& txtblocks, + unsigned nbits, + float p_cover) { - order_bbox(const scribo::component_set<L>& comps) - : comps_(comps) + const image2d<value::rgb8>& input = doc.image(); + const image2d<bool>& + seps = doc.paragraphs().lines().components().separators(); + + if (txt.border() != input.border() + || txtblocks.border() != input.border() + || seps.border() != input.border()) { + std::cerr << " txt.border() = " << txt.border() + << " - txtblocks.border() = " << txtblocks.border() + << " - input.border() = " << input.border() + << " - seps.border() = " << seps.border() + << std::endl; + std::cerr << "different sizes for borders! Resizing..." << std::endl; + + + border::resize(txt, border::thickness); + border::resize(input, border::thickness); + border::resize(txtblocks, border::thickness); + border::resize(seps, border::thickness); + // std::abort(); } - bool operator()(const unsigned& c1, const unsigned& c2) const + + const unsigned q_div = std::pow(2, 8 - nbits); + const unsigned q = unsigned(std::pow(2, nbits)); + const unsigned nelements = input.nelements(); + + + image3d<unsigned> h_bg(q, q, q); + data::fill(h_bg, 0); + + border::fill(txtblocks, false); // so h_bg is not updated by border pixels! + + unsigned n_bg = 0; { - if (comps_(c1).bbox().nsites() == comps_(c2).bbox().nsites()) - return c1 > c2; - return comps_(c1).bbox().nsites() > comps_(c2).bbox().nsites(); + // compute h_bg + for (unsigned i = 0; i < nelements; ++i) + if (txtblocks.element(i) == true) + { + ++n_bg; + const value::rgb8& c = input.element(i); + ++h_bg.at_(c.red() / q_div, c.green() / q_div, c.blue() / q_div); + } } - scribo::component_set<L> comps_; - }; + typedef std::map<unsigned, unsigned> map_t; + map_t ncells_with_nitems; + { + mln_piter_(box3d) c(h_bg.domain()); + for_all(c) + { + unsigned nitems_in_c = h_bg(c); + ++ncells_with_nitems[ nitems_in_c ]; + } + } - } // end of namespace scribo::primitive::extract::internal + unsigned n_items_min = 0; + { + map_t::const_reverse_iterator i; + unsigned N = 0; + for (i = ncells_with_nitems.rbegin(); i != ncells_with_nitems.rend(); ++i) + { + unsigned nitems = i->first, ncells = i->second; + N += nitems * ncells; + if (float(N) > p_cover * float(n_bg)) + { + n_items_min = nitems; + break; + } + } + } + if (n_items_min == 0) + n_items_min = 1; // safety - // FACADE + image3d<bool> bg(q, q, q); + { + mln_piter_(box3d) c(h_bg.domain()); + for_all(c) + bg(c) = (h_bg(c) >= n_items_min); + } - template <typename L, typename I> - component_set<L> - non_text(const document<L>& doc, const Image<I>& input_) - { - trace::entering("scribo::primitive::extract::non_text"); - const I& input = exact(input_); - mln_precondition(doc.is_valid()); - mln_precondition(input.is_valid()); + // outputing - const line_set<L>& lines = doc.lines(); + image2d<bool> output; + initialize(output, input); + { + for (unsigned i = 0; i < nelements; ++i) + if (txt.element(i) == true || seps.element(i) == true) + output.element(i) = false; + else + { + const value::rgb8& c = input.element(i); + output.element(i) = ! bg.at_(c.red() / q_div, c.green() / q_div, c.blue() / q_div); + } + } - // Element extraction + return output; + } - image2d<value::label_8> img_lbl8; + + + + + inline + image2d<bool> + cleaning(const image2d<bool>& input, unsigned lambda) { - image2d<bool> content; - initialize(content, input); - data::fill(content, true); + const box2d& dom = input.domain(); + + image2d<unsigned> area(dom); + image2d<unsigned> parent(dom); + image2d<bool> output(dom); + + unsigned max_area = 0; + + + // 1st pass = bg union-find + + { + union_find(input, false, // in + parent, area, max_area // out + ); + } + + + // echo + // std::cout << "max_area = " << max_area << std::endl; + + + // 2nd pass = bg biggest component selection + + { + const unsigned nelements = input.nelements(); + const bool* p_i = input.buffer(); + bool* p_o = output.buffer(); + const unsigned* p_a = area.buffer(); + const unsigned* p_par = parent.buffer(); + + for (unsigned i = 0; i < nelements; ++i) + { + if (*p_i == true) + *p_o = true; + else + { + if (*p_par == i) + *p_o = (*p_a != max_area); + else + *p_o = output.element(*p_par); + } + ++p_i; + ++p_o; + ++p_a; + ++p_par; + } + } + + + + // 3rd pass = fg union-find - for_all_lines(l, lines) - if (lines(l).type() == line::Text) - data::fill((content | lines(l).bbox()).rw(), false); + { + union_find(output, true, // in + parent, area, max_area // out + ); + } - typedef mln::value::rgb<5> t_rgb5; - typedef mln::fun::v2v::rgb8_to_rgbn<5> t_rgb8_to_rgb5; - image2d<t_rgb5> - img_rgb5 = mln::data::transform(doc.image(), t_rgb8_to_rgb5()); - img_lbl8 = - mln::clustering::kmean_rgb<double,5>((img_rgb5 | pw::value(content)), 3, 10, 10).unmorph_(); - data::fill((img_lbl8 | !pw::value(content)).rw(), 0u); + // 4th pass = cleaning fg - mln::util::array<unsigned> - card = mln::labeling::compute(accu::math::count<value::label_8>(), - img_lbl8, img_lbl8, 3); + { + const unsigned nelements = input.nelements(); + bool* p_o = output.buffer(); + const unsigned* p_a = area.buffer(); + const unsigned* p_par = parent.buffer(); - unsigned max = 0, bg_id = 0; - for_all_ncomponents(c, 3) - if (card(c) > max) + for (unsigned i = 0; i < nelements; ++i) { - max = card(c); - bg_id = c; + if (*p_o == true) + { + if (*p_par == i) + *p_o = (*p_a > lambda); + else + *p_o = output.element(*p_par); + } + ++p_o; + ++p_a; + ++p_par; } + } + - mln::fun::i2v::array<bool> f(4, true); - f(0) = false; - f(bg_id) = false; - labeling::relabel_inplace(img_lbl8, 4, f); + return output; } + } // end of namespace scribo::primitive::extract::internal - component_set<L> output; - std::cout << "Removing small elements" << std::endl; - { - image2d<bool> elts; - initialize(elts, img_lbl8); - data::fill(elts, false); - data::fill((elts | (pw::value(img_lbl8) != pw::cst(0))).rw(), true); - scribo::def::lbl_type nlabels; - elts = filter::components_small(elts, c8(), nlabels, 40); + // FACADE + + template <typename L> + component_set<L> + non_text(const document<L>& doc, unsigned nlines) + { + trace::entering("scribo::primitive::extract::non_text"); + - output = primitive::extract::components(elts, c8(), nlabels); + util::timer t; + t.start(); + + mln_precondition(doc.is_valid()); + + mln_precondition(doc.has_line_seps()); + mln_precondition(doc.has_text()); + + // FIXME: Do these images exist elsewhere? + image2d<bool> + txt = make::text_components_image(doc), + txtblocks = make::text_blocks_image(doc, nlines); + + unsigned nbits = 5; + float p = 0.9998; // 0.80 <= x < 1.0 + unsigned lambda = 1000; + + // enlarge the text mask so that "not txt" does not include + // any text pixel + txt = morpho::elementary::dilation(txt, c8()); + txt = morpho::elementary::dilation(txt, c4()); + + // FIXME: Make it faster? + data::fill((txtblocks | pw::value(txt)).rw(), false); + + // Debug + { + debug::logger().log_image(debug::Special,//debug::AuxiliaryResults, + txt, "txt_components"); + debug::logger().log_image(debug::Special,//debug::AuxiliaryResults, + txtblocks, "txt_blocks"); } + image2d<bool> + element_image = internal::learn(doc, txt, txtblocks, nbits, p); + element_image = internal::cleaning(element_image, lambda); - std::cout << "Ignoring inner elements" << std::endl; + mln_value(L) ncomps; + component_set<L> + elements = primitive::extract::components(element_image, + c8(), ncomps); + // Debug { - // FIXME: We would like to use the convex hull instead of the bbox. - internal::order_bbox<L> func(output); - util::array<unsigned> box_ordered_comps; - for (unsigned i = 1; i < output.nelements(); ++i) - box_ordered_comps.append(i); - std::sort(box_ordered_comps.hook_std_vector_().begin(), - box_ordered_comps.hook_std_vector_().end(), func); - - image2d<bool> merged_elts; - initialize(merged_elts, img_lbl8); - data::fill(merged_elts, false); - for (unsigned i = 0; i < box_ordered_comps.nelements(); ++i) - { - unsigned c = box_ordered_comps(i); - point2d - pminright = output(c).bbox().pmin(), - pmaxleft = output(c).bbox().pmax(); - pminright.col() = output(c).bbox().pmax().col(); - pmaxleft.col() = output(c).bbox().pmin().col(); - - if (merged_elts(output(c).bbox().pmin()) - && merged_elts(output(c).bbox().pmax()) - && merged_elts(pminright) - && merged_elts(pmaxleft)) - output(c).update_tag(component::Ignored); - else - mln::draw::box_plain(merged_elts, output(c).bbox(), true); - } + debug::logger().log_image(debug::Results, + elements.labeled_image(), + "non_text_components"); } trace::exiting("scribo::primitive::extract::non_text"); - return output; + return elements; } # endif // ! MLN_INCLUDE_ONLY diff --git a/scribo/scribo/primitive/extract/non_text.hh b/scribo/scribo/primitive/extract/non_text_kmean.hh similarity index 91% copy from scribo/scribo/primitive/extract/non_text.hh copy to scribo/scribo/primitive/extract/non_text_kmean.hh index 8528782..c76ce11 100644 --- a/scribo/scribo/primitive/extract/non_text.hh +++ b/scribo/scribo/primitive/extract/non_text_kmean.hh @@ -30,8 +30,8 @@ /// /// \fixme To be optimized! -#ifndef SCRIBO_PRIMITIVE_EXTRACT_NON_TEXT_HH -# define SCRIBO_PRIMITIVE_EXTRACT_NON_TEXT_HH +#ifndef SCRIBO_PRIMITIVE_EXTRACT_NON_TEXT_KMEAN_HH +# define SCRIBO_PRIMITIVE_EXTRACT_NON_TEXT_KMEAN_HH # include <mln/core/image/image2d.hh> # include <mln/core/alias/neighb2d.hh> @@ -72,7 +72,7 @@ namespace scribo template <typename L, typename I> component_set<L> - non_text(const document<L>& doc, const Image<I>& input); + non_text_kmean(const document<L>& doc, const Image<I>& input); # ifndef MLN_INCLUDE_ONLY @@ -107,9 +107,9 @@ namespace scribo template <typename L, typename I> component_set<L> - non_text(const document<L>& doc, const Image<I>& input_) + non_text_kmean(const document<L>& doc, const Image<I>& input_) { - trace::entering("scribo::primitive::extract::non_text"); + trace::entering("scribo::primitive::extract::non_text_kmean"); const I& input = exact(input_); mln_precondition(doc.is_valid()); @@ -136,7 +136,8 @@ namespace scribo img_rgb5 = mln::data::transform(doc.image(), t_rgb8_to_rgb5()); img_lbl8 = - mln::clustering::kmean_rgb<double,5>((img_rgb5 | pw::value(content)), 3, 10, 10).unmorph_(); + mln::clustering::kmean_rgb<double,5>( + (img_rgb5 | pw::value(content)), 3, 10, 10).unmorph_(); data::fill((img_lbl8 | !pw::value(content)).rw(), 0u); mln::util::array<unsigned> @@ -207,7 +208,7 @@ namespace scribo } } - trace::exiting("scribo::primitive::extract::non_text"); + trace::exiting("scribo::primitive::extract::non_text_kmean"); return output; } @@ -220,4 +221,4 @@ namespace scribo } // end of namespace scribo -#endif // ! SCRIBO_PRIMITIVE_EXTRACT_NON_TEXT_HH +#endif // ! SCRIBO_PRIMITIVE_EXTRACT_NON_TEXT_KMEAN_HH -- 1.5.6.5
participants (1)
-
Guillaume Lazzara