last-svn-commit-32-ge7ca877 scribo/src/text_in_photo_ppm.cc: Improve output.

--- scribo/ChangeLog | 4 + scribo/src/text_in_photo_ppm.cc | 246 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 234 insertions(+), 16 deletions(-) diff --git a/scribo/ChangeLog b/scribo/ChangeLog index 6eae06e..ee8e03c 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,5 +1,9 @@ 2010-02-19 Guillaume Lazzara <z@lrde.epita.fr> + * scribo/src/text_in_photo_ppm.cc: Improve output. + +2010-02-19 Guillaume Lazzara <z@lrde.epita.fr> + Cleanup and avoid warnings in Sauvola related files. * scribo/binarization/sauvola_ms.hh, diff --git a/scribo/src/text_in_photo_ppm.cc b/scribo/src/text_in_photo_ppm.cc index 4cb5631..9027ab0 100644 --- a/scribo/src/text_in_photo_ppm.cc +++ b/scribo/src/text_in_photo_ppm.cc @@ -27,6 +27,7 @@ #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> @@ -38,12 +39,16 @@ #include <mln/logical/not.hh> +#include <mln/fun/v2v/rgb_to_int_u.hh> + #include <mln/literal/colors.hh> #include <mln/value/rgb8.hh> #include <mln/value/label_16.hh> #include <mln/draw/box.hh> +#include <mln/geom/translate.hh> + #include <scribo/binarization/sauvola.hh> #include <scribo/draw/bounding_boxes.hh> @@ -58,6 +63,7 @@ #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> @@ -68,7 +74,6 @@ #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/debug/usage.hh> @@ -77,6 +82,9 @@ #include <scribo/make/debug_filename.hh> +#include <mln/util/timer.hh> +#include <mln/core/var.hh> + const char *args_desc[][2] = { { "input.ppm", "A color image." }, @@ -86,20 +94,117 @@ const char *args_desc[][2] = }; +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 != 4 && argc != 5) + if (argc != 3 && argc != 4 && argc != 5 && argc != 6) return scribo::debug::usage(argv, "Find text in a photo.", - "input.ppm output.ppm [debug_output_dir] [lambda]", + "input.ppm output.ppm [bg/fg] [debug_output_dir] [lambda]", args_desc, "A color image where the text is highlighted."); - if (argc > 3) - scribo::make::internal::debug_filename_prefix = argv[3]; + if (argc > 4) + scribo::make::internal::debug_filename_prefix = argv[4]; trace::entering("main"); @@ -108,22 +213,50 @@ int main(int argc, char* argv[]) unsigned lambda; - if (argc == 5) - lambda = atoi(argv[4]); + if (argc == 6) + lambda = atoi(argv[5]); else lambda = 1.2 * (input_rgb.nrows() + input_rgb.ncols()); + util::timer timer_; + // Extract foreground + image2d<value::int_u8> intensity_ima; std::cout << "Extracting foreground..." << std::endl; - image2d<value::rgb8> - fg = preprocessing::split_bg_fg(input_rgb, - lambda, - 32).second(); + timer_.start(); + + if (argc > 3 && atoi(argv[3]) != 0) + { + // Extract foreground + timer_.start(); + 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>()); + float t_ = timer_; + std::cout << "Foreground extracted. " << t_ << std::endl; + } + else + { + timer_.start(); + intensity_ima = data::transform(input_rgb, + mln::fun::v2v::rgb_to_int_u<8>()); + float t_ = timer_; + std::cout << "Intensity image " << t_ << std::endl; + } + float t_ = timer_; + std::cout << "Foreground extracted. " << t_ << std::endl; // Binarize foreground to use it in the processing chain. + // FIXME: TOO SLOW! std::cout << "Binarizing foreground..." << std::endl; - image2d<bool> input = binarization::sauvola(fg); + timer_.restart(); + image2d<bool> input = binarization::sauvola(intensity_ima, 11); + io::pbm::save(input, "input.pbm"); + t_ = timer_; + std::cout << "Foreground binarized. " << t_ << std::endl; @@ -131,25 +264,35 @@ int main(int argc, char* argv[]) /// Finding objects. std::cout << "Extracting objects..." << std::endl; + timer_.restart(); value::label_16 nobjects; object_image(L) objects = scribo::primitive::extract::objects(input, c8(), nobjects); - + t_ = timer_; + std::cout << "Object extracted" << t_ << std::endl; /// First filtering. std::cout << "Filtering objects..." << std::endl; + timer_.restart(); object_image(L) filtered_objects = filter::common::objects_photo(objects); + t_ = timer_; + std::cout << "Object filtered" << t_ << std::endl; /// linking potential objects std::cout << "Linking objects..." << std::endl; + timer_.restart(); 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 << "Right Link done" << t_ << std::endl; @@ -170,16 +313,22 @@ int main(int argc, char* argv[]) // 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. std::cout << "Filtering object links..." << std::endl; + timer_.restart(); object_links<L> hratio_filtered_links = filter::object_links_bbox_h_ratio(filtered_objects, merged_links, - 0.7f); + 1.50f); @@ -221,8 +370,11 @@ int main(int argc, char* argv[]) #endif + t_ = timer_; + std::cout << "Objects links filtered. " << t_ << std::endl; std::cout << "Grouping objects..." << std::endl; + timer_.restart(); object_groups<L> groups = primitive::group::from_single_link(filtered_objects, overlap_filtered_links); @@ -234,11 +386,31 @@ int main(int argc, char* argv[]) raw_group_image = primitive::group::apply(filtered_objects, filter::object_groups_small(groups, 2)); + t_ = timer_; + std::cout << "Objects grouped. " << t_ << std::endl; + +#ifndef NOUT + + if (argc > 3) + scribo::debug::save_bboxes_image(input, + raw_group_image.bboxes(), + literal::red, + scribo::make::debug_filename("group_image.ppm")); +#endif // !NOUT + std::cout << "Filtering groups..." << std::endl; + util::timer g_timer; + + timer_.restart(); // Remove objects part of groups with strictly less than 3 objects. + + g_timer.start(); object_groups<L> filtered_small_groups = filter::object_groups_small(groups, 3); + t_ = g_timer; + std::cout << "Small groups removed " << t_ << std::endl; + #ifndef NOUT @@ -256,8 +428,11 @@ int main(int argc, char* argv[]) // Remove objects part of groups having a mean thickness lower than 8. + g_timer.restart(); object_groups<L> filtered_thin_groups = filter::object_groups_v_thickness(filtered_small_groups, 8); + t_ = g_timer; + std::cout << "Groups too thin " << t_ << std::endl; #ifndef NOUT @@ -275,14 +450,19 @@ int main(int argc, char* argv[]) /// Apply grouping in the object image. + g_timer.restart(); + object_image(L) grouped_objects = primitive::group::apply(filtered_objects, filtered_thin_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::with_single_left_link(grouped_objects, 30); @@ -292,8 +472,28 @@ int main(int argc, char* argv[]) grouped_objects = primitive::group::apply(grouped_objects, groups); + t_ = g_timer; + std::cout << "Link and group again " << t_ << std::endl; + + timer_.stop(); + + io::ppm::save(mln::labeling::colorize(value::rgb8(), + grouped_objects, + grouped_objects.nlabels()), + scribo::make::debug_filename("out_before_hole_filter.ppm")); + + timer_.resume(); + g_timer.restart(); + /// Filter grouped objects not having enough background components. + grouped_objects = scribo::filter::objects_with_holes_slow(grouped_objects, 2); +// grouped_objects = scribo::filter::objects_with_holes(grouped_objects, 2, 2); + t_ = g_timer; + std::cout << "Objects_with_holes " << t_ << std::endl; + + t_ = timer_; + std::cout << "Objects groups filtered. " << t_ << std::endl; #ifndef NOUT if (argc > 3) @@ -313,6 +513,20 @@ int main(int argc, char* argv[]) grouped_objects.nlabels()), argv[2]); +#ifndef NOUT + io::ppm::save(compute_highlight_image(input_rgb, grouped_objects), + scribo::make::debug_filename("orig_with_bboxes.ppm")); +// scribo::debug::save_bboxes_image(input_rgb, grouped_objects.bboxes(), +// literal::red, +// scribo::make::debug_filename("orig_with_bboxes.ppm")); +#endif + + io::ppm::save(compute_text_image(input_rgb, grouped_objects), + scribo::make::debug_filename("out_text.ppm")); + + + std::cout << "# objects = " << grouped_objects.nlabels() << std::endl; trace::exiting("main"); + return grouped_objects.nlabels() != 0; } -- 1.5.6.5
participants (1)
-
Guillaume Lazzara