last-svn-commit-62-g04e5e93 Update examples.

* src/text_in_photo_ppm_fast.cc, * src/debug/show_links_bottom_aligned.cc, * src/debug/show_links_top_aligned.cc: Update calls to routines. * src/preprocessing/trash.cc, * src/text_in_photo_ppm_fast_2.cc, * src/preprocessing/split_bg_fg_ms.cc, * src/preprocessing/denoising.cc: Removed. * src/preprocessing/denoise.cc, * src/preprocessing/homogeneous_contrast.ccm, * src/preprocessing/subsample.cc: New. * src/preprocessing/Makefile.am: Add new files as target. * src/preprocessing/split_bg_fg.cc: Fix usage. * src/text_in_article.cc: Update processing chain. --- scribo/ChangeLog | 23 + scribo/src/debug/show_links_bottom_aligned.cc | 24 +- scribo/src/debug/show_links_top_aligned.cc | 22 +- scribo/src/preprocessing/Makefile.am | 13 +- .../denoise.cc} | 31 +- scribo/src/preprocessing/denoising.cc | 115 ----- scribo/src/preprocessing/homogeneous_contrast.cc | 44 ++ scribo/src/preprocessing/split_bg_fg.cc | 7 +- scribo/src/preprocessing/split_bg_fg_ms.cc | 109 ---- .../subsample.cc} | 34 +- scribo/src/text_in_article.cc | 289 +++-------- scribo/src/text_in_photo_ppm_fast.cc | 55 +- scribo/src/text_in_photo_ppm_fast_2.cc | 541 -------------------- 13 files changed, 242 insertions(+), 1065 deletions(-) copy scribo/src/{filter/objects_with_holes.cc => preprocessing/denoise.cc} (70%) delete mode 100644 scribo/src/preprocessing/denoising.cc create mode 100644 scribo/src/preprocessing/homogeneous_contrast.cc delete mode 100644 scribo/src/preprocessing/split_bg_fg_ms.cc copy scribo/src/{text/pbm_recognition.cc => preprocessing/subsample.cc} (74%) delete mode 100644 scribo/src/text_in_photo_ppm_fast_2.cc diff --git a/scribo/ChangeLog b/scribo/ChangeLog index f5deefc..87985ff 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,5 +1,28 @@ 2010-03-11 Guillaume Lazzara <z@lrde.epita.fr> + Update examples. + + * src/text_in_photo_ppm_fast.cc, + * src/debug/show_links_bottom_aligned.cc, + * src/debug/show_links_top_aligned.cc: Update calls to routines. + + * src/preprocessing/trash.cc, + * src/text_in_photo_ppm_fast_2.cc, + * src/preprocessing/split_bg_fg_ms.cc, + * src/preprocessing/denoising.cc: Removed. + + * src/preprocessing/denoise.cc, + * src/preprocessing/homogeneous_contrast.ccm, + * src/preprocessing/subsample.cc: New. + + * src/preprocessing/Makefile.am: Add new files as target. + + * src/preprocessing/split_bg_fg.cc: Fix usage. + + * src/text_in_article.cc: Update processing chain. + +2010-03-11 Guillaume Lazzara <z@lrde.epita.fr> + Improve text line merging algorithm. * text/merging.hh: Change merge rules and improve integration with diff --git a/scribo/src/debug/show_links_bottom_aligned.cc b/scribo/src/debug/show_links_bottom_aligned.cc index 4751308..337032a 100644 --- a/scribo/src/debug/show_links_bottom_aligned.cc +++ b/scribo/src/debug/show_links_bottom_aligned.cc @@ -37,7 +37,9 @@ #include <mln/io/pbm/load.hh> #include <mln/io/ppm/save.hh> -#include <scribo/primitive/extract/objects.hh> +#include <scribo/core/component_set.hh> + +#include <scribo/primitive/extract/components.hh> #include <scribo/primitive/link/with_single_right_link_bottom.hh> #include <scribo/filter/object_links_bottom_aligned.hh> @@ -49,6 +51,7 @@ const char *args_desc[][2] = { { "input.pbm", "A binary image. True for objects and False for the background." }, + { "max_dist", "Maximum distance lookup (common value 45)" }, { "max_alpha", "Max angle between two object bottoms. (common value : 5)" }, {0, 0} }; @@ -60,37 +63,38 @@ int main(int argc, char* argv[]) using namespace scribo::primitive::internal; using namespace mln; - if (argc != 4) + if (argc != 5) return scribo::debug::usage(argv, "Show valid or invalid links according the horizontal alignment (based on bottom line).", - "input.pbm max_alpha output.ppm", + "input.pbm max_dist max_alpha output.ppm", args_desc, "A color image. Valid links are drawn in green, invalid ones in red."); image2d<bool> input; io::pbm::load(input, argv[1]); - // Finding objects. + // Finding components. value::label_16 nbboxes; typedef image2d<value::label_16> L; - object_image(L) objects - = scribo::primitive::extract::objects(input, c8(), nbboxes); + component_set<L> components + = scribo::primitive::extract::components(input, c8(), nbboxes); // Finding right links. object_links<L> right_links - = primitive::link::with_single_right_link_bottom(objects); + = primitive::link::with_single_right_link_bottom(components, atoi(argv[2])); // Filtering. object_links<L> filtered_links - = filter::object_links_bottom_aligned(objects, right_links, atof(argv[2])); + = filter::object_links_bottom_aligned(right_links, atof(argv[3])); // Debug image. image2d<value::rgb8> decision_image = scribo::debug::alignment_decision_image(input, right_links, filtered_links, - scribo::debug::bottom); - io::ppm::save(decision_image, argv[3]); + scribo::debug::bottom, + atoi(argv[2])); + io::ppm::save(decision_image, argv[4]); } diff --git a/scribo/src/debug/show_links_top_aligned.cc b/scribo/src/debug/show_links_top_aligned.cc index 97b4a3b..ff01221 100644 --- a/scribo/src/debug/show_links_top_aligned.cc +++ b/scribo/src/debug/show_links_top_aligned.cc @@ -37,7 +37,7 @@ #include <mln/io/pbm/load.hh> #include <mln/io/ppm/save.hh> -#include <scribo/primitive/extract/objects.hh> +#include <scribo/primitive/extract/components.hh> #include <scribo/primitive/link/with_single_right_link_top.hh> #include <scribo/filter/object_links_top_aligned.hh> @@ -49,6 +49,7 @@ const char *args_desc[][2] = { { "input.pbm", "A binary image. True for objects and False for the background." }, + { "max_dist", "Maximum distance lookup (common value 45)" }, { "max_alpha", "Max angle between two object tops. (common value : 5)" }, {0, 0} }; @@ -60,30 +61,30 @@ int main(int argc, char* argv[]) using namespace scribo::primitive::internal; using namespace mln; - if (argc != 4) + if (argc != 5) return scribo::debug::usage(argv, "Show valid or invalid links according the horizontal alignment (based on top line).", - "input.pbm max_alpha output.ppm", + "input.pbm max_dist max_alpha output.ppm", args_desc, "A color image. Valid links are drawn in green, invalid ones in red."); image2d<bool> input; io::pbm::load(input, argv[1]); - // Finding objects. + // Finding components. value::label_16 nbboxes; typedef image2d<value::label_16> L; - object_image(L) objects - = scribo::primitive::extract::objects(input, c8(), nbboxes); + component_set<L> components + = scribo::primitive::extract::components(input, c8(), nbboxes); // Finding right links. object_links<L> right_links - = primitive::link::with_single_right_link_top(objects); + = primitive::link::with_single_right_link_top(components, atoi(argv[2])); // Filtering. object_links<L> filtered_links - = filter::object_links_top_aligned(objects, right_links, atof(argv[2])); + = filter::object_links_top_aligned(right_links, atof(argv[3])); // Debug image. @@ -91,7 +92,8 @@ int main(int argc, char* argv[]) = scribo::debug::alignment_decision_image(input, right_links, filtered_links, - scribo::debug::top); - io::ppm::save(decision_image, argv[3]); + scribo::debug::top, + atoi(argv[2])); + io::ppm::save(decision_image, argv[4]); } diff --git a/scribo/src/preprocessing/Makefile.am b/scribo/src/preprocessing/Makefile.am index 2422d87..501233a 100644 --- a/scribo/src/preprocessing/Makefile.am +++ b/scribo/src/preprocessing/Makefile.am @@ -1,4 +1,5 @@ -# Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE). +# Copyright (C) 2009, 2010 EPITA Research and Development Laboratory +# (LRDE). # # This file is part of Olena. # @@ -20,14 +21,16 @@ include $(top_srcdir)/scribo/scribo.mk bin_PROGRAMS = \ - denoising \ + denoise \ + homogeneous_contrast \ preprocess \ split_bg_fg \ - split_bg_fg_ms \ + subsample \ unskew -denoising_SOURCES = denoising.cc +denoise_SOURCES = denoise.cc +homogeneous_contrast_SOURCES = homogeneous_contrast.cc preprocess_SOURCES = preprocess.cc split_bg_fg_SOURCES = split_bg_fg.cc -split_bg_fg_ms_SOURCES = split_bg_fg_ms.cc +subsample_SOURCES = subsample.cc unskew_SOURCES = unskew.cc diff --git a/scribo/src/filter/objects_with_holes.cc b/scribo/src/preprocessing/denoise.cc similarity index 70% copy from scribo/src/filter/objects_with_holes.cc copy to scribo/src/preprocessing/denoise.cc index 0ebf89f..0eb567b 100644 --- a/scribo/src/filter/objects_with_holes.cc +++ b/scribo/src/preprocessing/denoise.cc @@ -1,4 +1,5 @@ -// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -24,30 +25,31 @@ // executable file might be covered by the GNU General Public License. #include <mln/core/image/image2d.hh> -#include <mln/core/alias/neighb2d.hh> -#include <mln/data/convert.hh> #include <mln/io/pbm/all.hh> -#include <mln/value/label_16.hh> -#include <scribo/filter/objects_with_holes.hh> #include <scribo/debug/usage.hh> +#include <scribo/preprocessing/denoise.hh> + + const char *args_desc[][2] = { { "input.pbm", "A binary image. 'True' for objects, 'False'\ for the background." }, - { "min_holes_count", "The minimum holes per objects." }, + { "fg_min_card", "The minimum neighbor count to be set to true." }, + { "bg_min_card", "The minimum neighbor count to be set to false." }, {0, 0} }; + int main(int argc, char *argv[]) { using namespace mln; - if (argc != 4) + if (argc != 5) return scribo::debug::usage(argv, - "Filter objects with holes", - "input.pbm min_holes_count output.pbm", + "Remove noise.", + "input.pbm fg_min_card bg_min_card output.pbm", args_desc, "A binary image."); @@ -57,14 +59,11 @@ int main(int argc, char *argv[]) I input; io::pbm::load(input, argv[1]); - value::label_16 nobjects; - typedef object_image(mln_ch_value_(I,value::label_16)) obj_ima_t; - obj_ima_t objects - = scribo::primitive::extract::objects(input, c8(), nobjects); + unsigned fg_min_card = atoi(argv[2]); + unsigned bg_min_card = atoi(argv[3]); - obj_ima_t filtered = scribo::filter::objects_with_holes(objects, atoi(argv[2])); - io::pbm::save(data::convert(bool(), filtered), argv[3]); + io::pbm::save(scribo::preprocessing::denoise(input, fg_min_card, bg_min_card), + argv[4]); trace::exiting("main"); - } diff --git a/scribo/src/preprocessing/denoising.cc b/scribo/src/preprocessing/denoising.cc deleted file mode 100644 index 769f75b..0000000 --- a/scribo/src/preprocessing/denoising.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2009 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. - -#include <mln/core/image/image2d.hh> -#include <mln/core/alias/neighb2d.hh> -#include <mln/data/convert.hh> -#include <mln/io/pbm/all.hh> -#include <mln/value/label.hh> -#include <mln/accu/math/count.hh> -#include <mln/labeling/relabel.hh> -#include <mln/labeling/compute.hh> -#include <mln/labeling/foreground.hh> - -#include <scribo/debug/usage.hh> - -const char *args_desc[][2] = -{ - { "input.pbm", "A binary image. 'True' for objects, 'False'\ -for the background." }, - { "nbh", "Select the neighborhood used for checking neighbors. '4' will use C4, '8' will use C8." }, - { "n_nbh", "The minimum neighbor count to be set to true." }, - {0, 0} -}; - -int main(int argc, char *argv[]) -{ - using namespace mln; - - if (argc != 5) - return scribo::debug::usage(argv, - "Remove noise.", - "input.pbm nbh min_nbh output.pbm", - args_desc, - "A binary image."); - - trace::entering("main"); - - typedef image2d<bool> I; - I input; - io::pbm::load(input, argv[1]); - - typedef value::label<30> V; - - neighb2d nbh; - if (atoi(argv[2]) == 4) - nbh = c4(); - else if (atoi(argv[2]) == 8) - nbh = c8(); - else - { - std::cout << "Error: nbh must be set to '4' or '8'!" << std::endl; - return 1; - } - - unsigned min_nbh = atoi(argv[3]); - - - V nlabels; - image2d<V> lbl = labeling::foreground(input, nbh, nlabels); - std::cout << nlabels << std::endl; - - - util::array<unsigned> result = labeling::compute(accu::meta::math::count(), lbl, nlabels); - - fun::i2v::array<bool> f(static_cast<unsigned>(nlabels) + 1, true); - for (unsigned i = 1; i <= nlabels; ++i) - if (result(i) < min_nbh) - f(i) = false; - - labeling::relabel_inplace(lbl, nlabels, f); - std::cout << nlabels << std::endl; - - -// mln_piter_(I) p(input.domain()); -// mln_niter_(neighb2d) n(nbh, p); -// unsigned n_nbh; -// for_all(p) -// if (input(p)) -// { -// n_nbh = 0; -// for_all(n) -// if (input(n)) -// ++n_nbh; - -// if (n_nbh < min_nbh) -// input(p) = false; -// } - - io::pbm::save(data::convert(bool(), lbl), argv[4]); - - trace::exiting("main"); - -} diff --git a/scribo/src/preprocessing/homogeneous_contrast.cc b/scribo/src/preprocessing/homogeneous_contrast.cc new file mode 100644 index 0000000..4930923 --- /dev/null +++ b/scribo/src/preprocessing/homogeneous_contrast.cc @@ -0,0 +1,44 @@ +#include <mln/value/int_u8.hh> +#include <mln/io/pgm/load.hh> +#include <mln/io/pgm/save.hh> + +#include <scribo/preprocessing/homogeneous_contrast.hh> +#include <scribo/debug/usage.hh> + +const char *args_desc[][2] = +{ + { "input.pgm", "A gray-level image." }, + { "h", "The height attribute value for the leveling closing." }, + {0, 0} +}; + + + +void usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " input.pgm h output.pgm" << std::endl; + abort(); +} + + + +int main(int argc, char* argv[]) +{ + using namespace mln; + using value::int_u8; + + if (argc != 4) + return scribo::debug::usage(argv, + "Remove noise.", + "input.pgm h output.pgm", + args_desc); + + + image2d<int_u8> input; + io::pgm::load(input, argv[1]); + + int h = std::atoi(argv[2]); + + io::pgm::save(scribo::preprocessing::homogeneous_contrast(input, h), + argv[3]); +} diff --git a/scribo/src/preprocessing/split_bg_fg.cc b/scribo/src/preprocessing/split_bg_fg.cc index 0d7ba8a..de7bd02 100644 --- a/scribo/src/preprocessing/split_bg_fg.cc +++ b/scribo/src/preprocessing/split_bg_fg.cc @@ -35,6 +35,7 @@ const char *args_desc[][2] = { "input.pbm", "A color image." }, { "lambda", "Lambda value. (FIX Description)" }, { "delta", "Delta value. (FIX Description)" }, + { "fg.ppm", "The foreground image (1st output)." }, { "bg.ppm", "The background image (2nd output)." }, {0, 0} }; @@ -49,7 +50,7 @@ int main(int argc, char *argv[]) if (argc != 6) return scribo::debug::usage(argv, "Split background and foreground.", - "input.pbm lambda delta bg.ppm fg.ppm", + "input.pbm lambda delta fg.ppm bg.ppm", args_desc, "The foreground image."); typedef image2d<value::rgb8> I; @@ -60,8 +61,8 @@ int main(int argc, char *argv[]) bg_fg = scribo::preprocessing::split_bg_fg(input, atoi(argv[2]), atoi(argv[3])); - io::ppm::save(bg_fg.first(), argv[4]); - io::ppm::save(bg_fg.second(), argv[5]); + io::ppm::save(bg_fg.first(), argv[5]); + io::ppm::save(bg_fg.second(), argv[4]); mln::trace::exiting("main"); } diff --git a/scribo/src/preprocessing/split_bg_fg_ms.cc b/scribo/src/preprocessing/split_bg_fg_ms.cc deleted file mode 100644 index 4c0180a..0000000 --- a/scribo/src/preprocessing/split_bg_fg_ms.cc +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (C) 2009 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. - -#include <mln/core/image/image2d.hh> -#include <mln/io/ppm/all.hh> - -#include <mln/debug/filename.hh> - -#include <mln/subsampling/subsampling.hh> - -#include <scribo/preprocessing/split_bg_fg.hh> -#include <scribo/debug/usage.hh> - - -const char *args_desc[][2] = -{ - { "input.pbm", "A color image." }, - { "lambda", "Lambda value. (FIX Description)" }, - { "delta", "Delta value. (FIX Description)" }, - { "lambda_sub2", "Lambda value. (FIX Description)" }, - { "delta_sub2", "Delta value. (FIX Description)" }, - { "lambda_sub4", "Lambda value. (FIX Description)" }, - { "delta_sub4", "Delta value. (FIX Description)" }, - {0, 0} -}; - - - -int main(int argc, char *argv[]) -{ - mln::trace::entering("main"); - using namespace mln; - dpoint2d none(0, 0); - - if (argc != 9) - return scribo::debug::usage(argv, - "Split background and foreground.", - "input.pbm lambda delta lambda_sub2 delta_sub2 lambda_sub3 delta_sub3 output_prefix", - args_desc, "The background and foreground images."); - - mln::debug::internal::filename_prefix = argv[8]; - - typedef image2d<value::rgb8> I; - I input; - io::ppm::load(input, argv[1]); - - util::couple<I,I> - bg_fg = scribo::preprocessing::split_bg_fg(input, - atoi(argv[2]), - atoi(argv[3])); - - io::ppm::save(bg_fg.first(), mln::debug::filename("out_bg.ppm")); - io::ppm::save(bg_fg.second(), mln::debug::filename("out_fg.ppm")); - - - { - // 1/2 - std::cout << "1/2" << std::endl; - I input_sub2x = mln::subsampling::subsampling(input, none, 2); - - util::couple<I,I> - bg_fg = scribo::preprocessing::split_bg_fg(input_sub2x, - atoi(argv[4]), - atoi(argv[5])); - - - io::ppm::save(bg_fg.first(), mln::debug::filename("out_bg_sub2x.ppm")); - io::ppm::save(bg_fg.second(), mln::debug::filename("out_fg_sub2x.ppm")); - } - - { - // 1/4 - std::cout << "1/4" << std::endl; - I input_sub4x = mln::subsampling::subsampling(input, none, 4); - - util::couple<I,I> - bg_fg = scribo::preprocessing::split_bg_fg(input_sub4x, - atoi(argv[6]), - atoi(argv[7])); - - - io::ppm::save(bg_fg.first(), mln::debug::filename("out_bg_sub4x.ppm")); - io::ppm::save(bg_fg.second(), mln::debug::filename("out_fg_sub4x.ppm")); - } - - mln::trace::exiting("main"); -} diff --git a/scribo/src/text/pbm_recognition.cc b/scribo/src/preprocessing/subsample.cc similarity index 74% copy from scribo/src/text/pbm_recognition.cc copy to scribo/src/preprocessing/subsample.cc index 70ceca1..388d4d9 100644 --- a/scribo/src/text/pbm_recognition.cc +++ b/scribo/src/preprocessing/subsample.cc @@ -23,43 +23,43 @@ // exception does not however invalidate any other reasons why the // executable file might be covered by the GNU General Public License. -#include <iostream> - #include <mln/core/image/image2d.hh> -#include <mln/io/pbm/load.hh> +#include <mln/core/alias/neighb2d.hh> +#include <mln/io/pgm/all.hh> + +#include <mln/subsampling/antialiased.hh> -#include <scribo/text/recognition.hh> +#include <mln/value/int_u8.hh> #include <scribo/debug/usage.hh> const char *args_desc[][2] = { - { "input.pbm", "A binary image. 'True' for objects, 'False'\ -for the background." }, + { "input.pgm", "A gray-scale image." }, + { "ratio", "Scale ratio." }, {0, 0} }; - -int main(int argc, char* argv[]) +int main(int argc, char *argv[]) { - using namespace scribo; using namespace mln; - if (argc != 2) + if (argc != 4) return scribo::debug::usage(argv, - "Text recognition", - "input.pbm", - args_desc, - "The text is printed on the standard output"); + "Subsample.", + "input.pgm ratio output.pgm", + args_desc); trace::entering("main"); - image2d<bool> input; - io::pbm::load(input, argv[1]); + typedef image2d<value::int_u8> I; + I input; + io::pgm::load(input, argv[1]); - scribo::text::recognition(input, "fra"); + unsigned ratio = atoi(argv[2]); + io::pgm::save(mln::subsampling::antialiased(input, ratio), argv[3]); trace::exiting("main"); } diff --git a/scribo/src/text_in_article.cc b/scribo/src/text_in_article.cc index 876eba5..2e6b1a6 100644 --- a/scribo/src/text_in_article.cc +++ b/scribo/src/text_in_article.cc @@ -36,64 +36,45 @@ #include <mln/io/ppm/save.hh> #include <mln/io/dump/save.hh> -#include <mln/math/min.hh> - #include <mln/literal/colors.hh> #include <mln/value/rgb8.hh> #include <mln/value/label_16.hh> -#include <mln/value/int_u16.hh> - -#include <mln/draw/box.hh> -#include <mln/draw/line.hh> - -#include <mln/data/convert.hh> - -#include <mln/extension/adjust.hh> - -#include <mln/accu/stat/median_h.hh> - -#include <mln/labeling/colorize.hh> -#include <mln/labeling/relabel.hh> -//#include <scribo/draw/bounding_boxes.hh> -#include <scribo/draw/bounding_box_links.hh> +#include <scribo/core/line_set.hh> #include <scribo/primitive/extract/components.hh> +#include <scribo/primitive/extract/vertical_separators.hh> + +#include <scribo/primitive/remove/separators.hh> #include <scribo/primitive/link/merge_double_link.hh> #include <scribo/primitive/link/with_single_left_link_dmax_ratio.hh> #include <scribo/primitive/link/with_single_right_link_dmax_ratio.hh> -#include <scribo/primitive/group/apply.hh> -// #include <scribo/primitive/group/from_double_link.hh> #include <scribo/primitive/group/from_single_link.hh> #include <scribo/filter/object_links_bbox_h_ratio.hh> -#include <scribo/filter/objects_small.hh> -// #include <scribo/filter/objects_thin.hh> -// #include <scribo/filter/objects_thick.hh> - -// #include <scribo/filter/object_groups_small.hh> - -// #include <scribo/debug/decision_image.hh> -// #include <scribo/debug/save_bboxes_image.hh> -// #include <scribo/debug/save_bboxes_image.hh> -// #include <scribo/debug/save_linked_bboxes_image.hh> - -#include <scribo/core/line_set.hh> -#include <scribo/io/xml/save_text_lines.hh> - #include <scribo/debug/usage.hh> +#include <scribo/debug/save_bboxes_image.hh> +#include <scribo/debug/bboxes_enlarged_image.hh> +#include <scribo/debug/mean_and_base_lines_image.hh> +#include <scribo/debug/looks_like_a_text_line_image.hh> #include <scribo/make/debug_filename.hh> -//#include <scribo/text/recognition.hh> +#include <scribo/text/recognition.hh> #include <scribo/text/merging.hh> +#include <scribo/preprocessing/denoise_fg.hh> + + +// #include <mln/morpho/closing/structural.hh> +// #include <mln/win/rectangle2d.hh> + const char *args_desc[][2] = { @@ -128,82 +109,60 @@ int main(int argc, char* argv[]) typedef value::label_16 V; typedef image2d<V> L; + + // Add whitespace separators. +// win::rectangle2d win = win::rectangle2d(151, 41); +// image2d<bool> whitespaces = morpho::closing::structural(input, win); +// logical::not_inplace(whitespaces); + + // Remove separators + std::cout << "Find vertical separators..." << std::endl; + image2d<bool> separators = primitive::extract::vertical_separators(input, 81); + + std::cout << "Remove separators..." << std::endl; + image2d<bool> input_cleaned = primitive::remove::separators(input, + separators); + +// whitespaces += separators; + + mln::io::pbm::save(separators, "vseparators.pbm"); +// mln::io::pbm::save(whitespaces, "separators.pbm"); + +// mln::io::pbm::save(input_cleaned, "input_no_separators.pbm"); + + // Denoise + std::cout << "Denoise..." << std::endl; + input_cleaned = preprocessing::denoise_fg(input_cleaned, c8(), 3); + +// mln::io::pbm::save(input_cleaned, "input_denoised.pbm"); + /// Finding components. std::cout << "Finding components..." << std::endl; V ncomponents; component_set<L> - components = scribo::primitive::extract::components(input, - c8(), + components = scribo::primitive::extract::components(input_cleaned, c8(), ncomponents); - /// First filtering. - std::cout << "Filtering components..." << std::endl; - component_set<L> filtered_components - = scribo::filter::components_small(components, 6); - - { - unsigned none = 0, ignored = 0; - for_all_comps(i, filtered_components) - { - if (filtered_components.info(i).tag() == component::Ignored) - ++ignored; - else - ++none; - } - std::cout << "stats - none = " << none << " - ignored = " << ignored << std::endl; + /// Set separator components. + components.add_separators(separators); +// components.add_separators(whitespaces); - } /// Linking potential objects std::cout << "Linking objects..." << std::endl; object_links<L> left_link - = primitive::link::with_single_left_link_dmax_ratio(filtered_components, 2); + = primitive::link::with_single_left_link_dmax_ratio(components, 2); object_links<L> right_link - = primitive::link::with_single_right_link_dmax_ratio(filtered_components, 2); + = primitive::link::with_single_right_link_dmax_ratio(components, 2); // Validating left and right links. object_links<L> - merged_links = primitive::link::merge_double_link(filtered_components, - left_link, - right_link); - -// #ifndef NOUT -// if (argc == 4) -// { -// image2d<value::rgb8> output = data::convert(value::rgb8(), input); -// scribo::draw::bounding_box_links(output, -// merged_links, -// literal::green); - -// mln::util::array<bool> drawn(static_cast<unsigned>(filtered_components.nelements()) + 1, 0); -// for_all_comps(i, filtered_components) -// if (filtered_components(i).tag() != component::Ignored) -// { -// if (merged_links[i] == i && ! drawn(i)) -// { -// mln::draw::box(output, filtered_components(i).bbox(), literal::orange); -// drawn[i] = true; -// } -// else -// { -// mln::draw::box(output, filtered_components(i).bbox(), literal::blue); -// mln::draw::box(output, filtered_components(merged_links[i]).bbox(), literal::blue); -// drawn[i] = true; -// drawn[merged_links[i]] = true; -// } -// } + merged_links = primitive::link::merge_double_link(left_link, right_link); -// mln::io::ppm::save(output, scribo::make::debug_filename("links.ppm")); -// } -// #endif // Remove links if bboxes have too different sizes. object_links<L> hratio_filtered_links - = filter::object_links_bbox_h_ratio(filtered_components, - merged_links, - 2.5f); - - + = filter::object_links_bbox_h_ratio(merged_links, 2.5f); // #ifndef NOUT @@ -224,8 +183,7 @@ int main(int argc, char* argv[]) // // // //###### object_groups<L> - groups = primitive::group::from_single_link(filtered_components, - hratio_filtered_links); + groups = primitive::group::from_single_link(hratio_filtered_links); // value::label_16 n_groups; // mln::fun::i2v::array<value::label_16> // groups_packed = mln::make::relabelfun(groups, @@ -235,64 +193,25 @@ int main(int argc, char* argv[]) -// mln::util::array<line_stats_extra> line_stats; + // Construct a line set. line_set<L> - lines = scribo::make::line_set(hratio_filtered_links, groups); + lines = scribo::make::line_set(groups); + //===== DEBUG ===== // Bboxes image. - { - image2d<value::rgb8> output = data::convert(value::rgb8(), input); - - for_all_lines(l, lines) - if (lines(l).tag() != line::Ignored) - mln::draw::box(output, lines(l).bbox(), literal::red); - - mln::io::ppm::save(output, - scribo::make::debug_filename("step1_bboxes.ppm")); - } + scribo::debug::save_bboxes_image(input, lines, + scribo::make::debug_filename("step1_bboxes.ppm")); // Bboxes enlarged - { - image2d<value::rgb8> output = data::convert(value::rgb8(), input); - - for_all_lines(l, lines) - if (lines(l).tag() != line::Ignored) - { - if (text::internal::looks_like_a_text_line(lines(l))) - { - box2d - b = text::internal::enlarge(lines(l).bbox(), - text::internal::delta_of_line(lines(l))); - b.crop_wrt(input.domain()); - mln::draw::box(output, b, literal::green); - } - else - mln::draw::box(output, lines(l).bbox(), literal::red); - } - - mln::io::ppm::save(output, - scribo::make::debug_filename("step1_bboxes_enlarged.ppm")); - } + mln::io::ppm::save(scribo::debug::bboxes_enlarged_image(input, lines), + scribo::make::debug_filename("step1_bboxes_enlarged.ppm")); // Looks like a text line - { - image2d<value::rgb8> output = data::convert(value::rgb8(), input); - - for_all_lines(l, lines) - if (lines(l).tag() != line::Ignored) - { - if (text::internal::looks_like_a_text_line(lines(l))) - mln::draw::box(output, lines(l).bbox(), literal::green); - else - mln::draw::box(output, lines(l).bbox(), literal::red); - } - - mln::io::ppm::save(output, - scribo::make::debug_filename("step1_looks_like_a_text_line.ppm")); - } + mln::io::ppm::save(scribo::debug::looks_like_a_text_line_image(input, lines), + scribo::make::debug_filename("step1_looks_like_a_text_line.ppm")); // Bboxes + line infos @@ -312,7 +231,7 @@ int main(int argc, char* argv[]) << lines(l).card() << " " << lines(l).baseline() << " " << lines(l).x_height() << " " - << lines(l).median() << " " + << lines(l).meanline() << " " << lines(l).d_height() << " " << lines(l).a_height() << " " << lines(l).char_space() << " " @@ -329,88 +248,38 @@ int main(int argc, char* argv[]) } - std::cout << "Merging lines..." << std::endl; - lines = scribo::text::merging(input.domain(), lines); + // mean and base lines. + mln::io::ppm::save(scribo::debug::mean_and_base_lines_image(input, lines), + scribo::make::debug_filename("step1_x_height.ppm")); - // Median and base lines. - { - image2d<value::rgb8> output = data::convert(value::rgb8(), input); + //===== END OF DEBUG ===== - for_all_lines(l, lines) - { - if (lines(l).tag() == line::Pathological) - mln::draw::box(output, lines(l).bbox(), literal::orange); - else if (lines(l).tag() != line::Merged) - { - if (lines(l).card() > 1) - { - point2d - b_top(lines(l).baseline() - lines(l).median(), lines(l).bbox().pmin().col()), - e_top(lines(l).baseline() - lines(l).median(), lines(l).bbox().pmax().col()), - b_bot(lines(l).baseline(), lines(l).bbox().pmin().col()), - e_bot(lines(l).baseline(), lines(l).bbox().pmax().col()); - - mln::draw::line(output, b_top, e_top, literal::blue); - mln::draw::line(output, b_bot, e_bot, literal::cyan); - -// std::cout << lines(l) << std::endl; - } - mln::draw::box(output, lines(l).bbox(), literal::purple); - } - } - mln::io::ppm::save(output, scribo::make::debug_filename("step2_x_height.ppm")); - } - - - // Bboxes image. - { - image2d<value::rgb8> output = data::convert(value::rgb8(), input); - - for_all_lines(l, lines) - if (lines(l).tag() != line::Merged - && lines(l).tag() != line::Ignored - && lines(l).tag() != line::Pathological) - { - mln::draw::box(output, lines(l).bbox(), literal::red); - } - - mln::io::ppm::save(output, argv[2]); - } -// // line label image. -// { -// util::array<V> -// f(static_cast<unsigned>(filtered_components.nelements()) + 1, 0); -// for_all_lines(l, lines) -// if (lines(l).tag() != line::Merged -// && lines(l).tag() != line::Ignored -// && lines(l).tag() != line::Pathological) -// { -// for_all_elements(c, lines(l).components()) -// f(lines(l).components()[c]) = l; -// } -// L line_label = duplicate(filtered_components.labeled_image()); -// V nlbl = filtered_components.nelements(); -// mln::labeling::relabel_inplace(line_label, nlbl, f); - -// mln::io::ppm::save(labeling::colorize(value::rgb8(), line_label), -// scribo::make::debug_filename("labeled_lines.ppm")); -// mln::io::dump::save(line_label, scribo::make::debug_filename("labeled_lines.dump")); -// } + std::cout << "Merging lines..." << std::endl; + lines = scribo::text::merging(lines); -// scribo::io::xml::save_text_lines(argv[1], lines, "out.xml"); + //===== DEBUG ===== + // mean and base lines. + mln::io::ppm::save(scribo::debug::mean_and_base_lines_image(input, lines), + scribo::make::debug_filename("step2_x_height.ppm")); + // Looks like a text line + mln::io::ppm::save(scribo::debug::looks_like_a_text_line_image(input, lines), + scribo::make::debug_filename("step2_looks_like_a_text_line.ppm")); + // Bboxes image. + scribo::debug::save_bboxes_image(input, lines, argv[2]); + //===== END OF DEBUG ===== -// scribo::text::recognition(lines, "fra", "out.txt"); + scribo::text::recognition(lines, "fra", "out.txt"); // // Display median character space. @@ -458,5 +327,5 @@ int main(int argc, char* argv[]) // } -// trace::exiting("main"); + trace::exiting("main"); } diff --git a/scribo/src/text_in_photo_ppm_fast.cc b/scribo/src/text_in_photo_ppm_fast.cc index e4ddd48..0e35487 100644 --- a/scribo/src/text_in_photo_ppm_fast.cc +++ b/scribo/src/text_in_photo_ppm_fast.cc @@ -1,4 +1,5 @@ -// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -153,7 +154,7 @@ namespace mln mask_non_text f(mask); mln_concrete(I) output = data::transform(input_rgb, f); - for_all_components(i, components) + for_all_comps(i, components) if (components(i).is_valid()) mln::draw::box(output, components(i).bbox(), literal::red); @@ -255,9 +256,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", timer_.start(); std::cout << "** Using split_bg_fg" << std::endl; image2d<value::rgb8> - fg = preprocessing::split_bg_fg(input_rgb, - lambda, - 32).second(); + fg = preprocessing::split_bg_fg(input_rgb, lambda, 32).second(); intensity_ima = data::transform(fg, mln::fun::v2v::rgb_to_int_u<8>()); t_ = timer_; std::cout << "Foreground extracted. " << t_ << std::endl; @@ -379,9 +378,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", // Validating left and right links. timer_.restart(); object_links<L> - merged_links = primitive::link::merge_double_link(filtered_components, - left_link, - right_link); + merged_links = primitive::link::merge_double_link(left_link, right_link); t_ = timer_; std::cout << "Right/Left Validation. " << t_ << std::endl; @@ -389,8 +386,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", // Remove links if bboxes have too different sizes. timer_.restart(); object_links<L> - hratio_filtered_links = filter::object_links_bbox_h_ratio(filtered_components, - merged_links, + hratio_filtered_links = filter::object_links_bbox_h_ratio(merged_links, 1.50f); @@ -413,9 +409,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", //Remove links if bboxes overlap too much. object_links<L> overlap_filtered_links - = filter::object_links_bbox_overlap(filtered_components, - hratio_filtered_links, - 0.80f); + = filter::object_links_bbox_overlap(hratio_filtered_links, 0.80f); @@ -438,16 +432,14 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", timer_.restart(); object_groups<L> - groups = primitive::group::from_single_link(filtered_components, - overlap_filtered_links); + groups = primitive::group::from_single_link(overlap_filtered_links); // Apply grouping in a temporary image (for debug purpose). #ifndef NOUT component_set<L> - raw_group_image = primitive::group::apply(filtered_components, - groups); + raw_group_image = primitive::group::apply(groups); #endif // !NOUT t_ = timer_; @@ -505,10 +497,9 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", { decision_image = data::convert(value::rgb8(), input); component_set<L> - grouped_objects = primitive::group::apply(filtered_components, - filtered_small_groups); + grouped_objects = primitive::group::apply(filtered_small_groups); - for_all_components(i, filtered_components) + for_all_comps(i, filtered_components) if (filtered_components(i).is_valid() && filtered_small_groups(i) != 0) mln::draw::box(decision_image, filtered_components(i).bbox(), literal::green); @@ -544,10 +535,9 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", decision_image = data::convert(value::rgb8(), input); component_set<L> - grouped_components = primitive::group::apply(filtered_components, - filtered_thin_groups); + grouped_components = primitive::group::apply(filtered_thin_groups); - for_all_components(i, filtered_components) + for_all_comps(i, filtered_components) if (filtered_components(i).is_valid() && filtered_thin_groups(i) != 0) mln::draw::box(decision_image, filtered_components(i).bbox(), literal::green); @@ -571,8 +561,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", // 30); component_set<L> - grouped_components = primitive::group::apply(filtered_components, - filtered_thin_groups); + grouped_components = primitive::group::apply(filtered_thin_groups); t_ = g_timer; std::cout << "Group applied to object image " << t_ << std::endl; @@ -588,10 +577,10 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", /// Grouping groups. - groups = primitive::group::from_single_link(grouped_components, left_link); + groups = primitive::group::from_single_link(left_link); -// component_set<L> - grouped_components = primitive::group::apply(grouped_components, groups); +// component_set<L> + grouped_components = primitive::group::apply(groups); t_ = g_timer; std::cout << "Link and group again " << t_ << std::endl; @@ -663,9 +652,17 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1", std::cout << "# objects = " << grouped_components.nelements() << std::endl; + std::cout << filtered_components << std::endl; + + for_all_comps(c, filtered_components) + if (filtered_components(c).is_valid()) + std::cout << filtered_components(c) << ", "; + std::cout << std::endl; + + std::cout << filtered_thin_groups << std::endl; scribo::line_set<L> - lines = scribo::line_set<L>(filtered_components, filtered_thin_groups); + lines = scribo::make::line_set(filtered_thin_groups); text::recognition(lines, "fra", "out.txt"); trace::exiting("main"); diff --git a/scribo/src/text_in_photo_ppm_fast_2.cc b/scribo/src/text_in_photo_ppm_fast_2.cc deleted file mode 100644 index bb24a11..0000000 --- a/scribo/src/text_in_photo_ppm_fast_2.cc +++ /dev/null @@ -1,541 +0,0 @@ -// Copyright (C) 2009 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. - -#include <libgen.h> -#include <iostream> - -#include <mln/core/image/image2d.hh> -#include <mln/core/image/imorph/tr_image.hh> -#include <mln/core/alias/neighb2d.hh> - -#include <mln/labeling/colorize.hh> - -#include <mln/data/stretch.hh> - -#include <mln/io/pbm/all.hh> -#include <mln/io/ppm/save.hh> - -#include <mln/math/min.hh> - -#include <mln/logical/not.hh> - -#include <mln/literal/colors.hh> -#include <mln/value/rgb8.hh> -#include <mln/value/label_16.hh> - -#include <mln/fun/v2v/rgb_to_int_u.hh> - -#include <mln/data/wrap.hh> - -#include <mln/draw/box.hh> - -#include <mln/geom/translate.hh> - -#include <scribo/draw/bounding_boxes.hh> - -#include <scribo/binarization/sauvola_ms.hh> -#include <scribo/binarization/sauvola.hh> - -#include <scribo/primitive/extract/objects.hh> - -#include <scribo/primitive/link/merge_double_link.hh> -#include <scribo/primitive/link/with_single_left_link.hh> -#include <scribo/primitive/link/with_single_right_link.hh> - -#include <scribo/primitive/group/apply.hh> -#include <scribo/primitive/group/from_double_link.hh> -#include <scribo/primitive/group/from_single_link.hh> - -#include <scribo/filter/objects_with_holes.hh> -#include <scribo/filter/object_links_bbox_h_ratio.hh> -#include <scribo/filter/object_links_bbox_overlap.hh> - -#include <scribo/filter/common/objects_photo.hh> - -#include <scribo/filter/object_groups_small.hh> -#include <scribo/filter/object_groups_v_thickness.hh> - -#include <scribo/debug/decision_image.hh> -#include <scribo/debug/save_bboxes_image.hh> -#include <scribo/debug/save_linked_bboxes_image.hh> - -#include <scribo/debug/usage.hh> - -#include <scribo/preprocessing/split_bg_fg.hh> - -#include <scribo/make/debug_filename.hh> - -#include <mln/util/timer.hh> -#include <mln/core/var.hh> - - -#include <scribo/src/afp/components.hh> -#include <scribo/src/afp/link.hh> -#include <scribo/src/afp/regroup.hh> - -const char *args_desc[][2] = -{ - { "input.ppm", "A color image." }, - { "debug_output_dir", "Directory were debug images will be saved" }, - { "lambda", "Lambda value used for foreground extraction" }, - {0, 0} -}; - - -namespace mln -{ - - struct mask_non_text : Function_v2v<mask_non_text> - { - typedef value::rgb8 result; - typedef image2d<bool> I; - - mask_non_text(const image2d<bool>& mask) - : mask_(mask), p_(mask_) - { - p_.start(); - } - - result operator()(const result& v) const - { - bool b = p_.val(); - p_.next(); - if (!b) - return v / 2; - else - return v; - - } - - I mask_; - mutable mln_pixter_(I) p_; - }; - - - template <typename I, typename L> - mln_concrete(I) - compute_highlight_image(const I& input_rgb, - const object_image<L>& objects) - { - mln_ch_value(I, bool) mask; - initialize(mask, input_rgb); - data::fill(mask, false); - - for_all_components(i, objects.bboxes()) - data::fill((mask | objects.bbox(i)).rw(), true); - - mask_non_text f(mask); - mln_concrete(I) output = data::transform(input_rgb, f); - - for_all_components(i, objects.bboxes()) - mln::draw::box(output, objects.bbox(i), literal::red); - - return output; - } - - template <typename I, typename L> - mln_concrete(I) - compute_text_image(const I& input_rgb, - const object_image<L>& grouped_objects) - { - const util::array<mln_domain(L)>& bboxes = grouped_objects.bboxes(); - - unsigned shift = 5; - float height = 1, width = 0; - for_all_components(i, bboxes) - { - height += bboxes(i).nrows() + shift; - width = math::max(static_cast<float>(bboxes(i).ncols()), width); - } - if (width == 0) - width = 1; - - I output(height, width); - data::fill(output, literal::black); - - algebra::vec<2, float> dv; - dv[0] = 0; - dv[1] = 0; - for_all_ncomponents(i, grouped_objects.nlabels()) - { - mln_VAR(tmp, duplicate(input_rgb | grouped_objects.bbox(i))); - - typedef fun::x2x::translation<mln_site_(I)::dim, float> trans_t; - trans_t trans(dv - grouped_objects.bbox(i).pmin().to_vec()); - - mln_domain(I) tr_box(grouped_objects.bbox(i).pmin().to_vec() + trans.t(), - grouped_objects.bbox(i).pmax().to_vec() + trans.t()); - - tr_image<mln_domain(I), tmp_t, trans_t> tr_ima(tr_box, tmp, trans); - - data::paste(tr_ima, output); - dv[0] += grouped_objects.bbox(i).nrows() + shift; - } - - return output; - } - -} // end of namespace mln - - -int main(int argc, char* argv[]) -{ - using namespace scribo; - using namespace mln; - - if (argc < 3 || argc > 10) - return scribo::debug::usage(argv, - "Find text in a photo.", - "input.ppm output.ppm [bg/fg enabled] [sauvola_ms enabled] [Bg comp filter enabled] [small group filter enabled] [thin group filter enabled] [debug_output_dir] [lambda]", - args_desc, - "A color image where the text is highlighted."); - - bool debug = false; - if (argc > 8) - { - scribo::make::internal::debug_filename_prefix = argv[8]; - debug = true; - } - - trace::entering("main"); - - image2d<value::rgb8> input_rgb; - io::ppm::load(input_rgb, argv[1]); - - - unsigned lambda; - if (argc == 6) - lambda = atoi(argv[9]); - else - lambda = 1.2 * (input_rgb.nrows() + input_rgb.ncols()); - - - image2d<value::int_u8> intensity_ima; - util::timer timer_, global_t_; - float t_; - - global_t_.start(); - - if (argc > 3 && atoi(argv[3]) != 0) - { - // Extract foreground - timer_.start(); - std::cout << "** Using split_bg_fg" << std::endl; - image2d<value::rgb8> - fg = preprocessing::split_bg_fg(input_rgb, - lambda, - 32).second(); - intensity_ima = data::transform(fg, mln::fun::v2v::rgb_to_int_u<8>()); - t_ = timer_; - std::cout << "Foreground extracted. " << t_ << std::endl; - } - else - { - timer_.start(); - std::cout << "** Using data::transform(intensity)" << std::endl; - intensity_ima = data::transform(input_rgb, - mln::fun::v2v::rgb_to_int_u<8>()); - t_ = timer_; - std::cout << "Intensity image " << t_ << std::endl; - } - - - // Binarize foreground to use it in the processing chain. - timer_.restart(); - image2d<bool> input; - unsigned w = std::min(intensity_ima.nrows() / 3, intensity_ima.ncols() / 3); - if (! w % 2) - ++w; - w = std::min(w, 101u); - if (argc > 4 && atoi(argv[4]) != 0) - { - std::cout << "** Using sauvola_ms with w_1 = " << w << std::endl; - input = binarization::sauvola_ms(intensity_ima, w, 3, 67); - } - else - { - std::cout << "** Using sauvola with w_1 = " << w << std::endl; - input = binarization::sauvola(intensity_ima, w); - } - - -// if (debug) -// io::pbm::save(input, "input.pbm"); - t_ = timer_; - std::cout << "Foreground binarized. " << t_ << std::endl; - - - - typedef image2d<value::label_16> L; - - /// Finding objects. - timer_.restart(); - - typedef object_image(L) Obj; - Obj filtered_objects; - - { - util::array<box2d> bboxes; - util::array<point2d> mass_centers; - - value::label_16 nobjects; - L components = extract_components(input, nobjects, bboxes, mass_centers); - - filtered_objects = Obj(components, nobjects, bboxes, mass_centers); - } - - t_ = timer_; - std::cout << "Object extracted " << t_ << " - " << filtered_objects.nlabels() << " objects" << std::endl; - -// if (debug) -// io::pgm::save(data::stretch(value::int_u8(), filtered_objects), "ref_objects.pgm"); - - - /// linking potential objects - timer_.restart(); - util::couple<object_links<L>, object_links<L> > - links = primitive::link::left_right(filtered_objects); - - object_links<L>& left_link = links.first(); - object_links<L>& right_link = links.second(); - -// object_links<L> left_link -// = primitive::link::with_single_left_link(filtered_objects, 30); -// t_ = timer_; -// std::cout << "Left Link done " << t_ << std::endl; - -// timer_.restart(); -// object_links<L> right_link -// = primitive::link::with_single_right_link(filtered_objects, 30); - t_ = timer_; - std::cout << "Link done " << t_ << std::endl; - - - -// #ifndef NOUT -// if (argc > 4) -// { -// std::cerr << "BEFORE - nobjects = " << filtered_objects.nlabels() << std::endl; -// scribo::debug::save_linked_bboxes_image(input, -// filtered_objects, -// left_link, right_link, -// literal::red, literal::cyan, -// literal::yellow, -// literal::green, -// scribo::make::debug_filename("links.ppm")); -// } -// #endif - - - - // Validating left and right links. - timer_.restart(); - object_links<L> - merged_links = primitive::link::merge_double_link(filtered_objects, - left_link, - right_link); - t_ = timer_; - std::cout << "Right/Left Validation. " << t_ << std::endl; - - - // Remove links if bboxes have too different sizes. - timer_.restart(); - object_links<L> - hratio_filtered_links = filter::object_links_bbox_h_ratio(filtered_objects, - merged_links, - 1.50f); - - - - -// #ifndef NOUT -// if (argc > 4) -// { -// image2d<value::rgb8> -// hratio_decision_image = scribo::debug::decision_image(input, -// merged_links, -// hratio_filtered_links); -// io::ppm::save(hratio_decision_image, -// scribo::make::debug_filename("hratio_links_decision_image.ppm")); -// } -// #endif - - - - - //Remove links if bboxes overlap too much. - object_links<L> overlap_filtered_links - = filter::object_links_bbox_overlap(filtered_objects, - hratio_filtered_links, - 0.80f); - - - - -// #ifndef NOUT -// if (argc > 4) -// { -// image2d<value::rgb8> overlap_decision_image -// = scribo::debug::decision_image(input, -// hratio_filtered_links, -// overlap_filtered_links); -// io::ppm::save(overlap_decision_image, -// scribo::make::debug_filename("overlap_links_decision_image.ppm")); -// } -// #endif - - - t_ = timer_; - std::cout << "Objects links filtered. " << t_ << std::endl; - - timer_.restart(); - object_groups<L> - groups = primitive::group::from_single_link(filtered_objects, - overlap_filtered_links); - - - - /// Apply grouping in a temporary image (for debug purpose). -// #ifndef NOUT -// object_image(L) -// raw_group_image = primitive::group::apply(filtered_objects, -// filter::object_groups_small(groups, 2)); -// #endif // !NOUT - - t_ = timer_; - std::cout << "Objects grouped. " << t_ << std::endl; - - - util::timer g_timer; - - object_image(L) - grouped_objects = primitive::group::apply(filtered_objects, - groups); - - t_ = g_timer; - std::cout << "Group applied to object image " << t_ << std::endl; - - /// Objects have been grouped. We try to link groups together. - /// This time a single link is enough since non-wanted objects have - /// been removed. - g_timer.restart(); - - left_link = primitive::link::left(grouped_objects, 30); -// left_link -// = primitive::link::with_single_left_link(grouped_objects, 30); - - - /// Grouping groups. - groups = primitive::group::from_single_link(grouped_objects, left_link); - -// object_image(L) - grouped_objects = primitive::group::apply(grouped_objects, groups); - - - - std::cout << "Filtering groups..." << std::endl; - - timer_.restart(); - // Remove objects part of groups with strictly less than 3 objects. - - g_timer.start(); - object_groups<L> filtered_small_groups; - if (argc > 6 && atoi(argv[6]) != 0) - { - std::cout << "** Using group too small" << std::endl; - filtered_small_groups = filter::object_groups_small(groups, 3); - } - else - filtered_small_groups = groups; - t_ = g_timer; - std::cout << "Small groups removed " << t_ << std::endl; - - - - // Remove objects part of groups having a mean thickness lower than 8. - g_timer.restart(); - object_groups<L> filtered_thin_groups; - if (argc > 7 && atoi(argv[7]) != 0) - { - std::cout << "** Using group too thin" << std::endl; - filtered_thin_groups - = filter::object_groups_v_thickness(filtered_small_groups, 8); - } - else - filtered_thin_groups = filtered_small_groups; - t_ = g_timer; - std::cout << "Groups too thin " << t_ << std::endl; - - - - t_ = g_timer; - std::cout << "Link and group again " << t_ << std::endl; - - timer_.stop(); - - - timer_.resume(); - - g_timer.restart(); - /// Filter grouped objects not having enough background components. - if (argc > 5 && atoi(argv[5]) != 0) - { - std::cout << "** Using objects_with_two_holes" << std::endl; - grouped_objects = scribo::filter::objects_with_two_holes(grouped_objects, 5); - t_ = g_timer; - std::cout << "Objects_with_holes " << t_ << std::endl; - } - - t_ = timer_; - std::cout << "Objects groups filtered. " << t_ << std::endl; - -// object_image(L) - grouped_objects = primitive::group::apply(grouped_objects, groups); - - - t_ = global_t_; - std::cout << "*** Result computed " << t_ << std::endl; - - timer_.restart(); - std::cout << "Saving result..." << std::endl; - io::ppm::save(mln::labeling::colorize(value::rgb8(), - grouped_objects, - grouped_objects.nlabels()), - argv[2]); - - - io::ppm::save(compute_highlight_image(input_rgb, grouped_objects), - scribo::make::debug_filename("orig_with_bboxes.ppm")); - io::ppm::save(compute_text_image(input_rgb, grouped_objects), - scribo::make::debug_filename("out_text.ppm")); - - t_ = timer_; - std::cout << "Output saved " << t_ << std::endl; - - std::cout << "# objects = " << grouped_objects.nlabels() << std::endl; - - trace::exiting("main"); - return grouped_objects.nlabels() != 0; -} -- 1.5.6.5
participants (1)
-
Guillaume Lazzara