
* scribo/core/tag/anchor.hh: Add new anchors. * scribo/filter/internal/alignment_angle.hh, * scribo/primitive/link/internal/compute_anchor.hh: Support new anchors. * scribo/primitive/extract/separators_nonvisible.hh: Remove dead code and comment debug code. * scribo/toolchain/internal/content_in_doc_functor.hh: Detect horizontal whitespace. --- scribo/ChangeLog | 16 + scribo/scribo/core/tag/anchor.hh | 5 +- scribo/scribo/filter/internal/alignment_angle.hh | 144 +++-- .../primitive/extract/separators_nonvisible.hh | 673 +++++++++----------- .../primitive/link/internal/compute_anchor.hh | 26 +- .../toolchain/internal/content_in_doc_functor.hh | 13 +- 6 files changed, 447 insertions(+), 430 deletions(-) diff --git a/scribo/ChangeLog b/scribo/ChangeLog index f03eb97..001e134 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,5 +1,21 @@ 2011-02-17 Guillaume Lazzara <z@lrde.epita.fr> + Improve and cleanup whitespace separator detection. + + * scribo/core/tag/anchor.hh: Add new anchors. + + * scribo/filter/internal/alignment_angle.hh, + * scribo/primitive/link/internal/compute_anchor.hh: Support new + anchors. + + * scribo/primitive/extract/separators_nonvisible.hh: Remove dead + code and comment debug code. + + * scribo/toolchain/internal/content_in_doc_functor.hh: Detect + horizontal whitespace. + +2011-02-17 Guillaume Lazzara <z@lrde.epita.fr> + Add new conversion routines from string to tag. * scribo/core/tag/component.hh, diff --git a/scribo/scribo/core/tag/anchor.hh b/scribo/scribo/core/tag/anchor.hh index 262a32d..bb6780c 100644 --- a/scribo/scribo/core/tag/anchor.hh +++ b/scribo/scribo/core/tag/anchor.hh @@ -1,4 +1,5 @@ -// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2009, 2011 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -43,9 +44,11 @@ namespace scribo ActualRight, Right, TopLeft, + TopStrictLeft, TopRight, BottomLeft, BottomRight, + BottomStrictRight, Invalid }; diff --git a/scribo/scribo/filter/internal/alignment_angle.hh b/scribo/scribo/filter/internal/alignment_angle.hh index 5b88012..33855a8 100644 --- a/scribo/scribo/filter/internal/alignment_angle.hh +++ b/scribo/scribo/filter/internal/alignment_angle.hh @@ -1,4 +1,4 @@ -// Copyright (C) 2010 EPITA Research and Development Laboratory +// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory // (LRDE) // // This file is part of Olena. @@ -73,76 +73,98 @@ namespace scribo unsigned current_object, unsigned nbh_object, anchor::Type anchor) { - trace::entering("scribo::filter::internal::alignment_angle_rad"); + trace::entering("scribo::filter::internal::alignment_angle"); mln_precondition(comps.is_valid()); - float dr, dc; + float dr, dc, result = 0; if (nbh_object == current_object) return 0; - // Center - if (anchor == anchor::Center) + switch(anchor) { - dr = math::abs(comps(current_object).bbox().pcenter().row() - - comps(nbh_object).bbox().pcenter().row()); - dc = math::abs(comps(current_object).bbox().pcenter().col() - - comps(nbh_object).bbox().pcenter().col()); - - return std::atan(dr / dc); - } - - // Top - else if (anchor == anchor::Top) - { - dr = math::abs(comps(current_object).bbox().pmin().row() - - comps(nbh_object).bbox().pmin().row()); - dc = math::abs(comps(current_object).bbox().pcenter().col() - - comps(nbh_object).bbox().pcenter().col()); - - return std::atan(dr / dc); + // Center + case anchor::Center: + { + dr = math::abs(comps(current_object).bbox().pcenter().row() + - comps(nbh_object).bbox().pcenter().row()); + dc = math::abs(comps(current_object).bbox().pcenter().col() + - comps(nbh_object).bbox().pcenter().col()); + + result = std::atan(dr / dc); + } + break; + + // Mass Center + case anchor::MassCenter: + { + dr = math::abs(comps(current_object).mass_center().row() + - comps(nbh_object).mass_center().row()); + dc = math::abs(comps(current_object).mass_center().col() + - comps(nbh_object).mass_center().col()); + + result = std::atan(dr / dc); + } + break; + + // Top + case anchor::TopStrictLeft: + case anchor::Top: + { + dr = math::abs(comps(current_object).bbox().pmin().row() + - comps(nbh_object).bbox().pmin().row()); + dc = math::abs(comps(current_object).bbox().pcenter().col() + - comps(nbh_object).bbox().pcenter().col()); + + result = std::atan(dr / dc); + } + break; + + // Bottom + case anchor::BottomStrictRight: + case anchor::Bottom: + { + dr = math::abs(comps(current_object).bbox().pmax().row() + - comps(nbh_object).bbox().pmax().row()); + dc = math::abs(comps(current_object).bbox().pcenter().col() + - comps(nbh_object).bbox().pcenter().col()); + + result = std::atan(dr / dc); + } + break; + + // Left + case anchor::Left: + { + dr = math::abs(comps(current_object).bbox().pcenter().row() + - comps(nbh_object).bbox().pcenter().row()); + dc = math::abs(comps(current_object).bbox().pmin().col() + - comps(nbh_object).bbox().pmin().col()); + + result = std::atan(dc / dr); + } + break; + + // Right + case anchor::Right: + { + dr = math::abs(comps(current_object).bbox().pcenter().row() + - comps(nbh_object).bbox().pcenter().row()); + dc = math::abs(comps(current_object).bbox().pmax().col() + - comps(nbh_object).bbox().pmax().col()); + + result = std::atan(dc / dr); + } + break; + + default: + trace::warning("scribo::filter::internal::alignment_angle," + " Invalid anchor value... Aborting computation."); } - // Bottom - else if (anchor == anchor::Bottom) - { - dr = math::abs(comps(current_object).bbox().pmax().row() - - comps(nbh_object).bbox().pmax().row()); - dc = math::abs(comps(current_object).bbox().pcenter().col() - - comps(nbh_object).bbox().pcenter().col()); - - return std::atan(dr / dc); - } - - // Left - else if (anchor == anchor::Left) - { - dr = math::abs(comps(current_object).bbox().pcenter().row() - - comps(nbh_object).bbox().pcenter().row()); - dc = math::abs(comps(current_object).bbox().pmin().col() - - comps(nbh_object).bbox().pmin().col()); - - return std::atan(dc / dr); - } - - // Right - else if (anchor == anchor::Right) - { - dr = math::abs(comps(current_object).bbox().pcenter().row() - - comps(nbh_object).bbox().pcenter().row()); - dc = math::abs(comps(current_object).bbox().pmax().col() - - comps(nbh_object).bbox().pmax().col()); - - return std::atan(dc / dr); - } - - else - trace::warning("Invalid anchor value... Aborting computation."); - - trace::exiting("scribo::filter::internal::alignment_angle_rad"); - return 0; - + trace::exiting("scribo::filter::internal::alignment_angle"); + return result; } # endif // ! MLN_INCLUDE_ONLY diff --git a/scribo/scribo/primitive/extract/separators_nonvisible.hh b/scribo/scribo/primitive/extract/separators_nonvisible.hh index 81ebd64..4e31650 100644 --- a/scribo/scribo/primitive/extract/separators_nonvisible.hh +++ b/scribo/scribo/primitive/extract/separators_nonvisible.hh @@ -86,6 +86,8 @@ #include <scribo/preprocessing/denoise_fg.hh> #include <scribo/preprocessing/rotate_90.hh> +#include <scribo/primitive/link/internal/compute_anchor.hh> + #include <scribo/primitive/link/internal/dmax_default.hh> #include <scribo/primitive/link/with_single_right_link_dmax_ratio.hh> @@ -128,80 +130,6 @@ namespace scribo namespace internal { - template <typename L> - void filter_bad_groups(object_groups<L>& top_groups, - object_groups<L>& bot_groups) - { - const component_set<L>& comps = top_groups.components(); - const L& lbl = comps.labeled_image(); - - for_all_groups(c, top_groups) - { - box2d b = comps(c).bbox(); - b.enlarge(0, comps(c).bbox().height()); - b.crop_wrt(lbl.domain()); - - typedef mln_value(L) V; - - const V* top_ptr = & lbl(b.pmin()); - const V* bot_ptr = & lbl(point2d(b.pmax().row(), b.pmin().col())); - - unsigned ntop = 0, nbot = 0; - for (unsigned n = 0; n < b.width(); ++n) - { - if (*top_ptr) - ++ntop; - if (*bot_ptr) - ++nbot; - } - - if (ntop / b.width() > 0.50f) - top_groups(c) = c; - - if (nbot / b.width() > 0.50f) - bot_groups(c) = c; - } - - } - - - template <typename L> - mln_site(L) - my_anchors(const component_set<L>& comps, - unsigned current_object, - anchor::Type anchor) - { - mln_site(L) sp;// = comps(current_object).bbox().pcenter(); - - unsigned h = comps(current_object).bbox().height(); - - switch (anchor) - { - default: - return sp; - - - // Bounding box top center - case anchor::Top: // FIXME: rename as TopLeft - sp.col() = comps(current_object).bbox().pmin().col(); - sp.row() = comps(current_object).bbox().pmin().row() - + math::min(2u, (h + 1) / 2 - 1); - break; - - - // Bounding box bottom center - case anchor::Bottom: // FIXME: rename as BottomLeft - sp.col() = comps(current_object).bbox().pmax().col(); - sp.row() = comps(current_object).bbox().pmax().row() - - math::min(2u, (h + 1) / 2 - 1); - break; - } - - return sp; - } - - - using namespace primitive::link::internal; template <typename L, typename E> @@ -225,12 +153,17 @@ namespace scribo anchor::Horizontal, dmax_default(dmax)), anchor(anchor_), - debug_(data::convert(value::rgb8(), input)), - debug_angle_(data::convert(value::rgb8(), input)), _debug_(debug) { + (void) input; // FIXME : remove this argument min_alpha_rad = (min_angle / 180.0f) * math::pi; max_alpha_rad = (max_angle / 180.0f) * math::pi; + + // if (_debug_) + // { + // debug_ = data::convert(value::rgb8(), input); + // debug_angle_ = data::convert(value::rgb8(), input); + // } } void compute_next_site_(P& p) @@ -247,7 +180,8 @@ namespace scribo mln_site(L) start_point_(unsigned current_object, anchor::Type anchor) { - return my_anchors(this->components_, current_object, anchor); + return link::internal::compute_anchor(this->components_, + current_object, anchor); } @@ -303,27 +237,29 @@ namespace scribo { super_::validate_link_(current_object, start_point, p, anchor); - if (_debug_) - { - mln_site(L) - p1 = my_anchors(this->components_, current_object, anchor), - p2 = my_anchors(this->components_, this->labeled_image_(p), - anchor); - mln::draw::line(debug_, p1, p2, literal::green); - - - float - angle = filter::internal::alignment_angle(this->components_, - current_object, - this->labeled_image_(p), - anchor); - angle = (angle * 180.0f) / math::pi; - angle = angle * 20.0f + 1.0f; - mln::draw::line(debug_angle_, p1, p2, - value::rgb8(unsigned(angle), - unsigned(angle), - unsigned(angle))); - } + // if (_debug_) + // { + // mln_site(L) + // p1 = link::internal::compute_anchor(this->components_, + // current_object, anchor), + // p2 = link::internal::compute_anchor(this->components_, + // this->labeled_image_(p), + // anchor); + // mln::draw::line(debug_, p1, p2, literal::green); + + + // float + // angle = filter::internal::alignment_angle(this->components_, + // current_object, + // this->labeled_image_(p), + // anchor); + // angle = (angle * 180.0f) / math::pi; + // angle = angle * 20.0f + 1.0f; + // mln::draw::line(debug_angle_, p1, p2, + // value::rgb8(unsigned(angle), + // unsigned(angle), + // unsigned(angle))); + // } } void invalidate_link_(unsigned current_object, @@ -333,33 +269,36 @@ namespace scribo { super_::invalidate_link_(current_object, start_point, p, anchor); - if (_debug_) - { - if (this->labeled_image_.domain().has(p) && this->labeled_image_(p) != 0) - { - mln_site(L) - p1 = my_anchors(this->components_, current_object, anchor), - p2 = my_anchors(this->components_, this->labeled_image_(p), - anchor); - if (this->labeled_image_.domain().has(p2) && norm::l1_distance(p1.to_vec(), p2.to_vec()) < 300) - { - mln::draw::line(debug_, p1, p2, literal::red); - } - - - float - angle = filter::internal::alignment_angle(this->components_, - current_object, - this->labeled_image_(p), - anchor); - angle = (angle * 180.0f) / math::pi; - angle = angle * 20.0f + 1.0f; - mln::draw::line(debug_angle_, p1, p2, - value::rgb8(unsigned(angle), - unsigned(angle), - unsigned(angle))); - } - } + // if (_debug_) + // { + // if (this->labeled_image_.domain().has(p) && this->labeled_image_(p) != 0) + // { + // mln_site(L) + // p1 = link::internal::compute_anchor(this->components_, + // current_object, anchor), + // p2 = link::internal::compute_anchor(this->components_, + // this->labeled_image_(p), + // anchor); + // if (this->labeled_image_.domain().has(p2) + // && norm::l1_distance(p1.to_vec(), p2.to_vec()) < 300) + // { + // mln::draw::line(debug_, p1, p2, literal::red); + // } + + + // float + // angle = filter::internal::alignment_angle(this->components_, + // current_object, + // this->labeled_image_(p), + // anchor); + // angle = (angle * 180.0f) / math::pi; + // angle = angle * 20.0f + 1.0f; + // mln::draw::line(debug_angle_, p1, p2, + // value::rgb8(unsigned(angle), + // unsigned(angle), + // unsigned(angle))); + // } + // } } @@ -368,8 +307,8 @@ namespace scribo anchor::Type anchor; - mln_ch_value(L, value::rgb8) debug_; - mln_ch_value(L, value::rgb8) debug_angle_; + // mln_ch_value(L, value::rgb8) debug_; + // mln_ch_value(L, value::rgb8) debug_angle_; bool _debug_; }; @@ -392,7 +331,8 @@ namespace scribo float max_angle, anchor::Type anchor, bool debug) - : super_(input, components, dmax, min_angle, max_angle, anchor, debug) + : super_(input, components, dmax, min_angle, + max_angle, anchor, debug) { } @@ -427,7 +367,8 @@ namespace scribo float max_angle, anchor::Type anchor, bool debug) - : super_(input, components, dmax, min_angle, max_angle, anchor, debug) + : super_(input, components, dmax, min_angle, + max_angle, anchor, debug) { } @@ -455,6 +396,8 @@ namespace scribo mln_concrete(I) separators_nonvisible(const Image<I>& in_) { + trace::entering("scribo::primitive::extract::separators_nonvisible"); + const I& in = exact(in_); mln_precondition(in.is_valid()); typedef mln_value(I) Vi; @@ -469,42 +412,35 @@ namespace scribo util::timer t; util::timer gt; - // Load (OK) - t.start(); - float t_ = t; - std::cout << "Image loaded - " << t_ << std::endl; - gt.start(); - // Remove horizontal lines. - t.restart(); + // // Remove horizontal lines. + // t.restart(); - mln_concrete(I) hlines = primitive::extract::lines_h_pattern(in, 50, 3); - mln_concrete(I) input = primitive::remove::separators(in, hlines); + // mln_concrete(I) hlines = primitive::extract::lines_h_pattern(in, 50, 3); + // mln_concrete(I) input = primitive::remove::separators(in, hlines); - t_ = t; - std::cout << "Horizontal lines removed - " << t_ << std::endl; + // t_ = t; + // std::cout << "Horizontal lines removed - " << t_ << std::endl; // Closing structural - Connect characters. - t.restart(); + t.start(); win::hline2d vl(17); - mln_concrete(I) input_clo = morpho::closing::structural(input, vl); + mln_concrete(I) input_clo = morpho::closing::structural(in, vl); -// input_clo = scribo::preprocessing::rotate_90(input_clo, true); - - t_ = t; + float t_ = t; std::cout << "closing_structural - " << t_ << std::endl; - if (_debug_) - { - // Restore input orientation. - input = scribo::preprocessing::rotate_90(input, false); + // if (_debug_) + // { + // // Restore input orientation. + // input = scribo::preprocessing::rotate_90(input, false); - io::pbm::save(input_clo, "input_clo.pbm"); - } + // io::pbm::save(input_clo, "input_clo.pbm"); + // } // Rotate (OK) t.restart(); @@ -526,9 +462,9 @@ namespace scribo t_ = t; std::cout << "extract::components - " << t_ << std::endl; - if (_debug_) - io::pgm::save(data::convert(value::int_u8(), components.labeled_image()), - "lbl.pgm"); + // if (_debug_) + // io::pgm::save(data::convert(value::int_u8(), components.labeled_image()), + // "lbl.pgm"); unsigned dmax = 5; @@ -543,39 +479,42 @@ namespace scribo { // Right internal::single_right_dmax_ratio_aligned_functor<L> - functor(input_clo, components, dmax, min_angle, max_angle, anchor::Top, _debug_); -// top_right = primitive::link::impl::compute_fastest(functor, anchor::Top); - top_right = primitive::link::compute(functor, anchor::Top); + functor(input_clo, components, dmax, min_angle, max_angle, + anchor::TopStrictLeft, _debug_); +// top_right = primitive::link::impl::compute_fastest(functor, anchor::TopStrictLeft); + top_right = primitive::link::compute(functor, anchor::TopStrictLeft); t.stop(); - if (_debug_) - { - io::ppm::save(functor.debug_, "right_top.ppm"); - io::ppm::save(functor.debug_angle_, "right_top_angle.ppm"); - } + // if (_debug_) + // { + // io::ppm::save(functor.debug_, "right_top.ppm"); + // io::ppm::save(functor.debug_angle_, "right_top_angle.ppm"); + // } t.resume(); // Left internal::single_left_dmax_ratio_aligned_functor<L> - lfunctor(input_clo, components, dmax, min_angle, max_angle, anchor::Top, _debug_); - top_left = primitive::link::compute(lfunctor, anchor::Top); + lfunctor(input_clo, components, dmax, min_angle, max_angle, + anchor::TopStrictLeft, _debug_); + top_left = primitive::link::compute(lfunctor, anchor::TopStrictLeft); t.stop(); - if (_debug_) - { - io::ppm::save(lfunctor.debug_, "left_top.ppm"); - io::ppm::save(lfunctor.debug_angle_, "left_top_angle.ppm"); + // if (_debug_) + // { + // io::ppm::save(lfunctor.debug_, "left_top.ppm"); + // io::ppm::save(lfunctor.debug_angle_, "left_top_angle.ppm"); - mln_ch_value(I, value::rgb8) output = duplicate(functor.debug_); - data::paste((lfunctor.debug_ | (pw::value(lfunctor.debug_) != pw::cst(literal::black))) | (pw::value(lfunctor.debug_) != pw::cst(literal::white)), output); + // mln_ch_value(I, value::rgb8) output = duplicate(functor.debug_); + // data::paste((lfunctor.debug_ | (pw::value(lfunctor.debug_) != pw::cst(literal::black))) + // | (pw::value(lfunctor.debug_) != pw::cst(literal::white)), output); - io::ppm::save(output, "left_right_top.ppm"); - } + // io::ppm::save(output, "left_right_top.ppm"); + // } t.resume(); } @@ -585,105 +524,53 @@ namespace scribo { // Right internal::single_right_dmax_ratio_aligned_functor<L> - functor(input_clo, components, dmax, min_angle, max_angle, anchor::Bottom, _debug_); - bot_right = primitive::link::compute(functor, anchor::Bottom); + functor(input_clo, components, dmax, min_angle, max_angle, + anchor::BottomStrictRight, _debug_); + bot_right = primitive::link::compute(functor, anchor::BottomStrictRight); t.stop(); - if (_debug_) - { - io::ppm::save(functor.debug_, "right_bot.ppm"); - io::ppm::save(functor.debug_angle_, "right_bot_angle.ppm"); - } + // if (_debug_) + // { + // io::ppm::save(functor.debug_, "right_bot.ppm"); + // io::ppm::save(functor.debug_angle_, "right_bot_angle.ppm"); + // } t.resume(); // Left internal::single_left_dmax_ratio_aligned_functor<L> - lfunctor(input_clo, components, dmax, min_angle, max_angle, anchor::Bottom, _debug_); - bot_left = primitive::link::compute(lfunctor, anchor::Bottom); + lfunctor(input_clo, components, dmax, min_angle, max_angle, + anchor::BottomStrictRight, _debug_); + bot_left = primitive::link::compute(lfunctor, anchor::BottomStrictRight); t.stop(); - if (_debug_) - { - io::ppm::save(lfunctor.debug_, "left_bot.ppm"); - io::ppm::save(lfunctor.debug_angle_, "left_bot_angle.ppm"); - } + // if (_debug_) + // { + // io::ppm::save(lfunctor.debug_, "left_bot.ppm"); + // io::ppm::save(lfunctor.debug_angle_, "left_bot_angle.ppm"); - if (_debug_) - { - mln_ch_value(I, value::rgb8) output = duplicate(functor.debug_); - data::paste((lfunctor.debug_ | (pw::value(lfunctor.debug_) != pw::cst(literal::black))) | (pw::value(lfunctor.debug_) != pw::cst(literal::white)), output); + // mln_ch_value(I, value::rgb8) output = duplicate(functor.debug_); + // data::paste((lfunctor.debug_ | (pw::value(lfunctor.debug_) != pw::cst(literal::black))) + // | (pw::value(lfunctor.debug_) != pw::cst(literal::white)), output); - io::ppm::save(output, "left_right_bot.ppm"); - } + // io::ppm::save(output, "left_right_bot.ppm"); + // } } t_ = t; std::cout << "links - " << t_ << std::endl; - + // Merge links and build CC groups t.restart(); - std::cout << "group - top" << std::endl; object_groups<L> top_groups = primitive::group::from_double_link_any(top_left, top_right); - std::cout << "group - bot" << std::endl; object_groups<L> bot_groups = primitive::group::from_double_link_any(bot_left, bot_right); t_ = t; std::cout << "group - " << t_ << std::endl; - t.restart(); - util::array<accu::shape::bbox<point2d> > - btop_accu(top_groups.nelements()), - bbot_accu(bot_groups.nelements()); - - - for_all_groups(c, top_groups) - { - btop_accu(top_groups(c)).take(components(c).bbox()); - bbot_accu(bot_groups(c)).take(components(c).bbox()); - } - t_ = t; - std::cout << "groups to group bboxes - " << t_ << std::endl; - - - - if (_debug_) - { - - mln_ch_value(I, value::rgb8) - wo_filtering = data::convert(value::rgb8(), input); - - for_all_comp_data(d, btop_accu) - { - if (btop_accu(d).is_valid()) - { - mln::draw::line(wo_filtering, - btop_accu(d).to_result().pmin(), - point2d(btop_accu(d).to_result().pmin().row(), - btop_accu(d).to_result().pmax().col()), - literal::green); - - } - } - - for_all_comp_data(d, bbot_accu) - { - if (bbot_accu(d).is_valid()) - { - mln::draw::line(wo_filtering, - point2d(bbot_accu(d).to_result().pmax().row(), - bbot_accu(d).to_result().pmin().col()), - bbot_accu(d).to_result().pmax(), - literal::green); - } - - } - io::ppm::save(wo_filtering, "wo_filtering.ppm"); - } - - + // Filter CC groups t.restart(); top_groups = filter::object_groups_small(top_groups, min_card); bot_groups = filter::object_groups_small(bot_groups, min_card); @@ -691,7 +578,7 @@ namespace scribo std::cout << "small groups - " << t_ << std::endl; - + // Compute group bboxes t.restart(); util::array<accu::shape::bbox<point2d> > top_accu(top_groups.nelements()), @@ -708,78 +595,35 @@ namespace scribo - - - - - t.restart(); mln_concrete(I) separators; initialize(separators, input_clo); + + // FIXME: any way to fill border AND data at the same time? data::fill(separators, false); + extension::fill(separators, false); + t_ = t; std::cout << "Initialize separators image - " << t_ << std::endl; - mln_ch_value(I, value::rgb8) both; - - if (_debug_) - both = data::convert(value::rgb8(), input); - - - t.restart(); for_all_comp_data(d, top_accu) { - if (top_accu(d).is_valid() || btop_accu(d).is_valid()) + if (top_accu(d).is_valid()) { - if (top_accu(d).is_valid()) - { - if (_debug_) - mln::draw::line(both, - top_accu(d).to_result().pmin(), - point2d(top_accu(d).to_result().pmin().row(), - top_accu(d).to_result().pmax().col()), - literal::green); - - mln::draw::line(separators, - top_accu(d).to_result().pmin(), - point2d(top_accu(d).to_result().pmin().row(), - top_accu(d).to_result().pmax().col()), - true); - } - else - if (_debug_ && btop_accu(d).is_valid()) - mln::draw::line(both, - btop_accu(d).to_result().pmin(), - point2d(btop_accu(d).to_result().pmin().row(), - btop_accu(d).to_result().pmax().col()), - literal::yellow); - + mln::draw::line(separators, + top_accu(d).to_result().pmin(), + point2d(top_accu(d).to_result().pmin().row(), + top_accu(d).to_result().pmax().col()), + true); } - if (bot_accu(d).is_valid() || bbot_accu(d).is_valid()) + if (bot_accu(d).is_valid()) { - if (bot_accu(d).is_valid()) - { - if (_debug_) - mln::draw::line(both, - point2d(bot_accu(d).to_result().pmax().row(), - bot_accu(d).to_result().pmin().col()), - bot_accu(d).to_result().pmax(), - literal::green); - - mln::draw::line(separators, - point2d(bot_accu(d).to_result().pmax().row(), - bot_accu(d).to_result().pmin().col()), - bot_accu(d).to_result().pmax(), - true); - } - else - if (_debug_ && bbot_accu(d).is_valid()) - mln::draw::line(both, - point2d(bbot_accu(d).to_result().pmax().row(), - bbot_accu(d).to_result().pmin().col()), - bbot_accu(d).to_result().pmax(), - literal::yellow); + mln::draw::line(separators, + point2d(bot_accu(d).to_result().pmax().row(), + bot_accu(d).to_result().pmin().col()), + bot_accu(d).to_result().pmax(), + true); } } @@ -787,22 +631,112 @@ namespace scribo std::cout << "Drawing output image - " << t_ << std::endl; - if (_debug_) - { - io::ppm::save(both, "both.ppm"); - io::pbm::save(separators, "separators.pbm"); - } + // if (_debug_) + // { + // // Restore input orientation. + // mln_concrete(I) input = scribo::preprocessing::rotate_90(in, false); + + + // // Debug group bboxes (includes all bboxes before filtering) + // util::array<accu::shape::bbox<point2d> > + // btop_accu(top_groups.nelements()), + // bbot_accu(bot_groups.nelements()); + + + // for_all_groups(c, top_groups) + // { + // btop_accu(top_groups(c)).take(components(c).bbox()); + // bbot_accu(bot_groups(c)).take(components(c).bbox()); + // } + + // mln_ch_value(I, value::rgb8) + // wo_filtering = data::convert(value::rgb8(), input); + + // for_all_comp_data(d, btop_accu) + // { + // if (btop_accu(d).is_valid()) + // { + // mln::draw::line(wo_filtering, + // btop_accu(d).to_result().pmin(), + // point2d(btop_accu(d).to_result().pmin().row(), + // btop_accu(d).to_result().pmax().col()), + // literal::green); + + // } + // } + + // for_all_comp_data(d, bbot_accu) + // { + // if (bbot_accu(d).is_valid()) + // { + // mln::draw::line(wo_filtering, + // point2d(bbot_accu(d).to_result().pmax().row(), + // bbot_accu(d).to_result().pmin().col()), + // bbot_accu(d).to_result().pmax(), + // literal::green); + // } + + // } + // io::ppm::save(wo_filtering, "wo_filtering.ppm"); + + // mln_ch_value(I, value::rgb8) both = data::convert(value::rgb8(), input); + + // for_all_comp_data(d, top_accu) + // { + // if (top_accu(d).is_valid() || btop_accu(d).is_valid()) + // { + // if (top_accu(d).is_valid()) + // { + // mln::draw::line(both, + // top_accu(d).to_result().pmin(), + // point2d(top_accu(d).to_result().pmin().row(), + // top_accu(d).to_result().pmax().col()), + // literal::green); + // } + // else + // if (btop_accu(d).is_valid()) + // mln::draw::line(both, + // btop_accu(d).to_result().pmin(), + // point2d(btop_accu(d).to_result().pmin().row(), + // btop_accu(d).to_result().pmax().col()), + // literal::yellow); + + // } + // if (bot_accu(d).is_valid() || bbot_accu(d).is_valid()) + // { + // if (bot_accu(d).is_valid()) + // { + // mln::draw::line(both, + // point2d(bot_accu(d).to_result().pmax().row(), + // bot_accu(d).to_result().pmin().col()), + // bot_accu(d).to_result().pmax(), + // literal::green); + // } + // else + // if (bbot_accu(d).is_valid()) + // mln::draw::line(both, + // point2d(bbot_accu(d).to_result().pmax().row(), + // bbot_accu(d).to_result().pmin().col()), + // bbot_accu(d).to_result().pmax(), + // literal::yellow); + // } + + // } + + // io::ppm::save(both, "both.ppm"); + // io::pbm::save(separators, "separators.pbm"); + // } // Hit or miss { - if (_debug_) - { - mln_concrete(I) input_with_seps = duplicate(input_clo); - data::paste(separators | pw::value(separators), input_with_seps); + // if (_debug_) + // { + // mln_concrete(I) input_with_seps = duplicate(input_clo); + // data::paste(separators | pw::value(separators), input_with_seps); - io::pbm::save(input_with_seps, "input_with_seps.pbm"); - } + // io::pbm::save(input_with_seps, "input_with_seps.pbm"); + // } t.restart(); unsigned length = 25; @@ -819,11 +753,12 @@ namespace scribo typedef mln_ch_value(I,unsigned) J; J tmp = accu::transform_line(accu, input_clo, length, 1); + t_ = t; std::cout << "* accu::transform_line - " << t_ << std::endl; - if (_debug_) - io::pgm::save(data::convert(value::int_u8(), tmp), "tmp.pgm"); + // if (_debug_) + // io::pgm::save(data::convert(value::int_u8(), tmp), "tmp.pgm"); t.restart(); @@ -841,25 +776,53 @@ namespace scribo unsigned invalid_ratio = unsigned(length * 0.30f); - mln_piter(I) p(separators.domain()); - for_all(p) - if (separators(p)) - { - unsigned lbl = sep_lbl(p); + extension::adjust_fill(tmp, 21, 0); + + value::int_u8 *sep_lbl_ptr = sep_lbl.buffer() + sep_lbl.index_of_point(sep_lbl.domain().pmin()); + bool *separators_ptr = separators.buffer() + separators.index_of_point(separators.domain().pmin()); + unsigned *tmp_ptr = tmp.buffer() + tmp.index_of_point(tmp.domain().pmin());; + int idx1 = tmp.delta_index(dp1); + int idx2 = tmp.delta_index(dp2); + + unsigned nrows = separators.nrows(); + unsigned ncols = separators.ncols(); - unsigned - top_count = tmp(p + dp1), - bot_count = tmp(p + dp2); + unsigned row_idx_sep_lbl = sep_lbl.delta_index(dpoint2d(+1, - ncols)); + unsigned row_idx_separators = separators.delta_index(dpoint2d(+1, - ncols)); + unsigned row_idx_tmp = tmp.delta_index(dpoint2d(+1, - ncols)); - // This site is wrapped between two lines of text so we don't - // want it. - if (top_count >= invalid_ratio + 1 - && bot_count >= invalid_ratio + 1) + for (unsigned row = 0; row < nrows; ++row) + { + for (unsigned col = 0; col < ncols; ++col) + { + if (*separators_ptr) { - relbl(lbl) = false; + unsigned lbl = *sep_lbl_ptr; + + unsigned + top_count = *(tmp_ptr + idx1), + bot_count = *(tmp_ptr + idx2); + + // This site is wrapped between two lines of text so we don't + // want it. + if (top_count >= invalid_ratio + 1 + && bot_count >= invalid_ratio + 1) + { + relbl(lbl) = false; + } } + + ++tmp_ptr; + ++sep_lbl_ptr; + ++separators_ptr; } + tmp_ptr += row_idx_tmp; + sep_lbl_ptr += row_idx_sep_lbl; + separators_ptr += row_idx_separators; + } + + t_ = t; std::cout << "* reading data - " << t_ << std::endl; @@ -870,37 +833,35 @@ namespace scribo mln_concrete(I) output = data::convert(bool(), sep_lbl); - if (_debug_) - { - io::pbm::save(output, "separators_hom.pbm"); - io::pbm::save(separators, "separators_filtered.pbm"); - } + // if (_debug_) + // { + // io::pbm::save(output, "separators_hom.pbm"); + // io::pbm::save(separators, "separators_filtered.pbm"); - t.restart(); - value::int_u16 ncomps; - component_set<L> comps = primitive::extract::components(output, c8(), ncomps); - mln_ch_value(I, value::rgb8) both; + // // value::int_u16 ncomps; + // // component_set<L> comps = primitive::extract::components(output, c8(), ncomps); + // // mln_ch_value(I, value::rgb8) both; - both = data::convert(value::rgb8(), input); + // // both = data::convert(value::rgb8(), input); - // Needed since the rotated image origin is (0,0). Rotation does - // not preserve rotated coordinates. - dpoint2d dp(input.domain().pcenter() - input_clo.domain().pcenter()); + // // // Needed since the rotated image origin is (0,0). + // // dpoint2d dp(input.domain().pcenter() - input_clo.domain().pcenter()); + + // // for_all_comps(c, comps) + // // { + // // box2d b = geom::rotate(comps(c).bbox(), -90, input_clo.domain().pcenter()); + // // mln::draw::line(both, + // // b.pmin() + dp, + // // b.pmax() + dp, + // // literal::green); + // // } + // } - for_all_comps(c, comps) - { - box2d b = geom::rotate(comps(c).bbox(), -90, input_clo.domain().pcenter()); - mln::draw::line(both, - b.pmin() + dp, - b.pmax() + dp, - literal::green); - } - t_ = t; - std::cout << "Output image - " << t_ << std::endl; gt.stop(); t_ = gt; - std::cout << "Total time: " << t_ << std::endl; + std::cout << "Non visible separators: " << t_ << std::endl; + trace::exiting("scribo::primitive::extract::separators_nonvisible"); return scribo::preprocessing::rotate_90(output, true); } } diff --git a/scribo/scribo/primitive/link/internal/compute_anchor.hh b/scribo/scribo/primitive/link/internal/compute_anchor.hh index 1c52b91..c1a9106 100644 --- a/scribo/scribo/primitive/link/internal/compute_anchor.hh +++ b/scribo/scribo/primitive/link/internal/compute_anchor.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. // @@ -88,10 +88,8 @@ namespace scribo { typedef mln_site(L) P; - unsigned h = components(current_object).bbox().pmax().row() - - components(current_object).bbox().pmin().row(); - unsigned w = components(current_object).bbox().pmax().col() - - components(current_object).bbox().pmin().col(); + unsigned h = components(current_object).bbox().height(); + unsigned w = components(current_object).bbox().width(); mln_site(L) sp = components(current_object).bbox().pcenter(); @@ -113,6 +111,22 @@ namespace scribo break; + // Bounding box top left + case anchor::TopStrictLeft: + sp.col() = components(current_object).bbox().pmin().col(); + sp.row() = components(current_object).bbox().pmin().row() + + math::min(2u, (h + 1) / 2 - 1); + break; + + + // Bounding box bottom right + case anchor::BottomStrictRight: + sp.col() = components(current_object).bbox().pmax().col(); + sp.row() = components(current_object).bbox().pmax().row() + - math::min(2u, (h + 1) / 2 - 1); + break; + + // Bounding box bottom center case anchor::Bottom: if (h < 30) diff --git a/scribo/scribo/toolchain/internal/content_in_doc_functor.hh b/scribo/scribo/toolchain/internal/content_in_doc_functor.hh index ed691e8..48098ba 100644 --- a/scribo/scribo/toolchain/internal/content_in_doc_functor.hh +++ b/scribo/scribo/toolchain/internal/content_in_doc_functor.hh @@ -34,11 +34,11 @@ # include <scribo/core/line_set.hh> # include <scribo/core/paragraph_set.hh> -# include <scribo/primitive/extract/elements.hh> +# include <scribo/primitive/extract/non_text.hh> # include <scribo/primitive/extract/components.hh> -# include <scribo/primitive/extract/vertical_separators.hh> +//# include <scribo/primitive/extract/vertical_separators.hh> +# include <scribo/primitive/extract/separators.hh> # include <scribo/primitive/extract/separators_nonvisible.hh> -# include <scribo/primitive/extract/elements.hh> # include <scribo/primitive/identify.hh> @@ -168,16 +168,17 @@ namespace scribo input_cleaned = exact(processed_image); if (enable_line_seps) { - on_new_progress_label("Find vertical separators..."); + on_new_progress_label("Find vertical and horizontal separators..."); - // Vertical separators - separators = primitive::extract::vertical_separators(processed_image, 81); + // Vertical and horizontal separators + separators = primitive::extract::separators(processed_image, 81); on_progress(); on_new_progress_label("Remove separators..."); input_cleaned = primitive::remove::separators(processed_image, separators); + doc.set_line_separators(separators); on_progress(); } -- 1.5.6.5