
* white_space/white_spaces.cc: Move... * z/white_space/white_spaces.cc: ... Here. Improve speed. * z/white_spaces/hom_sep.cc, * z/white_space/white_space_closing.cc: New. Other approaches. --- scribo/sandbox/ChangeLog | 9 + scribo/sandbox/z/white_spaces/hom_sep.cc | 133 ++++++++++++ .../sandbox/z/white_spaces/white_space_closing.cc | 123 +++++++++++ .../sandbox/{ => z}/white_spaces/white_spaces.cc | 220 ++++++++++++-------- 4 files changed, 400 insertions(+), 85 deletions(-) create mode 100644 scribo/sandbox/ChangeLog create mode 100644 scribo/sandbox/z/white_spaces/hom_sep.cc create mode 100644 scribo/sandbox/z/white_spaces/white_space_closing.cc rename scribo/sandbox/{ => z}/white_spaces/white_spaces.cc (84%) diff --git a/scribo/sandbox/ChangeLog b/scribo/sandbox/ChangeLog new file mode 100644 index 0000000..f428dce --- /dev/null +++ b/scribo/sandbox/ChangeLog @@ -0,0 +1,9 @@ +2010-06-25 Guillaume Lazzara <z@lrde.epita.fr> + + Add algorithms to retrieve white spaces. + + * white_space/white_spaces.cc: Move... + * z/white_space/white_spaces.cc: ... Here. Improve speed. + + * z/white_spaces/hom_sep.cc, + * z/white_space/white_space_closing.cc: New. Other approaches. diff --git a/scribo/sandbox/z/white_spaces/hom_sep.cc b/scribo/sandbox/z/white_spaces/hom_sep.cc new file mode 100644 index 0000000..53e8c45 --- /dev/null +++ b/scribo/sandbox/z/white_spaces/hom_sep.cc @@ -0,0 +1,133 @@ +#include <mln/core/image/image2d.hh> +#include <mln/core/image/dmorph/image_if.hh> +#include <mln/pw/all.hh> + +#include <mln/draw/line.hh> + +#include <mln/data/wrap.hh> +#include <mln/data/fill.hh> +#include <mln/data/convert.hh> + + +#include <mln/labeling/colorize.hh> + +#include <mln/morpho/closing/structural.hh> +#include <mln/morpho/closing/area.hh> +#include <mln/morpho/opening/structural.hh> +#include <mln/win/rectangle2d.hh> +#include <mln/win/vline2d.hh> + +#include <mln/logical/not.hh> +#include <mln/io/pbm/all.hh> +#include <mln/io/pgm/all.hh> +#include <mln/io/ppm/save.hh> + +#include <mln/literal/colors.hh> + +#include <mln/value/label_16.hh> +#include <mln/value/int_u8.hh> +#include <mln/value/int_u12.hh> +#include <mln/value/int_u16.hh> +#include <mln/value/rgb8.hh> + +#include <mln/draw/box_plain.hh> + +#include <mln/transform/influence_zone_geodesic.hh> + +#include <mln/data/stretch.hh> + +#include <mln/util/timer.hh> + +#include <mln/norm/l1.hh> + +#include <scribo/core/object_groups.hh> +#include <scribo/core/component_set.hh> +#include <scribo/primitive/extract/components.hh> + +#include <scribo/primitive/extract/lines_h_pattern.hh> +#include <scribo/primitive/remove/separators.hh> +#include <scribo/primitive/group/from_single_link.hh> +#include <scribo/preprocessing/denoise_fg.hh> +#include <scribo/preprocessing/rotate_90.hh> + +#include <scribo/primitive/link/with_single_right_link_dmax_ratio.hh> +#include <scribo/primitive/link/with_single_right_link_dmax_ratio_aligned.hh> + +#include <scribo/filter/object_links_top_aligned.hh> +#include <scribo/filter/object_groups_small.hh> +#include <scribo/filter/object_links_bottom_aligned.hh> +#include <scribo/debug/save_linked_bboxes_image.hh> +#include <scribo/debug/decision_image.hh> + +int main(int argc, char *argv[]) +{ + using namespace scribo; + using namespace mln; + + image2d<bool> separators; + mln::io::pbm::load(separators, argv[1]); + + float val = atof(argv[2]); + + util::timer t; + + t.start(); + + // Hit or miss + { + unsigned length = 100; + + unsigned space = atoi(argv[3]); + + window2d win; + dpoint2d + dp1(-space, 0), + dp2( space, 0); + win.insert(dp1); + win.insert(dp2); + + + // Adjusting extension. + extension::adjust_fill(separators, length / 2, 0); + + accu::count_value<bool> accu(true); + typedef image2d<unsigned> I; + + I tmp = accu::transform_line(accu, separators, length, 1); + + image2d<bool> output; + initialize(output, separators); + + mln_piter_(I) p(separators.domain()); +// mln_qiter(window2d) q(win, p); + bool is_foreground; + for_all(p) + { + + if (tmp(p) > unsigned(0.95f * length) + 1) + { + output(p) = false; + continue; + } + + is_foreground = true; + + unsigned + top_count = tmp(p + dp1), + bot_count = tmp(p + dp2); + + if ((top_count >= unsigned(length * val) + 1 + && bot_count <= unsigned(length * 0.1) + 1) + || + (top_count <= unsigned(length * 0.1) + 1 + && bot_count >= unsigned(length * val) + 1)) + is_foreground = false; + + output(p) = is_foreground; + + } + + io::pbm::save(output, "separators_hom.pbm"); + } + +} diff --git a/scribo/sandbox/z/white_spaces/white_space_closing.cc b/scribo/sandbox/z/white_spaces/white_space_closing.cc new file mode 100644 index 0000000..6e645bd --- /dev/null +++ b/scribo/sandbox/z/white_spaces/white_space_closing.cc @@ -0,0 +1,123 @@ +#include <mln/core/image/image2d.hh> +#include <mln/core/image/dmorph/image_if.hh> +#include <mln/pw/all.hh> + +#include <mln/draw/line.hh> + +#include <mln/data/wrap.hh> +#include <mln/data/fill.hh> +#include <mln/data/paste.hh> +#include <mln/data/convert.hh> + +#include <mln/subsampling/antialiased.hh> + +#include <mln/labeling/colorize.hh> + +#include <mln/morpho/closing/structural.hh> +#include <mln/morpho/closing/area.hh> +#include <mln/morpho/opening/structural.hh> +#include <mln/win/rectangle2d.hh> +#include <mln/win/vline2d.hh> + +#include <mln/logical/not.hh> +#include <mln/io/pbm/all.hh> +#include <mln/io/pgm/all.hh> +#include <mln/io/ppm/save.hh> + +#include <mln/literal/colors.hh> + +#include <mln/value/label_16.hh> +#include <mln/value/int_u8.hh> +#include <mln/value/int_u12.hh> +#include <mln/value/int_u16.hh> +#include <mln/value/rgb8.hh> + +#include <mln/draw/box_plain.hh> + +#include <mln/transform/influence_zone_geodesic.hh> + +#include <mln/data/stretch.hh> + +#include <mln/util/timer.hh> + +#include <scribo/core/object_groups.hh> +#include <scribo/primitive/extract/components.hh> + +#include <scribo/primitive/extract/vertical_separators.hh> +#include <scribo/primitive/remove/separators.hh> +#include <scribo/primitive/group/from_single_link.hh> +#include <scribo/preprocessing/denoise_fg.hh> + +#include <scribo/primitive/link/with_single_right_link_dmax_ratio.hh> + +#include <scribo/filter/object_links_top_aligned.hh> +#include <scribo/filter/object_groups_small.hh> +#include <scribo/filter/object_links_bottom_aligned.hh> +#include <scribo/debug/save_linked_bboxes_image.hh> + + +namespace mln +{ + + void process(image2d<bool> input, unsigned scale, unsigned l) + { + win::hline2d vl(l); + image2d<bool> input_op_line = morpho::opening::structural(input, vl); + + if (scale == 1) + io::pbm::save(input_op_line, "input_op_line_1.pbm"); + if (scale == 2) + io::pbm::save(input_op_line, "input_op_line_2.pbm"); + if (scale == 3) + io::pbm::save(input_op_line, "input_op_line_3.pbm"); + + win::rectangle2d rect(11, 11); + image2d<bool> input_op = morpho::opening::structural(input_op_line, rect); + + if (scale == 1) + io::pbm::save(input_op, "input_op_rect_1.pbm"); + if (scale == 2) + io::pbm::save(input_op, "input_op_rect_2.pbm"); + if (scale == 3) + io::pbm::save(input_op, "input_op_rect_3.pbm"); + + + image2d<value::rgb8> output = data::convert(value::rgb8(), logical::not_(input)); + data::fill((output | pw::value(input_op)).rw(), literal::red); + + if (scale == 1) + io::ppm::save(output, "output_1.ppm"); + if (scale == 2) + io::ppm::save(output, "output_2.ppm"); + if (scale == 3) + io::ppm::save(output, "output_3.ppm"); + } + +} + +int main(int argc, char *argv[]) +{ + using namespace scribo; + using namespace mln; + + typedef image2d<bool> I; + I input; + mln::io::pbm::load(input, argv[1]); + + logical::not_inplace(input); + + unsigned l = atoi(argv[2]); + + process(input, 1, l); + + + typedef image2d<value::int_u8> J; + J input_pgm = data::convert(value::int_u8(), input); + + I input_x2 = data::convert(bool(), subsampling::antialiased(input_pgm, 2)); + process(input_x2, 2, l / 2); + + + I input_x4 = data::convert(bool(), subsampling::antialiased(input_pgm, 4)); + process(input_x4, 3, l / 4); +} diff --git a/scribo/sandbox/white_spaces/white_spaces.cc b/scribo/sandbox/z/white_spaces/white_spaces.cc similarity index 84% rename from scribo/sandbox/white_spaces/white_spaces.cc rename to scribo/sandbox/z/white_spaces/white_spaces.cc index 1026569..d832d58 100644 --- a/scribo/sandbox/white_spaces/white_spaces.cc +++ b/scribo/sandbox/z/white_spaces/white_spaces.cc @@ -72,6 +72,11 @@ namespace mln using namespace scribo; + + // Enable debug. + bool _debug_; + + template <typename L> void filter_bad_groups(object_groups<L>& top_groups, object_groups<L>& bot_groups) @@ -181,6 +186,11 @@ namespace mln ++p.col(); } + void compute_next_site_f_(unsigned& p) + { + ++p; + } + mln_site(L) start_point_(unsigned current_object, anchor::Type anchor) @@ -211,14 +221,10 @@ namespace mln dist = math::abs(p[this->direction_] - b.pmin()[this->direction_]); -// int ldist = std::max(this->components_(current_object).bbox().width() / 2, -// this->components_(this->labeled_image_(p)).bbox().width() / 2); - int ldist = this->components_(current_object).bbox().width(); // Components are really close, so the angle is more permissive. if (dist < 3 * ldist) -// if (dist < (ldist + 0.7 * ldist)) { return filter::internal::component_aligned_rad(this->components_, @@ -245,40 +251,13 @@ namespace mln { super_::validate_link_(current_object, start_point, p, anchor); - mln_site(L) - p1 = mln::my_anchors(this->components_, current_object, anchor), - p2 = mln::my_anchors(this->components_, this->labeled_image_(p), - anchor); - 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; - draw::line(debug_angle_, p1, p2, value::rgb8(angle, angle, angle)); - } - - void invalidate_link_(unsigned current_object, - const P& start_point, - const P& p, - anchor::Type anchor) - { - super_::invalidate_link_(current_object, start_point, p, anchor); - - if (this->labeled_image_.domain().has(p) && this->labeled_image_(p) != 0) + if (_debug_) { mln_site(L) p1 = mln::my_anchors(this->components_, current_object, anchor), p2 = mln::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) - { - draw::line(debug_, p1, p2, literal::red); - } + draw::line(debug_, p1, p2, literal::green); float @@ -292,6 +271,39 @@ namespace mln } } + void invalidate_link_(unsigned current_object, + const P& start_point, + const P& p, + anchor::Type anchor) + { + 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 = mln::my_anchors(this->components_, current_object, anchor), + p2 = mln::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) + { + 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; + draw::line(debug_angle_, p1, p2, value::rgb8(angle, angle, angle)); + } + } + } + float min_alpha_rad; float max_alpha_rad; @@ -329,6 +341,11 @@ namespace mln ++p.col(); } + void compute_next_site_f_(unsigned& p) + { + ++p; + } + }; @@ -358,6 +375,12 @@ namespace mln --p.col(); } + void compute_next_site_f_(unsigned& p) + { + --p; + } + + }; } @@ -374,7 +397,7 @@ int main(int argc, char *argv[]) return 1; }; - bool debug = (argc == 7); + _debug_ = (argc == 7); util::timer t; util::timer gt; @@ -399,7 +422,7 @@ int main(int argc, char *argv[]) t_ = t; std::cout << "closing_structural - " << t_ << std::endl; - if (debug) + if (_debug_) { // Restore input orientation. input = scribo::preprocessing::rotate_90(input, false); @@ -427,7 +450,7 @@ int main(int argc, char *argv[]) t_ = t; std::cout << "extract::components - " << t_ << std::endl; - if (debug) + if (_debug_) io::pgm::save(data::convert(value::int_u8(), components.labeled_image()), "lbl.pgm"); @@ -447,12 +470,12 @@ int main(int argc, char *argv[]) // Right mln::single_right_dmax_ratio_aligned_functor<L> functor(input_clo, components, dmax, min_angle, max_angle, anchor::Top); - top_right = primitive::link::compute(functor, anchor::Top); + top_right = primitive::link::impl::compute_fastest(functor, anchor::Top); t.stop(); - if (debug) + if (_debug_) { io::ppm::save(functor.debug_, "right_top.ppm"); io::ppm::save(functor.debug_angle_, "right_top_angle.ppm"); @@ -468,7 +491,7 @@ int main(int argc, char *argv[]) t.stop(); - if (debug) + if (_debug_) { io::ppm::save(lfunctor.debug_, "left_top.ppm"); io::ppm::save(lfunctor.debug_angle_, "left_top_angle.ppm"); @@ -491,7 +514,7 @@ int main(int argc, char *argv[]) bot_right = primitive::link::compute(functor, anchor::Bottom); t.stop(); - if (debug) + if (_debug_) { io::ppm::save(functor.debug_, "right_bot.ppm"); io::ppm::save(functor.debug_angle_, "right_bot_angle.ppm"); @@ -505,13 +528,13 @@ int main(int argc, char *argv[]) bot_left = primitive::link::compute(lfunctor, anchor::Bottom); t.stop(); - if (debug) + if (_debug_) { io::ppm::save(lfunctor.debug_, "left_bot.ppm"); io::ppm::save(lfunctor.debug_angle_, "left_bot_angle.ppm"); } - if (debug) + if (_debug_) { image2d<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); @@ -555,7 +578,7 @@ int main(int argc, char *argv[]) - if (debug) + if (_debug_) { image2d<value::rgb8> @@ -628,7 +651,7 @@ int main(int argc, char *argv[]) image2d<value::rgb8> both; - if (debug) + if (_debug_) both = data::convert(value::rgb8(), input); @@ -640,7 +663,7 @@ int main(int argc, char *argv[]) { if (top_accu(d).is_valid()) { - if (debug) + if (_debug_) mln::draw::line(both, top_accu(d).to_result().pmin(), point2d(top_accu(d).to_result().pmin().row(), @@ -654,7 +677,7 @@ int main(int argc, char *argv[]) true); } else - if (debug && btop_accu(d).is_valid()) + 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(), @@ -666,7 +689,7 @@ int main(int argc, char *argv[]) { if (bot_accu(d).is_valid()) { - if (debug) + if (_debug_) mln::draw::line(both, point2d(bot_accu(d).to_result().pmax().row(), bot_accu(d).to_result().pmin().col()), @@ -680,7 +703,7 @@ int main(int argc, char *argv[]) true); } else - if (debug && bbot_accu(d).is_valid()) + 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()), @@ -693,7 +716,7 @@ int main(int argc, char *argv[]) std::cout << "Drawing output image - " << t_ << std::endl; - if (debug) + if (_debug_) { io::ppm::save(both, argv[5]); io::pbm::save(separators, "separators.pbm"); @@ -702,17 +725,13 @@ int main(int argc, char *argv[]) // Hit or miss { - t.restart(); - image2d<bool> input_with_seps = duplicate(input_clo); - data::paste(separators | pw::value(separators), input_with_seps); - t.stop(); - - t_ = t; - std::cout << "input with seps - " << t_ << std::endl; - + if (_debug_) + { + image2d<bool> input_with_seps = duplicate(input_clo); + data::paste(separators | pw::value(separators), input_with_seps); - if (debug) io::pbm::save(input_with_seps, "input_with_seps.pbm"); + } t.restart(); unsigned length = 25; @@ -722,45 +741,63 @@ int main(int argc, char *argv[]) dp2( 21, 0); // Adjusting extension. - extension::adjust_fill(separators, length / 2, 0); + t.restart(); + extension::adjust_fill(input_clo, length / 2, 0); accu::count_value<bool> accu(true); typedef image2d<unsigned> I; - I tmp = accu::transform_line(accu, input_with_seps, length, 1); + I tmp = accu::transform_line(accu, input_clo, length, 1); + t_ = t; + std::cout << "* accu::transform_line - " << t_ << std::endl; - if (debug) + if (_debug_) io::pgm::save(data::convert(value::int_u8(), tmp), "tmp.pgm"); - image2d<bool> output; - initialize(output, separators); - data::fill(output, false); + t.restart(); value::int_u8 nlabels; image2d<value::int_u8> - sep_lbl = labeling::blobs(separators, c8(), nlabels); + sep_lbl = labeling::value(separators, true, c8(), nlabels); + t_ = t; + std::cout << "* labeling seps - " << t_ << std::endl; - mln_piter_(I) p(separators.domain()); - util::array<unsigned> lcard(unsigned(nlabels) + 1, 0); - util::array<unsigned> lfalse(unsigned(nlabels) + 1, 0); + t.restart(); +// util::array<unsigned> lcard(unsigned(nlabels) + 1, 0); +// util::array<unsigned> lfalse(unsigned(nlabels) + 1, 0); util::array<bool> relbl(unsigned(nlabels) + 1, true); relbl(0) = false; - for_all(p) + +// unsigned +// tmp_next_line_dp1 = tmp.delta_index(dp1), +// tmp_next_line_dp2 = tmp.delta_index(dp2); + +// const mln_value(I)* val_sep = &separators(separators.domain().pmin()); +// const value::int_u8* val_lbl = &sep_lbl(sep_lbl.domain().pmin()); + +// bool go_next = false; + unsigned invalid_ratio = unsigned(length * 0.30f); + +// for (unsigned row = 0; i < nrows; ++row) +// { +// for (unsigned col = 0; col < ncols; ++col) +// { + +// } + +// val_sep += ; +// val_lbl += ; +// } + + mln_piter_(I) p(separators.domain()); + for_all(p) if (separators(p)) { unsigned lbl = sep_lbl(p); - ++lcard(lbl); - -// Useless since we already work on selected lines (separators image). -// -// if (tmp(p) > unsigned(0.95f * length) + 1) -// { -// output(p) = false; -// continue; -// } +// ++lcard(lbl); unsigned top_count = tmp(p + dp1), @@ -768,19 +805,32 @@ int main(int argc, char *argv[]) // This site is wrapped between two lines of text so we don't // want it. - if (top_count >= unsigned(length * 0.30f) + 1 - && bot_count >= unsigned(length * 0.30f) + 1) - ++lfalse(lbl); + if (top_count >= invalid_ratio + 1 + && bot_count >= invalid_ratio + 1) + { + relbl(lbl) = false; +// go_next = true; + } +// ++lfalse(lbl); } - for_all_comps(i, relbl) - relbl(i) = (lfalse(i) / (float) lcard(i)) < 0.02f; +// for_all_comps(i, relbl) +// relbl(i) = (lfalse(i) / (float) lcard(i)) < 0.02f; + t_ = t; + std::cout << "* reading data - " << t_ << std::endl; + t.restart(); labeling::relabel_inplace(sep_lbl, nlabels, relbl); - data::paste(sep_lbl | (pw::value(sep_lbl) != pw::cst(0)), output); + t_ = t; + std::cout << "* relabel_inplace - " << t_ << std::endl; + + image2d<bool> output = data::convert(bool(), sep_lbl); - if (debug) + if (_debug_) + { io::pbm::save(output, "separators_hom.pbm"); + io::pbm::save(separators, "separators_filtered.pbm"); + } } t_ = t; -- 1.5.6.5