Olena-patches
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
March 2010
- 4 participants
- 277 discussions
* src/preprocessing/Makefile.am,
* src/filter/Makefile.am,
* src/debug/Makefile.am: Add new targets.
* src/debug/show_info_median_inter_characters.cc,
* src/debug/show_info_x_height.cc,
* src/debug/show_links_single_down.cc,
* src/debug/show_links_single_down_left_aligned.cc,
* src/debug/show_links_single_down_right_aligned.cc,
* src/debug/show_links_single_up.cc,
* src/debug/show_links_single_up_left_aligned.cc,
* src/debug/show_links_single_up_right_aligned.cc,
* src/filter/objects_with_holes.cc,
* src/filter/objects_with_holes_pgm.cc,
* src/pbm_lines_in_doc.cc,
* src/preprocessing/split_bg_fg_ms.cc,
* src/text_in_article.cc,
* src/text_in_photo_ppm_fast.cc: New tools.
* src/debug/show_left_right_links_validation.cc: Rename as...
* src/debug/show_links_left_right_links_validation.cc: ...this.
* src/debug/show_links_bbox_h_ratio.cc: Add a missing argument.
---
scribo/ChangeLog | 28 +
scribo/src/debug/Makefile.am | 20 +-
.../src/debug/show_info_median_inter_characters.cc | 256 ++++++++
scribo/src/debug/show_info_x_height.cc | 281 +++++++++
.../src/debug/show_left_right_links_validation.cc | 122 ----
scribo/src/debug/show_links_bbox_h_ratio.cc | 2 +-
.../show_links_left_right_links_validation.cc | 122 ++++
scribo/src/debug/show_links_single_down.cc | 157 +++++
.../debug/show_links_single_down_left_aligned.cc | 99 +++
.../debug/show_links_single_down_right_aligned.cc | 99 +++
scribo/src/debug/show_links_single_up.cc | 157 +++++
.../src/debug/show_links_single_up_left_aligned.cc | 100 +++
.../debug/show_links_single_up_right_aligned.cc | 98 +++
scribo/src/filter/Makefile.am | 6 +-
scribo/src/filter/objects_with_holes.cc | 70 ++
scribo/src/filter/objects_with_holes_pgm.cc | 71 +++
scribo/src/pbm_lines_in_doc.cc | 299 +++++++++
scribo/src/preprocessing/Makefile.am | 2 +
scribo/src/preprocessing/split_bg_fg_ms.cc | 109 ++++
scribo/src/text_in_article.cc | 327 ++++++++++
scribo/src/text_in_photo_ppm_fast.cc | 658 ++++++++++++++++++++
21 files changed, 2957 insertions(+), 126 deletions(-)
create mode 100644 scribo/src/debug/show_info_median_inter_characters.cc
create mode 100644 scribo/src/debug/show_info_x_height.cc
delete mode 100644 scribo/src/debug/show_left_right_links_validation.cc
create mode 100644 scribo/src/debug/show_links_left_right_links_validation.cc
create mode 100644 scribo/src/debug/show_links_single_down.cc
create mode 100644 scribo/src/debug/show_links_single_down_left_aligned.cc
create mode 100644 scribo/src/debug/show_links_single_down_right_aligned.cc
create mode 100644 scribo/src/debug/show_links_single_up.cc
create mode 100644 scribo/src/debug/show_links_single_up_left_aligned.cc
create mode 100644 scribo/src/debug/show_links_single_up_right_aligned.cc
create mode 100644 scribo/src/filter/objects_with_holes.cc
create mode 100644 scribo/src/filter/objects_with_holes_pgm.cc
create mode 100644 scribo/src/pbm_lines_in_doc.cc
create mode 100644 scribo/src/preprocessing/split_bg_fg_ms.cc
create mode 100644 scribo/src/text_in_article.cc
create mode 100644 scribo/src/text_in_photo_ppm_fast.cc
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index ee8e03c..f7a0e58 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,33 @@
2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Add new tools in Scribo.
+
+ * src/preprocessing/Makefile.am,
+ * src/filter/Makefile.am,
+ * src/debug/Makefile.am: Add new targets.
+
+ * src/debug/show_info_median_inter_characters.cc,
+ * src/debug/show_info_x_height.cc,
+ * src/debug/show_links_single_down.cc,
+ * src/debug/show_links_single_down_left_aligned.cc,
+ * src/debug/show_links_single_down_right_aligned.cc,
+ * src/debug/show_links_single_up.cc,
+ * src/debug/show_links_single_up_left_aligned.cc,
+ * src/debug/show_links_single_up_right_aligned.cc,
+ * src/filter/objects_with_holes.cc,
+ * src/filter/objects_with_holes_pgm.cc,
+ * src/pbm_lines_in_doc.cc,
+ * src/preprocessing/split_bg_fg_ms.cc,
+ * src/text_in_article.cc,
+ * src/text_in_photo_ppm_fast.cc: New tools.
+
+ * src/debug/show_left_right_links_validation.cc: Rename as...
+ * src/debug/show_links_left_right_links_validation.cc: ...this.
+
+ * src/debug/show_links_bbox_h_ratio.cc: Add a missing argument.
+
+2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+
* scribo/src/text_in_photo_ppm.cc: Improve output.
2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
diff --git a/scribo/src/debug/Makefile.am b/scribo/src/debug/Makefile.am
index 28839dc..bb55bfb 100644
--- a/scribo/src/debug/Makefile.am
+++ b/scribo/src/debug/Makefile.am
@@ -20,7 +20,9 @@
include $(top_srcdir)/scribo/scribo.mk
bin_PROGRAMS = \
- show_left_right_links_validation \
+ show_info_x_height \
+ show_info_median_inter_characters \
+ show_links_left_right_links_validation \
show_links_bbox_h_ratio \
show_links_bbox_overlap \
show_links_bottom_aligned \
@@ -28,10 +30,16 @@ bin_PROGRAMS = \
show_links_non_h_aligned \
show_links_several_right \
show_links_several_right_overlap \
+ show_links_single_down \
+ show_links_single_down_left_aligned \
+ show_links_single_down_right_aligned \
show_links_single_left \
show_links_single_left_dmax_ratio \
show_links_single_right \
show_links_single_right_dmax_ratio \
+ show_links_single_up \
+ show_links_single_up_left_aligned \
+ show_links_single_up_right_aligned \
show_links_top_aligned \
show_objects_large \
show_objects_large_small \
@@ -40,7 +48,9 @@ bin_PROGRAMS = \
show_objects_thin
-show_left_right_links_validation_SOURCES = show_left_right_links_validation.cc
+show_info_x_height_SOURCES = show_info_x_height.cc
+show_info_median_inter_characters_SOURCES = show_info_median_inter_characters.cc
+show_links_left_right_links_validation_SOURCES = show_links_left_right_links_validation.cc
show_links_bbox_h_ratio_SOURCES = show_links_bbox_h_ratio.cc
show_links_bbox_overlap_SOURCES = show_links_bbox_overlap.cc
show_links_bottom_aligned_SOURCES = show_links_bottom_aligned.cc
@@ -48,10 +58,16 @@ show_links_center_aligned_SOURCES = show_links_center_aligned.cc
show_links_non_h_aligned_SOURCES = show_links_non_h_aligned.cc
show_links_several_right_SOURCES = show_links_several_right.cc
show_links_several_right_overlap_SOURCES = show_links_several_right_overlap.cc
+show_links_single_down_SOURCES = show_links_single_down.cc
+show_links_single_down_left_aligned_SOURCES = show_links_single_down_left_aligned.cc
+show_links_single_down_right_aligned_SOURCES = show_links_single_down_right_aligned.cc
show_links_single_left_SOURCES = show_links_single_left.cc
show_links_single_left_dmax_ratio_SOURCES = show_links_single_left_dmax_ratio.cc
show_links_single_right_SOURCES = show_links_single_right.cc
show_links_single_right_dmax_ratio_SOURCES = show_links_single_right_dmax_ratio.cc
+show_links_single_up_SOURCES = show_links_single_up.cc
+show_links_single_up_left_aligned_SOURCES = show_links_single_up_left_aligned.cc
+show_links_single_up_right_aligned_SOURCES = show_links_single_up_right_aligned.cc
show_links_top_aligned_SOURCES = show_links_top_aligned.cc
show_objects_large_SOURCES = show_objects_large.cc
show_objects_large_small_SOURCES = show_objects_large_small.cc
diff --git a/scribo/src/debug/show_info_median_inter_characters.cc b/scribo/src/debug/show_info_median_inter_characters.cc
new file mode 100644
index 0000000..e28ad96
--- /dev/null
+++ b/scribo/src/debug/show_info_median_inter_characters.cc
@@ -0,0 +1,256 @@
+// 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/alias/neighb2d.hh>
+
+#include <mln/io/pbm/all.hh>
+#include <mln/io/ppm/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/extension/adjust.hh>
+
+#include <mln/accu/stat/median_h.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/primitive/extract/objects.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/debug/usage.hh>
+
+#include <scribo/make/debug_filename.hh>
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. 'False' for objects, 'True'\
+for the background." },
+ { "debug_dir", "Output directory for debug image" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace mln;
+
+ if (argc != 3 && argc != 4)
+ return scribo::debug::usage(argv,
+ "Find text lines using left/right validation and display x-height in a binarized article.",
+ "input.pbm out.ppm <debug_dir>",
+ args_desc,
+ "A color image. The following colors are used : dark blue for object bboxes, orange for single object bboxes, purple for group bboxes and light blue for x-height.");
+
+ if (argc == 4)
+ scribo::make::internal::debug_filename_prefix = argv[3];
+
+ trace::entering("main");
+
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ typedef image2d<value::label_16> L;
+
+ /// Finding objects.
+ std::cout << "Finding objects..." << std::endl;
+ value::label_16 nobjects;
+ object_image(L)
+ objects = scribo::primitive::extract::objects(input,
+ c8(),
+ nobjects);
+
+
+ /// First filtering.
+ std::cout << "Filtering objects..." << std::endl;
+ object_image(L) filtered_objects
+ = scribo::filter::objects_small(objects, 6);
+
+ /// Linking potential objects
+ std::cout << "Linking objects..." << std::endl;
+ object_links<L> left_link
+ = primitive::link::with_single_left_link_dmax_ratio(filtered_objects);
+ object_links<L> right_link
+ = primitive::link::with_single_right_link_dmax_ratio(filtered_objects);
+
+
+ // Validating left and right links.
+ object_links<L>
+ merged_links = primitive::link::merge_double_link(filtered_objects,
+ 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);
+
+ util::array<bool> drawn(objects.nlabels(), 0);
+ for_all_components(i, objects.bboxes())
+ if (merged_links[i] == i && ! drawn(i))
+ {
+ mln::draw::box(output, objects.bbox(i), literal::orange);
+ drawn[i] = true;
+ }
+ else
+ {
+ mln::draw::box(output, objects.bbox(i), literal::blue);
+ mln::draw::box(output, objects.bbox(merged_links[i]), literal::blue);
+ drawn[i] = true;
+ drawn[merged_links[i]] = true;
+ }
+
+ 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_objects,
+ merged_links,
+ 2.0f);
+
+
+
+
+#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
+
+
+
+ // FIXME: from_single_link should return a packed object_groups?
+ //
+ //######
+ object_groups<L>
+ groups = primitive::group::from_single_link(filtered_objects,
+ hratio_filtered_links);
+ value::label_16 n_groups;
+ mln::fun::i2v::array<value::label_16>
+ groups_packed = mln::make::relabelfun(groups,
+ filtered_objects.nlabels(),
+ n_groups);
+ //######
+
+
+ std::cout << "Grouping objects..." << std::endl;
+ object_image(L)
+ grouped_objects = primitive::group::apply(filtered_objects, groups);
+
+
+
+ // Display median character space.
+ {
+ image2d<value::rgb8> output = data::convert(value::rgb8(), input);
+ typedef mln::value::int_u<8> median_t;
+ typedef mln::accu::stat::median_h<median_t> accu_t;
+ util::array<accu_t>
+ lspace_med(static_cast<unsigned>(grouped_objects.nlabels()) + 1);
+
+ for_all_components(i, filtered_objects.bboxes())
+ if (groups_packed(i) != 0)
+ {
+ if (hratio_filtered_links(i) != i)
+ {
+ unsigned
+ space = filtered_objects.bbox(i).pmin().col() - filtered_objects.bbox(hratio_filtered_links(i)).pmax().col();
+
+ lspace_med(groups_packed(i)).take(space);
+
+ }
+ }
+
+ for_all_components(i, filtered_objects.bboxes())
+ if (groups_packed(i) != 0 && lspace_med(groups_packed(i)).card() > 1)
+ {
+ unsigned med = lspace_med(groups_packed(i)).to_result();
+
+ mln::draw::box(output, grouped_objects.bbox(groups_packed(i)),
+ literal::purple);
+
+ point2d
+ beg = filtered_objects.bbox(i).pmax(),
+ end = beg;
+ beg.row() = filtered_objects.bbox(i).pmin().row();
+ mln::draw::line(output, beg, end, literal::cyan);
+ beg.col() += med;
+ end.col() += med;
+ mln::draw::line(output, beg, end, literal::cyan);
+
+ }
+
+ io::ppm::save(output, argv[2]);
+
+ }
+
+ trace::exiting("main");
+}
diff --git a/scribo/src/debug/show_info_x_height.cc b/scribo/src/debug/show_info_x_height.cc
new file mode 100644
index 0000000..e0c84a6
--- /dev/null
+++ b/scribo/src/debug/show_info_x_height.cc
@@ -0,0 +1,281 @@
+// 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/alias/neighb2d.hh>
+
+#include <mln/io/pbm/all.hh>
+#include <mln/io/ppm/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/extension/adjust.hh>
+
+#include <mln/accu/stat/median_h.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/primitive/extract/objects.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/debug/usage.hh>
+
+#include <scribo/make/debug_filename.hh>
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. 'False' for objects, 'True'\
+for the background." },
+ { "debug_dir", "Output directory for debug image" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace mln;
+
+ if (argc != 3 && argc != 4)
+ return scribo::debug::usage(argv,
+ "Find text lines using left/right validation and display x-height in a binarized article.",
+ "input.pbm out.ppm <debug_dir>",
+ args_desc,
+ "A color image. The following colors are used : dark blue for object bboxes, orange for single object bboxes, purple for group bboxes and light blue for x-height.");
+
+ if (argc == 4)
+ scribo::make::internal::debug_filename_prefix = argv[3];
+
+ trace::entering("main");
+
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ typedef image2d<value::label_16> L;
+
+ /// Finding objects.
+ std::cout << "Finding objects..." << std::endl;
+ value::label_16 nobjects;
+ object_image(L)
+ objects = scribo::primitive::extract::objects(input,
+ c8(),
+ nobjects);
+
+
+ /// First filtering.
+ std::cout << "Filtering objects..." << std::endl;
+ object_image(L) filtered_objects
+ = scribo::filter::objects_small(objects, 6);
+
+ /// Linking potential objects
+ std::cout << "Linking objects..." << std::endl;
+ object_links<L> left_link
+ = primitive::link::with_single_left_link_dmax_ratio(filtered_objects);
+ object_links<L> right_link
+ = primitive::link::with_single_right_link_dmax_ratio(filtered_objects);
+
+
+ // Validating left and right links.
+ object_links<L>
+ merged_links = primitive::link::merge_double_link(filtered_objects,
+ left_link,
+ right_link);
+
+#ifndef NOUT
+ if (argc == 4)
+ {
+ image2d<value::rgb8> output = data::convert(value::rgb8(), input);
+ scribo::draw::bounding_box_links(output,
+ filtered_objects.bboxes(),
+ merged_links,
+ literal::green);
+
+ util::array<bool> drawn(objects.nlabels(), 0);
+ for_all_components(i, objects.bboxes())
+ if (merged_links[i] == i && ! drawn(i))
+ {
+ mln::draw::box(output, objects.bbox(i), literal::orange);
+ drawn[i] = true;
+ }
+ else
+ {
+ mln::draw::box(output, objects.bbox(i), literal::blue);
+ mln::draw::box(output, objects.bbox(merged_links[i]), literal::blue);
+ drawn[i] = true;
+ drawn[merged_links[i]] = true;
+ }
+
+ 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_objects,
+ merged_links,
+ 2.0f);
+
+
+
+
+#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
+
+
+
+ // FIXME: from_single_link should return a packed object_groups?
+ //
+ //######
+ object_groups<L>
+ groups = primitive::group::from_single_link(filtered_objects,
+ hratio_filtered_links);
+ value::label_16 n_groups;
+ mln::fun::i2v::array<value::label_16>
+ groups_packed = mln::make::relabelfun(groups,
+ filtered_objects.nlabels(),
+ n_groups);
+ //######
+
+
+ std::cout << "Grouping objects..." << std::endl;
+ object_image(L)
+ grouped_objects = primitive::group::apply(filtered_objects, groups);
+
+
+
+ // Compute min_row/max_row median
+ std::cout << "Preparing output" << std::endl;
+ {
+ image2d<value::rgb8> output = data::convert(value::rgb8(), input);
+
+// scribo::draw::bounding_box_links(output,
+// filtered_objects.bboxes(),
+// hratio_filtered_links,
+// literal::green);
+
+ typedef mln::value::int_u<10> median_t;
+ typedef mln::accu::stat::median_h<median_t> accu_t;
+ util::array<accu_t>
+ med_min_row(static_cast<unsigned>(grouped_objects.nlabels()) + 1),
+ med_max_row(static_cast<unsigned>(grouped_objects.nlabels()) + 1);
+
+// std::cout << "Find median min/max rows" << std::endl;
+ for_all_components(i, filtered_objects.bboxes())
+ {
+ if (groups_packed(i) != 0)
+ {
+ med_min_row(groups_packed(i)).take(filtered_objects.bbox(i).pmin().row() - grouped_objects.bbox(groups_packed(i)).pmin().row());
+
+ med_max_row(groups_packed(i)).take(grouped_objects.bbox(groups_packed(i)).pmax().row() - filtered_objects.bbox(i).pmax().row());
+ }
+ }
+
+ // Output
+ std::cout << "Drawing bboxes" << std::endl;
+ util::array<bool> drawn(static_cast<unsigned>(filtered_objects.nlabels()) + 1, 0);
+ util::array<bool> single(static_cast<unsigned>(grouped_objects.nlabels()) + 1);
+ for_all_components(i, filtered_objects.bboxes())
+ if (hratio_filtered_links[i] == i && ! drawn(i))
+ {
+ mln::draw::box(output, filtered_objects.bbox(i), literal::orange);
+ drawn[i] = true;
+ single(groups_packed(i)) = true;
+ }
+ else
+ {
+ mln::draw::box(output, filtered_objects.bbox(i), literal::blue);
+ mln::draw::box(output, filtered_objects.bbox(hratio_filtered_links[i]),
+ literal::blue);
+ drawn[i] = true;
+ drawn[hratio_filtered_links[i]] = true;
+ single(groups_packed(i)) = false;
+ }
+
+// std::cout << "Drawing median lines" << std::endl;
+ for_all_components(i, grouped_objects.bboxes())
+ {
+ if (! single(i))
+ {
+ point2d
+ b_top(grouped_objects.bbox(i).pmin().row() + med_min_row(i).to_result(), grouped_objects.bbox(i).pmin().col()),
+ e_top(grouped_objects.bbox(i).pmin().row() + med_min_row(i).to_result(), grouped_objects.bbox(i).pmax().col()),
+ b_bot(grouped_objects.bbox(i).pmax().row() - med_max_row(i).to_result(), grouped_objects.bbox(i).pmin().col()),
+ e_bot(grouped_objects.bbox(i).pmax().row() - med_max_row(i).to_result(), grouped_objects.bbox(i).pmax().col());
+
+ mln::draw::box(output, grouped_objects.bbox(i), literal::purple);
+ mln::draw::line(output, b_top, e_top, literal::cyan);
+ mln::draw::line(output, b_bot, e_bot, literal::cyan);
+ }
+ }
+
+ io::ppm::save(output, argv[2]);
+ }
+
+ trace::exiting("main");
+}
diff --git a/scribo/src/debug/show_left_right_links_validation.cc b/scribo/src/debug/show_left_right_links_validation.cc
deleted file mode 100644
index bb23dd5..0000000
--- a/scribo/src/debug/show_left_right_links_validation.cc
+++ /dev/null
@@ -1,122 +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 <iostream>
-
-#include <mln/core/image/image2d.hh>
-#include <mln/labeling/colorize.hh>
-#include <mln/debug/println.hh>
-#include <mln/data/convert.hh>
-#include <mln/util/array.hh>
-#include <mln/literal/colors.hh>
-#include <mln/io/pbm/load.hh>
-#include <mln/io/ppm/save.hh>
-#include <mln/core/alias/neighb2d.hh>
-#include <mln/value/label_16.hh>
-
-#include <scribo/core/object_links.hh>
-#include <scribo/core/object_image.hh>
-
-#include <scribo/primitive/extract/objects.hh>
-
-#include <scribo/primitive/link/with_single_left_link.hh>
-#include <scribo/primitive/link/with_single_right_link.hh>
-#include <scribo/primitive/link/merge_double_link.hh>
-
-#include <scribo/draw/bounding_boxes.hh>
-#include <scribo/draw/bounding_box_links.hh>
-
-#include <scribo/debug/usage.hh>
-
-
-
-const char *args_desc[][2] =
-{
- { "input.pbm", "A binary image. 'True' for objects, 'False'\
-for the background." },
- { "hlmax", "Maximum distance between two grouped objects while browsing on the left." },
- { "hrmax", "Maximum distance between two grouped objects while browsing on the right." },
- {0, 0}
-};
-
-int main(int argc, char *argv[])
-{
- using namespace scribo;
- using namespace mln;
-
- if (argc != 5)
- return scribo::debug::usage(argv,
- "Display double validated (left and right) links between objects",
- "<input.pbm> <hlmax> <hrmax> <output.ppm>",
- args_desc,
- "A color image. Validated links are drawn in green.");
-
- image2d<bool> input;
- io::pbm::load(input, argv[1]);
-
- // Finding objects.
- value::label_16 nbboxes;
- typedef image2d<value::label_16> L;
- object_image(L) objects = primitive::extract::objects(input, c8(), nbboxes);
-
- // Left links.
- object_links<L> left_link
- = primitive::link::with_single_left_link(objects, atoi(argv[2]));
-
- // Right links.
- object_links<L> right_link
- = primitive::link::with_single_right_link(objects, atoi(argv[3]));
-
- // Validation.
- object_links<L>
- links = primitive::link::merge_double_link(objects, left_link, right_link);
-
-
- // Saving result.
- image2d<value::rgb8> output = data::convert(value::rgb8(), input);
-
-// scribo::draw::bounding_boxes(output, objects, literal::blue);
- scribo::draw::bounding_box_links(output,
- objects.bboxes(),
- links,
- literal::green);
-
- util::array<bool> drawn(objects.nlabels(), 0);
- for_all_components(i, objects.bboxes())
- if (links[i] == i && ! drawn(i))
- {
- mln::draw::box(output, objects.bbox(i), literal::orange);
- drawn[i] = true;
- }
- else
- {
- mln::draw::box(output, objects.bbox(i), literal::blue);
- mln::draw::box(output, objects.bbox(links[i]), literal::blue);
- drawn[i] = true;
- drawn[links[i]] = true;
- }
-
- io::ppm::save(output, argv[4]);
-}
diff --git a/scribo/src/debug/show_links_bbox_h_ratio.cc b/scribo/src/debug/show_links_bbox_h_ratio.cc
index 86841c6..4377b41 100644
--- a/scribo/src/debug/show_links_bbox_h_ratio.cc
+++ b/scribo/src/debug/show_links_bbox_h_ratio.cc
@@ -92,7 +92,7 @@ int main(int argc, char* argv[])
image2d<value::rgb8> hratio_decision_image
= scribo::debug::links_decision_image(input,
right_links,
- hratio_filtered_links);
+ hratio_filtered_links, 200);
io::ppm::save(hratio_decision_image, argv[3]);
}
diff --git a/scribo/src/debug/show_links_left_right_links_validation.cc b/scribo/src/debug/show_links_left_right_links_validation.cc
new file mode 100644
index 0000000..3c5d1bf
--- /dev/null
+++ b/scribo/src/debug/show_links_left_right_links_validation.cc
@@ -0,0 +1,122 @@
+// 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 <iostream>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/labeling/colorize.hh>
+#include <mln/debug/println.hh>
+#include <mln/data/convert.hh>
+#include <mln/util/array.hh>
+#include <mln/literal/colors.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/ppm/save.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/value/label_16.hh>
+
+#include <scribo/core/object_links.hh>
+#include <scribo/core/object_image.hh>
+
+#include <scribo/primitive/extract/objects.hh>
+
+#include <scribo/primitive/link/with_single_left_link.hh>
+#include <scribo/primitive/link/with_single_right_link.hh>
+#include <scribo/primitive/link/merge_double_link.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+#include <scribo/draw/bounding_box_links.hh>
+
+#include <scribo/debug/usage.hh>
+
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. 'True' for objects, 'False'\
+for the background." },
+ { "hlmax", "Maximum distance between two grouped objects while browsing on the left." },
+ { "hrmax", "Maximum distance between two grouped objects while browsing on the right." },
+ {0, 0}
+};
+
+int main(int argc, char *argv[])
+{
+ using namespace scribo;
+ using namespace mln;
+
+ if (argc != 5)
+ return scribo::debug::usage(argv,
+ "Display double validated (left and right) links between objects",
+ "<input.pbm> <hlmax> <hrmax> <output.ppm>",
+ args_desc,
+ "A color image. Validated links are drawn in green.");
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ // Finding objects.
+ value::label_16 nbboxes;
+ typedef image2d<value::label_16> L;
+ object_image(L) objects = primitive::extract::objects(input, c8(), nbboxes);
+
+ // Left links.
+ object_links<L> left_link
+ = primitive::link::with_single_left_link(objects, atoi(argv[2]));
+
+ // Right links.
+ object_links<L> right_link
+ = primitive::link::with_single_right_link(objects, atoi(argv[3]));
+
+ // Validation.
+ object_links<L>
+ links = primitive::link::merge_double_link(objects, left_link, right_link);
+
+
+ // Saving result.
+ image2d<value::rgb8> output = data::convert(value::rgb8(), input);
+
+// scribo::draw::bounding_boxes(output, objects, literal::blue);
+ scribo::draw::bounding_box_links(output,
+ objects.bboxes(),
+ links,
+ literal::green);
+
+ util::array<bool> drawn(static_cast<unsigned>(objects.nlabels()) + 1, 0);
+ for_all_components(i, objects.bboxes())
+ if (links[i] == i && ! drawn(i))
+ {
+ mln::draw::box(output, objects.bbox(i), literal::orange);
+ drawn[i] = true;
+ }
+ else
+ {
+ mln::draw::box(output, objects.bbox(i), literal::blue);
+ mln::draw::box(output, objects.bbox(links[i]), literal::blue);
+ drawn[i] = true;
+ drawn[links[i]] = true;
+ }
+
+ io::ppm::save(output, argv[4]);
+}
diff --git a/scribo/src/debug/show_links_single_down.cc b/scribo/src/debug/show_links_single_down.cc
new file mode 100644
index 0000000..37325d2
--- /dev/null
+++ b/scribo/src/debug/show_links_single_down.cc
@@ -0,0 +1,157 @@
+// 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 <iostream>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/data/convert.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/label_16.hh>
+#include <mln/literal/colors.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/draw/line.hh>
+
+#include <scribo/primitive/extract/objects.hh>
+#include <scribo/primitive/link/internal/link_ms_dmax_base.hh>
+#include <scribo/primitive/link/compute.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/debug/save_linked_bboxes_image.hh>
+#include <scribo/debug/usage.hh>
+
+
+namespace scribo
+{
+
+ template <typename I, typename L>
+ struct single_down_link_debug_functor
+ : primitive::link::internal::link_ms_dmax_base<L,
+ single_down_link_debug_functor<I, L> >
+ {
+ typedef single_down_link_debug_functor<I, L> self_t;
+ typedef
+ primitive::link::internal::link_ms_dmax_base<L, self_t> super_;
+
+ public:
+ typedef mln_site(L) P;
+
+ single_down_link_debug_functor(const I& input,
+ const object_image(L)& objects,
+ float dmax)
+ : super_(objects, dmax, 0)
+ {
+ output_ = data::convert(value::rgb8(), input);
+ scribo::draw::bounding_boxes(output_, objects, literal::blue);
+ mln_postcondition(output_.is_valid());
+ }
+
+ void validate_link_(unsigned current_object,
+ const P& start_point,
+ const P& p,
+ anchor::Type anchor)
+ {
+ mln::draw::line(output_, start_point, p, literal::green);
+
+ super_::validate_link_(current_object, start_point, p, anchor);
+ }
+
+
+
+ void invalidate_link_(unsigned current_object,
+ const P& start_point,
+ const P& p,
+ anchor::Type anchor)
+ {
+ if (output_.domain().has(p))
+ mln::draw::line(output_, start_point, p, literal::red);
+ else
+ {
+ P tmp = p;
+ --tmp.row();
+ mln::draw::line(output_, start_point, tmp, literal::red);
+ }
+
+ super_::invalidate_link_(current_object, start_point, p, anchor);
+ }
+
+
+
+ void compute_next_site_(P& p)
+ {
+ ++p.row();
+ }
+
+
+ image2d<value::rgb8> output_;
+ };
+
+
+}
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. True for objects and False for the background." },
+ { "max_nbh_dist", "The maximum lookup distance. (common value : 30)" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace scribo::primitive::internal;
+ using namespace mln;
+
+ if (argc != 4)
+ return scribo::debug::usage(argv,
+ "Show sucessful/unsuccessful down links between components.",
+ "input.pbm max_nbh_dist output.ppm",
+ args_desc,
+ "A color image. Valid links are drawn in green, invalid ones in red.");
+
+ typedef image2d<bool> I;
+ I input;
+ io::pbm::load(input, argv[1]);
+
+ // Finding objects.
+ value::label_16 nbboxes;
+ typedef image2d<value::label_16> L;
+ object_image(L) objects
+ = scribo::primitive::extract::objects(input, c8(), nbboxes);
+
+ // Write debug image.
+ single_down_link_debug_functor<I, L> functor(input, objects, atof(argv[2]));
+ primitive::link::compute(functor);
+
+ io::ppm::save(functor.output_, argv[3]);
+}
diff --git a/scribo/src/debug/show_links_single_down_left_aligned.cc b/scribo/src/debug/show_links_single_down_left_aligned.cc
new file mode 100644
index 0000000..b094d6e
--- /dev/null
+++ b/scribo/src/debug/show_links_single_down_left_aligned.cc
@@ -0,0 +1,99 @@
+// 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 <iostream>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/data/convert.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/label_16.hh>
+#include <mln/literal/colors.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/math/pi.hh>
+
+#include <mln/draw/line.hh>
+
+#include <scribo/primitive/extract/objects.hh>
+#include <scribo/primitive/link/with_single_down_link.hh>
+#include <scribo/primitive/link/compute.hh>
+#include <scribo/filter/object_links_left_aligned.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/debug/save_linked_bboxes_image.hh>
+#include <scribo/debug/usage.hh>
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. True for objects and False for the background." },
+ { "dmax", "The maximum lookup distance. (common value : 300)" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace scribo::primitive::internal;
+ using namespace mln;
+
+ if (argc != 4)
+ return scribo::debug::usage(argv,
+ "Show sucessful/unsuccessful down links between components.",
+ "input.pbm dmax output.ppm",
+ args_desc,
+ "A color image. Valid links are drawn in green, invalid ones in red.");
+
+ typedef image2d<bool> I;
+ I input;
+ io::pbm::load(input, argv[1]);
+
+ // Finding objects.
+ value::label_16 nbboxes;
+ typedef image2d<value::label_16> L;
+ object_image(L) objects
+ = scribo::primitive::extract::objects(input, c8(), nbboxes);
+
+
+ object_links<L>
+ down_links = primitive::link::with_single_down_link(objects,
+ atof(argv[2]),
+ anchor::Left);
+
+ // Filtering.
+ down_links = filter::object_links_left_aligned(objects, down_links, 5);
+
+
+ scribo::debug::save_linked_bboxes_image(input, objects, down_links,
+ literal::blue, literal::green,
+ argv[3], anchor::ActualLeft);
+}
diff --git a/scribo/src/debug/show_links_single_down_right_aligned.cc b/scribo/src/debug/show_links_single_down_right_aligned.cc
new file mode 100644
index 0000000..9a12c0d
--- /dev/null
+++ b/scribo/src/debug/show_links_single_down_right_aligned.cc
@@ -0,0 +1,99 @@
+// 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 <iostream>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/data/convert.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/label_16.hh>
+#include <mln/literal/colors.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/math/pi.hh>
+
+#include <mln/draw/line.hh>
+
+#include <scribo/primitive/extract/objects.hh>
+#include <scribo/primitive/link/with_single_down_link.hh>
+#include <scribo/primitive/link/compute.hh>
+#include <scribo/filter/object_links_right_aligned.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/debug/save_linked_bboxes_image.hh>
+#include <scribo/debug/usage.hh>
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. True for objects and False for the background." },
+ { "dmax", "The maximum lookup distance. (common value : 300)" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace scribo::primitive::internal;
+ using namespace mln;
+
+ if (argc != 4)
+ return scribo::debug::usage(argv,
+ "Show sucessful/unsuccessful down links between components.",
+ "input.pbm dmax output.ppm",
+ args_desc,
+ "A color image. Valid links are drawn in green, invalid ones in red.");
+
+ typedef image2d<bool> I;
+ I input;
+ io::pbm::load(input, argv[1]);
+
+ // Finding objects.
+ value::label_16 nbboxes;
+ typedef image2d<value::label_16> L;
+ object_image(L) objects
+ = scribo::primitive::extract::objects(input, c8(), nbboxes);
+
+
+ object_links<L>
+ down_links = primitive::link::with_single_down_link(objects,
+ atof(argv[2]),
+ anchor::Right);
+
+ // Filtering.
+ down_links = filter::object_links_right_aligned(objects, down_links, 5);
+
+
+ scribo::debug::save_linked_bboxes_image(input, objects, down_links,
+ literal::blue, literal::green,
+ argv[3], anchor::ActualRight);
+}
diff --git a/scribo/src/debug/show_links_single_up.cc b/scribo/src/debug/show_links_single_up.cc
new file mode 100644
index 0000000..59c8ce5
--- /dev/null
+++ b/scribo/src/debug/show_links_single_up.cc
@@ -0,0 +1,157 @@
+// 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 <iostream>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/data/convert.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/label_16.hh>
+#include <mln/literal/colors.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/draw/line.hh>
+
+#include <scribo/primitive/extract/objects.hh>
+#include <scribo/primitive/link/internal/link_ms_dmax_base.hh>
+#include <scribo/primitive/link/compute.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/debug/save_linked_bboxes_image.hh>
+#include <scribo/debug/usage.hh>
+
+
+namespace scribo
+{
+
+ template <typename I, typename L>
+ struct single_up_link_debug_functor
+ : primitive::link::internal::link_ms_dmax_base<L,
+ single_up_link_debug_functor<I, L> >
+ {
+ typedef single_up_link_debug_functor<I, L> self_t;
+ typedef
+ primitive::link::internal::link_ms_dmax_base<L, self_t> super_;
+
+ public:
+ typedef mln_site(L) P;
+
+ single_up_link_debug_functor(const I& input,
+ const object_image(L)& objects,
+ float dmax)
+ : super_(objects, dmax)
+ {
+ output_ = data::convert(value::rgb8(), input);
+ scribo::draw::bounding_boxes(output_, objects, literal::blue);
+ mln_postcondition(output_.is_valid());
+ }
+
+ void validate_link_(unsigned current_object,
+ const P& start_point,
+ const P& p,
+ anchor::Type anchor)
+ {
+ mln::draw::line(output_, start_point, p, literal::green);
+
+ super_::validate_link_(current_object, start_point, p, anchor);
+ }
+
+
+
+ void invalidate_link_(unsigned current_object,
+ const P& start_point,
+ const P& p,
+ anchor::Type anchor)
+ {
+ if (output_.domain().has(p))
+ mln::draw::line(output_, start_point, p, literal::red);
+ else
+ {
+ P tmp = p;
+ ++tmp.row();
+ mln::draw::line(output_, start_point, tmp, literal::red);
+ }
+
+ super_::invalidate_link_(current_object, start_point, p, anchor);
+ }
+
+
+
+ void compute_next_site_(P& p)
+ {
+ --p.row();
+ }
+
+
+ image2d<value::rgb8> output_;
+ };
+
+
+}
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. True for objects and False for the background." },
+ { "max_nbh_dist", "The maximum lookup distance. (common value : 30)" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace scribo::primitive::internal;
+ using namespace mln;
+
+ if (argc != 4)
+ return scribo::debug::usage(argv,
+ "Show sucessful/unsuccessful up links between components.",
+ "input.pbm max_nbh_dist output.ppm",
+ args_desc,
+ "A color image. Valid links are drawn in green, invalid ones in red.");
+
+ typedef image2d<bool> I;
+ I input;
+ io::pbm::load(input, argv[1]);
+
+ // Finding objects.
+ value::label_16 nbboxes;
+ typedef image2d<value::label_16> L;
+ object_image(L) objects
+ = scribo::primitive::extract::objects(input, c8(), nbboxes);
+
+ // Write debug image.
+ single_up_link_debug_functor<I, L> functor(input, objects, atof(argv[2]));
+ primitive::link::compute(functor);
+
+ io::ppm::save(functor.output_, argv[3]);
+}
diff --git a/scribo/src/debug/show_links_single_up_left_aligned.cc b/scribo/src/debug/show_links_single_up_left_aligned.cc
new file mode 100644
index 0000000..5239619
--- /dev/null
+++ b/scribo/src/debug/show_links_single_up_left_aligned.cc
@@ -0,0 +1,100 @@
+// 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 <iostream>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/data/convert.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/label_16.hh>
+#include <mln/literal/colors.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/math/pi.hh>
+
+#include <mln/draw/line.hh>
+
+#include <scribo/primitive/extract/objects.hh>
+#include <scribo/primitive/link/with_single_up_link.hh>
+#include <scribo/primitive/link/compute.hh>
+#include <scribo/filter/object_links_left_aligned.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/debug/save_linked_bboxes_image.hh>
+#include <scribo/debug/usage.hh>
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. True for objects and False for the background." },
+ { "dmax", "The maximum lookup distance. (common value : 300)" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace scribo::primitive::internal;
+ using namespace mln;
+
+ if (argc != 4)
+ return scribo::debug::usage(argv,
+ "Show sucessful/unsuccessful up links between components.",
+ "input.pbm dmax output.ppm",
+ args_desc,
+ "A color image. Valid links are drawn in green, invalid ones in red.");
+
+ typedef image2d<bool> I;
+ I input;
+ io::pbm::load(input, argv[1]);
+
+ // Finding objects.
+ value::label_16 nbboxes;
+ typedef image2d<value::label_16> L;
+ object_image(L) objects
+ = scribo::primitive::extract::objects(input, c8(), nbboxes);
+
+
+ object_links<L>
+ up_links = primitive::link::with_single_up_link(objects,
+ atof(argv[2]),
+ anchor::Left);
+
+
+ // Filtering.
+ up_links = filter::object_links_left_aligned(objects, up_links, 5);
+
+
+ scribo::debug::save_linked_bboxes_image(input, objects, up_links,
+ literal::blue, literal::green,
+ argv[3], anchor::ActualLeft);
+}
diff --git a/scribo/src/debug/show_links_single_up_right_aligned.cc b/scribo/src/debug/show_links_single_up_right_aligned.cc
new file mode 100644
index 0000000..8c1841e
--- /dev/null
+++ b/scribo/src/debug/show_links_single_up_right_aligned.cc
@@ -0,0 +1,98 @@
+// 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 <iostream>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/data/convert.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/label_16.hh>
+#include <mln/literal/colors.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/math/pi.hh>
+
+#include <mln/draw/line.hh>
+
+#include <scribo/primitive/extract/objects.hh>
+#include <scribo/primitive/link/with_single_up_link.hh>
+#include <scribo/primitive/link/compute.hh>
+#include <scribo/filter/object_links_right_aligned.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/debug/save_linked_bboxes_image.hh>
+#include <scribo/debug/usage.hh>
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. True for objects and False for the background." },
+ { "dmax", "The maximum lookup distance. (common value : 300)" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace scribo::primitive::internal;
+ using namespace mln;
+
+ if (argc != 4)
+ return scribo::debug::usage(argv,
+ "Show sucessful/unsuccessful up links between components.",
+ "input.pbm dmax output.ppm",
+ args_desc,
+ "A color image. Valid links are drawn in green, invalid ones in red.");
+
+ typedef image2d<bool> I;
+ I input;
+ io::pbm::load(input, argv[1]);
+
+ // Finding objects.
+ value::label_16 nbboxes;
+ typedef image2d<value::label_16> L;
+ object_image(L) objects
+ = scribo::primitive::extract::objects(input, c8(), nbboxes);
+
+ object_links<L>
+ up_links = primitive::link::with_single_up_link(objects,
+ atof(argv[2]),
+ anchor::Right);
+
+ // Filtering.
+ up_links = filter::object_links_right_aligned(objects, up_links, 5);
+
+
+ scribo::debug::save_linked_bboxes_image(input, objects, up_links,
+ literal::blue, literal::green,
+ argv[3], anchor::ActualRight);
+}
diff --git a/scribo/src/filter/Makefile.am b/scribo/src/filter/Makefile.am
index e8a2b9c..98f8371 100644
--- a/scribo/src/filter/Makefile.am
+++ b/scribo/src/filter/Makefile.am
@@ -23,9 +23,13 @@ bin_PROGRAMS = \
objects_large \
objects_small \
objects_thick \
- objects_thin
+ objects_thin \
+ objects_with_holes \
+ objects_with_holes_pgm
objects_large_SOURCES = objects_large.cc
objects_small_SOURCES = objects_small.cc
objects_thick_SOURCES = objects_thick.cc
objects_thin_SOURCES = objects_thin.cc
+objects_with_holes_SOURCES = objects_with_holes.cc
+objects_with_holes_pgm_SOURCES = objects_with_holes_pgm.cc
diff --git a/scribo/src/filter/objects_with_holes.cc b/scribo/src/filter/objects_with_holes.cc
new file mode 100644
index 0000000..0ebf89f
--- /dev/null
+++ b/scribo/src/filter/objects_with_holes.cc
@@ -0,0 +1,70 @@
+// 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_16.hh>
+
+#include <scribo/filter/objects_with_holes.hh>
+#include <scribo/debug/usage.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." },
+ {0, 0}
+};
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+
+ if (argc != 4)
+ return scribo::debug::usage(argv,
+ "Filter objects with holes",
+ "input.pbm min_holes_count output.pbm",
+ args_desc,
+ "A binary image.");
+
+ trace::entering("main");
+
+ typedef image2d<bool> I;
+ 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);
+
+ obj_ima_t filtered = scribo::filter::objects_with_holes(objects, atoi(argv[2]));
+ io::pbm::save(data::convert(bool(), filtered), argv[3]);
+
+ trace::exiting("main");
+
+}
diff --git a/scribo/src/filter/objects_with_holes_pgm.cc b/scribo/src/filter/objects_with_holes_pgm.cc
new file mode 100644
index 0000000..c834538
--- /dev/null
+++ b/scribo/src/filter/objects_with_holes_pgm.cc
@@ -0,0 +1,71 @@
+// 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/data/compute.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/value/label_8.hh>
+#include <mln/accu/stat/max.hh>
+
+#include <scribo/filter/objects_with_holes.hh>
+#include <scribo/debug/usage.hh>
+
+const char *args_desc[][2] =
+{
+ { "input.pgm", "A label image. 'True' for objects, 'False'\
+for the background." },
+ { "min_holes_count", "The minimum holes per objects." },
+ {0, 0}
+};
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+
+ if (argc != 4)
+ return scribo::debug::usage(argv,
+ "Filter objects with holes",
+ "input.pgm min_holes_count output.pbm",
+ args_desc,
+ "A binary image.");
+
+ trace::entering("main");
+
+ typedef image2d<value::label_8> I;
+ I input;
+ io::pgm::load(input, argv[1]);
+
+ value::label_8 nobjects = data::compute(accu::meta::stat::max(), input);
+ object_image(I) objects(input, nobjects);
+
+ object_image(I) filtered = scribo::filter::objects_with_holes(objects, atoi(argv[2]));
+ io::pbm::save(data::convert(bool(), filtered), argv[3]);
+
+ trace::exiting("main");
+
+}
diff --git a/scribo/src/pbm_lines_in_doc.cc b/scribo/src/pbm_lines_in_doc.cc
new file mode 100644
index 0000000..8363b61
--- /dev/null
+++ b/scribo/src/pbm_lines_in_doc.cc
@@ -0,0 +1,299 @@
+// 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 <fstream>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+
+#include <mln/logical/not.hh>
+
+#include <mln/labeling/colorize.hh>
+
+#include <mln/io/pbm/all.hh>
+#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/draw/box.hh>
+
+#include <mln/extension/adjust.hh>
+
+#include <scribo/table/erase.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/primitive/extract/objects.hh>
+#include <scribo/primitive/extract/lines_h_discontinued.hh>
+#include <scribo/primitive/extract/lines_v_discontinued.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_bottom_aligned.hh>
+#include <scribo/filter/object_links_bbox_h_ratio.hh>
+#include <scribo/filter/object_links_bbox_overlap.hh>
+
+#include <scribo/filter/objects_large.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/debug/usage.hh>
+
+#include <scribo/make/debug_filename.hh>
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. 'False' for objects, 'True'\
+for the background." },
+ { "out.ppm", "Show the text found in the input." },
+ { "object_label.dump", "Object labeled image." },
+ { "line_label.dump", "Text lines labeled image." },
+ { "bbox_100p.txt", "Text file containing pmin and pmax of text line bounding boxes." },
+ { "bbox_50p.txt", "Text file containing pmin and pmax of text line bounding boxes." },
+ { "output_dir", "Output directory for debug image" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace mln;
+
+ if (argc != 7 && argc != 8)
+ return scribo::debug::usage(argv,
+ "Find text lines in a document",
+ "input.pbm out.ppm object_label.dump line_label.dump bbox_100p.txt bbox_50p.txt [output_dir]",
+ args_desc,
+ "Debug outputs. The recognized text is printed in the standard output.");
+
+ if (argc == 8)
+ scribo::make::internal::debug_filename_prefix = argv[7];
+
+ trace::entering("main");
+
+
+ bool enable_debug = (argc == 5);
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ typedef image2d<value::label_16> L;
+
+ /// Finding objects.
+ std::cout << "Finding objects..." << std::endl;
+ value::label_16 nobjects;
+ object_image(L)
+ objects = scribo::primitive::extract::objects(input,
+ c8(),
+ nobjects);
+
+
+ /// First filtering.
+ std::cout << "Filtering objects..." << std::endl;
+ object_image(L) filtered_objects
+ = scribo::filter::objects_small(objects, 6);
+
+
+ filtered_objects
+ = scribo::filter::objects_large(filtered_objects,
+ math::min(input.ncols(), input.nrows())
+ * math::min(input.ncols(), input.nrows()) / 5);
+
+
+
+ /// Linking potential objects
+ std::cout << "Linking objects..." << std::endl;
+ object_links<L> left_link
+ = primitive::link::with_single_left_link_dmax_ratio(filtered_objects);
+ object_links<L> right_link
+ = primitive::link::with_single_right_link_dmax_ratio(filtered_objects);
+
+
+#ifndef NOUT
+ if (enable_debug)
+ {
+ std::cerr << "BEFORE - nobjects = " << nobjects << 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.
+ object_links<L>
+ merged_links = primitive::link::merge_double_link(filtered_objects,
+ left_link,
+ right_link);
+
+
+
+
+ // Remove links if bboxes have too different sizes.
+ object_links<L> hratio_filtered_links
+ = filter::object_links_bbox_h_ratio(filtered_objects,
+ merged_links,
+ 2.0f);
+
+
+
+
+#ifndef NOUT
+ if (enable_debug)
+ {
+ 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.8f);
+
+
+
+
+#ifndef NOUT
+ if (enable_debug)
+ {
+ 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
+
+
+
+
+ object_groups<L>
+ groups = primitive::group::from_single_link(filtered_objects,
+ overlap_filtered_links);
+
+
+ std::cout << "Grouping objects..." << std::endl;
+ object_image(L)
+ grouped_objects = primitive::group::apply(filtered_objects, groups);
+
+
+
+ std::cout << "Saving line bboxes..." << std::endl;
+
+ // 100p bboxes
+ {
+ std::ofstream out;
+ out.open(argv[5], std::ios_base::trunc);
+
+ if (! out)
+ {
+ std::cout << "Can't create output file!" << std::endl;
+ return 1;
+ }
+
+ for_all_ncomponents(i, grouped_objects.nlabels())
+ {
+ out << grouped_objects.bbox(i).pmin().row() << " "
+ << grouped_objects.bbox(i).pmin().col()
+ << " "
+ << grouped_objects.bbox(i).pmax().row() << " "
+ << grouped_objects.bbox(i).pmax().col()
+ << std::endl;
+ }
+ out.close();
+
+ }
+
+ // 50p bboxes
+ {
+ std::ofstream out;
+ out.open(argv[6], std::ios_base::trunc);
+
+ if (! out)
+ {
+ std::cout << "Can't create output file!" << std::endl;
+ return 1;
+ }
+
+ for_all_ncomponents(i, grouped_objects.nlabels())
+ {
+ out << grouped_objects.bbox(i).pmin().row() / 2 << " "
+ << grouped_objects.bbox(i).pmin().col() / 2
+ << " "
+ << grouped_objects.bbox(i).pmax().row() / 2 << " "
+ << grouped_objects.bbox(i).pmax().col() / 2
+ << std::endl;
+ }
+ out.close();
+
+ }
+
+ scribo::debug::save_bboxes_image(input, grouped_objects.bboxes(),
+ literal::red,
+ argv[2]);
+
+ io::dump::save(filtered_objects, argv[3]);
+ io::dump::save(grouped_objects, argv[4]);
+
+ trace::exiting("main");
+}
diff --git a/scribo/src/preprocessing/Makefile.am b/scribo/src/preprocessing/Makefile.am
index 8c1cd80..086a70f 100644
--- a/scribo/src/preprocessing/Makefile.am
+++ b/scribo/src/preprocessing/Makefile.am
@@ -22,8 +22,10 @@ include $(top_srcdir)/scribo/scribo.mk
bin_PROGRAMS = \
preprocess \
split_bg_fg \
+ split_bg_fg_ms \
unskew
preprocess_SOURCES = preprocess.cc
split_bg_fg_SOURCES = split_bg_fg.cc
+split_bg_fg_ms_SOURCES = split_bg_fg_ms.cc
unskew_SOURCES = unskew.cc
diff --git a/scribo/src/preprocessing/split_bg_fg_ms.cc b/scribo/src/preprocessing/split_bg_fg_ms.cc
new file mode 100644
index 0000000..4c0180a
--- /dev/null
+++ b/scribo/src/preprocessing/split_bg_fg_ms.cc
@@ -0,0 +1,109 @@
+// 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_in_article.cc b/scribo/src/text_in_article.cc
new file mode 100644
index 0000000..d140719
--- /dev/null
+++ b/scribo/src/text_in_article.cc
@@ -0,0 +1,327 @@
+// 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/alias/neighb2d.hh>
+
+#include <mln/io/pbm/all.hh>
+#include <mln/io/ppm/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/extension/adjust.hh>
+
+#include <mln/accu/stat/median_h.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+#include <scribo/primitive/extract/objects.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/debug/usage.hh>
+
+#include <scribo/make/debug_filename.hh>
+
+
+const char *args_desc[][2] =
+{
+ { "input.pbm", "A binary image. 'False' for objects, 'True'\
+for the background." },
+ { "debug_dir", "Output directory for debug image" },
+ {0, 0}
+};
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace mln;
+
+ if (argc != 3 && argc != 4)
+ return scribo::debug::usage(argv,
+ "Find text lines using left/right validation and display x-height in a binarized article.",
+ "input.pbm out.ppm <debug_dir>",
+ args_desc,
+ "A color image. The following colors are used : dark blue for object bboxes, orange for single object bboxes, purple for group bboxes and light blue for x-height.");
+
+ if (argc == 4)
+ scribo::make::internal::debug_filename_prefix = argv[3];
+
+ trace::entering("main");
+
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ typedef image2d<value::label_16> L;
+
+ /// Finding objects.
+ std::cout << "Finding objects..." << std::endl;
+ value::label_16 nobjects;
+ object_image(L)
+ objects = scribo::primitive::extract::objects(input,
+ c8(),
+ nobjects);
+
+
+ /// First filtering.
+ std::cout << "Filtering objects..." << std::endl;
+ object_image(L) filtered_objects
+ = scribo::filter::objects_small(objects, 6);
+
+ /// Linking potential objects
+ std::cout << "Linking objects..." << std::endl;
+ object_links<L> left_link
+ = primitive::link::with_single_left_link_dmax_ratio(filtered_objects);
+ object_links<L> right_link
+ = primitive::link::with_single_right_link_dmax_ratio(filtered_objects);
+
+
+ // Validating left and right links.
+ object_links<L>
+ merged_links = primitive::link::merge_double_link(filtered_objects,
+ 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);
+
+ util::array<bool> drawn(objects.nlabels(), 0);
+ for_all_components(i, objects.bboxes())
+ if (merged_links[i] == i && ! drawn(i))
+ {
+ mln::draw::box(output, objects.bbox(i), literal::orange);
+ drawn[i] = true;
+ }
+ else
+ {
+ mln::draw::box(output, objects.bbox(i), literal::blue);
+ mln::draw::box(output, objects.bbox(merged_links[i]), literal::blue);
+ drawn[i] = true;
+ drawn[merged_links[i]] = true;
+ }
+
+ 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_objects,
+ merged_links,
+ 2.0f);
+
+
+
+
+#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
+
+
+
+ // FIXME: from_single_link should return a packed object_groups?
+ //
+ //######
+ object_groups<L>
+ groups = primitive::group::from_single_link(filtered_objects,
+ hratio_filtered_links);
+ value::label_16 n_groups;
+ mln::fun::i2v::array<value::label_16>
+ groups_packed = mln::make::relabelfun(groups,
+ filtered_objects.nlabels(),
+ n_groups);
+ //######
+
+
+ std::cout << "Grouping objects..." << std::endl;
+ object_image(L)
+ grouped_objects = primitive::group::apply(filtered_objects, groups);
+
+
+
+ // Compute min_row/max_row median
+ std::cout << "Preparing output" << std::endl;
+ {
+ image2d<value::rgb8> output = data::convert(value::rgb8(), input);
+
+// scribo::draw::bounding_box_links(output,
+// filtered_objects.bboxes(),
+// hratio_filtered_links,
+// literal::green);
+
+ typedef mln::value::int_u<10> median_t;
+ typedef mln::accu::stat::median_h<median_t> accu_t;
+ util::array<accu_t>
+ med_min_row(static_cast<unsigned>(grouped_objects.nlabels()) + 1),
+ med_max_row(static_cast<unsigned>(grouped_objects.nlabels()) + 1);
+
+// std::cout << "Find median min/max rows" << std::endl;
+ for_all_components(i, filtered_objects.bboxes())
+ {
+ if (groups_packed(i) != 0)
+ {
+ med_min_row(groups_packed(i)).take(filtered_objects.bbox(i).pmin().row() - grouped_objects.bbox(groups_packed(i)).pmin().row());
+
+ med_max_row(groups_packed(i)).take(grouped_objects.bbox(groups_packed(i)).pmax().row() - filtered_objects.bbox(i).pmax().row());
+ }
+ }
+
+ // Output
+ std::cout << "Drawing bboxes" << std::endl;
+ util::array<bool> drawn(static_cast<unsigned>(filtered_objects.nlabels()) + 1, 0);
+ util::array<bool> single(static_cast<unsigned>(grouped_objects.nlabels()) + 1);
+ for_all_components(i, filtered_objects.bboxes())
+ if (hratio_filtered_links[i] == i && ! drawn(i))
+ {
+ mln::draw::box(output, filtered_objects.bbox(i), literal::orange);
+ drawn[i] = true;
+ single(groups_packed(i)) = true;
+ }
+ else
+ {
+ mln::draw::box(output, filtered_objects.bbox(i), literal::blue);
+ mln::draw::box(output, filtered_objects.bbox(hratio_filtered_links[i]),
+ literal::blue);
+ drawn[i] = true;
+ drawn[hratio_filtered_links[i]] = true;
+ single(groups_packed(i)) = false;
+ }
+
+// std::cout << "Drawing median lines" << std::endl;
+ for_all_components(i, grouped_objects.bboxes())
+ {
+ if (! single(i))
+ {
+ point2d
+ b_top(grouped_objects.bbox(i).pmin().row() + med_min_row(i).to_result(), grouped_objects.bbox(i).pmin().col()),
+ e_top(grouped_objects.bbox(i).pmin().row() + med_min_row(i).to_result(), grouped_objects.bbox(i).pmax().col()),
+ b_bot(grouped_objects.bbox(i).pmax().row() - med_max_row(i).to_result(), grouped_objects.bbox(i).pmin().col()),
+ e_bot(grouped_objects.bbox(i).pmax().row() - med_max_row(i).to_result(), grouped_objects.bbox(i).pmax().col());
+
+ mln::draw::box(output, grouped_objects.bbox(i), literal::purple);
+ mln::draw::line(output, b_top, e_top, literal::cyan);
+ mln::draw::line(output, b_bot, e_bot, literal::cyan);
+ }
+ }
+
+ io::ppm::save(output, argv[2]);
+ }
+
+
+
+ // Display median character space.
+ {
+ image2d<value::rgb8> output = data::convert(value::rgb8(), input);
+ typedef mln::value::int_u<8> median_t;
+ typedef mln::accu::stat::median_h<median_t> accu_t;
+ util::array<accu_t>
+ lspace_med(static_cast<unsigned>(grouped_objects.nlabels()) + 1);
+
+ for_all_components(i, filtered_objects.bboxes())
+ if (groups_packed(i) != 0)
+ {
+ if (hratio_filtered_links(i) != i)
+ {
+ unsigned
+ space = filtered_objects.bbox(i).pmin().col() - filtered_objects.bbox(hratio_filtered_links(i)).pmax().col();
+
+ lspace_med(groups_packed(i)).take(space);
+
+ }
+ }
+
+ std::cout << "Drawing median character space" << std::endl;
+ for_all_components(i, filtered_objects.bboxes())
+ if (groups_packed(i) != 0 && lspace_med(groups_packed(i)).card() > 1)
+ {
+ unsigned med = lspace_med(groups_packed(i)).to_result();
+
+ mln::draw::box(output, grouped_objects.bbox(groups_packed(i)),
+ literal::purple);
+
+ point2d
+ beg = filtered_objects.bbox(i).pmax(),
+ end = beg;
+ beg.row() = filtered_objects.bbox(i).pmin().row();
+ mln::draw::line(output, beg, end, literal::cyan);
+ beg.col() += med;
+ end.col() += med;
+ mln::draw::line(output, beg, end, literal::cyan);
+
+ }
+
+ io::ppm::save(output, "median_wspace.ppm");
+
+ }
+
+ trace::exiting("main");
+}
diff --git a/scribo/src/text_in_photo_ppm_fast.cc b/scribo/src/text_in_photo_ppm_fast.cc
new file mode 100644
index 0000000..4a7562f
--- /dev/null
+++ b/scribo/src/text_in_photo_ppm_fast.cc
@@ -0,0 +1,658 @@
+// 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.\n\n\
+Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1 1",
+ "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.");
+
+ std::string out_base_dir;
+ bool debug = false;
+ if (argc > 8)
+ {
+ scribo::make::internal::debug_filename_prefix = argv[8];
+ debug = true;
+ out_base_dir = argv[8];
+ }
+
+ trace::entering("main");
+
+ image2d<value::rgb8> input_rgb;
+ io::ppm::load(input_rgb, argv[1]);
+
+
+ unsigned lambda;
+ if (argc == 10)
+ lambda = atoi(argv[9]);
+ else
+ lambda = 1.2 * (input_rgb.nrows() + input_rgb.ncols());
+
+ std::cout << "Using lambda = " << lambda << std::endl;
+
+ 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;
+
+#ifndef NOUT
+ if (debug)
+ {
+ io::ppm::save(fg, scribo::make::debug_filename("foreground.ppm"));
+ }
+
+#endif // !NOUT
+ }
+ 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);
+ }
+#ifndef NOUT
+ if (debug)
+ {
+ io::pbm::save(input,
+ scribo::make::debug_filename("binarization.pbm"));
+ }
+
+#endif // !NOUT
+
+
+// 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 (debug)
+ {
+ 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 (debug)
+ {
+ 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 (debug)
+ {
+ 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,
+ groups);
+#endif // !NOUT
+
+ t_ = timer_;
+ std::cout << "Objects grouped. " << t_ << std::endl;
+
+#ifndef NOUT
+
+ if (debug)
+ {
+ image2d<value::rgb8> decision_image = data::convert(value::rgb8(), input);
+
+ scribo::draw::bounding_boxes(decision_image, filtered_objects, literal::green);
+ scribo::draw::bounding_boxes(decision_image, raw_group_image, literal::blue);
+
+ io::ppm::save(decision_image,
+ scribo::make::debug_filename("group_and_object_image.ppm"));
+
+ decision_image = data::convert(value::rgb8(), input);
+ scribo::draw::bounding_boxes(decision_image, raw_group_image, literal::blue);
+ io::ppm::save(decision_image,
+ 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;
+ 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;
+
+
+
+#ifndef NOUT
+ object_image(L) debug_image;
+ image2d<value::rgb8> decision_image;
+ if (debug)
+ {
+ decision_image = data::convert(value::rgb8(), input);
+ object_image(L)
+ grouped_objects = primitive::group::apply(filtered_objects,
+ filtered_small_groups);
+
+ for_all_components(i, filtered_objects.bboxes())
+ if (filtered_small_groups(i) != 0)
+ mln::draw::box(decision_image, filtered_objects.bbox(i), literal::green);
+ scribo::draw::bounding_boxes(decision_image, raw_group_image, literal::red);
+ scribo::draw::bounding_boxes(decision_image, grouped_objects, literal::blue);
+
+ io::ppm::save(decision_image,
+ scribo::make::debug_filename("small_groups_filter.ppm"));
+ debug_image = grouped_objects;
+ }
+#endif
+
+
+
+ // 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;
+
+
+#ifndef NOUT
+ if (debug)
+ {
+ decision_image = data::convert(value::rgb8(), input);
+
+ object_image(L)
+ grouped_objects = primitive::group::apply(filtered_objects,
+ filtered_thin_groups);
+
+ for_all_components(i, filtered_objects.bboxes())
+ {
+ if (filtered_thin_groups(i) != 0)
+ mln::draw::box(decision_image, filtered_objects.bbox(i), literal::green);
+ }
+
+ scribo::draw::bounding_boxes(decision_image, debug_image, literal::red);
+ scribo::draw::bounding_boxes(decision_image, grouped_objects, literal::blue);
+
+ io::ppm::save(decision_image,
+ scribo::make::debug_filename("thin_groups_filter.ppm"));
+ debug_image = grouped_objects;
+ }
+#endif
+
+
+
+ /// Apply grouping in the object image.
+ g_timer.restart();
+
+// groups = primitive::group::regroup_left(filtered_objects,
+// filtered_thin_groups,
+// 30);
+
+ 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::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);
+
+ t_ = g_timer;
+ std::cout << "Link and group again " << t_ << std::endl;
+
+ timer_.stop();
+
+// if (debug)
+// io::ppm::save(mln::labeling::colorize(value::rgb8(),
+// grouped_objects,
+// grouped_objects.nlabels()),
+// scribo::make::debug_filename("out_raw.ppm"));
+
+
+ timer_.resume();
+
+// io::pgm::save(data::wrap(value::int_u8(), grouped_objects.labeled_image_()), "lbl_to_be_filtered.pgm");
+
+ 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;
+
+
+ t_ = global_t_;
+ std::cout << "*** Result computed " << t_ << std::endl;
+
+#ifndef NOUT
+ if (debug)
+ {
+ decision_image = data::convert(value::rgb8(), input);
+
+ scribo::draw::bounding_boxes(decision_image, debug_image, literal::red);
+ scribo::draw::bounding_boxes(decision_image, grouped_objects, literal::blue);
+ io::ppm::save(decision_image, scribo::make::debug_filename("group_with_holes_filter.ppm"));
+
+ std::cerr << "AFTER - nobjects = " << grouped_objects.nlabels() << std::endl;
+ }
+#endif
+
+ timer_.restart();
+ std::cout << "Saving result..." << std::endl;
+ io::ppm::save(mln::labeling::colorize(value::rgb8(),
+ grouped_objects,
+ grouped_objects.nlabels()),
+ argv[2]);
+
+#ifndef NOUT
+// 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_highlight_image(input_rgb, grouped_objects),
+ out_base_dir + "_input_with_bboxes.ppm");
+ io::ppm::save(compute_text_image(input_rgb, grouped_objects),
+ out_base_dir + "_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
1
0
last-svn-commit-32-ge7ca877 scribo/src/text_in_photo_ppm.cc: Improve output.
by Guillaume Lazzara 11 Mar '10
by Guillaume Lazzara 11 Mar '10
11 Mar '10
---
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(a)lrde.epita.fr>
+ * scribo/src/text_in_photo_ppm.cc: Improve output.
+
+2010-02-19 Guillaume Lazzara <z(a)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
1
0
last-svn-commit-31-g750fe21 Cleanup and avoid warnings in Sauvola related files.
by Guillaume Lazzara 11 Mar '10
by Guillaume Lazzara 11 Mar '10
11 Mar '10
* scribo/binarization/sauvola_ms.hh,
* scribo/binarization/sauvola_threshold.hh,
* scribo/canvas/integral_browsing.hh,
* scribo/src/binarization/sauvola_ms.cc,
* scribo/src/binarization/sauvola_pgm.cc,x
* scribo/subsampling/integral_single_image.hh: Cleanup and avoir
warnings.
---
scribo/ChangeLog | 12 +
scribo/binarization/sauvola_ms.hh | 845 ++++++++++++++-------------
scribo/binarization/sauvola_threshold.hh | 5 -
scribo/canvas/integral_browsing.hh | 69 +--
scribo/src/binarization/sauvola_ms.cc | 30 +-
scribo/src/binarization/sauvola_pgm.cc | 10 +-
scribo/subsampling/integral_single_image.hh | 4 +-
7 files changed, 494 insertions(+), 481 deletions(-)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 745540f..6eae06e 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,3 +1,15 @@
+2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Cleanup and avoid warnings in Sauvola related files.
+
+ * scribo/binarization/sauvola_ms.hh,
+ * scribo/binarization/sauvola_threshold.hh,
+ * scribo/canvas/integral_browsing.hh,
+ * scribo/src/binarization/sauvola_ms.cc,
+ * scribo/src/binarization/sauvola_pgm.cc,x
+ * scribo/subsampling/integral_single_image.hh: Cleanup and avoir
+ warnings.
+
2009-12-15 Guillaume Lazzara <z(a)lrde.epita.fr>
Add a new test for object_image.
diff --git a/scribo/binarization/sauvola_ms.hh b/scribo/binarization/sauvola_ms.hh
index bc52620..fce5832 100644
--- a/scribo/binarization/sauvola_ms.hh
+++ b/scribo/binarization/sauvola_ms.hh
@@ -61,640 +61,648 @@ namespace scribo
using value::int_u8;
- unsigned my_find_root(image2d<unsigned>& parent, unsigned x)
+ namespace internal
{
- if (parent.element(x) == x)
- return x;
- return parent.element(x) = my_find_root(parent,
- parent.element(x));
- }
+ template <typename V>
+ V my_find_root(image2d<V>& parent, const V& x)
+ {
+ if (parent.element(x) == x)
+ return x;
+ return parent.element(x) = my_find_root(parent,
+ parent.element(x));
+ }
- image2d<int_u8>
- compute_t_n_and_e_2(const image2d<int_u8>& sub, image2d<int_u8>& e_2,
- unsigned lambda_min, unsigned lambda_max,
- unsigned s,
- unsigned q, unsigned i, unsigned w,
- const image2d<util::couple<double,double> >& integral_sum_sum_2)
- {
- typedef image2d<int_u8> I;
- typedef point2d P;
- unsigned ratio = std::pow(q, i - 2); // Ratio in comparison to e_2
+ image2d<int_u8>
+ compute_t_n_and_e_2(const image2d<int_u8>& sub, image2d<int_u8>& e_2,
+ unsigned lambda_min, unsigned lambda_max,
+ unsigned s,
+ unsigned q, unsigned i, unsigned w,
+ const image2d<util::couple<double,double> >& integral_sum_sum_2)
+ {
+ typedef image2d<int_u8> I;
+ typedef point2d P;
- unsigned
- w_local = w * ratio,
- w_local_h = w_local,
- w_local_w = w_local;
+ unsigned ratio = std::pow(q, i - 2); // Ratio in comparison to e_2
- if (! (w_local % 2))
- {
- --w_local_w;
- ++w_local_h;
- }
+ unsigned
+ w_local = w * ratio,
+ w_local_h = w_local,
+ w_local_w = w_local;
- // 1st pass
- scribo::binarization::internal::first_pass_functor< image2d<int_u8> >
- f(sub);
- scribo::canvas::integral_browsing(integral_sum_sum_2,
- ratio,
- w_local_w, w_local_h,
- s,
- f);
+ if (! (w_local % 2))
+ {
+ --w_local_w;
+ ++w_local_h;
+ }
- // 2nd pass
- {
- util::array<mln_value_(I) *> ptr(ratio);
- unsigned nrows = geom::nrows(e_2);
+ // 1st pass
+ scribo::binarization::internal::first_pass_functor< image2d<int_u8> >
+ f(sub);
+ scribo::canvas::integral_browsing(integral_sum_sum_2,
+ ratio,
+ w_local_w, w_local_h,
+ s,
+ f);
- mln_box_runend_piter_(I) sp(sub.domain()); // Backward.
- unsigned ncols = sp.run_length();
- for_all(sp)
+ // 2nd pass
{
- unsigned p = &sub(sp) - sub.buffer(); // Offset
- P site = sp;
+ util::array<mln_value_(I) *> ptr(ratio);
+ unsigned nrows = geom::nrows(e_2);
+ mln_box_runend_piter_(I) sp(sub.domain()); // Backward.
+ unsigned ncols = sp.run_length();
+ for_all(sp)
{
- P tmp = site * ratio;
-
- // FIXME: to be removed!
- if (tmp.row() + ratio >= nrows)
- ptr.resize(nrows - tmp.row());
+ unsigned p = &sub(sp) - sub.buffer(); // Offset
+ P site = sp;
- ptr(0) = &e_2(tmp);
- // FIXME: pointers could just be updated with an offset.
- for (unsigned j = 1; j < ptr.size(); ++j)
{
- tmp[0] += 1;
- ptr(j) = & e_2(tmp);
- }
- }
+ P tmp = site * ratio;
- for (unsigned j = 0; j < ncols; ++j)
- {
- if (f.msk.element(p))
- {
+ // FIXME: to be removed!
+ if (tmp.row() + ratio >= nrows)
+ ptr.resize(nrows - tmp.row());
- mln_site_(I) sq = site * ratio;
+ ptr(0) = &e_2(tmp);
+ // FIXME: pointers could just be updated with an offset.
+ for (unsigned j = 1; j < ptr.size(); ++j)
+ {
+ tmp[0] += 1;
+ ptr(j) = & e_2(tmp);
+ }
+ }
- if (f.parent.element(p) == p)
+ for (unsigned j = 0; j < ncols; ++j)
+ {
+ if (f.msk.element(p))
{
- // test over the component cardinality
- f.msk.element(p) = f.card.element(p) > lambda_min
- && f.card.element(p) < lambda_max;
- if (f.msk.element(p) && e_2(sq) == 0u)
+ mln_site_(I) sq = site * ratio;
+
+ if (f.parent.element(p) == p)
{
- for (unsigned l = 0; l < ptr.size(); ++l)
- std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
- }
+ // test over the component cardinality
+ f.msk.element(p) = f.card.element(p) > lambda_min
+ && f.card.element(p) < lambda_max;
- }
- else
- {
- // Propagation
- f.msk.element(p) = f.msk.element(f.parent.element(p));
+ if (f.msk.element(p) && e_2(sq) == 0u)
+ {
+ for (unsigned l = 0; l < ptr.size(); ++l)
+ std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
+ }
- if (f.msk.element(p) && e_2(sq) == 0u)
- {
- for (unsigned l = 0; l < ptr.size(); ++l)
- std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
}
+ else
+ {
+ // Propagation
+ f.msk.element(p) = f.msk.element(f.parent.element(p));
+
+ if (f.msk.element(p) && e_2(sq) == 0u)
+ {
+ for (unsigned l = 0; l < ptr.size(); ++l)
+ std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
+ }
+ }
}
- }
- for (unsigned l = 0; l < ptr.size(); ++l)
- ptr(l) -= ratio;
+ for (unsigned l = 0; l < ptr.size(); ++l)
+ ptr(l) -= ratio;
- --site[1];
- --p;
- }
+ --site[1];
+ --p;
+ }
- }
- } // end of 2nd pass
+ }
+ } // end of 2nd pass
- return f.t_sub;
- }
+ return f.t_sub;
+ }
- template <typename I, typename J, typename K>
- mln_ch_value(I, bool)
- multi_scale_binarization(const I& in, const J& e2,
- const util::array<K>& t_ima,
- unsigned s)
- {
- mln_ch_value(I,bool) out;
- initialize(out, in);
+ template <typename I, typename J, typename K>
+ mln_ch_value(I, bool)
+ multi_scale_binarization(const I& in, const J& e2,
+ const util::array<K>& t_ima,
+ unsigned s)
+ {
+ mln_ch_value(I,bool) out;
+ initialize(out, in);
- typedef const mln_value(K)* ptr_type;
+ typedef const mln_value(K)* ptr_type;
- ptr_type ptr_t[5];
- ptr_t[2] = & t_ima[2].at_(0, 0);
- ptr_t[3] = & t_ima[3].at_(0, 0);
- ptr_t[4] = & t_ima[4].at_(0, 0);
+ ptr_type ptr_t[5];
+ ptr_t[2] = & t_ima[2].at_(0, 0);
+ ptr_t[3] = & t_ima[3].at_(0, 0);
+ ptr_t[4] = & t_ima[4].at_(0, 0);
- const mln_value(J)* ptr_e2 = & e2.at_(0, 0);
- const mln_value(I)* ptr__in = & in.at_(0, 0);
- bool* ptr__out = & out.at_(0, 0);
+ const mln_value(J)* ptr_e2 = & e2.at_(0, 0);
+ const mln_value(I)* ptr__in = & in.at_(0, 0);
+ bool* ptr__out = & out.at_(0, 0);
- // Since we iterate from a smaller image in the largest ones and
- // image at scale 1 does not always have a size which can be
- // divided by (4*s), some sites in the border may not be processed
- // and we must skip them.
- int more_offset = - ((4 * s) - in.ncols() % (4 * s));
+ // Since we iterate from a smaller image in the largest ones and
+ // image at scale 1 does not always have a size which can be
+ // divided by (4*s), some sites in the border may not be processed
+ // and we must skip them.
+ int more_offset = - ((4 * s) - in.ncols() % (4 * s));
- if (more_offset == - (static_cast<int>(4*s)))
- more_offset = 0; // No offset needed.
+ if (more_offset == - (static_cast<int>(4*s)))
+ more_offset = 0; // No offset needed.
- const int
- nrows4 = t_ima[4].nrows(), ncols4 = t_ima[4].ncols(),
+ const int
+ nrows4 = t_ima[4].nrows(), ncols4 = t_ima[4].ncols(),
- delta1 = in.delta_index(dpoint2d(+1, -(s - 1))),
- delta1b = in.delta_index(dpoint2d(+1, -(s + s - 1))),
- delta1c = in.delta_index(dpoint2d(-(s + s - 1), +1)),
- delta1d = in.delta_index(dpoint2d(+1, -(s * 4 - 1))),
- delta1e = in.delta_index(dpoint2d(-(s * 4 - 1), +1)),
- delta1f = in.delta_index(dpoint2d(-(s - 1), +1)),
+ delta1 = in.delta_index(dpoint2d(+1, -(s - 1))),
+ delta1b = in.delta_index(dpoint2d(+1, -(s + s - 1))),
+ delta1c = in.delta_index(dpoint2d(-(s + s - 1), +1)),
+ delta1d = in.delta_index(dpoint2d(+1, -(s * 4 - 1))),
+ delta1e = in.delta_index(dpoint2d(-(s * 4 - 1), +1)),
+ delta1f = in.delta_index(dpoint2d(-(s - 1), +1)),
- delta2 = t_ima[2].delta_index(dpoint2d(+1, -1)),
- delta2b = t_ima[2].delta_index(dpoint2d(+1, -3)),
- delta2c = t_ima[2].delta_index(dpoint2d(-3, +1)),
+ delta2 = t_ima[2].delta_index(dpoint2d(+1, -1)),
+ delta2b = t_ima[2].delta_index(dpoint2d(+1, -3)),
+ delta2c = t_ima[2].delta_index(dpoint2d(-3, +1)),
- delta3 = t_ima[3].delta_index(dpoint2d(+1, -1)),
+ delta3 = t_ima[3].delta_index(dpoint2d(+1, -1)),
- eor1 = in.delta_index(dpoint2d(+4 * s, - in.ncols())) + more_offset,
- eor2 = t_ima[2].delta_index(dpoint2d(+4,- t_ima[2].ncols())),
- eor3 = t_ima[3].delta_index(dpoint2d(+2,- t_ima[3].ncols())),
- eor4 = t_ima[4].delta_index(dpoint2d(+1,- t_ima[4].ncols()));
+ eor1 = in.delta_index(dpoint2d(+4 * s, - in.ncols())) + more_offset,
+ eor2 = t_ima[2].delta_index(dpoint2d(+4,- t_ima[2].ncols())),
+ eor3 = t_ima[3].delta_index(dpoint2d(+2,- t_ima[3].ncols())),
+ eor4 = t_ima[4].delta_index(dpoint2d(+1,- t_ima[4].ncols()));
- mln_value(J) threshold;
- for (int row4 = 0; row4 < nrows4; ++row4)
- {
- for (int col4 = 0; col4 < ncols4; ++col4)
+ mln_value(J) threshold;
+ for (int row4 = 0; row4 < nrows4; ++row4)
{
- // top left 1
+ for (int col4 = 0; col4 < ncols4; ++col4)
{
- threshold = *ptr_t[*ptr_e2];
+ // top left 1
{
- for (unsigned i = 1; i < s; ++i)
+ threshold = *ptr_t[*ptr_e2];
{
- for (unsigned j = 1; j < s; ++j)
+ for (unsigned i = 1; i < s; ++i)
{
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
*ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
+ ptr__out += delta1; ptr__in += delta1;
}
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
-
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1f; ptr__in += delta1f;
}
- for (unsigned j = 1; j < s; ++j)
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1b; ptr__in += delta1b;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- ptr_t[2] += delta2; ptr_e2 += delta2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1b; ptr__in += delta1b;
}
- for (unsigned j = 1; j < s; ++j)
+ ptr_t[2] += delta2; ptr_e2 += delta2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
- }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1f; ptr__in += delta1f;
+
}
- for (unsigned j = 1; j < s; ++j)
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1c; ptr__in += delta1c;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
- ptr_t[2] -= delta2; ptr_e2 -= delta2;
- }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- // top right 1
- ptr_t[3] += 1;
- {
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1c; ptr__in += delta1c;
}
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
+ ptr_t[2] -= delta2; ptr_e2 -= delta2;
}
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
+ // top right 1
+ ptr_t[3] += 1;
{
- for (unsigned i = 1; i < s; ++i)
+ threshold = *ptr_t[*ptr_e2];
{
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1f; ptr__in += delta1f;
}
- for (unsigned j = 1; j < s; ++j)
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1b; ptr__in += delta1b;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- ptr_t[2] += delta2; ptr_e2 += delta2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1b; ptr__in += delta1b;
}
- for (unsigned j = 1; j < s; ++j)
+ ptr_t[2] += delta2; ptr_e2 += delta2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1f; ptr__in += delta1f;
}
- for (unsigned j = 1; j < s; ++j)
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1d; ptr__in += delta1d;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
- ptr_t[2] += delta2b; ptr_e2 += delta2b;
- }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- // bot left 1
- ptr_t[3] += delta3;
- {
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1d; ptr__in += delta1d;
}
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
+ ptr_t[2] += delta2b; ptr_e2 += delta2b;
}
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
+ // bot left 1
+ ptr_t[3] += delta3;
{
- for (unsigned i = 1; i < s; ++i)
+ threshold = *ptr_t[*ptr_e2];
{
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1f; ptr__in += delta1f;
}
- for (unsigned j = 1; j < s; ++j)
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1b; ptr__in += delta1b;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- ptr_t[2] += delta2; ptr_e2 += delta2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1b; ptr__in += delta1b;
}
- for (unsigned j = 1; j < s; ++j)
+ ptr_t[2] += delta2; ptr_e2 += delta2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1f; ptr__in += delta1f;
}
- for (unsigned j = 1; j < s; ++j)
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1c; ptr__in += delta1c;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
- ptr_t[2] -= delta2; ptr_e2 -= delta2;
- }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- // bot right 1
- ptr_t[3] += 1;
- {
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1c; ptr__in += delta1c;
}
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
+ ptr_t[2] -= delta2; ptr_e2 -= delta2;
}
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
+ // bot right 1
+ ptr_t[3] += 1;
{
- for (unsigned i = 1; i < s; ++i)
+ threshold = *ptr_t[*ptr_e2];
{
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1f; ptr__in += delta1f;
}
- for (unsigned j = 1; j < s; ++j)
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1b; ptr__in += delta1b;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- ptr_t[2] += delta2; ptr_e2 += delta2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1b; ptr__in += delta1b;
}
- for (unsigned j = 1; j < s; ++j)
+ ptr_t[2] += delta2; ptr_e2 += delta2;
+ threshold = *ptr_t[*ptr_e2];
{
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
for (unsigned j = 1; j < s; ++j)
{
*ptr__out = *ptr__in < threshold;
++ptr__out; ++ptr__in;
}
-
*ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
+ ptr__out += delta1f; ptr__in += delta1f;
}
- for (unsigned j = 1; j < s; ++j)
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
{
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
*ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
+ ptr__out += delta1e; ptr__in += delta1e;
}
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1e; ptr__in += delta1e;
}
+
+ // bot right -> next top left
+ ptr_t[2] += delta2c; ptr_e2 += delta2c;
+ ptr_t[3] = ptr_t[3] - delta3;
+ ptr_t[4] += 1;
}
- // bot right -> next top left
- ptr_t[2] += delta2c; ptr_e2 += delta2c;
- ptr_t[3] = ptr_t[3] - delta3;
- ptr_t[4] += 1;
+ // eof -> next bof
+ ptr__out += eor1; ptr__in += eor1;
+ ptr_t[2] += eor2; ptr_e2 += eor2;
+ ptr_t[3] += eor3;
+ ptr_t[4] += eor4;
}
- // eof -> next bof
- ptr__out += eor1; ptr__in += eor1;
- ptr_t[2] += eor2; ptr_e2 += eor2;
- ptr_t[3] += eor3;
- ptr_t[4] += eor4;
+ return out;
}
- return out;
- }
+ unsigned sub(unsigned nbr, unsigned down_scaling)
+ {
+ return (nbr + down_scaling - 1) / down_scaling;
+ }
- unsigned sub(unsigned nbr, unsigned down_scaling)
- {
- return (nbr + down_scaling - 1) / down_scaling;
- }
+ // Compute domains of subsampled images and make sure they can be
+ // divided by 2.
+ template <typename I>
+ util::array<util::couple<mln_domain(I), unsigned> >
+ compute_sub_domains(const I& ima, unsigned n_scales, unsigned s)
+ {
+ util::array<util::couple<unsigned, unsigned> > n(n_scales + 2);
+
+ n(1) = make::couple(ima.nrows(), ima.ncols());
+ n(2) = make::couple(sub(n(1).first(), s),
+ sub(n(1).second(), s));
+ for (unsigned i = 3; i <= n_scales + 1; ++i)
+ n(i) = make::couple(sub(n(i - 1).first(), 2),
+ sub(n(i - 1).second(), 2));
- // Compute domains of subsampled images and make sure they can be
- // divided by 2.
- template <typename I>
- util::array<util::couple<mln_domain(I), unsigned> >
- compute_sub_domains(const I& ima, unsigned n_scales, unsigned s)
- {
- util::array<util::couple<unsigned, unsigned> > n(n_scales + 2);
- n(1) = make::couple(ima.nrows(), ima.ncols());
- n(2) = make::couple(sub(n(1).first(), s),
- sub(n(1).second(), s));
- for (unsigned i = 3; i <= n_scales + 1; ++i)
- n(i) = make::couple(sub(n(i - 1).first(), 2),
- sub(n(i - 1).second(), 2));
+ util::array<util::couple<mln_domain(I), unsigned> > out(n.size());
+ out(0) = make::couple(make::box2d(1,1), 1u);
+ out(1) = make::couple(make::box2d(ima.nrows(), ima.ncols()), 2u);
+ out(n_scales + 1) = make::couple(make::box2d(n(n_scales + 1).first(),
+ n(n_scales + 1).second()),
+ 1u);
+ for (unsigned i = n_scales; i > 1; --i)
+ out(i) = make::couple(make::box2d(2 * out(i + 1).first().nrows(),
+ 2 * out(i + 1).first().ncols()),
+ 2 * out(i + 1).second());
- util::array<util::couple<mln_domain(I), unsigned> > out(n.size());
- out(0) = make::couple(make::box2d(1,1), 1u);
- out(1) = make::couple(make::box2d(ima.nrows(), ima.ncols()), 2u);
- out(n_scales + 1) = make::couple(make::box2d(n(n_scales + 1).first(),
- n(n_scales + 1).second()),
- 1u);
+ out(1).second() = std::max(out(2).first().ncols() * s - ima.ncols(),
+ out(2).first().nrows() * s - ima.nrows());
- for (unsigned i = n_scales; i > 1; --i)
- out(i) = make::couple(make::box2d(2 * out(i + 1).first().nrows(),
- 2 * out(i + 1).first().ncols()),
- 2 * out(i + 1).second());
+ return out;
+ }
+
+ } // end of namespace scribo::binarization::internal
- out(1).second() = std::max(out(2).first().ncols() * s - ima.ncols(),
- out(2).first().nrows() * s - ima.nrows());
- return out;
- }
template <typename I>
mln_ch_value(I,bool)
@@ -743,7 +751,7 @@ namespace scribo
}
util::array<util::couple<box2d, unsigned> >
- sub_domains = compute_sub_domains(input_1, nb_subscale, s);
+ sub_domains = internal::compute_sub_domains(input_1, nb_subscale, s);
border::adjust(input_1, sub_domains(1).second());
border::mirror(input_1);
@@ -776,11 +784,12 @@ namespace scribo
{
int i = sub_ima.size() - 1;
unsigned ratio = std::pow(q, i - 2); // Ratio compared to e_2
- t_ima[i] = compute_t_n_and_e_2(sub_ima[i], e_2,
- lambda_min_2 / ratio,
- mln_max(unsigned),
- s,
- q, i, w_work, integral_sum_sum_2);
+ t_ima[i] = internal::compute_t_n_and_e_2(sub_ima[i], e_2,
+ lambda_min_2 / ratio,
+ mln_max(unsigned),
+ s,
+ q, i, w_work,
+ integral_sum_sum_2);
}
// Other scales -> maximum and minimum component size.
@@ -788,18 +797,21 @@ namespace scribo
for (int i = sub_ima.size() - 2; i > 2; --i)
{
unsigned ratio = std::pow(q, i - 2); // Ratio compared to e_2
- t_ima[i] = compute_t_n_and_e_2(sub_ima[i], e_2,
- lambda_min_2 / ratio,
- lambda_max_2 / ratio,
- s,
- q, i, w_work, integral_sum_sum_2);
+ t_ima[i] = internal::compute_t_n_and_e_2(sub_ima[i], e_2,
+ lambda_min_2 / ratio,
+ lambda_max_2 / ratio,
+ s,
+ q, i, w_work,
+ integral_sum_sum_2);
}
}
// Lowest scale -> no minimum component size.
{
- t_ima[2] = compute_t_n_and_e_2(sub_ima[2], e_2, 0, lambda_max_2,
- s, 1, 2, w_work, integral_sum_sum_2);
+ t_ima[2] = internal::compute_t_n_and_e_2(sub_ima[2], e_2, 0,
+ lambda_max_2,
+ s, 1, 2, w_work,
+ integral_sum_sum_2);
}
@@ -808,7 +820,8 @@ namespace scribo
// Binarize
- image2d<bool> output = multi_scale_binarization(input_1, e_2, t_ima, s);
+ image2d<bool>
+ output = internal::multi_scale_binarization(input_1, e_2, t_ima, s);
trace::exiting("scribo::binarization::sauvola_ms");
return output;
diff --git a/scribo/binarization/sauvola_threshold.hh b/scribo/binarization/sauvola_threshold.hh
index 20abc50..01bd1b0 100644
--- a/scribo/binarization/sauvola_threshold.hh
+++ b/scribo/binarization/sauvola_threshold.hh
@@ -48,9 +48,6 @@
# include <scribo/core/init_integral_image.hh>
-
-#include <mln/io/pgm/save.hh>
-
namespace scribo
{
@@ -476,8 +473,6 @@ namespace scribo
exact(simple),
exact(squared));
-// std::cout << std::endl << " ------- " << std::endl;
- io::pgm::save(output, "ref_2_t.pgm");
trace::exiting("scribo::text::ppm2pbm");
return output;
}
diff --git a/scribo/canvas/integral_browsing.hh b/scribo/canvas/integral_browsing.hh
index 44d73a0..45ff38d 100644
--- a/scribo/canvas/integral_browsing.hh
+++ b/scribo/canvas/integral_browsing.hh
@@ -63,7 +63,11 @@ namespace scribo
// std::cout << "(" << mean << " - " << stddev << " - " << n << "),";
// unbias version:
- stddev = std::sqrt((sum_2 - sum * sum / n) / (n - 1));
+ double num = (sum_2 - sum * sum / n);
+ if (num > 0)
+ stddev = std::sqrt(num / (n - 1));
+ else
+ stddev = 0;
}
@@ -83,18 +87,21 @@ namespace scribo
typedef const V* Ptr;
Ptr a_ima, b_ima, c_ima, d_ima;
- const unsigned
+// mln_precondition((h/2) < ima.nrows());
+// mln_precondition((w/2) < ima.ncols());
+
+ const int
nrows = ima.nrows(),
ncols = ima.ncols(),
row_0 = step / 2,
col_0 = step / 2;
- const unsigned
+ const int
offset_down = ima.delta_index(dpoint2d(step, 0)),
offset_ante = ima.delta_index(dpoint2d(0, -w)),
offset_below = ima.delta_index(dpoint2d(+h, 0));
- const unsigned
+ const int
max_row_top = h/2,
max_row_mid = nrows - 1 - h/2,
max_col_left = w/2,
@@ -105,10 +112,11 @@ namespace scribo
h_top = row_0 + h/2 + 1,
w_left = col_0 + w/2 + 1;
- unsigned row, col;
+
+ int row, col;
for (col = col_0; col <= max_col_mid; col += step) ;
- unsigned w_right = ncols - col + w/2;
+ int w_right = ncols - col + w/2;
Ptr
d_tl_start, d_tr_start,
@@ -119,6 +127,18 @@ namespace scribo
unsigned s_2 = s * s;
+ // Make sure the window fits in the image domain.
+ if (w >= static_cast<const unsigned>(ncols))
+ {
+ w = ncols - 1;
+ trace::warning("integral_browsing - Adjusting window width since it was larger than image width.");
+ }
+ if (h >= static_cast<const unsigned>(nrows))
+ {
+ h = nrows - 1;
+ trace::warning("integral_browsing - Adjusting window height since it was larger than image height.");
+ }
+
// -------------------------------
// T (top)
@@ -128,7 +148,7 @@ namespace scribo
delta_start_left = step * w_left,
delta_start_right = step * w_right,
step_w = step * w;
- unsigned
+ int
size_tl_start = h_top * w_left,
size_tl,
delta_size_tl = h_top * step,
@@ -209,7 +229,6 @@ namespace scribo
}
-
// -------------------------------
// (M) middle
// -------------------------------
@@ -266,25 +285,6 @@ namespace scribo
{
// D + A - B - C
-// if (row == 3 && col == 3)
-// std::cout << "p(" << row << "," << col << ") - "
-
-// << "A" << ima.point_at_index(a_ima - ima.buffer())
-// << "=" << a_ima->first() << " - "
-
-// << "B" << ima.point_at_index(b_ima - ima.buffer())
-// << "=" << b_ima->first() << " - "
-
-// << "C" << ima.point_at_index(c_ima - ima.buffer())
-// << "=" << c_ima->first() << " - "
-
-// << "D" << ima.point_at_index(d_ima - ima.buffer())
-// << "=" << d_ima->first() << " - "
-
-// << "n =" << size_mc << " - "
-// << "n*s_2 =" << size_mc * s_2
-// << std::endl;
-
internal::compute_stats((d_ima->first() - b_ima->first()) + (a_ima->first() - c_ima->first()),
(d_ima->second() - b_ima->second()) + (a_ima->second() - c_ima->second()),
size_mc * s_2,
@@ -292,13 +292,6 @@ namespace scribo
functor.exec(mean, stddev);
-// std::cout << " - " << mean
-// << " - " << stddev
-// << " - " << (d_ima->first() - b_ima->first()) + (a_ima->first() - c_ima->first())
-// << " - " << (d_ima->second() - b_ima->second()) + (a_ima->second() - c_ima->second())
-// << std::endl;
-
-
a_ima += step;
b_ima += step;
c_ima += step;
@@ -332,7 +325,6 @@ namespace scribo
}
-
// -------------------------------
// B (bottom)
// -------------------------------
@@ -342,6 +334,7 @@ namespace scribo
size_bl,
delta_size_bl = (nrows - row + h/2) * step,
size_bc = (nrows - row + h/2) * w,
+
size_br_start = (nrows - row + h/2) * w_right,
delta_size_br = (nrows - row + h/2) * step,
size_br;
@@ -392,12 +385,6 @@ namespace scribo
(d_ima->second() - b_ima->second()) + (a_ima->second() - c_ima->second()),
size_bc * s_2,
mean, stddev);
-// std::cout << (d_ima->second() - b_ima->second()) + (a_ima->second() - c_ima->second()) << std::endl;
-
-// std::cout << d_ima->second() << " - " << b_ima->second() << " - "
-// << a_ima->second() << " - " << c_ima->second() << std::endl;
-// std::cout << d_ima->first() << " - " << b_ima->first() << " - "
-// << a_ima->first() << " - " << c_ima->first() << std::endl;
functor.exec(mean, stddev);
a_ima += step;
b_ima += step;
diff --git a/scribo/src/binarization/sauvola_ms.cc b/scribo/src/binarization/sauvola_ms.cc
index b3b4791..61887af 100644
--- a/scribo/src/binarization/sauvola_ms.cc
+++ b/scribo/src/binarization/sauvola_ms.cc
@@ -31,7 +31,6 @@
#include <scribo/binarization/sauvola_ms.hh>
#include <scribo/debug/usage.hh>
-
bool check_args(int argc, char * argv[])
{
if (argc < 5 || argc > 6)
@@ -88,21 +87,20 @@ int main(int argc, char *argv[])
image2d<value::int_u8> input_1;
io::pgm::load(input_1, argv[1]);
- {
- unsigned max_dim = math::max(input_1.ncols(),
- input_1.nrows());
- if (w_1 > max_dim)
- {
- std::cout << "------------------" << std::endl;
- std::cout << "The window is too large! Image size is only "
- << input_1.nrows() << "x" << input_1.ncols()
- << std::endl
- << "Window size must not exceed " << max_dim
- << std::endl;
- return 1;
- }
- }
-
+// {
+// unsigned max_dim = math::min(input_1.ncols() / s,
+// input_1.nrows() / s);
+// if ((w_1 / s * 4) > max_dim)
+// {
+// std::cout << "------------------" << std::endl;
+// std::cout << "The window is too large! Image size is only "
+// << input_1.nrows() << "x" << input_1.ncols()
+// << std::endl
+// << "Window size must not exceed " << max_dim * s / 4
+// << std::endl;
+// return 1;
+// }
+// }
image2d<bool>
output = scribo::binarization::sauvola_ms(input_1, w_1, s, lambda_min_1);
diff --git a/scribo/src/binarization/sauvola_pgm.cc b/scribo/src/binarization/sauvola_pgm.cc
index f05ed5f..380d369 100644
--- a/scribo/src/binarization/sauvola_pgm.cc
+++ b/scribo/src/binarization/sauvola_pgm.cc
@@ -29,6 +29,7 @@
#include <scribo/binarization/sauvola.hh>
#include <scribo/debug/usage.hh>
+#include <mln/util/timer.hh>
const char *args_desc[][2] =
{
@@ -56,7 +57,14 @@ int main(int argc, char *argv[])
image2d<int_u8> input;
io::pgm::load(input, argv[1]);
- io::pbm::save(scribo::binarization::sauvola(input, w), argv[3]);
+ util::timer t;
+ t.start();
+ image2d<bool> out = scribo::binarization::sauvola(input, w);
+ t.stop();
+ std::cout << t << std::endl;
+
+
+ io::pbm::save(out, argv[3]);
trace::exiting("main");
diff --git a/scribo/subsampling/integral_single_image.hh b/scribo/subsampling/integral_single_image.hh
index 6ed1cc6..cd25fc1 100644
--- a/scribo/subsampling/integral_single_image.hh
+++ b/scribo/subsampling/integral_single_image.hh
@@ -123,7 +123,7 @@ namespace scribo
integral_sum_sum_2.init_(output_domain, border_thickness);
V2* p_integ = integral_sum_sum_2.buffer();
- const unsigned up = sub.delta_index(dpoint2d(-1, 0));
+ const int up = sub.delta_index(dpoint2d(-1, 0));
const unsigned nrows = 3 * output_domain.nrows();
const unsigned ncols = 3 * output_domain.ncols();
@@ -242,7 +242,7 @@ namespace scribo
integral_sum_sum_2.init_(output_domain, border_thickness);
V2* p_integ = integral_sum_sum_2.buffer();
- const unsigned up = sub.delta_index(dpoint2d(-1, 0));
+ const int up = sub.delta_index(dpoint2d(-1, 0));
const unsigned nrows = 2 * output_domain.nrows();
const unsigned ncols = 2 * output_domain.ncols();
--
1.5.6.5
1
0
last-svn-commit-30-gc24686e configure.ac: Configure scribo/tests/core.
by Guillaume Lazzara 11 Mar '10
by Guillaume Lazzara 11 Mar '10
11 Mar '10
---
ChangeLog | 4 ++++
configure.ac | 1 +
2 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 9b360b9..961ff85 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2009-12-15 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ * configure.ac: Configure scribo/tests/core.
+
2009-10-02 Roland Levillain <roland(a)lrde.epita.fr>
Configure Makefiles under milena/apps/papers/.
diff --git a/configure.ac b/configure.ac
index f46a22d..0f66fa3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -230,6 +230,7 @@ AC_CONFIG_FILES([scribo/tests/data.hh])
AC_CONFIG_FILES([
scribo/tests/Makefile
+ scribo/tests/core/Makefile
scribo/tests/filter/Makefile
scribo/tests/preprocessing/Makefile
scribo/tests/table/Makefile
--
1.5.6.5
1
0
11 Mar '10
* tests/Makefile.am,
* tests/core/Makefile.am: Update build system.
* tests/core/object_image.cc: New test.
---
scribo/ChangeLog | 9 ++++
scribo/tests/Makefile.am | 1 +
scribo/tests/{preprocessing => core}/Makefile.am | 4 +-
.../tests/core/object_image.cc | 51 +++++++++++++-------
4 files changed, 45 insertions(+), 20 deletions(-)
copy scribo/tests/{preprocessing => core}/Makefile.am (93%)
copy milena/tests/core/image/dmorph/unproject_image.cc => scribo/tests/core/object_image.cc (60%)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index a11166a..745540f 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,14 @@
2009-12-15 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Add a new test for object_image.
+
+ * tests/Makefile.am,
+ * tests/core/Makefile.am: Update build system.
+
+ * tests/core/object_image.cc: New test.
+
+2009-12-15 Guillaume Lazzara <z(a)lrde.epita.fr>
+
* primitive/extract/objects.hh: Compute and store mass centers.
2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
diff --git a/scribo/tests/Makefile.am b/scribo/tests/Makefile.am
index e36d250..67d6d25 100644
--- a/scribo/tests/Makefile.am
+++ b/scribo/tests/Makefile.am
@@ -19,6 +19,7 @@ include $(srcdir)/tests.mk
## Process this file through Automake to create Makefile.in.
SUBDIRS = \
+ core \
filter \
preprocessing \
table \
diff --git a/scribo/tests/preprocessing/Makefile.am b/scribo/tests/core/Makefile.am
similarity index 93%
copy from scribo/tests/preprocessing/Makefile.am
copy to scribo/tests/core/Makefile.am
index 4666033..a7773ec 100644
--- a/scribo/tests/preprocessing/Makefile.am
+++ b/scribo/tests/core/Makefile.am
@@ -20,8 +20,8 @@
include $(top_srcdir)/scribo/tests/tests.mk
check_PROGRAMS = \
- unskew
+ object_image
-unskew_SOURCES = unskew.cc
+object_image_SOURCES = object_image.cc
TESTS = $(check_PROGRAMS)
diff --git a/milena/tests/core/image/dmorph/unproject_image.cc b/scribo/tests/core/object_image.cc
similarity index 60%
copy from milena/tests/core/image/dmorph/unproject_image.cc
copy to scribo/tests/core/object_image.cc
index bb7dbde..9ac6152 100644
--- a/milena/tests/core/image/dmorph/unproject_image.cc
+++ b/scribo/tests/core/object_image.cc
@@ -23,35 +23,50 @@
// 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/image1d.hh>
+#include <iostream>
+
#include <mln/core/image/image2d.hh>
-#include <mln/core/image/dmorph/unproject_image.hh>
-#include <mln/core/var.hh>
+#include <mln/make/image.hh>
+#include <mln/fun/i2v/array.hh>
-#include <mln/fun/v2v/projection.hh>
+#include <scribo/core/object_image.hh>
-#include <mln/debug/iota.hh>
#include <mln/debug/println.hh>
-
-
-int main()
+int main(int argc, char* argv[])
{
using namespace mln;
- image1d<int> ima(3);
- debug::iota(ima);
+ unsigned data[4][4] = { {1, 0, 0, 0},
+ {0, 0, 2, 0},
+ {3, 0, 0, 0},
+ {0, 0, 4, 0} };
+
+ typedef image2d<unsigned> I;
+ I ima = make::image(data);
+
+ object_image(I) lbl(ima, 4);
+
+ fun::i2v::array<unsigned> f(5);
+ f(0) = 0;
+ f(1) = 1;
+ f(2) = 4;
+ f(3) = 3;
+ f(4) = 4;
- debug::println(ima);
- std::cout << std::endl;
+ // { {1, 0, 0, 0},
+ // {0, 0, 2, 0},
+ // {3, 0, 0, 0},
+ // {0, 0, 2, 0} };
+ lbl.relabel(f);
- fun::v2v::projection<point2d, 0> f;
- mln_VAR( ima_, unproject(ima, make::box2d(3, 3), f) );
- debug::println(ima_);
+ mln_assertion(lbl.bbox(1) == make::box2d(0, 0, 0,0));
+ mln_assertion(lbl.mass_center(1) == point2d(0,0));
- ima_(point2d(1,1)) = 9;
- debug::println(ima_);
+ mln_assertion(lbl.bbox(2) == make::box2d(1, 2, 3,2));
+ mln_assertion(lbl.mass_center(2) == point2d(2,2));
- debug::println(ima);
+ mln_assertion(lbl.bbox(3) == make::box2d(2, 0, 2,0));
+ mln_assertion(lbl.mass_center(3) == point2d(2,0));
}
--
1.5.6.5
1
0
last-svn-commit-28-g80b330e primitive/extract/objects.hh: Compute and store mass centers.
by Guillaume Lazzara 11 Mar '10
by Guillaume Lazzara 11 Mar '10
11 Mar '10
---
scribo/ChangeLog | 5 ++++-
scribo/primitive/extract/objects.hh | 8 +++++++-
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index dfbf01a..a11166a 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,3 +1,7 @@
+2009-12-15 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ * primitive/extract/objects.hh: Compute and store mass centers.
+
2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
Fix object links filters.
@@ -8,7 +12,6 @@
* filter/object_links_top_aligned.hh: Pass the proper dimension as
routine argument.
-
2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
Cleanup Sauvola's binarization code.
diff --git a/scribo/primitive/extract/objects.hh b/scribo/primitive/extract/objects.hh
index 2ca2f5d..3f1af7c 100644
--- a/scribo/primitive/extract/objects.hh
+++ b/scribo/primitive/extract/objects.hh
@@ -119,8 +119,14 @@ namespace scribo
results = labeling::blobs_and_compute(input, nbh, nobjects,
accu_bbox());
+ // FIXME: enable mass centers computation and maybe merge this
+ // computation with blobs computation above.
+ util::array<mln_result(accu::center<mln_site(I)>)>
+ mass_centers;
+ mass_centers = labeling::compute(accu::meta::center(),
+ results.first(), nobjects);
object_image(L)
- output(results.first(), nobjects, results.second());
+ output(results.first(), nobjects, results.second(), mass_centers);
trace::exiting("scribo::objects");
return output;
--
1.5.6.5
1
0
* filter/object_links_bottom_aligned.hh,
* filter/object_links_center_aligned.hh,
* filter/object_links_non_aligned_simple.hh,
* filter/object_links_top_aligned.hh: Pass the proper dimension as
routine argument.
---
scribo/ChangeLog | 11 +++++++
scribo/filter/object_links_bottom_aligned.hh | 2 +-
scribo/filter/object_links_center_aligned.hh | 2 +-
scribo/filter/object_links_non_aligned_simple.hh | 32 ++++++++++++---------
scribo/filter/object_links_top_aligned.hh | 2 +-
5 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 8488ae3..dfbf01a 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,16 @@
2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Fix object links filters.
+
+ * filter/object_links_bottom_aligned.hh,
+ * filter/object_links_center_aligned.hh,
+ * filter/object_links_non_aligned_simple.hh,
+ * filter/object_links_top_aligned.hh: Pass the proper dimension as
+ routine argument.
+
+
+2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
+
Cleanup Sauvola's binarization code.
* binarization/sauvola_threshold.hh,
diff --git a/scribo/filter/object_links_bottom_aligned.hh b/scribo/filter/object_links_bottom_aligned.hh
index d950a6e..1afebf7 100644
--- a/scribo/filter/object_links_bottom_aligned.hh
+++ b/scribo/filter/object_links_bottom_aligned.hh
@@ -102,7 +102,7 @@ namespace scribo
object_links<L>
output = object_links_non_aligned_simple(objects, links,
- 1, max_alpha);
+ 2, max_alpha);
trace::exiting("scribo::filter::object_links_bottom_aligned");
return output;
diff --git a/scribo/filter/object_links_center_aligned.hh b/scribo/filter/object_links_center_aligned.hh
index e44f3cd..abbac9e 100644
--- a/scribo/filter/object_links_center_aligned.hh
+++ b/scribo/filter/object_links_center_aligned.hh
@@ -95,7 +95,7 @@ namespace scribo
object_links<L>
output = object_links_non_aligned_simple(objects, links,
- 2, max_alpha);
+ 0, max_alpha);
trace::exiting("scribo::filter::object_links_center_aligned");
return output;
diff --git a/scribo/filter/object_links_non_aligned_simple.hh b/scribo/filter/object_links_non_aligned_simple.hh
index 032b4d0..706497d 100644
--- a/scribo/filter/object_links_non_aligned_simple.hh
+++ b/scribo/filter/object_links_non_aligned_simple.hh
@@ -81,9 +81,9 @@ namespace scribo
The angle between the two bottoms must be lower than \p alpha.
edge values :
- 0 = top
- 1 = bottom
- 2 = center
+ 0 = center
+ 1 = top
+ 2 = bottom
*/
template <typename L>
@@ -117,44 +117,47 @@ namespace scribo
float max_alpha_rad = (max_alpha / 180.0f) * math::pi;
- // Top
+ // Center
if (edge == 0)
{
for_all_components(i, objects.bboxes())
+ {
if (links[i] != i)
{
- dr = math::abs(bboxes[i].pmin().row()
- - bboxes[links[i]].pmin().row());
+ dr = math::abs(bboxes[i].center().row()
+ - bboxes[links[i]].center().row());
dc = math::abs(bboxes[i].center().col()
- bboxes[links[i]].center().col());
if (std::atan(dr / dc) > max_alpha_rad)
output[i] = i;
}
+ }
}
- // Bottom
+ // Top
else if (edge == 1)
+ {
for_all_components(i, objects.bboxes())
- {
if (links[i] != i)
{
- dr = math::abs(bboxes[i].pmax().row()
- - bboxes[links[i]].pmax().row());
+ dr = math::abs(bboxes[i].pmin().row()
+ - bboxes[links[i]].pmin().row());
dc = math::abs(bboxes[i].center().col()
- bboxes[links[i]].center().col());
if (std::atan(dr / dc) > max_alpha_rad)
output[i] = i;
}
- }
- // Center
+ }
+ // Bottom
else if (edge == 2)
+ {
for_all_components(i, objects.bboxes())
{
if (links[i] != i)
{
- dr = math::abs(bboxes[i].center().row()
- - bboxes[links[i]].center().row());
+ dr = math::abs(bboxes[i].pmax().row()
+ - bboxes[links[i]].pmax().row());
dc = math::abs(bboxes[i].center().col()
- bboxes[links[i]].center().col());
@@ -162,6 +165,7 @@ namespace scribo
output[i] = i;
}
}
+ }
else
{
trace::warning("Invalid edge value... Aborting computation.");
diff --git a/scribo/filter/object_links_top_aligned.hh b/scribo/filter/object_links_top_aligned.hh
index 47e26c8..4a92c96 100644
--- a/scribo/filter/object_links_top_aligned.hh
+++ b/scribo/filter/object_links_top_aligned.hh
@@ -102,7 +102,7 @@ namespace scribo
object_links<L>
output = object_links_non_aligned_simple(objects, links,
- 0,
+ 1,
max_alpha);
trace::exiting("scribo::filter::object_links_top_aligned");
--
1.5.6.5
1
0
11 Mar '10
* binarization/sauvola_threshold.hh,
* binarization/sauvola.hh: Use fun::v2v::rgb_to_int_u8.
* binarization/sauvola_ms.hh: New. Sauvola multi-scale routine.
* src/binarization/sauvola.cc: Make the window size a program
argument.
* src/binarization/sauvola_ms.cc: Use Sauvola multi-scale routine.
---
scribo/ChangeLog | 14 +
scribo/binarization/sauvola.hh | 4 +-
scribo/binarization/sauvola_ms.hh | 822 +++++++++++++++
scribo/binarization/sauvola_threshold.hh | 14 +-
scribo/src/binarization/sauvola.cc | 7 +-
scribo/src/binarization/sauvola_ms.cc | 1669 +-----------------------------
6 files changed, 876 insertions(+), 1654 deletions(-)
create mode 100644 scribo/binarization/sauvola_ms.hh
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index a5c7fea..8488ae3 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,19 @@
2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Cleanup Sauvola's binarization code.
+
+ * binarization/sauvola_threshold.hh,
+ * binarization/sauvola.hh: Use fun::v2v::rgb_to_int_u8.
+
+ * binarization/sauvola_ms.hh: New. Sauvola multi-scale routine.
+
+ * src/binarization/sauvola.cc: Make the window size a program
+ argument.
+
+ * src/binarization/sauvola_ms.cc: Use Sauvola multi-scale routine.
+
+2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
+
* core/object_image.hh: Make use of mln::labeled_image_base.
2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
diff --git a/scribo/binarization/sauvola.hh b/scribo/binarization/sauvola.hh
index 5323847..1339c66 100644
--- a/scribo/binarization/sauvola.hh
+++ b/scribo/binarization/sauvola.hh
@@ -35,6 +35,8 @@
# include <mln/value/int_u8.hh>
# include <mln/value/rgb8.hh>
+# include <mln/fun/v2v/rgb_to_int_u.hh>
+
# include <scribo/binarization/sauvola_threshold.hh>
# include <scribo/binarization/binarize.hh>
@@ -106,7 +108,7 @@ namespace scribo
mln_precondition(exact(input).is_valid());
mln_ch_value(I, value::int_u8) gima;
- gima = data::transform(input, internal::rgb8_to_int_u8());
+ gima = data::transform(input, mln::fun::v2v::rgb_to_int_u<8>());
mln_ch_value(I, bool)
output = binarize(gima,
diff --git a/scribo/binarization/sauvola_ms.hh b/scribo/binarization/sauvola_ms.hh
new file mode 100644
index 0000000..bc52620
--- /dev/null
+++ b/scribo/binarization/sauvola_ms.hh
@@ -0,0 +1,822 @@
+// 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.
+
+
+#ifndef SCRIBO_BINARIZATION_SAUVOLA_MS_HH
+# define SCRIBO_BINARIZATION_SAUVOLA_MS_HH
+
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/data/fill.hh>
+
+# include <mln/subsampling/antialiased.hh>
+
+# include <mln/transform/influence_zone_geodesic.hh>
+
+# include <mln/value/int_u8.hh>
+# include <mln/border/mirror.hh>
+# include <mln/border/adjust.hh>
+
+# include <mln/core/box_runend_piter.hh>
+
+# include <scribo/subsampling/integral_single_image.hh>
+
+# include <scribo/core/macros.hh>
+# include <scribo/core/object_image.hh>
+
+# include <scribo/binarization/sauvola_threshold.hh>
+# include <scribo/binarization/internal/first_pass_functor.hh>
+
+# include <scribo/canvas/integral_browsing.hh>
+
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ using namespace mln;
+ using value::int_u8;
+
+
+ unsigned my_find_root(image2d<unsigned>& parent, unsigned x)
+ {
+ if (parent.element(x) == x)
+ return x;
+ return parent.element(x) = my_find_root(parent,
+ parent.element(x));
+ }
+
+
+ image2d<int_u8>
+ compute_t_n_and_e_2(const image2d<int_u8>& sub, image2d<int_u8>& e_2,
+ unsigned lambda_min, unsigned lambda_max,
+ unsigned s,
+ unsigned q, unsigned i, unsigned w,
+ const image2d<util::couple<double,double> >& integral_sum_sum_2)
+ {
+ typedef image2d<int_u8> I;
+ typedef point2d P;
+
+ unsigned ratio = std::pow(q, i - 2); // Ratio in comparison to e_2
+
+ unsigned
+ w_local = w * ratio,
+ w_local_h = w_local,
+ w_local_w = w_local;
+
+ if (! (w_local % 2))
+ {
+ --w_local_w;
+ ++w_local_h;
+ }
+
+ // 1st pass
+ scribo::binarization::internal::first_pass_functor< image2d<int_u8> >
+ f(sub);
+ scribo::canvas::integral_browsing(integral_sum_sum_2,
+ ratio,
+ w_local_w, w_local_h,
+ s,
+ f);
+
+ // 2nd pass
+ {
+ util::array<mln_value_(I) *> ptr(ratio);
+ unsigned nrows = geom::nrows(e_2);
+
+ mln_box_runend_piter_(I) sp(sub.domain()); // Backward.
+ unsigned ncols = sp.run_length();
+ for_all(sp)
+ {
+ unsigned p = &sub(sp) - sub.buffer(); // Offset
+ P site = sp;
+
+ {
+ P tmp = site * ratio;
+
+ // FIXME: to be removed!
+ if (tmp.row() + ratio >= nrows)
+ ptr.resize(nrows - tmp.row());
+
+ ptr(0) = &e_2(tmp);
+ // FIXME: pointers could just be updated with an offset.
+ for (unsigned j = 1; j < ptr.size(); ++j)
+ {
+ tmp[0] += 1;
+ ptr(j) = & e_2(tmp);
+ }
+ }
+
+ for (unsigned j = 0; j < ncols; ++j)
+ {
+ if (f.msk.element(p))
+ {
+
+ mln_site_(I) sq = site * ratio;
+
+ if (f.parent.element(p) == p)
+ {
+ // test over the component cardinality
+ f.msk.element(p) = f.card.element(p) > lambda_min
+ && f.card.element(p) < lambda_max;
+
+ if (f.msk.element(p) && e_2(sq) == 0u)
+ {
+ for (unsigned l = 0; l < ptr.size(); ++l)
+ std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
+ }
+
+ }
+ else
+ {
+ // Propagation
+ f.msk.element(p) = f.msk.element(f.parent.element(p));
+
+ if (f.msk.element(p) && e_2(sq) == 0u)
+ {
+ for (unsigned l = 0; l < ptr.size(); ++l)
+ std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
+ }
+
+ }
+ }
+
+ for (unsigned l = 0; l < ptr.size(); ++l)
+ ptr(l) -= ratio;
+
+ --site[1];
+ --p;
+ }
+
+ }
+ } // end of 2nd pass
+
+ return f.t_sub;
+ }
+
+
+
+ template <typename I, typename J, typename K>
+ mln_ch_value(I, bool)
+ multi_scale_binarization(const I& in, const J& e2,
+ const util::array<K>& t_ima,
+ unsigned s)
+ {
+ mln_ch_value(I,bool) out;
+ initialize(out, in);
+
+ typedef const mln_value(K)* ptr_type;
+
+ ptr_type ptr_t[5];
+ ptr_t[2] = & t_ima[2].at_(0, 0);
+ ptr_t[3] = & t_ima[3].at_(0, 0);
+ ptr_t[4] = & t_ima[4].at_(0, 0);
+
+
+ const mln_value(J)* ptr_e2 = & e2.at_(0, 0);
+ const mln_value(I)* ptr__in = & in.at_(0, 0);
+ bool* ptr__out = & out.at_(0, 0);
+
+
+ // Since we iterate from a smaller image in the largest ones and
+ // image at scale 1 does not always have a size which can be
+ // divided by (4*s), some sites in the border may not be processed
+ // and we must skip them.
+ int more_offset = - ((4 * s) - in.ncols() % (4 * s));
+
+ if (more_offset == - (static_cast<int>(4*s)))
+ more_offset = 0; // No offset needed.
+
+ const int
+ nrows4 = t_ima[4].nrows(), ncols4 = t_ima[4].ncols(),
+
+
+ delta1 = in.delta_index(dpoint2d(+1, -(s - 1))),
+ delta1b = in.delta_index(dpoint2d(+1, -(s + s - 1))),
+ delta1c = in.delta_index(dpoint2d(-(s + s - 1), +1)),
+ delta1d = in.delta_index(dpoint2d(+1, -(s * 4 - 1))),
+ delta1e = in.delta_index(dpoint2d(-(s * 4 - 1), +1)),
+ delta1f = in.delta_index(dpoint2d(-(s - 1), +1)),
+
+ delta2 = t_ima[2].delta_index(dpoint2d(+1, -1)),
+ delta2b = t_ima[2].delta_index(dpoint2d(+1, -3)),
+ delta2c = t_ima[2].delta_index(dpoint2d(-3, +1)),
+
+ delta3 = t_ima[3].delta_index(dpoint2d(+1, -1)),
+
+ eor1 = in.delta_index(dpoint2d(+4 * s, - in.ncols())) + more_offset,
+ eor2 = t_ima[2].delta_index(dpoint2d(+4,- t_ima[2].ncols())),
+ eor3 = t_ima[3].delta_index(dpoint2d(+2,- t_ima[3].ncols())),
+ eor4 = t_ima[4].delta_index(dpoint2d(+1,- t_ima[4].ncols()));
+
+ mln_value(J) threshold;
+ for (int row4 = 0; row4 < nrows4; ++row4)
+ {
+ for (int col4 = 0; col4 < ncols4; ++col4)
+ {
+ // top left 1
+ {
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1f; ptr__in += delta1f;
+ }
+
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1b; ptr__in += delta1b;
+ }
+
+ ptr_t[2] += delta2; ptr_e2 += delta2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1f; ptr__in += delta1f;
+
+ }
+
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1c; ptr__in += delta1c;
+ }
+
+ ptr_t[2] -= delta2; ptr_e2 -= delta2;
+ }
+
+ // top right 1
+ ptr_t[3] += 1;
+ {
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1f; ptr__in += delta1f;
+ }
+
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1b; ptr__in += delta1b;
+ }
+
+ ptr_t[2] += delta2; ptr_e2 += delta2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1f; ptr__in += delta1f;
+ }
+
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1d; ptr__in += delta1d;
+ }
+
+ ptr_t[2] += delta2b; ptr_e2 += delta2b;
+ }
+
+ // bot left 1
+ ptr_t[3] += delta3;
+ {
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1f; ptr__in += delta1f;
+ }
+
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1b; ptr__in += delta1b;
+ }
+
+ ptr_t[2] += delta2; ptr_e2 += delta2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1f; ptr__in += delta1f;
+ }
+
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1c; ptr__in += delta1c;
+ }
+
+ ptr_t[2] -= delta2; ptr_e2 -= delta2;
+ }
+
+ // bot right 1
+ ptr_t[3] += 1;
+ {
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1f; ptr__in += delta1f;
+ }
+
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1b; ptr__in += delta1b;
+ }
+
+ ptr_t[2] += delta2; ptr_e2 += delta2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1f; ptr__in += delta1f;
+ }
+
+ ++ptr_t[2]; ++ptr_e2;
+ threshold = *ptr_t[*ptr_e2];
+ {
+ for (unsigned i = 1; i < s; ++i)
+ {
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1; ptr__in += delta1;
+ }
+
+ for (unsigned j = 1; j < s; ++j)
+ {
+ *ptr__out = *ptr__in < threshold;
+ ++ptr__out; ++ptr__in;
+ }
+ *ptr__out = *ptr__in < threshold;
+ ptr__out += delta1e; ptr__in += delta1e;
+ }
+ }
+
+ // bot right -> next top left
+ ptr_t[2] += delta2c; ptr_e2 += delta2c;
+ ptr_t[3] = ptr_t[3] - delta3;
+ ptr_t[4] += 1;
+ }
+
+ // eof -> next bof
+ ptr__out += eor1; ptr__in += eor1;
+ ptr_t[2] += eor2; ptr_e2 += eor2;
+ ptr_t[3] += eor3;
+ ptr_t[4] += eor4;
+ }
+
+ return out;
+ }
+
+
+
+ unsigned sub(unsigned nbr, unsigned down_scaling)
+ {
+ return (nbr + down_scaling - 1) / down_scaling;
+ }
+
+ // Compute domains of subsampled images and make sure they can be
+ // divided by 2.
+ template <typename I>
+ util::array<util::couple<mln_domain(I), unsigned> >
+ compute_sub_domains(const I& ima, unsigned n_scales, unsigned s)
+ {
+ util::array<util::couple<unsigned, unsigned> > n(n_scales + 2);
+
+ n(1) = make::couple(ima.nrows(), ima.ncols());
+ n(2) = make::couple(sub(n(1).first(), s),
+ sub(n(1).second(), s));
+ for (unsigned i = 3; i <= n_scales + 1; ++i)
+ n(i) = make::couple(sub(n(i - 1).first(), 2),
+ sub(n(i - 1).second(), 2));
+
+
+ util::array<util::couple<mln_domain(I), unsigned> > out(n.size());
+ out(0) = make::couple(make::box2d(1,1), 1u);
+ out(1) = make::couple(make::box2d(ima.nrows(), ima.ncols()), 2u);
+ out(n_scales + 1) = make::couple(make::box2d(n(n_scales + 1).first(),
+ n(n_scales + 1).second()),
+ 1u);
+
+ for (unsigned i = n_scales; i > 1; --i)
+ out(i) = make::couple(make::box2d(2 * out(i + 1).first().nrows(),
+ 2 * out(i + 1).first().ncols()),
+ 2 * out(i + 1).second());
+
+ out(1).second() = std::max(out(2).first().ncols() * s - ima.ncols(),
+ out(2).first().nrows() * s - ima.nrows());
+
+ return out;
+ }
+
+ template <typename I>
+ mln_ch_value(I,bool)
+ sauvola_ms(const Image<I>& input_1_, unsigned w_1,
+ unsigned s, unsigned lambda_min_1)
+ {
+ trace::entering("scribo::binarization::sauvola_ms");
+
+ const I& input_1 = exact(input_1_);
+
+ mlc_is_a(mln_value(I), value::Scalar)::check();
+ mln_precondition(input_1.is_valid());
+
+ dpoint2d none(0, 0);
+
+ // Number of subscales.
+ unsigned nb_subscale = 3;
+
+ // Window size.
+ unsigned w_work = w_1 / s; // Scale 2
+
+
+ // Subscale step.
+ unsigned q = 2;
+
+ unsigned lambda_min_2 = lambda_min_1 / s;
+ unsigned lambda_max_2 = lambda_min_2 * q;
+
+
+ util::array<I> t_ima;
+
+ // Make sure t_ima indexes start from 2.
+ {
+ I dummy(1,1);
+ for (unsigned i = 0; i < nb_subscale + 2; ++i)
+ t_ima.append(dummy);
+ }
+
+ util::array<I> sub_ima;
+
+ // Make sure sub_ima indexes start from 2.
+ {
+ I dummy(1,1);
+ sub_ima.append(dummy);
+ sub_ima.append(dummy);
+ }
+
+ util::array<util::couple<box2d, unsigned> >
+ sub_domains = compute_sub_domains(input_1, nb_subscale, s);
+
+ border::adjust(input_1, sub_domains(1).second());
+ border::mirror(input_1);
+
+
+ // Resize input and compute integral images.
+ typedef image2d<util::couple<double,double> > integral_t;
+ integral_t integral_sum_sum_2;
+
+ // Subsampling from scale 1 to 2.
+ sub_ima.append(scribo::subsampling::integral(input_1, s,
+ integral_sum_sum_2,
+ sub_domains[2].first(),
+ sub_domains[2].second()));
+
+
+ // Subsampling to scale 3 and 4.
+ for (unsigned i = 3; i <= nb_subscale + 1; ++i)
+ sub_ima.append(mln::subsampling::antialiased(sub_ima[i - 1], q, none,
+ sub_domains[i].first(),
+ sub_domains[i].second()));
+
+
+ // Compute threshold images.
+ image2d<int_u8> e_2;
+ initialize(e_2, sub_ima[2]);
+ data::fill(e_2, 0u);
+
+ // Highest scale -> no maximum component size.
+ {
+ int i = sub_ima.size() - 1;
+ unsigned ratio = std::pow(q, i - 2); // Ratio compared to e_2
+ t_ima[i] = compute_t_n_and_e_2(sub_ima[i], e_2,
+ lambda_min_2 / ratio,
+ mln_max(unsigned),
+ s,
+ q, i, w_work, integral_sum_sum_2);
+ }
+
+ // Other scales -> maximum and minimum component size.
+ {
+ for (int i = sub_ima.size() - 2; i > 2; --i)
+ {
+ unsigned ratio = std::pow(q, i - 2); // Ratio compared to e_2
+ t_ima[i] = compute_t_n_and_e_2(sub_ima[i], e_2,
+ lambda_min_2 / ratio,
+ lambda_max_2 / ratio,
+ s,
+ q, i, w_work, integral_sum_sum_2);
+ }
+ }
+
+ // Lowest scale -> no minimum component size.
+ {
+ t_ima[2] = compute_t_n_and_e_2(sub_ima[2], e_2, 0, lambda_max_2,
+ s, 1, 2, w_work, integral_sum_sum_2);
+ }
+
+
+ // Propagate scale values.
+ e_2 = transform::influence_zone_geodesic(e_2, c8());
+
+
+ // Binarize
+ image2d<bool> output = multi_scale_binarization(input_1, e_2, t_ima, s);
+
+ trace::exiting("scribo::binarization::sauvola_ms");
+ return output;
+ }
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+
+#endif // SCRIBO_BINARIZATION_SAUVOLA_MS_HH
diff --git a/scribo/binarization/sauvola_threshold.hh b/scribo/binarization/sauvola_threshold.hh
index b1f9a81..20abc50 100644
--- a/scribo/binarization/sauvola_threshold.hh
+++ b/scribo/binarization/sauvola_threshold.hh
@@ -44,6 +44,8 @@
# include <mln/pw/all.hh>
# include <mln/core/routine/duplicate.hh>
+# include <mln/fun/v2v/rgb_to_int_u.hh>
+
# include <scribo/core/init_integral_image.hh>
@@ -96,16 +98,6 @@ namespace scribo
namespace internal
{
- struct rgb8_to_int_u8 : Function_v2v< rgb8_to_int_u8 >
- {
- typedef value::int_u8 result;
- result operator()(const value::rgb8& c) const
- {
- return (c.red() + c.green() + c.blue()) / 3;
- }
- };
-
-
/*! \brief compute Sauvola's threshold applying directly the formula.
\param[in] m_x_y Mean value.
@@ -383,7 +375,7 @@ namespace scribo
mln_ch_value(I, value::int_u8) gima;
gima = data::transform(input,
- internal::rgb8_to_int_u8());
+ mln::fun::v2v::rgb_to_int_u<8>());
mln_ch_value(I, value::int_u8)
output = impl::generic::sauvola_threshold(gima, window_size,
diff --git a/scribo/src/binarization/sauvola.cc b/scribo/src/binarization/sauvola.cc
index 28d3ae7..efe4787 100644
--- a/scribo/src/binarization/sauvola.cc
+++ b/scribo/src/binarization/sauvola.cc
@@ -33,6 +33,7 @@
const char *args_desc[][2] =
{
{ "input.ppm", "A color image." },
+ { "wsize", "Window size (Common value: 51)." },
{0, 0}
};
@@ -42,10 +43,10 @@ int main(int argc, char *argv[])
using namespace mln;
using value::rgb8;
- if (argc != 3)
+ if (argc != 4)
return scribo::debug::usage(argv,
"Binarization of a color image based on Sauvola's algorithm.",
- "input.ppm output.pbm",
+ "input.ppm wsize output.pbm",
args_desc, "A binary image.");
trace::entering("main");
@@ -53,7 +54,7 @@ int main(int argc, char *argv[])
image2d<rgb8> input;
io::ppm::load(input, argv[1]);
- io::pbm::save(scribo::binarization::sauvola(input), argv[2]);
+ io::pbm::save(scribo::binarization::sauvola(input, atoi(argv[2])), argv[3]);
trace::exiting("main");
diff --git a/scribo/src/binarization/sauvola_ms.cc b/scribo/src/binarization/sauvola_ms.cc
index ff5a99d..b3b4791 100644
--- a/scribo/src/binarization/sauvola_ms.cc
+++ b/scribo/src/binarization/sauvola_ms.cc
@@ -23,1300 +23,39 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-#include <mln/core/alias/neighb2d.hh>
-#include <mln/data/stretch.hh>
-#include <mln/data/paste.hh>
-#include <mln/debug/iota.hh>
-#include <mln/debug/quiet.hh>
-#include <mln/debug/println.hh>
-#include <mln/debug/println_with_border.hh>
-#include <mln/debug/filename.hh>
-#include <mln/fun/i2v/array.hh>
-#include <mln/io/pbm/all.hh>
-#include <mln/io/pgm/all.hh>
-#include <mln/io/ppm/all.hh>
-#include <mln/literal/colors.hh>
-#include <mln/math/sqr.hh>
-#include <mln/math/abs.hh>
-
-#include <mln/subsampling/antialiased.hh>
-
-#include <mln/transform/influence_zone_geodesic.hh>
-#include <mln/util/timer.hh>
-#include <mln/value/int_u16.hh>
+#include <mln/core/image/image2d.hh>
#include <mln/value/int_u8.hh>
-#include <mln/value/label_16.hh>
-#include <mln/value/rgb8.hh>
-#include <mln/border/equalize.hh>
-#include <mln/border/mirror.hh>
-#include <mln/border/adjust.hh>
-#include <mln/debug/filename.hh>
-
-#include <mln/core/box_runend_piter.hh>
-#include <mln/core/box_runstart_piter.hh>
-
-#include <scribo/subsampling/integral_single_image.hh>
-//#include <scribo/subsampling/integral.hh>
-
-#include <scribo/core/macros.hh>
-#include <scribo/core/object_image.hh>
-
-#include <scribo/filter/objects_small.hh>
-#include <scribo/filter/objects_large.hh>
-
-#include <scribo/filter/objects_thin.hh>
-#include <scribo/filter/objects_thick.hh>
-
-#include <scribo/primitive/extract/objects.hh>
-
-#include <scribo/binarization/sauvola_threshold.hh>
-#include <scribo/binarization/internal/first_pass_functor.hh>
-
-#include <scribo/canvas/integral_browsing.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pbm/save.hh>
+#include <scribo/binarization/sauvola_ms.hh>
#include <scribo/debug/usage.hh>
-#include <scribo/debug/save_object_diff.hh>
-namespace mln
+bool check_args(int argc, char * argv[])
{
+ if (argc < 5 || argc > 6)
+ return false;
- using value::int_u8;
-
-
- unsigned my_find_root(image2d<unsigned>& parent, unsigned x)
- {
- if (parent.element(x) == x)
- return x;
- return parent.element(x) = my_find_root(parent,
- parent.element(x));
- }
-
-
- image2d<int_u8>
- compute_t_n_and_e_2(const image2d<int_u8>& sub, image2d<int_u8>& e_2,
- unsigned lambda_min, unsigned lambda_max,
- unsigned s,
- unsigned q, unsigned i, unsigned w,
- const image2d<util::couple<double,double> >& integral_sum_sum_2)
- // lambdas: limits of component cardinality at this scale
- {
- typedef image2d<int_u8> I;
- typedef point2d P;
-
- util::timer tt;
- float t_;
-
- unsigned ratio = std::pow(q, i - 2); // Ratio in comparison to e_2
-
-
- tt.restart();
-
- unsigned
- w_local = w * ratio,
- w_local_h = w_local,
- w_local_w = w_local;
-
- if (! (w_local % 2))
- {
- --w_local_w;
- ++w_local_h;
- }
-
-// std::cout << "Echelle " << i
-// << " - w_local_h = " << w_local_h
-// << " - w_local_w = " << w_local_w
-// << " - w_1 = " << (w_local - 1) * s + 1
-// << std::endl;
-
-// std::cout << "Ratio = " << ratio << std::endl;
-// std::cout << " -----------" << std::endl;
-
- // 1st pass
- scribo::binarization::internal::first_pass_functor< image2d<int_u8> >
- f(sub);
- scribo::canvas::integral_browsing(integral_sum_sum_2,
- ratio,
- w_local_w, w_local_h,
- s,
- f);
-
-
- t_ = tt;
- if (! mln::debug::quiet)
- std::cout << "1st pass - " << t_ << std::endl;
-
- tt.restart();
-
- {
- util::array<mln_value_(I) *> ptr(ratio);
- unsigned nrows = geom::nrows(e_2);
-
- mln_box_runend_piter_(I) sp(sub.domain()); // Backward.
- unsigned ncols = sp.run_length();
- for_all(sp)
- {
- unsigned p = &sub(sp) - sub.buffer(); // Offset
- P site = sp;
-
- {
- P tmp = site * ratio;
-
- // FIXME: to be removed!
- if (tmp.row() + ratio >= nrows)
- ptr.resize(nrows - tmp.row());
-
- ptr(0) = &e_2(tmp);
- // FIXME: pointers could just be updated with an offset.
- for (unsigned j = 1; j < ptr.size(); ++j)
- {
- tmp[0] += 1;
- ptr(j) = & e_2(tmp);
- }
- }
-
- for (unsigned j = 0; j < ncols; ++j)
- {
- if (f.msk.element(p))
- {
-
- mln_site_(I) sq = site * ratio;
-
- if (f.parent.element(p) == p)
- {
- // test over the component cardinality
- f.msk.element(p) = f.card.element(p) > lambda_min
- && f.card.element(p) < lambda_max;
-
- if (f.msk.element(p) && e_2(sq) == 0u)
- {
- for (unsigned l = 0; l < ptr.size(); ++l)
- std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
- }
-
- }
- else
- {
- // Propagation
- f.msk.element(p) = f.msk.element(f.parent.element(p));
-
- if (f.msk.element(p) && e_2(sq) == 0u)
- {
- for (unsigned l = 0; l < ptr.size(); ++l)
- std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
- }
-
- }
- }
-
- for (unsigned l = 0; l < ptr.size(); ++l)
- ptr(l) -= ratio;
-
- --site[1];
- --p;
- }
-
- }
-
- t_ = tt;
- if (! mln::debug::quiet)
- std::cout << "2nd pass - " << t_ << std::endl;
-
-// io::pgm::save(e_2, mln::debug::filename("e.pgm", i));
-// io::pbm::save(f.msk, mln::debug::filename("mask.pbm", i));
-// io::pgm::save(data::stretch(int_u8(), card), mln::debug::filename("card.pgm"));
- } // end of 2nd pass
-
-// io::pgm::save(f.t_sub, mln::debug::filename("t.pgm", i));
- return f.t_sub;
- }
-
-
-
- template <typename I, typename J, typename K>
- mln_ch_value(I, bool)
- binarize_generic(const I& in, const J& e2, const util::array<K>& t_ima,
- unsigned s)
- {
- mln_ch_value(I,bool) out;
- initialize(out, in);
-
- typedef const mln_value(K)* ptr_type;
-
- ptr_type ptr_t[5];
- ptr_t[2] = & t_ima[2].at_(0, 0);
- ptr_t[3] = & t_ima[3].at_(0, 0);
- ptr_t[4] = & t_ima[4].at_(0, 0);
-
-
- const mln_value(J)* ptr_e2 = & e2.at_(0, 0);
- const mln_value(I)* ptr__in = & in.at_(0, 0);
- bool* ptr__out = & out.at_(0, 0);
-
-
- // Since we iterate from a smaller image in the largest ones and
- // image at scale 1 does not always have a size which can be
- // divided by (4*s), some sites in the border may not be processed
- // and we must skip them.
- int more_offset = - ((4 * s) - in.ncols() % (4 * s));
-
- if (more_offset == - (static_cast<int>(4*s)))
- more_offset = 0; // No offset needed.
-
- const int
- nrows4 = t_ima[4].nrows(), ncols4 = t_ima[4].ncols(),
-
-
- delta1 = in.delta_index(dpoint2d(+1, -(s - 1))),
- delta1b = in.delta_index(dpoint2d(+1, -(s + s - 1))),
- delta1c = in.delta_index(dpoint2d(-(s + s - 1), +1)),
- delta1d = in.delta_index(dpoint2d(+1, -(s * 4 - 1))),
- delta1e = in.delta_index(dpoint2d(-(s * 4 - 1), +1)),
- delta1f = in.delta_index(dpoint2d(-(s - 1), +1)),
-
- delta2 = t_ima[2].delta_index(dpoint2d(+1, -1)),
- delta2b = t_ima[2].delta_index(dpoint2d(+1, -3)),
- delta2c = t_ima[2].delta_index(dpoint2d(-3, +1)),
-
- delta3 = t_ima[3].delta_index(dpoint2d(+1, -1)),
-
- eor1 = in.delta_index(dpoint2d(+4 * s, - in.ncols())) + more_offset,
- eor2 = t_ima[2].delta_index(dpoint2d(+4,- t_ima[2].ncols())),
- eor3 = t_ima[3].delta_index(dpoint2d(+2,- t_ima[3].ncols())),
- eor4 = t_ima[4].delta_index(dpoint2d(+1,- t_ima[4].ncols()));
-
- mln_value(J) threshold;
- for (int row4 = 0; row4 < nrows4; ++row4)
- {
- for (int col4 = 0; col4 < ncols4; ++col4)
- {
- // top left 1
- {
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
-
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1b; ptr__in += delta1b;
- }
-
- ptr_t[2] += delta2; ptr_e2 += delta2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
-
- }
-
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1c; ptr__in += delta1c;
- }
-
- ptr_t[2] -= delta2; ptr_e2 -= delta2;
- }
-
- // top right 1
- ptr_t[3] += 1;
- {
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
-
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1b; ptr__in += delta1b;
- }
-
- ptr_t[2] += delta2; ptr_e2 += delta2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
-
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1d; ptr__in += delta1d;
- }
-
- ptr_t[2] += delta2b; ptr_e2 += delta2b;
- }
-
- // bot left 1
- ptr_t[3] += delta3;
- {
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
-
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1b; ptr__in += delta1b;
- }
-
- ptr_t[2] += delta2; ptr_e2 += delta2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
-
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1c; ptr__in += delta1c;
- }
-
- ptr_t[2] -= delta2; ptr_e2 -= delta2;
- }
-
- // bot right 1
- ptr_t[3] += 1;
- {
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
-
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1b; ptr__in += delta1b;
- }
-
- ptr_t[2] += delta2; ptr_e2 += delta2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1f; ptr__in += delta1f;
- }
-
- ++ptr_t[2]; ++ptr_e2;
- threshold = *ptr_t[*ptr_e2];
- {
- for (unsigned i = 1; i < s; ++i)
- {
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
-
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1; ptr__in += delta1;
- }
-
- for (unsigned j = 1; j < s; ++j)
- {
- *ptr__out = *ptr__in < threshold;
- ++ptr__out; ++ptr__in;
- }
- *ptr__out = *ptr__in < threshold;
- ptr__out += delta1e; ptr__in += delta1e;
- }
- }
-
- // bot right -> next top left
- ptr_t[2] += delta2c; ptr_e2 += delta2c;
- ptr_t[3] = ptr_t[3] - delta3;
- ptr_t[4] += 1;
- }
-
- // eof -> next bof
- ptr__out += eor1; ptr__in += eor1;
- ptr_t[2] += eor2; ptr_e2 += eor2;
- ptr_t[3] += eor3;
- ptr_t[4] += eor4;
- }
-
-
-// mln::debug::println(out);
-
- return out;
- }
-
-
-
-// template <typename I, typename J, typename K>
-// mln_ch_value(I, unsigned)
-// binarize_generic_debug(const I& in, const J& e2, const util::array<K>& t_ima,
-// unsigned s)
-// {
-// mln_ch_value(I,unsigned) out;
-// initialize(out, in);
-// data::fill(out, 0);
-
-// typedef const mln_value(K)* ptr_type;
-
-// ptr_type ptr_t[5];
-// ptr_t[2] = & t_ima[2].at_(0, 0);
-// ptr_t[3] = & t_ima[3].at_(0, 0);
-// ptr_t[4] = & t_ima[4].at_(0, 0);
-
-
-// const mln_value(J)* ptr_e2 = & e2.at_(0, 0);
-// const mln_value(I)* ptr__in = & in.at_(0, 0);
-// unsigned* ptr__out = & out.at_(0, 0);
-
-
-// // Since we iterate from a smaller image in the largest ones and
-// // image at scale 1 does not always have a size which can be
-// // divided by (4*s), some sites in the border may not be processed
-// // and we must skip them.
-
-// std::cout << in.ncols() << std::endl;
-// std::cout << in.ncols() % (4 * s) << std::endl;
-// int more_offset = - ((4 * s) - in.ncols() % (4 * s));
-
-// if (more_offset == - (4*s))
-// more_offset = 0; // No offset needed.
-
-// std::cout << "more_offset == " << more_offset << std::endl;
-// std::cout << "- b1 = " << in.border()
-// << "- b2 = " << t_ima[2].border()
-// << "- b3 = " << t_ima[3].border()
-// << "- b4 = " << t_ima[4].border()
-// << std::endl;
-
-// const int
-// nrows4 = t_ima[4].nrows(), ncols4 = t_ima[4].ncols(),
-
-
-// delta1 = in.delta_index(dpoint2d(+1, -(s - 1))),
-// delta1b = in.delta_index(dpoint2d(+1, -(s + s - 1))),
-// delta1c = in.delta_index(dpoint2d(-(s + s - 1), +1)),
-// delta1d = in.delta_index(dpoint2d(+1, -(s * 4 - 1))),
-// delta1e = in.delta_index(dpoint2d(-(s * 4 - 1), +1)),
-// delta1f = in.delta_index(dpoint2d(-(s - 1), +1)),
-
-// delta2 = t_ima[2].delta_index(dpoint2d(+1, -1)),
-// delta2b = t_ima[2].delta_index(dpoint2d(+1, -3)),
-// delta2c = t_ima[2].delta_index(dpoint2d(-3, +1)),
-
-// delta3 = t_ima[3].delta_index(dpoint2d(+1, -1)),
-
-// eor1 = in.delta_index(dpoint2d(+4 * s, - in.ncols())) + more_offset,
-// eor2 = t_ima[2].delta_index(dpoint2d(+4,- t_ima[2].ncols())),
-// eor3 = t_ima[3].delta_index(dpoint2d(+2,- t_ima[3].ncols())),
-// eor4 = t_ima[4].delta_index(dpoint2d(+1,- t_ima[4].ncols()));
-
-// unsigned pid = 0;
-
-// mln_value(J) threshold;
-// for (int row4 = 0; row4 < nrows4; ++row4)
-// {
-// for (int col4 = 0; col4 < ncols4; ++col4)
-// {
-// // top left 1
-// {
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1f; ptr__in += delta1f;
-// }
-
-// ++ptr_t[2]; ++ptr_e2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1b; ptr__in += delta1b;
-// }
-
-// ptr_t[2] += delta2; ptr_e2 += delta2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1f; ptr__in += delta1f;
-
-// }
-
-// ++ptr_t[2]; ++ptr_e2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1c; ptr__in += delta1c;
-// }
-
-// ptr_t[2] -= delta2; ptr_e2 -= delta2;
-// }
-
-// // top right 1
-// ptr_t[3] += 1;
-// {
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1f; ptr__in += delta1f;
-// }
-
-// ++ptr_t[2]; ++ptr_e2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1b; ptr__in += delta1b;
-// }
-
-// ptr_t[2] += delta2; ptr_e2 += delta2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1f; ptr__in += delta1f;
-// }
-
-// ++ptr_t[2]; ++ptr_e2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1d; ptr__in += delta1d;
-// }
+ int s = atoi(argv[3]);
-// ptr_t[2] += delta2b; ptr_e2 += delta2b;
-// }
-
-// // bot left 1
-// ptr_t[3] += delta3;
-// {
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1f; ptr__in += delta1f;
-// }
-
-// ++ptr_t[2]; ++ptr_e2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1b; ptr__in += delta1b;
-// }
-
-// ptr_t[2] += delta2; ptr_e2 += delta2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1f; ptr__in += delta1f;
-// }
-
-// ++ptr_t[2]; ++ptr_e2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1c; ptr__in += delta1c;
-// }
-
-// ptr_t[2] -= delta2; ptr_e2 -= delta2;
-// }
-
-// // bot right 1
-// ptr_t[3] += 1;
-// {
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1f; ptr__in += delta1f;
-// }
-
-// ++ptr_t[2]; ++ptr_e2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1b; ptr__in += delta1b;
-// }
-
-// ptr_t[2] += delta2; ptr_e2 += delta2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1f; ptr__in += delta1f;
-// }
-
-// ++ptr_t[2]; ++ptr_e2;
-// threshold = *ptr_t[*ptr_e2];
-// {
-// for (unsigned i = 1; i < s; ++i)
-// {
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-
-// *ptr__out = pid++;
-// ptr__out += delta1; ptr__in += delta1;
-// }
-
-// for (unsigned j = 1; j < s; ++j)
-// {
-// *ptr__out = pid++;
-// ++ptr__out; ++ptr__in;
-// }
-// *ptr__out = pid++;
-// ptr__out += delta1e; ptr__in += delta1e;
-// }
-// }
-
-// // bot right -> next top left
-// ptr_t[2] += delta2c; ptr_e2 += delta2c;
-// ptr_t[3] = ptr_t[3] - delta3;
-// ptr_t[4] += 1;
-// }
-
-// // eof -> next bof
-// ptr__out += eor1; ptr__in += eor1;
-// ptr_t[2] += eor2; ptr_e2 += eor2;
-// ptr_t[3] += eor3;
-// ptr_t[4] += eor4;
-// }
-
-
-// // mln::debug::println(out);
-
-// return out;
-// }
-
-
-
-
- unsigned sub(unsigned nbr, unsigned down_scaling)
- {
- return (nbr + down_scaling - 1) / down_scaling;
- }
-
- template <typename I>
- util::array<util::couple<mln_domain(I), unsigned> >
- compute_sub_domains(const I& ima, unsigned n_scales, unsigned s)
+ if (s < 1 || s > 3)
{
- util::array<util::couple<unsigned, unsigned> > n(n_scales + 2);
-
- n(1) = make::couple(ima.nrows(), ima.ncols());
- n(2) = make::couple(sub(n(1).first(), s),
- sub(n(1).second(), s));
- for (unsigned i = 3; i <= n_scales + 1; ++i)
- n(i) = make::couple(sub(n(i - 1).first(), 2),
- sub(n(i - 1).second(), 2));
-
-
- util::array<util::couple<mln_domain(I), unsigned> > out(n.size());
- out(0) = make::couple(make::box2d(1,1), 1u);
- out(1) = make::couple(make::box2d(ima.nrows(), ima.ncols()), 2u);
- out(n_scales + 1) = make::couple(make::box2d(n(n_scales + 1).first(),
- n(n_scales + 1).second()),
- 1u);
-
- for (unsigned i = n_scales; i > 1; --i)
- out(i) = make::couple(make::box2d(2 * out(i + 1).first().nrows(),
- 2 * out(i + 1).first().ncols()),
- 2 * out(i + 1).second());
-
- out(1).second() = std::max(out(2).first().ncols() * s - ima.ncols(),
- out(2).first().nrows() * s - ima.nrows());
-
-// out(1).second() = std::max(ima.ncols() % (4 * s),
-// ima.nrows() % (4 * s));
-
-// out(2).first().ncols() * s - ima.ncols(),
-// out(2).first().nrows() * s - ima.nrows() );
-
- return out;
- }
-
-
-
- bool
- check_args(int argc, char * argv[])
- {
- if (argc < 5 || argc > 7)
- return false;
-
-// int nb_scale = atoi(argv[3]);
- int s = atoi(argv[3]);
-// int q = atoi(argv[5]);
-
-// if (q < 2)
-// {
-// std::cout << "q must be greater than 2." << std::endl;
-// return false;
-// }
- if (s < 1 || s > 3)// || s < q)
- {
- std::cout << "s must be set to 2 or 3."
- << std::endl;
- return false;
- }
-
-
-// if (nb_scale < 1)
-// {
-// std::cout << "Not enough scales." << std::endl;
-// return false;
-// }
-
-// if ((argc - 7) != (nb_scale - 1))
-// {
-// std::cout << "Not enough area threshold."
-// << "There must be nb_scale - 1 thresholds."
-// << std::endl;
-// return false;
-// }
-
- return true;
- }
-
-
- void data_rand(image2d<unsigned>& e2)
- {
- unsigned v = 2;
- mln_piter_(box2d) p(e2.domain());
- for_all(p)
- {
- e2(p) = v++;
- if (v == 5) v = 2;
- }
+ std::cout << "s must be set to 2 or 3."
+ << std::endl;
+ return false;
}
-
-} // end of namespace mln;
-
-
+ return true;
+}
const char *args_desc[][2] =
{
{ "input.pgm", "A graylevel image." },
{ "w", "Window size at scale 1. (Common value: 101)" },
- { "s", "First subsampling ratio (Common value: 2)." },
- { "min_area", "Minimum object area (at scale 2) (Common value: 200)" },
- { "debug", "Display debug/bench data if set to 1" },
+ { "s", "First subsampling ratio (Common value: 3)." },
+ { "min_area", "Minimum object area at scale 1 (Common value: 67)" },
{0, 0}
};
@@ -1327,71 +66,36 @@ int main(int argc, char *argv[])
{
using namespace mln;
using namespace scribo;
- using value::rgb8;
- using value::int_u8;
- using value::int_u16;
- using value::label_16;
-
- typedef image2d<label_16> L;
if (!check_args(argc, argv))
return scribo::debug::usage(argv,
"Multi-Scale Binarization of a color image based on Sauvola's algorithm.",
- "input.pgm w s area_thresholds output.pbm [debug]",
+ "input.pgm w s area_threshold output.pbm",
args_desc, "A binary image.");
trace::entering("main");
- mln::debug::internal::filename_prefix = argv[1];
+ // Window size
+ unsigned w_1 = atoi(argv[2]); // Scale 1
// First subsampling scale.
unsigned s = atoi(argv[3]);
- // Window size.
- unsigned
- w_1 = atoi(argv[2]), // Scale 1
- w_work = w_1 / s; // Scale 2
-
- // Number of subscales.
- unsigned nb_subscale = 3;//atoi(argv[3]);
+ // Lambda value
+ unsigned lambda_min_1 = atoi(argv[4]);
- // Subscale step.
- unsigned q = 2;//atoi(argv[5]);
-
- mln::debug::quiet = true;
-
- if (argc == 7)
- mln::debug::quiet = ! atoi(argv[6]);
-
-
- if (! mln::debug::quiet)
- std::cout << "Running Sauvola_ms with w_1 = " << w_1
- << ", s = " << s
- << ", nb_subscale = " << nb_subscale
- << ", q = " << q
- << std::endl;
- typedef image2d<value::int_u8> I;
- dpoint2d none(0, 0);
-
- mln::util::timer
- timer_,
- sauvola_timer_;;
-
- // Tmp variable used for timer results;
- float t_;
-
- I input_full;
- io::pgm::load(input_full, argv[1]);
+ image2d<value::int_u8> input_1;
+ io::pgm::load(input_1, argv[1]);
{
- unsigned max_dim = math::max(input_full.ncols() / s,
- input_full.nrows() / s);
- if (w_work > max_dim)
+ unsigned max_dim = math::max(input_1.ncols(),
+ input_1.nrows());
+ if (w_1 > max_dim)
{
std::cout << "------------------" << std::endl;
std::cout << "The window is too large! Image size is only "
- << input_full.nrows() / s << "x" << input_full.ncols() / s
+ << input_1.nrows() << "x" << input_1.ncols()
<< std::endl
<< "Window size must not exceed " << max_dim
<< std::endl;
@@ -1399,324 +103,11 @@ int main(int argc, char *argv[])
}
}
-// I input_full(9,9);
-// mln::debug::iota(input_full);
-
- sauvola_timer_.start();
-
- unsigned lambda_min = atoi(argv[4]);
- unsigned lambda_max = lambda_min * q; // * atoi(argv[7])
-
-
- util::array<I> t_ima;
-
- // Make sure t_ima indexes start from 2.
- {
- I dummy(1,1);
- for (unsigned i = 0; i < nb_subscale + 2; ++i)
- t_ima.append(dummy);
- }
+ image2d<bool>
+ output = scribo::binarization::sauvola_ms(input_1, w_1, s, lambda_min_1);
-
- image2d<int_u8> e_2;
- util::array<I> sub_ima;
-
- // Make sure sub_ima indexes start from 2.
- {
- I dummy(1,1);
- sub_ima.append(dummy);
- sub_ima.append(dummy);
- }
-
-
- timer_.restart();
-
- util::array<util::couple<box2d, unsigned> >
- sub_domains = compute_sub_domains(input_full, nb_subscale, s);
-
- if (! mln::debug::quiet)
- std::cout << "adjusting input border to " << sub_domains(1).second()
- << std::endl;
-
- border::adjust(input_full, sub_domains(1).second());
- border::mirror(input_full);
-
-// mln::debug::println_with_border(input_full);
-
- t_ = timer_;
- if (! mln::debug::quiet)
- std::cout << "sub domains computed and adjust input border size - "
- << t_ << std::endl;
-
- // Resize input and compute integral images.
- timer_.restart();
- typedef image2d<util::couple<double,double> > integral_t;
- integral_t integral_sum_sum_2;
-
- if (! mln::debug::quiet)
- std::cout << "sub_domain(2).domain() == " << sub_domains(2).first() << std::endl;
-
- sub_ima.append(scribo::subsampling::integral(input_full, s,
- integral_sum_sum_2,
- sub_domains[2].first(),
- sub_domains[2].second()));
-
-// {
-// io::pgm::save(sub_ima[2], "in_50p.pgm");
-// mln_piter_(integral_t) p(integral_sum_sum_2.domain());
-// for_all(p)
-// {
-// std::cout << integral_sum_sum_2(p).first() << ", ";
-// }
-// std::cout << std::endl << " ------- " << std::endl;
-
-// for_all(p)
-// {
-// std::cout << integral_sum_sum_2(p).second() << ", ";
-// }
-// std::cout << std::endl << " ------- " << std::endl;
-// }
-
-// mln::debug::println(integral_sum_sum_2);
-
- t_ = timer_;
- if (! mln::debug::quiet)
- std::cout << "subsampling 1 -> 2 And integral images - " << t_
- << " - nsites = "
- << input_full.domain().nsites() << " -> "
- << sub_ima[2].domain().nsites() << " - "
- << input_full.domain() << " -> "
- << sub_ima[2].domain() << std::endl;
-
-
- for (unsigned i = 3; i <= nb_subscale + 1; ++i)
- {
- timer_.restart();
- sub_ima.append(mln::subsampling::antialiased(sub_ima[i - 1], q, none,
- sub_domains[i].first(),
- sub_domains[i].second()));
- t_ = timer_;
- if (! mln::debug::quiet)
- std::cout << "subsampling " << (i - 1) << " -> " << i
- << " - " << t_
- << " - nsites = "
- << sub_ima[i].domain().nsites() << " - "
- << sub_ima[i].domain()
- << std::endl;
- }
-
-
- initialize(e_2, sub_ima[2]);
- data::fill(e_2, 0u);
-
- // Compute threshold image.
-
- // Highest scale -> no maximum component size.
- {
- timer_.restart();
- int i = sub_ima.size() - 1;
- unsigned ratio = std::pow(q, i - 2); // Ratio compared to e_2
- t_ima[i] = compute_t_n_and_e_2(sub_ima[i], e_2,
- lambda_min / ratio,
- mln_max(unsigned),
- s,
- q, i, w_work, integral_sum_sum_2);
-
- t_ = timer_;
- if (! mln::debug::quiet)
- std::cout << "Scale " << i
- << " - 1/" << s * ratio
- << " compute t_n and update e - " << t_ << std::endl;
- }
-
- // Other scales -> maximum and minimum component size.
- {
- for (int i = sub_ima.size() - 2; i > 2; --i)
- {
- timer_.restart();
- unsigned ratio = std::pow(q, i - 2); // Ratio compared to e_2
- t_ima[i] = compute_t_n_and_e_2(sub_ima[i], e_2,
- lambda_min / ratio,
- lambda_max / ratio,
- s,
- q, i, w_work, integral_sum_sum_2);
-
- t_ = timer_;
- if (! mln::debug::quiet)
- std::cout << "Scale " << i
- << " - 1/" << s * ratio
- << " compute t_n and update e - " << t_ << std::endl;
- }
- }
-
- // Lowest scale -> no minimum component size.
- {
- timer_.restart();
- t_ima[2] = compute_t_n_and_e_2(sub_ima[2], e_2, 0, lambda_max,
- s, 1, 2, w_work, integral_sum_sum_2);
- t_ = timer_;
- if (! mln::debug::quiet)
- std::cout << "Scale " << 2
- << " - 1/" << s
- << " compute t_n and update e - " << t_ << std::endl;
-
- }
-
- if (! mln::debug::quiet)
- std::cout << "--------" << std::endl;
-// io::pgm::save(e_2, mln::debug::filename("e.pgm"));
-
-
-
- timer_.restart();
- e_2 = transform::influence_zone_geodesic(e_2, c8());
- t_ = timer_;
- if (! mln::debug::quiet)
- std::cout << "influence zone - " << t_ << std::endl;
-
-
-
-// Saving influence zone scale image.
-// io::pgm::save(e_2, mln::debug::filename("e_ext.pgm"));
-// io::pbm::save(bin, argv[8]);
-// io::pgm::save(t, mln::debug::filename("t.pgm"));
-
-// for (unsigned i = 2; i < t_ima.size(); ++i)
-// io::pgm::save(t_ima[i], mln::debug::filename("t.pgm", i));
-
-// {
-// image2d<bool> out_2;
-// initialize(out_2, e_2);
-// mln_piter_(image2d<int_u8>) p(e_2.domain());
-// for_all(p)
-// {
-// out_2(p) = sub_ima[2](p) < t_ima[2](p);
-// }
-// io::pbm::save(out_2, argv[5]);
-// }
-
-
- timer_.restart();
- image2d<bool> out_new = binarize_generic(input_full, e_2, t_ima, s);
-// image2d<bool> out_new = binarize(input_full, e_2, t_ima);
- t_ = timer_;
- if (! mln::debug::quiet)
- std::cout << "Compute bin - " << t_ << std::endl;
-
- t_ = sauvola_timer_;
- if (! mln::debug::quiet)
- std::cout << "Sauvola : " << t_ << std::endl;
-
- io::pbm::save(out_new, argv[5]);
-// abort();
+ io::pbm::save(output, argv[5]);
}
-
-
-// int main(int argc, char *argv[])
-// {
-// using namespace mln;
-// using namespace scribo;
-// using value::rgb8;
-// using value::int_u8;
-// using value::int_u16;
-// using value::label_16;
-
-// typedef image2d<label_16> L;
-
-// unsigned s = atoi(argv[3]);
-
-
-// typedef image2d<value::int_u8> I;
-// dpoint2d none(0, 0);
-
-// I input_full(atoi(argv[1]),atoi(argv[2]));
-// // I input_full(30,20); // Cas pourri
-// // I input_full(30,24); // Cas 'row <<'
-// // I input_full(36,24); // Cas ideal
-// // I input_full(36,20); // Cas 'col <<'
-// mln::debug::iota(input_full);
-
-// mln::debug::println(input_full);
-
-
-// util::array<I> sub_ima;
-// util::array<I> t_ima;
-
-
-// // Make sure t_ima indexes start from 2.
-// {
-// I dummy(1,1);
-// for (unsigned i = 0; i < 3 + 2; ++i)
-// t_ima.append(dummy);
-// }
-
-// // Make sure sub_ima indexes start from 2.
-// {
-// I dummy(1,1);
-// sub_ima.append(dummy);
-// sub_ima.append(dummy);
-// }
-
-
-
-// util::array<util::couple<box2d, unsigned> >
-// sub_domains = compute_sub_domains(input_full, 3, s);
-
-// border::adjust(input_full, sub_domains(1).second());
-// border::mirror(input_full);
-
-// // Resize input and compute integral images.
-// typedef image2d<util::couple<double,double> > integral_t;
-// integral_t integral_sum_sum_2;
-
-// sub_ima.append(scribo::subsampling::integral(input_full, s,
-// integral_sum_sum_2,
-// sub_domains[2].first(),
-// sub_domains[2].second()));
-
-// std::cout << "input border = " << input_full.border() << std::endl;
-// std::cout << "subsampling 1 -> 2 And integral images - "
-// << " - nsites = "
-// << input_full.domain().nsites() << " -> "
-// << sub_ima[2].domain().nsites() << " - "
-// << input_full.domain() << " -> "
-// << sub_ima[2].domain() << std::endl;
-
-
-// for (unsigned i = 3; i <= 3 + 1; ++i)
-// {
-// sub_ima.append(mln::subsampling::antialiased(sub_ima[i - 1], 2, none,
-// sub_domains[i].first(),
-// sub_domains[i].second()));
-// std::cout << "subsampling " << (i - 1) << " -> " << i
-// << " - "
-// << " - nsites = "
-// << sub_ima[i].domain().nsites() << " - "
-// << sub_ima[i].domain()
-// << std::endl;
-// t_ima[i] = I(sub_ima[i].domain());
-// }
-
-
-
-
-
-// image2d<int_u8> e_2;
-// initialize(e_2, sub_ima[2]);
-// data::fill(e_2, 2);
-
-// data::fill(t_ima[2], 30);
-
-// image2d<unsigned> out_new = binarize_generic_debug(input_full, e_2, t_ima, s);
-
-// mln::debug::println_with_border(out_new);
-// // io::pgm::save(out_new, "out.pgm");
-
-// std::cout << "------------" << std::endl;
-
-// // out_new = binarize_generic_debug(input_full, e_2, t_ima, 2);
-// // mln::debug::println(out_new);
-// }
--
1.5.6.5
1
0
last-svn-commit-25-g8d114a2 core/object_image.hh: Make use of mln::labeled_image_base.
by Guillaume Lazzara 11 Mar '10
by Guillaume Lazzara 11 Mar '10
11 Mar '10
---
scribo/ChangeLog | 4 +
scribo/core/object_image.hh | 347 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 347 insertions(+), 4 deletions(-)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 2897a58..a5c7fea 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,9 @@
2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
+ * core/object_image.hh: Make use of mln::labeled_image_base.
+
+2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
+
Improve linking routines.
* core/anchors.hh: New. Add anchor types.
diff --git a/scribo/core/object_image.hh b/scribo/core/object_image.hh
index a920680..5eaae67 100644
--- a/scribo/core/object_image.hh
+++ b/scribo/core/object_image.hh
@@ -28,11 +28,350 @@
/// \file
///
-/// FIXME.
+/// \brief Definition of a morpher on a labeled image.
-# include <mln/core/image/imorph/labeled_image.hh>
+# include <mln/core/internal/labeled_image_base.hh>
-# define object_image(L) \
- labeled_image<L>
+# include <mln/core/routine/duplicate.hh>
+
+# include <mln/util/array.hh>
+
+# include <mln/data/compute.hh>
+
+# include <mln/accu/center.hh>
+# include <mln/accu/shape/bbox.hh>
+# include <mln/accu/stat/max.hh>
+
+# include <mln/labeling/compute.hh>
+
+namespace mln
+{
+
+ // Forward declarations.
+ template <typename I> struct object_image;
+
+ namespace internal
+ {
+ using namespace mln;
+
+ /// Data structure for \c mln::object_image<I>.
+ template <typename I>
+ struct data< object_image<I> >
+ : data< labeled_image_base<I, object_image<I> > >
+ {
+ typedef data< labeled_image_base<I, object_image<I> > > super_;
+ typedef mln_psite(I) ms_t;
+ typedef mln_result(accu::center<mln_site(I)>) accu_res_t;
+
+ data(const I& ima, const mln_value(I)& nlabels);
+ data(const I& ima, const mln_value(I)& nlabels,
+ const util::array<mln_box(I)>& bboxes,
+ const util::array<ms_t>& mass_centers);
+ data(const I& ima, const mln_value(I)& nlabels,
+ const util::array<mln_box(I)>& bboxes,
+ const util::array<accu_res_t>& mass_centers);
+
+ mutable util::array<ms_t> mass_centers_;
+
+ util::array<accu::center<mln_psite(I)> > tmp_accus_;
+ };
+
+ } // end of namespace mln::internal
+
+
+ namespace trait
+ {
+
+ template <typename I>
+ struct image_< object_image<I> >
+ : image_< labeled_image_base< I, object_image<I> > >
+ {
+ };
+
+ } // end of namespace mln::trait
+
+
+
+ /// Morpher providing an improved interface for labeled image.
+ ///
+ /// \tparam I The label image type.
+ ///
+ /// This image type allows to access every site set at a given
+ /// label.
+ ///
+ /// This image type guaranties that labels are contiguous (from 1 to
+ /// n).
+ ///
+ /// \ingroup modimageidmorpher
+ //
+ template <typename I>
+ class object_image
+ : public mln::labeled_image_base<I, object_image<I> >
+ {
+ typedef mln::labeled_image_base<I, object_image<I> > super_;
+
+ public:
+
+ /// Skeleton.
+ typedef object_image< tag::image_<I> > skeleton;
+
+ /// Mass center type.
+ typedef typename internal::data< object_image<I> >::ms_t ms_t;
+ typedef mln_result(accu::center<mln_site(I)>) accu_res_t;
+
+ /// Constructors
+ /// @{
+ /// Constructor without argument.
+ object_image();
+
+ /// Constructor from an image \p ima and the number of labels \p nlabels.
+ object_image(const I& ima, const mln_value(I)& nlabels);
+
+ /// Constructor from an image \p ima, the number of labels \p
+ /// nlabels and the object bounding boxes.
+ template <typename P>
+ object_image(const I& ima, const mln_value(I)& nlabels,
+ const util::array<mln_box(I)>& bboxes,
+ const util::array<P>& mass_centers);
+ /// @}
+
+ /// Deferred initialization from a labeled image \p ima and the number
+ /// of labels \p nlabels.
+ void init_(const I& ima, const mln_value(I)& nlabels);
+
+ /// Duplicate the underlying image and create a new object_image.
+ void init_from_(const object_image<I>& model);
+
+ /// Return an array of mass centers.
+ const util::array<ms_t>& mass_centers() const;
+
+ /// Return the mass center of an object with label \p label.
+ const mln_psite(I)& mass_center(const mln_value(I)& label) const;
+
+ /// Return the underlying labeled image
+ const I& labeled_image_() const;
+
+ /// Update mass centers when objects are merged.
+ void init_update_data_();
+ void prepare_update_data_(const mln_value(I)& lbl,
+ const mln_value(I)& new_lbl);
+ void update_data_(const fun::i2v::array<mln_value(I)>& relabel_fun);
+ };
+
+
+ // init_
+
+ //FIXME: not enough generic? We would like 'J' instead of
+ // 'object_image<I>'.
+ template <typename I, typename J>
+ void init_(tag::image_t, object_image<I>& target,
+ const object_image<J>& model);
+
+
+
+ namespace make
+ {
+
+ template <typename I>
+ mln::object_image<I>
+ object_image(const Image<I>& ima, const mln_value(I)& nlabels);
+
+ } // end of namespace mln::make
+
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ // internal::data< object_image<I> >
+
+ namespace internal
+ {
+
+
+ // data< object_image<I> >
+
+ template <typename I>
+ inline
+ data< object_image<I> >::data(const I& ima, const mln_value(I)& nlabels)
+ : super_(ima, nlabels)
+ {
+ }
+
+ template <typename I>
+ inline
+ data< object_image<I> >::data(const I& ima, const mln_value(I)& nlabels,
+ const util::array<mln_box(I)>& bboxes,
+ const util::array<ms_t>& mass_centers)
+ : super_(ima, nlabels, bboxes), mass_centers_(mass_centers)
+ {
+ }
+
+
+ template <typename I>
+ inline
+ data< object_image<I> >::data(const I& ima, const mln_value(I)& nlabels,
+ const util::array<mln_box(I)>& bboxes,
+ const util::array<accu_res_t>& mass_centers)
+ : super_(ima, nlabels, bboxes)
+ {
+ convert::from_to(mass_centers, mass_centers_);
+ }
+
+
+ } // end of namespace mln::internal
+
+
+ template <typename I>
+ inline
+ object_image<I>::object_image()
+ {
+ }
+
+ template <typename I>
+ inline
+ object_image<I>::object_image(const I& ima, const mln_value(I)& nlabels)
+ {
+ init_(ima, nlabels);
+ }
+
+ template <typename I>
+ template <typename P>
+ inline
+ object_image<I>::object_image(const I& ima, const mln_value(I)& nlabels,
+ const util::array<mln_box(I)>& bboxes,
+ const util::array<P>& mass_centers)
+ {
+ mln_precondition(data::compute(accu::meta::stat::max(), ima) == nlabels);
+ this->data_ = new internal::data< object_image<I> >(ima, nlabels,
+ bboxes, mass_centers);
+ }
+
+
+ template <typename I>
+ inline
+ void
+ object_image<I>::init_(const I& ima, const mln_value(I)& nlabels)
+ {
+ mln_precondition(data::compute(accu::meta::stat::max(), ima) == nlabels);
+ this->data_ = new internal::data< object_image<I> >(ima, nlabels);
+
+ // FIXME: could be improved!
+ this->data_->bboxes_ = labeling::compute(accu::meta::shape::bbox(),
+ this->data_->ima_,
+ this->data_->nlabels_);
+ convert::from_to(labeling::compute(accu::meta::center(),
+ this->data_->ima_,
+ this->data_->nlabels_),
+ this->data_->mass_centers_);
+ }
+
+
+ template <typename I>
+ inline
+ void
+ object_image<I>::init_from_(const object_image<I>& model)
+ {
+ typedef internal::data< object_image<I> > data_t;
+ this->data_
+ = new data_t(duplicate(model.hook_data_()->ima_),
+ model.nlabels(),
+ model.hook_data_()->bboxes_,
+ model.hook_data_()->mass_centers_);
+ }
+
+
+ template <typename I>
+ inline
+ const util::array<typename object_image<I>::ms_t>&
+ object_image<I>::mass_centers() const
+ {
+ return this->data_->mass_centers_;
+ }
+
+ template <typename I>
+ inline
+ const mln_psite(I)&
+ object_image<I>::mass_center(const mln_value(I)& label) const
+ {
+ return this->data_->mass_centers_(label);
+ }
+
+
+ template <typename I>
+ inline
+ const I&
+ object_image<I>::labeled_image_() const
+ {
+ return this->data_->ima_;
+ }
+
+ template <typename I>
+ inline
+ void
+ object_image<I>::init_update_data_()
+ {
+ // this->nlabels_ is supposed to be updated when this method is
+ // called.
+ this->data_->tmp_accus_.resize(static_cast<unsigned>(this->data_->nlabels_) + 1);
+ }
+
+
+ template <typename I>
+ inline
+ void
+ object_image<I>::prepare_update_data_(const mln_value(I)& lbl,
+ const mln_value(I)& new_lbl)
+ {
+ this->data_->tmp_accus_[new_lbl].take(this->data_->mass_centers_[lbl]);
+ }
+
+
+ template <typename I>
+ inline
+ void
+ object_image<I>::update_data_(
+ const fun::i2v::array<mln_value(I)>& relabel_fun)
+ {
+ (void) relabel_fun;
+ convert::from_to(this->data_->tmp_accus_, this->data_->mass_centers_);
+ }
+
+
+ // init_
+
+ template <typename I, typename J>
+ void init_(tag::image_t, object_image<I>& target,
+ const object_image<J>& model)
+ {
+ I ima;
+ init_(tag::image, ima, model);
+ target.init_(ima, model.nlabels());
+ }
+
+
+ // Make routines.
+
+ namespace make
+ {
+
+ template <typename I>
+ mln::object_image<I>
+ object_image(const Image<I>& ima, const mln_value(I)& nlabels)
+ {
+ mln_precondition(exact(ima).is_valid());
+ mln::object_image<I> tmp(exact(ima), nlabels);
+ return tmp;
+ }
+
+ } // end of namespace mln::make
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+# define object_image(L) mln::object_image<L>
#endif // ! SCRIBO_CORE_OBJECT_IMAGE_HH
--
1.5.6.5
1
0
* core/anchors.hh: New. Add anchor types.
* filter/objects_thin.hh: Use filter::internal::compute.
* primitive/link/internal/find_several_links.hh,
* primitive/link/internal/find_link.hh,
* primitive/link/compute.hh: Update functor interface in order to
specify anchors.
* primitive/link/compute_several.hh: Fix an invalid namespace.
* primitive/link/internal/anchors_3.hh: Move...
* primitive/link/internal/compute_anchor.hh: ... here.
* primitive/link/internal/link_functor_base.hh: Use anchor type.
* primitive/link/internal/link_several_dmax_base.hh: New.
* primitive/link/internal/link_center_dmax_base.hh,
* primitive/link/internal/link_center_dmax_ratio_base.hh: Removed.
* primitive/link/with_several_right_links_overlap.hh: Fix includes.
* primitive/link/with_single_right_link_bottom.hh,
* primitive/link/with_single_right_link_top.hh,
* primitive/link/with_single_left_link.hh,
* primitive/link/with_single_right_link.hh: Use
link_single_dmax_base functor.
* src/debug/show_links_several_right_overlap.cc,
* src/debug/show_links_single_left.cc,
* src/debug/show_links_single_left_dmax_ratio.cc,
* src/debug/show_links_single_right.cc,
* src/debug/show_links_single_right_dmax_ratio.cc: Update functor
interface.
---
scribo/ChangeLog | 41 +++
scribo/{util/all.hh => core/anchors.hh} | 26 +-
scribo/filter/objects_thin.hh | 7 +-
scribo/primitive/link/compute.hh | 39 ++-
scribo/primitive/link/compute_several.hh | 2 +-
.../internal/{anchors_3.hh => compute_anchor.hh} | 56 +++--
scribo/primitive/link/internal/find_link.hh | 14 +-
.../primitive/link/internal/find_several_links.hh | 102 +++++----
.../primitive/link/internal/link_functor_base.hh | 56 +++--
.../link/internal/link_several_dmax_base.hh | 265 ++++++++++++++++++++
...enter_dmax_base.hh => link_single_dmax_base.hh} | 57 ++---
...atio_base.hh => link_single_dmax_ratio_base.hh} | 43 ++--
.../link/with_several_right_links_overlap.hh | 10 +-
scribo/primitive/link/with_single_left_link.hh | 6 +-
scribo/primitive/link/with_single_right_link.hh | 9 +-
.../link/with_single_right_link_bottom.hh | 13 +-
.../primitive/link/with_single_right_link_top.hh | 17 +-
.../src/debug/show_links_several_right_overlap.cc | 51 ++--
scribo/src/debug/show_links_single_left.cc | 4 +-
.../src/debug/show_links_single_left_dmax_ratio.cc | 4 +-
scribo/src/debug/show_links_single_right.cc | 4 +-
.../debug/show_links_single_right_dmax_ratio.cc | 4 +-
22 files changed, 586 insertions(+), 244 deletions(-)
copy scribo/{util/all.hh => core/anchors.hh} (82%)
rename scribo/primitive/link/internal/{anchors_3.hh => compute_anchor.hh} (75%)
create mode 100644 scribo/primitive/link/internal/link_several_dmax_base.hh
rename scribo/primitive/link/internal/{link_center_dmax_base.hh => link_single_dmax_base.hh} (73%)
rename scribo/primitive/link/internal/{link_center_dmax_ratio_base.hh => link_single_dmax_ratio_base.hh} (79%)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 0fcd35f..2897a58 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,3 +1,44 @@
+2009-12-14 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Improve linking routines.
+
+ * core/anchors.hh: New. Add anchor types.
+
+ * filter/objects_thin.hh: Use filter::internal::compute.
+
+ * primitive/link/internal/find_several_links.hh,
+ * primitive/link/internal/find_link.hh,
+ * primitive/link/compute.hh: Update functor interface in order to
+ specify anchors.
+
+ * primitive/link/compute_several.hh: Fix an invalid namespace.
+
+ * primitive/link/internal/anchors_3.hh: Move...
+
+ * primitive/link/internal/compute_anchor.hh: ... here.
+
+ * primitive/link/internal/link_functor_base.hh: Use anchor type.
+
+ * primitive/link/internal/link_several_dmax_base.hh: New.
+
+ * primitive/link/internal/link_center_dmax_base.hh,
+ * primitive/link/internal/link_center_dmax_ratio_base.hh: Removed.
+
+ * primitive/link/with_several_right_links_overlap.hh: Fix includes.
+
+ * primitive/link/with_single_right_link_bottom.hh,
+ * primitive/link/with_single_right_link_top.hh,
+ * primitive/link/with_single_left_link.hh,
+ * primitive/link/with_single_right_link.hh: Use
+ link_single_dmax_base functor.
+
+ * src/debug/show_links_several_right_overlap.cc,
+ * src/debug/show_links_single_left.cc,
+ * src/debug/show_links_single_left_dmax_ratio.cc,
+ * src/debug/show_links_single_right.cc,
+ * src/debug/show_links_single_right_dmax_ratio.cc: Update functor
+ interface.
+
2009-12-11 Guillaume Lazzara <z(a)lrde.epita.fr>
Improve Sauvola Multi-scale.
diff --git a/scribo/util/all.hh b/scribo/core/anchors.hh
similarity index 82%
copy from scribo/util/all.hh
copy to scribo/core/anchors.hh
index 3eef9ff..a2994b1 100644
--- a/scribo/util/all.hh
+++ b/scribo/core/anchors.hh
@@ -23,24 +23,26 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-#ifndef SCRIBO_UTIL_ALL_HH
-# define SCRIBO_UTIL_ALL_HH
-
-/// \file
-///
-/// Include all headers located in scribo/util.
+#ifndef SCRIBO_CORE_ANCHORS_HH
+# define SCRIBO_CORE_ANCHORS_HH
namespace scribo
{
- /// Namespace of useful classes and routines.
- namespace util
+ namespace anchor
{
- } // end of namespace scribo::util
+ enum Type
+ {
+ MassCenter = 0,
+ Top,
+ Bottom,
+ Center,
+ Invalid
+ };
-} // end of namespace scribo
+ }
-# include <scribo/util/text.hh>
+} // end of namespace scribo
-#endif // ! SCRIBO_UTIL_ALL_HH
+#endif // ! SCRIBO_CORE_ANCHORS_HH
diff --git a/scribo/filter/objects_thin.hh b/scribo/filter/objects_thin.hh
index e9c869b..ea8a5af 100644
--- a/scribo/filter/objects_thin.hh
+++ b/scribo/filter/objects_thin.hh
@@ -39,6 +39,7 @@
# include <scribo/core/object_image.hh>
# include <scribo/primitive/extract/objects.hh>
+# include <scribo/filter/internal/compute.hh>
namespace scribo
{
@@ -91,8 +92,6 @@ namespace scribo
struct objects_thin_filter
: Function_v2b< objects_thin_filter<L> >
{
- typedef accu::shape::bbox<mln_psite(L)> box_accu_t;
-
/// Constructor
///
/// \param[in] objects object bounding boxes.
@@ -175,9 +174,7 @@ namespace scribo
typedef internal::objects_thin_filter<L> func_t;
func_t is_not_too_thin(objects, min_thickness);
- object_image(L) output;
- output.init_from_(objects);
- output.relabel(is_not_too_thin);
+ object_image(L) output = internal::compute(objects, is_not_too_thin);
trace::exiting("scribo::filter::objects_thin");
return output;
diff --git a/scribo/primitive/link/compute.hh b/scribo/primitive/link/compute.hh
index bf94787..349721c 100644
--- a/scribo/primitive/link/compute.hh
+++ b/scribo/primitive/link/compute.hh
@@ -55,39 +55,44 @@ namespace scribo
Functors must implement the following interface :
- bool is_potential_link(unsigned current_object,
+ bool is_potential_link_(unsigned current_object,
const P& start_point, const P& p) const
- bool valid_link(unsigned current_object,
+ bool valid_link_(unsigned current_object,
const P& start_point, const P& p)
- bool verify_link_criterion(unsigned current_object,
+ bool verify_link_criterion_(unsigned current_object,
const P& start_point, const P& p)
- void validate_link(unsigned current_object,
- const P& start_point, const P& p)
+ void validate_link_(unsigned current_object,
+ const P& start_point, const P& p, unsigned anchor)
- void invalidate_link(unsigned current_object,
- const P& start_point, const P& p)
+ void invalidate_link_(unsigned current_object,
+ const P& start_point, const P& p, unsigned anchor)
- void compute_next_site(P& p)
+ void compute_next_site_(P& p)
- const mln_site(L)& start_point(unsigned current_object)
+ const mln_site(L)& start_point_(unsigned current_object, unsigned anchor)
- void start_processing_object(unsigned current_object)
+ void start_processing_object_(unsigned current_object)
*/
template <typename F>
object_links<scribo_support(F)>
- compute(Link_Functor<F>& functor);
+ compute(Link_Functor<F>& functor, anchor::Type anchor);
+ /// \overload
+ /// The default anchor is set to 0, the mass center.
+ template <typename F>
+ object_links<scribo_support(F)>
+ compute(Link_Functor<F>& functor);
# ifndef MLN_INCLUDE_ONLY
template <typename F>
object_links<scribo_support(F)>
- compute(Link_Functor<F>& functor_)
+ compute(Link_Functor<F>& functor_, anchor::Type anchor)
{
trace::entering("scribo::primitive::link::compute");
@@ -96,7 +101,7 @@ namespace scribo
for_all_ncomponents(current_object, functor.objects().nlabels())
{
functor.start_processing_object(current_object); //<-- start_processing_object
- primitive::internal::find_link(functor, current_object);
+ primitive::internal::find_link(functor, current_object, anchor);
}
trace::exiting("scribo::primitive::link::compute");
@@ -104,6 +109,14 @@ namespace scribo
}
+ template <typename F>
+ object_links<scribo_support(F)>
+ compute(Link_Functor<F>& functor)
+ {
+ return compute(functor, anchor::MassCenter);
+ }
+
+
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace scribo::primitive::link
diff --git a/scribo/primitive/link/compute_several.hh b/scribo/primitive/link/compute_several.hh
index 0597d99..929a7cb 100644
--- a/scribo/primitive/link/compute_several.hh
+++ b/scribo/primitive/link/compute_several.hh
@@ -98,7 +98,7 @@ namespace scribo
for_all_ncomponents(current_object, functor.objects().nlabels())
{
functor.start_processing_object(current_object); //<-- start_processing_object
- primitive::internal::find_several_links(functor, current_object);
+ internal::find_several_links(functor, current_object);
}
trace::exiting("scribo::primitive::link::compute_several");
diff --git a/scribo/primitive/link/internal/anchors_3.hh b/scribo/primitive/link/internal/compute_anchor.hh
similarity index 75%
rename from scribo/primitive/link/internal/anchors_3.hh
rename to scribo/primitive/link/internal/compute_anchor.hh
index 85fa80b..c7bae11 100644
--- a/scribo/primitive/link/internal/anchors_3.hh
+++ b/scribo/primitive/link/internal/compute_anchor.hh
@@ -23,14 +23,15 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-#ifndef SCRIBO_PRIMITIVE_LINK_INTERNAL_ANCHORS_3_HH
-# define SCRIBO_PRIMITIVE_LINK_INTERNAL_ANCHORS_3_HH
+#ifndef SCRIBO_PRIMITIVE_LINK_INTERNAL_COMPUTE_ANCHOR_HH
+# define SCRIBO_PRIMITIVE_LINK_INTERNAL_COMPUTE_ANCHOR_HH
/// \file
///
-/// Routine providing 3 anchors for neighbor seeking.
+/// Routine providing anchors for neighbor seeking.
# include <mln/math/min.hh>
+# include <mln/util/array.hh>
# include <scribo/core/object_image.hh>
@@ -46,20 +47,20 @@ namespace scribo
namespace internal
{
+ using namespace mln;
/*! \brief Return the proper anchor used to find a neighbor.
- This routine provides up to 3 different anchors.
-
\param[in] objects An object image.
\param[in] mass_centers Object mass centers.
\param[in] current_object An object id.
\param[in] anchor The expected anchor.
Anchor can take one of the following values:
- - 0, top anchor.
- - 1, center anchor. It is the mass center.
- - 2, bottom anchor.
+ - anchor::MassCenter, mass center anchor.
+ - anchor::Top, top anchor.
+ - anchor::Bottom, bottom anchor.
+ - anchor::Center, center anchor.
Top and bottom anchors are respectively computed from the
@@ -77,53 +78,56 @@ namespace scribo
*/
template <typename L, typename P>
mln_site(L)
- anchors_3(const object_image(L)& objects,
- const mln::util::array<P>& mass_centers,
- unsigned current_object, unsigned anchor);
+ compute_anchor(const object_image(L)& objects,
+ const mln::util::array<P>& mass_centers,
+ unsigned current_object, anchor::Type anchor);
# ifndef MLN_INCLUDE_ONLY
template <typename L, typename P>
mln_site(L)
- anchors_3(const object_image(L)& objects,
- const mln::util::array<P>& mass_centers,
- unsigned current_object, unsigned anchor)
+ compute_anchor(const object_image(L)& objects,
+ const mln::util::array<P>& mass_centers,
+ unsigned current_object, anchor::Type anchor)
{
unsigned h = objects.bbox(current_object).pmax().row()
- objects.bbox(current_object).pmin().row();
mln_site(L) sp = objects.bbox(current_object).center();
- def::coord r;
+ def::coord r = 0;
switch (anchor)
{
+ // Masss Center
+ case anchor::MassCenter:
+ return mass_centers(current_object);
+
+
// Top
- case 0:
+ case anchor::Top:
if (h < 30)
r = objects.bbox(current_object).pmin().row()
+ math::min(2u, (h + 1) / 2 - 1);
else
r = objects.bbox(current_object).pmin().row()
- - math::min(10u, h /10);
+ + math::min(10u, h /10);
break;
- // Center
- case 1:
- return mass_centers(current_object);
-
-
- // Bottom
- case 2:
+ // Bottom
+ case anchor::Bottom:
if (h < 30)
r = objects.bbox(current_object).pmax().row()
- + math::min(2u, (h + 1) / 2 - 1);
+ - math::min(2u, (h + 1) / 2 - 1);
else
r = objects.bbox(current_object).pmax().row()
- math::min(10u, h /10);
break;
+ case anchor::Center:
+ return objects.bbox(current_object).center();
+
default:
trace::warning("Non handled anchor");
mln_assertion(anchor > 2);
@@ -143,4 +147,4 @@ namespace scribo
} // end of namespace scribo
-#endif // ! SCRIBO_PRIMITIVE_LINK_INTERNAL_ANCHORS_3_HH
+#endif // ! SCRIBO_PRIMITIVE_LINK_INTERNAL_COMPUTE_ANCHOR_HH
diff --git a/scribo/primitive/link/internal/find_link.hh b/scribo/primitive/link/internal/find_link.hh
index 8a2544e..b950280 100644
--- a/scribo/primitive/link/internal/find_link.hh
+++ b/scribo/primitive/link/internal/find_link.hh
@@ -38,6 +38,7 @@
# include <mln/util/couple.hh>
# include <scribo/core/concept/link_functor.hh>
+# include <scribo/core/anchors.hh>
# include <scribo/core/object_image.hh>
# include <scribo/core/object_links.hh>
# include <scribo/primitive/internal/update_link_array.hh>
@@ -59,27 +60,30 @@ namespace scribo
\param[in,out] functor Functor used to compute the
links. Stores the results.
\param[in] current_object Current object id.
+ \param[in] anchor The lookup anchor.
\return A couple. The first argument tells whether a valid
link has been found, the second one is link anchor if exists.
*/
template <typename F>
mln::util::couple<bool, mln_site(scribo_support_(F))>
- find_link(Link_Functor<F>& functor, unsigned current_object);
+ find_link(Link_Functor<F>& functor, unsigned current_object,
+ anchor::Type anchor);
# ifndef MLN_INCLUDE_ONLY
template <typename F>
mln::util::couple<bool, mln_site(scribo_support_(F))>
- find_link(Link_Functor<F>& functor_, unsigned current_object)
+ find_link(Link_Functor<F>& functor_, unsigned current_object,
+ anchor::Type anchor)
{
F& functor = exact(functor_);
functor.initialize_link(current_object); // <-- initialize_link
mln_site(scribo_support_(F))
- start_point = functor.start_point(current_object),
+ start_point = functor.start_point(current_object, anchor), // <-- start_point
p = start_point;
mln_postcondition(p == start_point);
@@ -93,9 +97,9 @@ namespace scribo
functor.compute_next_site(p); // <-- compute_next_site
if (functor.valid_link(current_object, start_point, p)) // <-- valid_link
- functor.validate_link(current_object, start_point, p); // <-- validate_link
+ functor.validate_link(current_object, start_point, p, anchor); // <-- validate_link
else
- functor.invalidate_link(current_object, start_point, p); // <-- invalidate_link
+ functor.invalidate_link(current_object, start_point, p, anchor); // <-- invalidate_link
functor.finalize_link(current_object); // <-- finalize_link
diff --git a/scribo/primitive/link/internal/find_several_links.hh b/scribo/primitive/link/internal/find_several_links.hh
index a07ee70..a690f10 100644
--- a/scribo/primitive/link/internal/find_several_links.hh
+++ b/scribo/primitive/link/internal/find_several_links.hh
@@ -29,6 +29,9 @@
/// \file
///
/// Find the neighbor of a line of text if exists.
+///
+/// \fixme do not iterate over the number of anchor types but use a
+/// set of anchors specified in the functor.
# include <mln/core/concept/image.hh>
@@ -38,6 +41,7 @@
# include <mln/util/couple.hh>
# include <scribo/core/concept/link_functor.hh>
+# include <scribo/core/anchors.hh>
# include <scribo/core/object_image.hh>
# include <scribo/core/object_links.hh>
# include <scribo/primitive/internal/update_link_array.hh>
@@ -51,70 +55,82 @@ namespace scribo
namespace primitive
{
- namespace internal
+ namespace link
{
- /*! Find the neighbor of a line of text if exists.
+ namespace internal
+ {
+
+ /*! Find the neighbor of a line of text if exists.
- \param[in,out] functor Functor used to compute the
- links. Stores the results.
- \param current_object Current object id.
+ \param[in,out] functor Functor used to compute the
+ links. Stores the results.
+ \param current_object Current object id.
- \return A couple. The first argument tells whether a valid
- link has been found, the second one is link anchor if exists.
- */
- template <typename F>
- mln::util::couple<bool, mln_site(scribo_support_(F))>
- find_several_links(Link_Functor<F>& functor,
- unsigned current_object);
+ \return A couple. The first argument tells whether a valid
+ link has been found, the second one is link anchor if exists.
+ */
+ template <typename F>
+ mln::util::couple<bool,
+ mln::util::couple<anchor::Type,
+ mln_site(scribo_support_(F))> >
+ find_several_links(Link_Functor<F>& functor,
+ unsigned current_object);
# ifndef MLN_INCLUDE_ONLY
- template <typename F>
- mln::util::couple<bool, mln_site(scribo_support_(F))>
- find_several_links(Link_Functor<F>& functor_,
- unsigned current_object)
- {
- F& functor = exact(functor_);
+ template <typename F>
+ mln::util::couple<bool,
+ mln::util::couple<anchor::Type,
+ mln_site(scribo_support_(F))> >
+ find_several_links(Link_Functor<F>& functor_,
+ unsigned current_object)
+ {
+ F& functor = exact(functor_);
- typedef mln_site(scribo_support_(F)) P;
- typedef mln::util::couple<unsigned, P> link_t;
+ typedef mln_site(scribo_support_(F)) P;
+ typedef mln::util::couple<anchor::Type, P> link_t;
- P lp = functor.initialize_link(current_object); // <-- initialize_link
+ functor.initialize_link(current_object); // <-- initialize_link
- for (unsigned anchor = 0; anchor < functor.nanchors(); ++anchor) // <-- nanchor
- {
- mln_site(scribo_support_(F))
- start_point = functor.start_point(current_object, anchor), // <-- start_point
- p = start_point;
+ for (unsigned anchor_ = 0; anchor_ < functor.nanchors(); ++anchor_) // <-- nanchor
+ {
+ // FIXME : See fixme at the beginning of this file.
+ anchor::Type anchor = static_cast<anchor::Type>(anchor_);
- mln_postcondition(p == start_point);
+ mln_site(scribo_support_(F))
+ start_point = functor.start_point(current_object, anchor), // <-- start_point
+ p = start_point;
- while (functor.objects().domain().has(p)
- && ! functor.is_potential_link(current_object,
- start_point, p) // <-- is_potential_link
- && functor.verify_link_criterion(current_object,
- start_point, p)) // <-- verify_link_criterion
- functor.compute_next_site(p); // <-- compute_next_site
+ mln_postcondition(p == start_point);
- if (functor.valid_link(current_object, start_point, p)) // <-- valid_link
- functor.validate_link(current_object, start_point, p, anchor); // <-- validate_link
- else
- functor.invalidate_link(current_object, start_point, p, anchor); // <-- invalidate_link
+ while (functor.objects().domain().has(p)
+ && ! functor.is_potential_link(current_object,
+ start_point, p) // <-- is_potential_link
+ && functor.verify_link_criterion(current_object,
+ start_point, p)) // <-- verify_link_criterion
+ functor.compute_next_site(p); // <-- compute_next_site
- }
+ if (functor.valid_link(current_object, start_point, p)) // <-- valid_link
+ functor.validate_link(current_object, start_point, p, anchor); // <-- validate_link
+ else
+ functor.invalidate_link(current_object, start_point, p, anchor); // <-- invalidate_link
- P lp = functor.finalize_link(current_object);
+ }
- bool b = (functor.link(current_object) != current_object); // <-- link
- return mln::make::couple(b, lp);
- }
+ link_t l = functor.finalize_link(current_object);
+
+ bool b = (functor.link(current_object) != current_object); // <-- link
+ return mln::make::couple(b, l);
+ }
# endif // MLN_INCLUDE_ONLY
- } // end of namespace scribo::primitive::internal
+ } // end of namespace scribo::primitive::link::internal
+
+ } // end of namespace scribo::primitive::link
} // end of namespace scribo::primitive
diff --git a/scribo/primitive/link/internal/link_functor_base.hh b/scribo/primitive/link/internal/link_functor_base.hh
index e35f52d..dcc43d4 100644
--- a/scribo/primitive/link/internal/link_functor_base.hh
+++ b/scribo/primitive/link/internal/link_functor_base.hh
@@ -37,14 +37,18 @@
# include <mln/util/array.hh>
# include <mln/util/couple.hh>
+# include <mln/labeling/compute.hh>
+# include <mln/accu/center.hh>
+
+# include <scribo/core/anchors.hh>
# include <scribo/core/object_image.hh>
# include <scribo/core/object_links.hh>
# include <scribo/core/concept/link_functor.hh>
+# include <scribo/primitive/link/internal/compute_anchor.hh>
# include <scribo/primitive/internal/update_link_array.hh>
# include <scribo/primitive/internal/init_link_array.hh>
# include <scribo/primitive/internal/is_invalid_link.hh>
-
# define scribo_support(T) typename T::support
# define scribo_support_(T) T::support
@@ -68,6 +72,7 @@ namespace scribo
typedef L support;
typedef mln_site(L) P;
+ typedef mln::util::couple<anchor::Type, P> couple_t;
link_functor_base(const object_image(L)& objects, unsigned nanchors);
@@ -85,7 +90,7 @@ namespace scribo
void initialize_link(unsigned current_object);
- mln_site(L) finalize_link(unsigned current_object);
+ couple_t finalize_link(unsigned current_object);
bool verify_link_criterion(unsigned current_object,
@@ -106,7 +111,7 @@ namespace scribo
void validate_link(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor);
+ anchor::Type anchor);
/// \overload
/// \p anchor is set to 0.
@@ -115,7 +120,7 @@ namespace scribo
void invalidate_link(unsigned current_object,
const P& start_point, const P& p,
- unsigned anchor);
+ anchor::Type anchor);
/// \overload
/// \p anchor is set to 0
@@ -130,7 +135,7 @@ namespace scribo
void compute_next_site(P& p);
- mln_site(L) start_point(unsigned current_object, unsigned anchor);
+ mln_site(L) start_point(unsigned current_object, anchor::Type anchor);
/// \overload
/// \p anchor is set to 0.
@@ -146,7 +151,7 @@ namespace scribo
// methods.
void initialize_link_(unsigned current_object);
- mln_site(L) finalize_link_(unsigned current_object);
+ couple_t finalize_link_(unsigned current_object);
bool is_potential_link_(unsigned current_object,
const P& start_point, const P& p) const;
@@ -159,21 +164,24 @@ namespace scribo
void validate_link_(unsigned current_object,
const P& start_point, const P& p,
- unsigned anchor);
+ anchor::Type anchor);
void invalidate_link_(unsigned current_object,
const P& start_point, const P& p,
- unsigned anchor);
+ anchor::Type anchor);
void compute_next_site_(P& p);
void start_processing_object_(unsigned current_object);
+ mln_site(L) start_point_(unsigned current_object,
+ anchor::Type anchor);
protected:
object_links<L> links_;
const object_image(L) objects_;
unsigned nanchors_;
+ util::array<mln_result(accu::center<mln_site(L)>)> mass_centers_;
};
@@ -191,6 +199,9 @@ namespace scribo
nanchors_(nanchors)
{
primitive::internal::init_link_array(links_);
+
+ mass_centers_ = labeling::compute(accu::meta::center(),
+ objects, objects.nlabels());
}
@@ -203,6 +214,9 @@ namespace scribo
nanchors_(1)
{
primitive::internal::init_link_array(links_);
+
+ mass_centers_ = labeling::compute(accu::meta::center(),
+ objects, objects.nlabels());
}
@@ -266,7 +280,7 @@ namespace scribo
template <typename L, typename E>
inline
- mln_site(L)
+ mln::util::couple<anchor::Type, mln_site(L)>
link_functor_base<L,E>::finalize_link(unsigned current_object)
{
return exact(this)->finalize_link_(current_object);
@@ -303,7 +317,7 @@ namespace scribo
link_functor_base<L,E>::validate_link(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
exact(this)->validate_link_(current_object, start_point, p, anchor);
}
@@ -327,7 +341,7 @@ namespace scribo
link_functor_base<L,E>::invalidate_link(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
exact(this)->invalidate_link_(current_object, start_point, p, anchor);
}
@@ -361,7 +375,7 @@ namespace scribo
inline
mln_site(L)
link_functor_base<L,E>::start_point(unsigned current_object,
- unsigned anchor)
+ anchor::Type anchor)
{
return exact(this)->start_point_(current_object, anchor);
}
@@ -404,12 +418,12 @@ namespace scribo
template <typename L, typename E>
inline
- mln_site(L)
+ mln::util::couple<anchor::Type, mln_site(L)>
link_functor_base<L,E>::finalize_link_(unsigned current_object)
{
(void) current_object;
// No-Op
- return P();
+ return mln::make::couple(anchor::Invalid, P());
}
@@ -460,7 +474,7 @@ namespace scribo
link_functor_base<L,E>::validate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
(void) start_point;
(void) anchor;
@@ -474,7 +488,7 @@ namespace scribo
link_functor_base<L,E>::invalidate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
(void) current_object;
(void) start_point;
@@ -486,11 +500,13 @@ namespace scribo
template <typename L, typename E>
inline
- void
- link_functor_base<L,E>::compute_next_site_(P& p)
+ mln_site(L)
+ link_functor_base<L,E>::start_point_(unsigned current_object,
+ anchor::Type anchor)
{
- (void) p;
- // No-Op
+ (void) anchor;
+ return internal::compute_anchor(this->objects_, mass_centers_,
+ current_object, anchor);
}
template <typename L, typename E>
diff --git a/scribo/primitive/link/internal/link_several_dmax_base.hh b/scribo/primitive/link/internal/link_several_dmax_base.hh
new file mode 100644
index 0000000..3d4fbae
--- /dev/null
+++ b/scribo/primitive/link/internal/link_several_dmax_base.hh
@@ -0,0 +1,265 @@
+// 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.
+
+#ifndef SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_SEVERAL_DMAX_HH_
+# define SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_SEVERAL_DMAX_HH_
+
+/// \file
+///
+/// Base class for link functors using mass centers and a given max
+/// distance.
+
+
+# include <mln/accu/center.hh>
+# include <mln/labeling/compute.hh>
+# include <mln/math/abs.hh>
+# include <mln/util/array.hh>
+
+# include <scribo/core/macros.hh>
+# include <scribo/core/anchors.hh>
+# include <scribo/core/object_image.hh>
+# include <scribo/core/object_links.hh>
+
+# include <scribo/primitive/link/internal/find_link.hh>
+# include <scribo/primitive/link/internal/link_functor_base.hh>
+
+# include <scribo/primitive/link/compute.hh>
+
+
+namespace scribo
+{
+
+ namespace primitive
+ {
+
+ namespace link
+ {
+
+ namespace internal
+ {
+
+ /// \brief Base class for link functors using mass centers and
+ /// a given max distance.
+ //
+ template <typename L, typename E>
+ class link_several_dmax_base
+ : public link_functor_base<L, E>
+ {
+ typedef mln_site(L) P;
+ typedef link_functor_base<L,E> super_;
+ typedef mln_result(accu::center<mln_psite(L)>) ms_t;
+ typedef mln::util::couple<anchor::Type, P> couple_t;
+
+ public:
+
+ link_several_dmax_base(const object_image(L)& objects,
+ unsigned neighb_max_distance,
+ unsigned nanchors);
+
+
+
+ bool verify_link_criterion_(unsigned current_object,
+ const P& start_point, const P& p) const;
+
+ void start_processing_object_(unsigned current_object);
+
+ void validate_link_(unsigned current_object, const P& start_point,
+ const P& p, anchor::Type anchor);
+
+ void initialize_link_(unsigned current_object);
+ couple_t finalize_link_(unsigned current_object);
+
+
+
+ protected:
+ mln::util::array<ms_t> mass_centers_;
+ mln::util::array<couple_t> potential_links_;
+ float dmax_;
+ float neighb_max_distance_;
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ template <typename L, typename E>
+ inline
+ link_several_dmax_base<L, E>::link_several_dmax_base(
+ const object_image(L)& objects,
+ unsigned neighb_max_distance,
+ unsigned nanchors)
+
+ : super_(objects, nanchors),
+ dmax_(0),
+ neighb_max_distance_(neighb_max_distance)
+ {
+
+ mass_centers_ = labeling::compute(accu::meta::center(),
+ objects, objects.nlabels());
+ }
+
+ template <typename L, typename E>
+ inline
+ bool
+ link_several_dmax_base<L, E>::verify_link_criterion_(
+ unsigned current_object,
+ const P& start_point,
+ const P& p) const
+ {
+ (void) current_object;
+
+ float dist = math::abs(p.col() - start_point.col());
+ return dist <= dmax_; // Not too far
+ }
+
+
+ template <typename L, typename E>
+ inline
+ void
+ link_several_dmax_base<L, E>::start_processing_object_(
+ unsigned current_object)
+ {
+ float
+ midcol = (this->objects_.bbox(current_object).pmax().col()
+ - this->objects_.bbox(current_object).pmin().col()) / 2;
+ dmax_ = midcol + neighb_max_distance_;
+ }
+
+
+ template <typename L, typename E>
+ inline
+ void
+ link_several_dmax_base<L, E>::validate_link_(unsigned current_object,
+ const P& start_point,
+ const P& p,
+ anchor::Type anchor)
+ {
+ (void) current_object;
+ (void) start_point;
+ this->potential_links_.append(mln::make::couple(anchor, p));
+ }
+
+
+ template <typename L, typename E>
+ inline
+ void
+ link_several_dmax_base<L, E>::initialize_link_(unsigned current_object)
+ {
+ (void) current_object;
+ this->links_.clear();
+ this->potential_links_.clear();
+ }
+
+
+ template <typename L, typename E>
+ inline
+ mln::util::couple<anchor::Type, mln_site(L)>
+ link_several_dmax_base<L, E>::finalize_link_(unsigned current_object)
+ {
+ //TODO
+ mln::util::array<unsigned> dist;
+ unsigned
+ min = mln_max(unsigned),
+ tmp;
+
+ if (this->potential_links_.nelements() > 0)
+ {
+ for(unsigned i = 0; i < this->potential_links_.nelements(); ++i)
+ {
+ tmp = math::abs(this->objects_.bbox(current_object).pmax().col()
+ - this->potential_links_(i).second().col());
+ dist.append(tmp);
+ if (tmp < min)
+ min = tmp;
+ }
+
+ mln_assertion(min != mln_max(unsigned));
+
+ // Keep closest links and compute vertical overlap.
+ unsigned
+ nratio = 0,
+ id_max_ratio = 0;
+ mln_value(L) nbh_id;
+ mln::util::array<float> overlap;
+ for(unsigned i = 0; i < this->potential_links_.nelements(); ++i)
+ if (dist[i] < (1.2 * min))
+ {
+ unsigned
+ other_object = this->objects_(potential_links_(i).second());
+ nbh_id = other_object;
+
+ float
+ dr
+ = math::min(this->objects_.bbox(current_object).pmax().row(),
+ this->objects_.bbox(other_object).pmax().row())
+ - math::min(this->objects_.bbox(current_object).pmin().row(),
+ this->objects_.bbox(other_object).pmin().row()),
+ dh = this->objects_.bbox(other_object).pmax().row()
+ - this->objects_.bbox(other_object).pmin().row(),
+ ratio = dr / dh;
+
+ overlap.append(ratio);
+ if (ratio > overlap(id_max_ratio) || nratio == 0)
+ {
+ id_max_ratio = i;
+ nratio = 1;
+ nbh_id = other_object;
+ }
+ else if (ratio == overlap(id_max_ratio)
+ && other_object != nbh_id)
+ ++nratio;
+ }
+ else
+ overlap.append(0);
+
+ if (nratio == 1)
+ {
+ this->links_(current_object)
+ = this->objects_(potential_links_(id_max_ratio).second());
+
+ return potential_links_(id_max_ratio);
+ }
+
+ }
+
+ this->links_(current_object) = current_object;
+ return mln::make::couple(anchor::Invalid, P());
+ }
+
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+
+ } // end of namespace scribo::primitive::link::internal
+
+ } // end of namespace scribo::primitive::link
+
+ } // end of namespace scribo::primitive
+
+} // end of namespace scribo
+
+
+#endif // SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_SEVERAL_DMAX_HH_
diff --git a/scribo/primitive/link/internal/link_center_dmax_base.hh b/scribo/primitive/link/internal/link_single_dmax_base.hh
similarity index 73%
rename from scribo/primitive/link/internal/link_center_dmax_base.hh
rename to scribo/primitive/link/internal/link_single_dmax_base.hh
index 1a7a48d..4f571af 100644
--- a/scribo/primitive/link/internal/link_center_dmax_base.hh
+++ b/scribo/primitive/link/internal/link_single_dmax_base.hh
@@ -23,8 +23,8 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-#ifndef SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_CENTER_DMAX_HH_
-# define SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_CENTER_DMAX_HH_
+#ifndef SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_SINGLE_DMAX_BASE_HH_
+# define SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_SINGLE_DMAX_BASE_HH_
/// \file
///
@@ -38,10 +38,12 @@
# include <mln/util/array.hh>
# include <scribo/core/macros.hh>
+# include <scribo/core/anchors.hh>
# include <scribo/core/object_image.hh>
# include <scribo/core/object_links.hh>
# include <scribo/primitive/link/internal/find_link.hh>
+# include <scribo/primitive/link/internal/compute_anchor.hh>
# include <scribo/primitive/link/internal/link_functor_base.hh>
# include <scribo/primitive/link/compute.hh>
@@ -63,41 +65,32 @@ namespace scribo
/// a given max distance.
//
template <typename L, typename E>
- class link_center_dmax_base
+ class link_single_dmax_base
: public link_functor_base<L, E>
{
typedef link_functor_base<L,E> super_;
+ typedef mln_result(accu::center<mln_psite(L)>) ms_t;
public:
typedef mln_site(L) P;
-
- /*!
-
- center_type can have the following values:
- 0 - top bounding box center
- 1 - bounding box center
- 2 - bottom bounding box center
-
- */
- link_center_dmax_base(const object_image(L)& objects,
- unsigned neighb_max_distance,
- unsigned center_type);
+ link_single_dmax_base(const object_image(L)& objects,
+ unsigned neighb_max_distance);
bool verify_link_criterion_(unsigned current_object,
const P& start_point, const P& p) const;
mln_site(L) start_point_(unsigned current_object,
- unsigned anchor);
+ anchor::Type anchor);
void start_processing_object_(unsigned current_object);
private:
float dmax_;
float neighb_max_distance_;
- unsigned center_type_;
+// mln::util::array<ms_t> mass_centers_;
};
@@ -106,23 +99,23 @@ namespace scribo
template <typename L, typename E>
inline
- link_center_dmax_base<L, E>::link_center_dmax_base(
+ link_single_dmax_base<L, E>::link_single_dmax_base(
const object_image(L)& objects,
- unsigned neighb_max_distance,
- unsigned center_type)
+ unsigned neighb_max_distance)
: super_(objects),
dmax_(0),
- neighb_max_distance_(neighb_max_distance),
- center_type_(center_type)
+ neighb_max_distance_(neighb_max_distance)
{
+// mass_centers_ = labeling::compute(accu::meta::center(),
+// objects, objects.nlabels());
}
template <typename L, typename E>
inline
bool
- link_center_dmax_base<L, E>::verify_link_criterion_(
+ link_single_dmax_base<L, E>::verify_link_criterion_(
unsigned current_object,
const P& start_point,
const P& p) const
@@ -137,24 +130,18 @@ namespace scribo
template <typename L, typename E>
inline
mln_site(L)
- link_center_dmax_base<L, E>::start_point_(unsigned current_object,
- unsigned anchor)
+ link_single_dmax_base<L, E>::start_point_(unsigned current_object,
+ anchor::Type anchor)
{
- (void) anchor;
- mln_site(L) sp = this->objects_.bbox(current_object).center();
- if (center_type_ == 0)
- sp.row() = this->objects_.bbox(current_object).pmin().row();
- else if (center_type_ == 2)
- sp.row() = this->objects_.bbox(current_object).pmax().row();
-
- return sp;
+ return internal::compute_anchor(this->objects_, this->objects_.mass_centers(),//mass_centers_,
+ current_object, anchor);
}
template <typename L, typename E>
inline
void
- link_center_dmax_base<L, E>::start_processing_object_(
+ link_single_dmax_base<L, E>::start_processing_object_(
unsigned current_object)
{
float
@@ -176,4 +163,4 @@ namespace scribo
} // end of namespace scribo
-#endif // SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_CENTER_DMAX_HH_
+#endif // SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_SINGLE_DMAX_BASE_HH_
diff --git a/scribo/primitive/link/internal/link_center_dmax_ratio_base.hh b/scribo/primitive/link/internal/link_single_dmax_ratio_base.hh
similarity index 79%
rename from scribo/primitive/link/internal/link_center_dmax_ratio_base.hh
rename to scribo/primitive/link/internal/link_single_dmax_ratio_base.hh
index 0740ec9..9eadba7 100644
--- a/scribo/primitive/link/internal/link_center_dmax_ratio_base.hh
+++ b/scribo/primitive/link/internal/link_single_dmax_ratio_base.hh
@@ -23,8 +23,8 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-#ifndef SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_CENTER_DMAX_RATIO_BASE_HH_
-# define SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_CENTER_DMAX_RATIO_BASE_HH_
+#ifndef SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_SINGLE_DMAX_RATIO_BASE_HH_
+# define SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_SINGLE_DMAX_RATIO_BASE_HH_
/// \file
///
@@ -39,9 +39,11 @@
# include <mln/util/array.hh>
# include <scribo/core/macros.hh>
+# include <scribo/core/anchors.hh>
# include <scribo/core/object_image.hh>
# include <scribo/core/object_links.hh>
+# include <scribo/primitive/link/internal/compute_anchor.hh>
# include <scribo/primitive/link/internal/find_link.hh>
# include <scribo/primitive/link/internal/link_functor_base.hh>
@@ -64,7 +66,7 @@ namespace scribo
/// center and a proportional max distance.
//
template <typename L, typename E>
- class link_center_dmax_ratio_base
+ class link_single_dmax_ratio_base
: public link_functor_base<L, E>
{
typedef link_functor_base<L,E> super_;
@@ -75,7 +77,7 @@ namespace scribo
typedef mln_site(L) P;
- link_center_dmax_ratio_base(const object_image(L)& objects,
+ link_single_dmax_ratio_base(const object_image(L)& objects,
float dmax_ratio,
unsigned center_type_);
@@ -85,14 +87,14 @@ namespace scribo
const P& start_point, const P& p) const;
mln_site(L) start_point_(unsigned current_object,
- unsigned anchor);
+ anchor::Type anchor);
void start_processing_object_(unsigned current_object);
private:
float dmax_ratio_;
float dmax_;
- unsigned center_type_;
+ mln::util::array<ms_t> mass_centers_;
};
@@ -101,22 +103,22 @@ namespace scribo
template <typename L, typename E>
inline
- link_center_dmax_ratio_base<L, E>::link_center_dmax_ratio_base(
+ link_single_dmax_ratio_base<L, E>::link_single_dmax_ratio_base(
const object_image(L)& objects,
- float dmax_ratio,
- unsigned center_type)
+ float dmax_ratio)
: super_(objects),
dmax_ratio_(dmax_ratio),
- dmax_(0),
- center_type_(center_type)
+ dmax_(0)
{
+ mass_centers_ = labeling::compute(accu::meta::center(),
+ objects, objects.nlabels());
}
template <typename L, typename E>
inline
bool
- link_center_dmax_ratio_base<L, E>::verify_link_criterion_(
+ link_single_dmax_ratio_base<L, E>::verify_link_criterion_(
unsigned current_object,
const P& start_point,
const P& p) const
@@ -131,24 +133,19 @@ namespace scribo
template <typename L, typename E>
inline
mln_site(L)
- link_center_dmax_ratio_base<L, E>::start_point_(unsigned current_object,
- unsigned anchor)
+ link_single_dmax_ratio_base<L, E>::start_point_(unsigned current_object,
+ anchor::Type anchor)
{
(void) anchor;
- mln_site(L) sp = this->objects_.bbox(current_object).center();
- if (center_type_ == 0)
- sp.row() = this->objects_.bbox(current_object).pmin().row();
- else if (center_type_ == 2)
- sp.row() = this->objects_.bbox(current_object).pmax().row();
-
- return sp;
+ return internal::compute_anchors(this->objects_, mass_centers_,
+ current_object, anchor);
}
template <typename L, typename E>
inline
void
- link_center_dmax_ratio_base<L, E>::start_processing_object_(
+ link_single_dmax_ratio_base<L, E>::start_processing_object_(
unsigned current_object)
{
float
@@ -172,4 +169,4 @@ namespace scribo
} // end of namespace scribo
-#endif // SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_CENTER_DMAX_RATIO_BASE_HH_
+#endif // SCRIBO_PRIMITIVE_LINK_INTERNAL_LINK_SINGLE_DMAX_RATIO_BASE_HH_
diff --git a/scribo/primitive/link/with_several_right_links_overlap.hh b/scribo/primitive/link/with_several_right_links_overlap.hh
index 27d9d49..f9fd5a4 100644
--- a/scribo/primitive/link/with_several_right_links_overlap.hh
+++ b/scribo/primitive/link/with_several_right_links_overlap.hh
@@ -39,7 +39,8 @@
# include <scribo/core/object_image.hh>
# include <scribo/core/macros.hh>
# include <scribo/primitive/internal/init_link_array.hh>
-# include <scribo/primitive/internal/find_right_link.hh>
+# include <scribo/primitive/link/internal/find_several_links.hh>
+# include <scribo/primitive/link/internal/link_several_dmax_base.hh>
# include <scribo/util/text.hh>
@@ -94,8 +95,6 @@ namespace scribo
{
}
- template <typename L, typename E>
- inline
mln_site(L)
start_point_(unsigned current_object, unsigned anchor)
{
@@ -109,6 +108,8 @@ namespace scribo
++p.col();
}
+ };
+
} // end of namespace scribo::primitive::link::internal
@@ -122,7 +123,8 @@ namespace scribo
mln_precondition(objects.is_valid());
- several_right_overlap_functor<L> functor(objects, neighb_max_distance);
+ internal::several_right_overlap_functor<L>
+ functor(objects, neighb_max_distance);
for_all_ncomponents(current_object, objects.nlabels())
internal::find_several_links(functor, current_object);
diff --git a/scribo/primitive/link/with_single_left_link.hh b/scribo/primitive/link/with_single_left_link.hh
index bef9ea3..2cf0c5a 100644
--- a/scribo/primitive/link/with_single_left_link.hh
+++ b/scribo/primitive/link/with_single_left_link.hh
@@ -47,7 +47,7 @@
# include <scribo/core/object_links.hh>
# include <scribo/primitive/link/internal/find_link.hh>
-# include <scribo/primitive/link/internal/link_ms_dmax_base.hh>
+# include <scribo/primitive/link/internal/link_single_dmax_base.hh>
# include <scribo/primitive/link/compute.hh>
@@ -93,10 +93,10 @@ namespace scribo
template <typename L>
class single_left_functor
- : public internal::link_ms_dmax_base<L, single_left_functor<L> >
+ : public internal::link_single_dmax_base<L, single_left_functor<L> >
{
typedef
- internal::link_ms_dmax_base<L, single_left_functor<L> > super_;
+ internal::link_single_dmax_base<L, single_left_functor<L> > super_;
public:
typedef mln_site(L) P;
diff --git a/scribo/primitive/link/with_single_right_link.hh b/scribo/primitive/link/with_single_right_link.hh
index 236884b..f7272ee 100644
--- a/scribo/primitive/link/with_single_right_link.hh
+++ b/scribo/primitive/link/with_single_right_link.hh
@@ -40,11 +40,12 @@
# include <mln/util/array.hh>
# include <scribo/core/macros.hh>
+# include <scribo/core/anchors.hh>
# include <scribo/core/object_image.hh>
# include <scribo/core/object_links.hh>
# include <scribo/primitive/link/internal/find_link.hh>
-# include <scribo/primitive/link/internal/link_ms_dmax_base.hh>
+# include <scribo/primitive/link/internal/link_single_dmax_base.hh>
# include <scribo/primitive/link/compute.hh>
@@ -92,10 +93,10 @@ namespace scribo
template <typename L>
class single_right_functor
- : public internal::link_ms_dmax_base<L, single_right_functor<L> >
+ : public internal::link_single_dmax_base<L, single_right_functor<L> >
{
typedef
- internal::link_ms_dmax_base<L, single_right_functor<L> > super_;
+ internal::link_single_dmax_base<L, single_right_functor<L> > super_;
public:
typedef mln_site(L) P;
@@ -131,7 +132,7 @@ namespace scribo
internal::single_right_functor<L>
functor(objects, neighb_max_distance);
- object_links<L> output = compute(functor);
+ object_links<L> output = compute(functor, anchor::MassCenter);
trace::exiting("scribo::primitive::link::with_single_right_link");
return output;
diff --git a/scribo/primitive/link/with_single_right_link_bottom.hh b/scribo/primitive/link/with_single_right_link_bottom.hh
index 5976f22..3b1f6e7 100644
--- a/scribo/primitive/link/with_single_right_link_bottom.hh
+++ b/scribo/primitive/link/with_single_right_link_bottom.hh
@@ -40,11 +40,12 @@
# include <mln/util/array.hh>
# include <scribo/core/macros.hh>
+# include <scribo/core/anchors.hh>
# include <scribo/core/object_image.hh>
# include <scribo/core/object_links.hh>
# include <scribo/primitive/link/internal/find_link.hh>
-# include <scribo/primitive/link/internal/link_center_dmax_base.hh>
+# include <scribo/primitive/link/internal/link_single_dmax_base.hh>
# include <scribo/primitive/link/compute.hh>
@@ -70,7 +71,7 @@ namespace scribo
inline
object_links<L>
with_single_right_link_bottom(const object_image(L)& objects,
- unsigned neighb_max_distance);
+ unsigned neighb_max_distance);
/// \overload
@@ -92,11 +93,11 @@ namespace scribo
template <typename L>
class single_right_bottom_functor
- : public link_center_dmax_base<L,
+ : public link_single_dmax_base<L,
single_right_bottom_functor<L> >
{
typedef
- link_center_dmax_base<L, single_right_bottom_functor<L> >
+ link_single_dmax_base<L, single_right_bottom_functor<L> >
super_;
public:
@@ -104,7 +105,7 @@ namespace scribo
single_right_bottom_functor(const object_image(L)& objects,
unsigned dmax)
- : super_(objects, dmax, 2)
+ : super_(objects, dmax)
{
}
@@ -134,7 +135,7 @@ namespace scribo
internal::single_right_bottom_functor<L>
functor(objects, neighb_max_distance);
- object_links<L> output = compute(functor);
+ object_links<L> output = compute(functor, anchor::Bottom);
trace::exiting("scribo::primitive::link::with_single_right_link_bottom");
return output;
diff --git a/scribo/primitive/link/with_single_right_link_top.hh b/scribo/primitive/link/with_single_right_link_top.hh
index 13bb583..1e3e0df 100644
--- a/scribo/primitive/link/with_single_right_link_top.hh
+++ b/scribo/primitive/link/with_single_right_link_top.hh
@@ -40,11 +40,12 @@
# include <mln/util/array.hh>
# include <scribo/core/macros.hh>
+# include <scribo/core/anchors.hh>
# include <scribo/core/object_image.hh>
# include <scribo/core/object_links.hh>
# include <scribo/primitive/link/internal/find_link.hh>
-# include <scribo/primitive/link/internal/link_center_dmax_base.hh>
+# include <scribo/primitive/link/internal/link_single_dmax_base.hh>
# include <scribo/primitive/link/compute.hh>
@@ -70,7 +71,7 @@ namespace scribo
inline
object_links<L>
with_single_right_link_top(const object_image(L)& objects,
- unsigned neighb_max_distance);
+ unsigned neighb_max_distance);
/// \overload
@@ -92,19 +93,19 @@ namespace scribo
template <typename L>
class single_right_top_functor
- : public link_center_dmax_base<L,
+ : public link_single_dmax_base<L,
single_right_top_functor<L> >
{
typedef
- link_center_dmax_base<L, single_right_top_functor<L> >
+ link_single_dmax_base<L, single_right_top_functor<L> >
super_;
public:
typedef mln_site(L) P;
single_right_top_functor(const object_image(L)& objects,
- unsigned dmax)
- : super_(objects, dmax, 0)
+ unsigned dmax)
+ : super_(objects, dmax)
{
}
@@ -125,7 +126,7 @@ namespace scribo
inline
object_links<L>
with_single_right_link_top(const object_image(L)& objects,
- unsigned neighb_max_distance)
+ unsigned neighb_max_distance)
{
trace::entering("scribo::primitive::link::with_single_right_link_top");
@@ -134,7 +135,7 @@ namespace scribo
internal::single_right_top_functor<L>
functor(objects, neighb_max_distance);
- object_links<L> output = compute(functor);
+ object_links<L> output = compute(functor, anchor::Top);
trace::exiting("scribo::primitive::link::with_single_right_link_top");
return output;
diff --git a/scribo/src/debug/show_links_several_right_overlap.cc b/scribo/src/debug/show_links_several_right_overlap.cc
index 6b2a66a..f2824f3 100644
--- a/scribo/src/debug/show_links_several_right_overlap.cc
+++ b/scribo/src/debug/show_links_several_right_overlap.cc
@@ -30,6 +30,8 @@
#include <mln/data/convert.hh>
+#include <mln/util/couple.hh>
+
#include <mln/value/rgb8.hh>
#include <mln/value/label_16.hh>
#include <mln/literal/colors.hh>
@@ -41,7 +43,7 @@
#include <scribo/primitive/extract/objects.hh>
#include <scribo/primitive/link/internal/link_several_dmax_base.hh>
-#include <scribo/primitive/link/internal/anchors_3.hh>
+#include <scribo/primitive/link/internal/compute_anchor.hh>
#include <scribo/primitive/link/compute_several.hh>
#include <scribo/draw/bounding_boxes.hh>
@@ -61,11 +63,7 @@ namespace scribo
typedef
primitive::link::internal::link_several_dmax_base<L, self_t> super_;
- typedef
- mln::util::array<mln::util::couple<unsigned, mln_site(L)>
- potential_links_t;
-
- public:
+ public:
typedef mln_site(L) P;
several_right_overlap_debug_functor(const I& input,
@@ -79,35 +77,32 @@ namespace scribo
}
- void validate_link_(unsigned current_object,
- const P& start_point,
- const P& p,
- unsigned anchor)
+ mln::util::couple<anchor::Type, mln_site(L)>
+ finalize_link_(unsigned current_object)
{
- mln::draw::line(output_, start_point, p, literal::green);
-
- super_::validate_link_(current_object, start_point, p, anchor);
- }
+ mln::util::couple<anchor::Type, mln_site(L)>
+ c = super_::finalize_link_(current_object);
-
-
- void invalidate_link_(unsigned current_object,
- const P& start_point,
- const P& p,
- unsigned anchor)
- {
- if (output_.domain().has(p))
- mln::draw::line(output_, start_point, p, literal::red);
- else
+ if (c.first() != anchor::Invalid)
{
- P tmp = p;
- ++tmp.col();
- mln::draw::line(output_, start_point, tmp, literal::red);
+ mln_site(L)
+ p = primitive::link::internal::compute_anchor(this->objects_,
+ this->mass_centers_,
+ current_object,
+ c.first());
+ mln::draw::line(output_, p, c.second(), literal::green);
}
- super_::invalidate_link_(current_object, start_point, p, anchor);
+ return c;
}
+ mln_site(L)
+ start_point_(unsigned current_object, anchor::Type anchor)
+ {
+ return primitive::link::internal::compute_anchor(this->objects_,
+ this->mass_centers_,
+ current_object, anchor);
+ }
void compute_next_site_(P& p)
diff --git a/scribo/src/debug/show_links_single_left.cc b/scribo/src/debug/show_links_single_left.cc
index 094ca85..26f78e2 100644
--- a/scribo/src/debug/show_links_single_left.cc
+++ b/scribo/src/debug/show_links_single_left.cc
@@ -78,7 +78,7 @@ namespace scribo
void validate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
mln::draw::line(output_, start_point, p, literal::green);
@@ -90,7 +90,7 @@ namespace scribo
void invalidate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
if (output_.domain().has(p))
mln::draw::line(output_, start_point, p, literal::red);
diff --git a/scribo/src/debug/show_links_single_left_dmax_ratio.cc b/scribo/src/debug/show_links_single_left_dmax_ratio.cc
index 2ba0ace..e133507 100644
--- a/scribo/src/debug/show_links_single_left_dmax_ratio.cc
+++ b/scribo/src/debug/show_links_single_left_dmax_ratio.cc
@@ -78,7 +78,7 @@ namespace scribo
void validate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
mln::draw::line(output_, start_point, p, literal::green);
@@ -90,7 +90,7 @@ namespace scribo
void invalidate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
if (output_.domain().has(p))
mln::draw::line(output_, start_point, p, literal::red);
diff --git a/scribo/src/debug/show_links_single_right.cc b/scribo/src/debug/show_links_single_right.cc
index c121cce..7a25306 100644
--- a/scribo/src/debug/show_links_single_right.cc
+++ b/scribo/src/debug/show_links_single_right.cc
@@ -78,7 +78,7 @@ namespace scribo
void validate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
mln::draw::line(output_, start_point, p, literal::green);
@@ -90,7 +90,7 @@ namespace scribo
void invalidate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
if (output_.domain().has(p))
mln::draw::line(output_, start_point, p, literal::red);
diff --git a/scribo/src/debug/show_links_single_right_dmax_ratio.cc b/scribo/src/debug/show_links_single_right_dmax_ratio.cc
index 81415bc..806114c 100644
--- a/scribo/src/debug/show_links_single_right_dmax_ratio.cc
+++ b/scribo/src/debug/show_links_single_right_dmax_ratio.cc
@@ -78,7 +78,7 @@ namespace scribo
void validate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
mln::draw::line(output_, start_point, p, literal::green);
@@ -90,7 +90,7 @@ namespace scribo
void invalidate_link_(unsigned current_object,
const P& start_point,
const P& p,
- unsigned anchor)
+ anchor::Type anchor)
{
if (output_.domain().has(p))
mln::draw::line(output_, start_point, p, literal::red);
--
1.5.6.5
1
0