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
- 9625 discussions
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-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
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-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
* 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-34-g7681799 Add dedicated routines for AFP's use case.
by Guillaume Lazzara 11 Mar '10
by Guillaume Lazzara 11 Mar '10
11 Mar '10
* scribo/src/afp/components.hh,
* scribo/src/afp/link.hh,
* scribo/src/afp/regroup.hh: New.
---
scribo/ChangeLog | 8 ++
scribo/src/afp/components.hh | 255 ++++++++++++++++++++++++++++++++++++++++++
scribo/src/afp/link.hh | 138 +++++++++++++++++++++++
scribo/src/afp/regroup.hh | 84 ++++++++++++++
4 files changed, 485 insertions(+), 0 deletions(-)
create mode 100644 scribo/src/afp/components.hh
create mode 100644 scribo/src/afp/link.hh
create mode 100644 scribo/src/afp/regroup.hh
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index f7a0e58..d35119e 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,13 @@
2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Add dedicated routines for AFP's use case.
+
+ * scribo/src/afp/components.hh,
+ * scribo/src/afp/link.hh,
+ * scribo/src/afp/regroup.hh: New.
+
+2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+
Add new tools in Scribo.
* src/preprocessing/Makefile.am,
diff --git a/scribo/src/afp/components.hh b/scribo/src/afp/components.hh
new file mode 100644
index 0000000..7db8572
--- /dev/null
+++ b/scribo/src/afp/components.hh
@@ -0,0 +1,255 @@
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/save.hh>
+
+#include <mln/extension/adjust.hh>
+#include <mln/extension/fill.hh>
+#include <mln/data/fill.hh>
+#include <mln/accu/shape/bbox.hh>
+
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/pw/value.hh>
+#include <mln/debug/println.hh>
+
+#include <mln/util/timer.hh>
+#include <mln/labeling/foreground.hh>
+#include <mln/labeling/wrap.hh>
+#include <mln/extension/fill.hh>
+#include <mln/data/compare.hh>
+
+
+namespace mln
+{
+
+ template <typename I>
+ unsigned my_find_root(image2d<I>& data, unsigned x)
+ {
+ if (data.element(x).parent == x)
+ return x;
+ else
+ return data.element(x).parent = my_find_root(data,
+ data.element(x).parent);
+ }
+
+
+
+ struct info
+ {
+ unsigned parent;
+ unsigned card;
+ float row_sum, col_sum;
+ point2d p_min, p_max;
+
+ int width() const
+ {
+ return p_max.col() - p_min.col();
+ }
+
+ int height() const
+ {
+ return p_max.row() - p_min.row();
+ }
+
+ void init(unsigned p, int row, int col)
+ {
+ parent = p;
+ card = 1;
+ row_sum = row;
+ col_sum = col;
+ p_min.row() = row;
+ p_max.row() = row;
+ p_min.col() = col;
+ p_max.col() = col;
+ }
+
+ void update(info& r)
+ {
+ r.parent = this->parent;
+ card += r.card;
+ row_sum += r.row_sum;
+ col_sum += r.col_sum;
+
+ // bkd browsing => p is always higher (lower row) than r
+ mln_invariant(p_min.row() <= r.p_min.row());
+
+ if (r.p_min.col() < p_min.col())
+ p_min.col() = r.p_min.col();
+ if (r.p_max.row() > p_max.row())
+ p_max.row() = r.p_max.row();
+ if (r.p_max.col() > p_max.col())
+ p_max.col() = r.p_max.col();
+ }
+ };
+
+
+
+ template <typename V>
+ image2d<V>
+ extract_components(const image2d<bool>& input,
+ V& nlabels,
+ util::array<box2d>& bboxes,
+ util::array<point2d>& mass_centers)
+ {
+ typedef image2d<bool> I;
+
+ neighb2d nbh = c8();
+ const int
+ nrows = input.nrows(),
+ ncols = input.ncols();
+
+ bboxes.resize(1);
+ mass_centers.resize(1);
+
+ image2d<info> data;
+ image2d<V> label;
+ V current_label = 0;
+ int N, dp_border;
+
+// util::timer time;
+// time.start();
+
+ // init
+ {
+ extension::adjust(input, nbh);
+ N = input.nelements();
+ dp_border = 2 * input.border();
+ extension::fill(input, false);
+ initialize(data, input);
+ }
+
+// float t = time;
+// std::cout << "init = " << t << std::endl;
+// time.restart();
+
+ // 1st pass
+ {
+ util::array<int> dp = positive_offsets_wrt(input, nbh);
+ const unsigned n_nbhs = dp.nelements();
+
+ // Backward.
+ unsigned p = input.index_of_point(point2d(nrows - 1, ncols - 1));
+ for (int row = nrows - 1; row >= 0; --row, p -= dp_border)
+ for (int col = ncols - 1; col >= 0; --col, --p)
+ {
+ if (! input.element(p))
+ continue;
+
+ data.element(p).init(p, row, col); // init
+
+ for (unsigned i = 0; i < n_nbhs; ++i)
+ {
+ unsigned n = p + dp[i];
+ if (! input.element(n))
+ continue;
+ unsigned r = my_find_root(data, n);
+ if (r != p)
+ {
+ data.element(p).update( data.element(r) ); // update
+ }
+ }
+ }
+ }
+
+// t = time;
+// std::cout << "1st pass = " << t << std::endl;
+// time.restart();
+
+ // 2nd pass
+ {
+ initialize(label, input);
+ data::fill(label, 0);
+
+ // Forward.
+ unsigned p = input.index_of_point(point2d(0, 0));
+ for (int row = 0; row < nrows; ++row, p += dp_border)
+ for (int col = 0; col < ncols; ++col, ++p)
+ {
+ if (! input.element(p))
+ continue;
+ const info& dta = data.element(p);
+ if (dta.parent == p)
+ {
+ if (dta.card > 5
+ && (dta.width() >= 1
+ && dta.height() >= 1))
+ {
+ label.element(p) = ++current_label;
+
+ bboxes.append(box2d(dta.p_min, dta.p_max));
+ mass_centers.append(point2d(dta.row_sum / dta.card,
+ dta.col_sum / dta.card));
+ }
+ }
+ else
+ label.element(p) = label.element(dta.parent);
+ }
+ }
+// t = time;
+// std::cout << "2nd pass = " << t << std::endl;
+
+ nlabels = current_label;
+ return label;
+ }
+
+
+} // mln
+
+
+
+// void usage(char* argv[])
+// {
+// std::cerr << argv[0] << " input.pbm output.pgm" << std::endl;
+// std::abort();
+// }
+
+
+// int main(int argc, char* argv[])
+// {
+// if (argc != 3)
+// usage(argv);
+
+// using namespace mln;
+
+// image2d<bool> input;
+// io::pbm::load(input, argv[1]);
+
+
+// image2d<unsigned> ref;
+
+// // {
+// // util::timer t;
+// // t.start();
+
+// // unsigned nlabels;
+// // ref = labeling::foreground(input, c4(), nlabels);
+
+// // float ts = t.stop();
+// // std::cout << "tufa: " << ts << " " << nlabels << std::endl;
+// // }
+
+// {
+// util::timer t;
+// t.start();
+
+
+// util::array<box2d> bboxes(1, box2d(1,1));
+// util::array<point2d> mass_centers(1, point2d(0,0));
+
+// // util::array<std::pair<box2d, point2d> > data_out(1);
+// unsigned nlabels;
+// image2d<unsigned> comps = extract_components(input, nlabels, bboxes, mass_centers);
+
+// float ts = t.stop();
+// std::cout << ts << " " << nlabels << std::endl;
+
+// // std::cout << bboxes << std::endl;
+// // std::cout << mass_centers << std::endl;
+
+// // if (comps != ref)
+// // std::cout << "diff" << std::endl;
+
+// io::pgm::save(labeling::wrap(value::int_u8(), comps),
+// argv[2]);
+// }
+
+// }
diff --git a/scribo/src/afp/link.hh b/scribo/src/afp/link.hh
new file mode 100644
index 0000000..b899957
--- /dev/null
+++ b/scribo/src/afp/link.hh
@@ -0,0 +1,138 @@
+#include <mln/geom/ncols.hh>
+#include <mln/geom/nrows.hh>
+#include <mln/util/couple.hh>
+#include <scribo/core/object_image.hh>
+#include <scribo/core/macros.hh>
+#include <scribo/primitive/internal/init_link_array.hh>
+
+namespace scribo
+{
+
+ namespace primitive
+ {
+
+ namespace link
+ {
+
+
+ template <typename L>
+ util::couple<object_links<L>, object_links<L> >
+ left_right(const object_image(L)& objects)
+ {
+ object_links<L>
+ right(objects, static_cast<unsigned>(objects.nlabels()) + 1);
+ primitive::internal::init_link_array(right);
+
+ object_links<L>
+ left(objects, static_cast<unsigned>(objects.nlabels()) + 1);
+ primitive::internal::init_link_array(left);
+
+ for_all_components(i, objects.bboxes())
+ {
+ float
+ w = (objects.bbox(i).pmax().col()
+ - objects.bbox(i).pmin().col()),
+ h = (objects.bbox(i).pmax().row()
+ - objects.bbox(i).pmin().row());
+ unsigned dmax = (w / 2.0f) + (3 * math::max(w, h));
+
+
+ const mln_site(L) c = objects.mass_center(i);
+
+ int
+ midcol = (objects.bbox(i).pmax().col()
+ - objects.bbox(i).pmin().col()) / 2;
+ int
+ nrightima = geom::ncols(objects) - c.col(),
+ nleftima = c.col(),
+ nright = std::min(static_cast<unsigned>(nrightima), midcol + dmax),
+ nleft = std::min(static_cast<unsigned>(nleftima), midcol + dmax);
+
+ // Right
+ {
+ const mln_value(L)
+ *p = &objects(c),
+ *pstop = p + nright + 1;
+
+ for (; p != pstop; ++p)
+ {
+ if (*p != literal::zero // Not the background
+ && *p != i // Not the current component
+ && right[*p] != i) // No loops
+ {
+ right[i] = *p;
+ break;
+ }
+ }
+ }
+
+
+ // Left
+ {
+ const mln_value(L)
+ *p = &objects(c),
+ *pstop = p - nleft - 1;
+
+ for (; p != pstop; --p)
+ {
+ if (*p != literal::zero // Not the background
+ && *p != i // Not the current component
+ && left[*p] != i) // No loops
+ {
+ left[i] = *p;
+ break;
+ }
+ }
+ }
+ }
+
+ return mln::make::couple(left, right);
+ }
+
+
+ template <typename L>
+ object_links<L>
+ left(const object_image(L)& objects, unsigned dmax)
+ {
+ object_links<L>
+ left(objects, static_cast<unsigned>(objects.nlabels()) + 1);
+ primitive::internal::init_link_array(left);
+
+ for_all_components(i, objects.bboxes())
+ {
+ const mln_site(L) c = objects.mass_center(i);
+
+ int
+ midcol = (objects.bbox(i).pmax().col()
+ - objects.bbox(i).pmin().col()) / 2;
+ int
+ nleftima = c.col(),
+ nleft = std::min(static_cast<unsigned>(nleftima), midcol + dmax);
+
+ // Left
+ {
+ const mln_value(L)
+ *p = &objects(c),
+ *pstop = p - nleft - 1;
+
+ for (; p != pstop; --p)
+ {
+ if (*p != literal::zero // Not the background
+ && *p != i // Not the current component
+ && left[*p] != i) // No loops
+ {
+ left[i] = *p;
+ break;
+ }
+ }
+ }
+ }
+
+ return left;
+ }
+
+ } // end of namespace scribo::primitive::link
+
+ } // end of namespace scribo::primitive
+
+} // end of namespace scribo
diff --git a/scribo/src/afp/regroup.hh b/scribo/src/afp/regroup.hh
new file mode 100644
index 0000000..c24880b
--- /dev/null
+++ b/scribo/src/afp/regroup.hh
@@ -0,0 +1,84 @@
+#include <mln/geom/ncols.hh>
+#include <mln/geom/nrows.hh>
+#include <mln/util/couple.hh>
+#include <scribo/core/object_image.hh>
+#include <scribo/core/macros.hh>
+#include <scribo/primitive/internal/init_link_array.hh>
+
+namespace scribo
+{
+
+ namespace primitive
+ {
+
+ namespace group
+ {
+
+ template <typename L>
+ object_groups<L>
+ regroup_left(const object_image(L)& objects,
+ const object_groups<L>& groups,
+ unsigned dmax)
+ {
+ trace::entering("scribo::primitive::group::regroup_left");
+
+ mln_precondition(groups.is_valid());
+
+ object_groups<L>
+ new_groups(objects, static_cast<unsigned>(objects.nlabels()) + 1, 0);
+
+ unsigned ngroups = 0;
+ for_all_components(i, objects.bboxes())
+ {
+ if (groups[i] == 0)
+ continue;
+
+ // We MUST set a group id here since the most left group
+ // component won't have any id otherwise.
+ if (new_groups[i] == 0)
+ new_groups[i] = ++ngroups;
+
+ const mln_site(L) c = objects.mass_center(i);
+
+ int
+ midcol = (objects.bbox(i).pmax().col()
+ - objects.bbox(i).pmin().col()) / 2;
+ int
+ nleftima = geom::ncols(objects),
+ nleft = std::min(static_cast<unsigned>(nleftima), midcol + dmax);
+
+ // Left
+ {
+ const mln_value(L)
+ *p = &objects(c),
+ *pstop = p - nleft - 1;
+
+ for (; p != pstop; --p)
+ {
+ if (*p != literal::zero // Not the background
+ && *p != i // Not the current component
+// && new_groups[*p] != ngroups
+ && groups[*p] != 0)
+ {
+ if (new_groups[*p] == 0)
+ new_groups[*p] = ngroups;
+ else
+ {
+ new_groups[i] = new_groups[*p];
+ --ngroups;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ return new_groups;
+ }
+
+ } // end of namespace scribo::primitive::group
+
+ } // end of namespace scribo::primitive
+
+} // end of namespace scribo
--
1.5.6.5
1
0
last-svn-commit-35-gdb3dc85 scribo/draw/bounding_boxes.hh: Do not draw box centers anymore.
by Guillaume Lazzara 11 Mar '10
by Guillaume Lazzara 11 Mar '10
11 Mar '10
---
scribo/ChangeLog | 4 ++++
scribo/draw/bounding_boxes.hh | 9 +++------
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index d35119e..bfde10a 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,9 @@
2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+ * scribo/draw/bounding_boxes.hh: Do not draw box centers anymore.
+
+2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+
Add dedicated routines for AFP's use case.
* scribo/src/afp/components.hh,
diff --git a/scribo/draw/bounding_boxes.hh b/scribo/draw/bounding_boxes.hh
index 2fe2cd3..0d4ab9b 100644
--- a/scribo/draw/bounding_boxes.hh
+++ b/scribo/draw/bounding_boxes.hh
@@ -28,7 +28,7 @@
/// \file
///
-/// Draw a list of bounding boxes and their associated mass center.
+/// Draw a list of bounding boxes
# include <mln/core/concept/image.hh>
# include <mln/draw/box.hh>
@@ -45,7 +45,7 @@ namespace scribo
using namespace mln;
- /// Draw a list of bounding boxes and their associated mass center.
+ /// Draw a list of bounding boxes.
template <typename I>
void
bounding_boxes(Image<I>& input_,
@@ -53,7 +53,7 @@ namespace scribo
const mln_value(I)& value);
- /// Draw object bounding boxes and their associated mass center.
+ /// Draw object bounding boxes.
template <typename I, typename L>
void
bounding_boxes(Image<I>& input_,
@@ -79,10 +79,7 @@ namespace scribo
for_all_components(i, boxes)
if (boxes[i].is_valid())
- {
- input(boxes[i].center()) = value;
mln::draw::box(input, boxes[i], value);
- }
trace::exiting("scribo::draw::bounding_boxes");
}
--
1.5.6.5
1
0
last-svn-commit-36-g55f2abf scribo/filter/objects_with_holes.hh: New component filter.
by Guillaume Lazzara 11 Mar '10
by Guillaume Lazzara 11 Mar '10
11 Mar '10
---
scribo/ChangeLog | 4 +
scribo/filter/objects_with_holes.hh | 575 +++++++++++++++++++++++++++++++++++
2 files changed, 579 insertions(+), 0 deletions(-)
create mode 100644 scribo/filter/objects_with_holes.hh
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index bfde10a..891cd30 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,9 @@
2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+ * scribo/filter/objects_with_holes.hh: New component filter.
+
+2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+
* scribo/draw/bounding_boxes.hh: Do not draw box centers anymore.
2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
diff --git a/scribo/filter/objects_with_holes.hh b/scribo/filter/objects_with_holes.hh
new file mode 100644
index 0000000..c448e58
--- /dev/null
+++ b/scribo/filter/objects_with_holes.hh
@@ -0,0 +1,575 @@
+// 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_FILTER_OBJECTS_WITH_HOLES_HH
+# define SCRIBO_FILTER_OBJECTS_WITH_HOLES_HH
+
+/// \file
+///
+/// \brief Remove objects having a minimum number of holes.
+
+# include <sstream>
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/core/routine/extend.hh>
+# include <mln/core/image/dmorph/extended.hh>
+
+# include <mln/extension/duplicate.hh>
+
+# include <mln/draw/box_plain.hh>
+# include <mln/util/array.hh>
+
+# include <mln/labeling/blobs_and_compute.hh>
+
+# include <mln/accu/math/count.hh>
+
+# include <mln/fun/i2v/array.hh>
+
+# include <mln/io/pbm/save.hh>
+# include <mln/io/pgm/save.hh>
+
+# include <mln/data/convert.hh>
+
+# include <mln/labeling/background.hh>
+
+# include <scribo/core/macros.hh>
+# include <scribo/core/object_image.hh>
+# include <scribo/filter/internal/compute.hh>
+
+# include <mln/data/fill.hh>
+# include <mln/data/paste.hh>
+
+# include <mln/util/timer.hh>
+
+# include <mln/value/label_16.hh>
+# include <mln/core/var.hh>
+
+
+#include <mln/debug/filename.hh>
+
+namespace scribo
+{
+
+ namespace filter
+ {
+
+ using namespace mln;
+
+ /*! \brief Remove objects having a minimum number of holes.
+
+
+
+ */
+ template <typename L>
+ object_image(L)
+ objects_with_holes(const object_image(L)& objects,
+ unsigned min_holes_count,
+ unsigned min_size);
+
+
+ template <typename L>
+ inline
+ object_image(L)
+ objects_with_two_holes(const object_image(L)& objects,
+ unsigned min_size);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+
+ 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));
+ }
+
+
+ template <typename L>
+ mln_concrete(L)
+ compute_bboxes_image(const object_image(L)& objects)
+ {
+ typedef mln_psite(L) P;
+ typedef mln_dpsite(P) D;
+
+ extension::adjust_fill(objects, 1, 0);
+
+ mln_concrete(L) output;
+ initialize(output, objects);
+ data::fill(output, 0);
+
+ for_all_components(i, objects.bboxes())
+ {
+ mln_box(L) b = objects.bbox(i);
+ b.enlarge(1);
+
+ unsigned
+ nrows = b.pmax().row() - b.pmin().row() + 1,
+ ncols = b.pmax().col() - b.pmin().col() + 1,
+ row_offset = objects.labeled_image_().delta_index(D(+1, -ncols));
+
+ mln_value(L) *ptr = &output(b.pmin());
+ for (unsigned row = 0; row < nrows; ++row, ptr += row_offset)
+ for (unsigned col = 0; col < ncols; ++col)
+ *ptr++ = i;
+ }
+
+ extension::duplicate(output);
+
+ return output;
+ }
+
+
+ } // end of namespace scribo::filter::internal
+
+
+
+ /*!
+ Label the background and count the number of background
+ components in an object bounding box.
+ */
+ template <typename L>
+ inline
+ object_image(L)
+ objects_with_holes(const object_image(L)& objects,
+ unsigned min_holes_count,
+ unsigned min_size)
+ {
+ trace::entering("scribo::filter::objects_with_holes");
+
+ typedef object_image(L) O;
+ neighb2d nbh = c4();
+
+ image2d<unsigned> parent, card;
+ L bboxes_ima;
+
+ util::array<util::set<unsigned> > bg_comps(
+ static_cast<unsigned>(objects.nlabels()) + 1);
+
+ fun::i2v::array<bool>
+ to_keep(static_cast<unsigned>(objects.nlabels()) + 1,
+ false);
+
+ const L& lbl = objects.labeled_image_();
+
+ std::cout << "objects.nlabels = " << objects.nlabels() << std::endl;
+
+ util::timer timer_;
+ timer_.start();
+
+ // init
+ {
+ extension::adjust_fill(objects, nbh, mln_max(mln_value(L)));
+ initialize(parent, objects);
+ data::fill(parent, 0u);
+
+ initialize(card, objects);
+ data::fill(card, 1);
+
+
+ // FIXME: Improve.
+ util::timer t2;
+ t2.start();
+ bboxes_ima = internal::compute_bboxes_image(objects);
+ float t2_ = t2;
+ std::cout << "compute bboxes image " << t2_ << std::endl;
+
+ to_keep(0) = true;
+ }
+ float t_ = timer_;
+ std::cout << "init = " << t_ << std::endl;
+
+ // 1st pass
+ timer_.restart();
+ {
+ util::array<int> dp = positive_offsets_wrt(lbl, nbh);
+ const unsigned n_nbhs = dp.nelements();
+
+ mln_bkd_pixter(const L) pxl(lbl); // Backward.
+ for_all(pxl)
+ {
+ unsigned p = pxl.offset();
+ if (bboxes_ima.element(p) == 0 || lbl.element(p) != literal::zero)
+ continue;
+
+ parent.element(p) = p;
+ for (unsigned i = 0; i < n_nbhs; ++i)
+ {
+ unsigned n = p + dp[i];
+ if (bboxes_ima.element(n) == 0 || lbl.element(n) != literal::zero)
+ continue;
+
+ unsigned r = internal::my_find_root(parent, n);
+ if (r != p)
+ {
+ parent.element(r) = p;
+ card.element(p) += card.element(r);
+ }
+ } // for_all(n)
+
+ } // for_all(pxl)
+
+ }
+ t_ = timer_;
+ std::cout << "1st pass = " << t_ << std::endl;
+
+ // FIXME: Iterate over another label when a label is marked as
+ // "to be kept".
+
+ // 2nd pass
+ timer_.restart();
+ {
+ unsigned kept = 0;
+ mln_fwd_pixter(const L) pxl(bboxes_ima); // Forward.
+ for_all(pxl)
+ {
+ unsigned p = pxl.offset();
+
+ // Foreground, ignored.
+ if (parent.element(p) == 0 || bboxes_ima.element(p) == literal::zero)
+ continue;
+
+ unsigned& parent_p = parent.element(p);
+
+ if (parent_p != p) // Not root => propagation
+ parent_p = parent.element(parent_p);
+ else // Root
+ if (card.element(p) < min_size)
+ {
+ parent_p = 0;
+ continue;
+ }
+
+// if (bboxes_ima.element(p) != literal::zero)
+// {
+ mln_value(L) object_id = bboxes_ima.element(p);
+ if (parent_p != 0 // Check parent again since
+ // parent's may have been set to
+ // 0.
+ && bg_comps(object_id).nelements() < min_holes_count)
+ {
+ if (! bg_comps(object_id).has(parent_p))
+ {
+ bg_comps(object_id).insert(parent_p);
+
+ if (bg_comps(object_id).nelements() == min_holes_count)
+ {
+ to_keep(object_id) = true;
+ ++kept;
+ }
+ }
+ }
+// }
+ }
+
+ float t_ = timer_;
+ std::cout << "2nd pass = " << t_ << std::endl;
+
+ std::cout << "kept = " << kept << std::endl;
+// debug::println(parent);
+// std::cout << bg_comps << std::endl;
+// std::cout << to_keep << std::endl;
+
+ timer_.restart();
+ object_image(L) output;
+
+ if (kept == objects.nlabels())
+ {
+ trace::exiting("scribo::filter::objects_with_holes");
+ return objects;
+ }
+
+ output.init_from_(objects);
+ output.relabel(to_keep);
+ t_ = timer_;
+ std::cout << "init output = " << t_ << std::endl;
+
+ trace::exiting("scribo::filter::objects_with_holes");
+ return output;
+ }
+
+
+ }
+
+
+ template <typename L>
+ inline
+ object_image(L)
+ objects_with_two_holes(const object_image(L)& objects,
+ unsigned min_size)
+ {
+ trace::entering("scribo::filter::objects_with_holes");
+
+ std::cout << objects.nlabels() << std::endl;
+
+ typedef object_image(L) O;
+ neighb2d nbh = c8();
+
+ image2d<unsigned> parent, card;
+ L bboxes_ima;
+
+ util::array<unsigned> bg_comps(
+ static_cast<unsigned>(objects.nlabels()) + 1, 0);
+ util::array<bool> bg_comps_done(
+ static_cast<unsigned>(objects.nlabels()) + 1, false);
+
+ fun::i2v::array<bool>
+ to_keep(static_cast<unsigned>(objects.nlabels()) + 1,
+ false);
+
+ const L& lbl = objects.labeled_image_();
+
+ // init
+ {
+ extension::fill(objects, mln_max(mln_value(L)));
+// extension::adjust_fill(objects, nbh, mln_max(mln_value(L)));
+ initialize(parent, objects);
+ data::fill(parent, 0u);
+
+ initialize(card, objects);
+ data::fill(card, 1);
+ border::fill(card, 1);
+
+ bboxes_ima = internal::compute_bboxes_image(objects);
+
+ to_keep(0) = true;
+ }
+
+ // 1st pass
+ std::cout << "1st pass" << std::endl;
+ {
+ util::array<int> dp = positive_offsets_wrt(lbl, nbh);
+ const unsigned n_nbhs = dp.nelements();
+
+ mln_bkd_pixter(const L) pxl(lbl); // Backward.
+ for_all(pxl)
+ {
+ unsigned p = pxl.offset();
+ if (bboxes_ima.element(p) == 0 || lbl.element(p) != literal::zero)
+ continue;
+
+ parent.element(p) = p;
+ for (unsigned i = 0; i < n_nbhs; ++i)
+ {
+ unsigned n = p + dp[i];
+ if (bboxes_ima.element(n) == 0 || lbl.element(n) != literal::zero)
+ continue;
+
+ unsigned r = internal::my_find_root(parent, n);
+ if (r != p)
+ {
+ parent.element(r) = p;
+ card.element(p) += card.element(r);
+ }
+ } // for_all(n)
+
+ } // for_all(pxl)
+
+ }
+
+ // 2nd pass
+ std::cout << "2nd pass" << std::endl;
+ {
+ unsigned kept = 0;
+ mln_fwd_pixter(const L) pxl(bboxes_ima); // Forward.
+ for_all(pxl)
+ {
+ unsigned p = pxl.offset();
+ if (parent.element(p) == 0) // Foreground, ignored.
+ continue;
+
+ unsigned& parent_p = parent.element(p);
+
+ if (parent_p != p) // Not root => propagation
+ parent_p = parent.element(parent_p);
+ else // Root
+ if (card.element(p) < min_size)
+ {
+ parent_p = 0;
+ continue;
+ }
+
+ if (parent_p != 0 // Check parent again since
+ // parent's may have been set to
+ // 0.
+ && bboxes_ima.element(p) != literal::zero)
+ {
+ mln_value(L) object_id = bboxes_ima.element(p);
+ if (!bg_comps_done(object_id))
+ {
+ if (bg_comps(object_id) == 0)
+ {
+ bg_comps(object_id) = parent_p;
+ }
+ else if (bg_comps(object_id) != parent_p)
+ {
+ bg_comps_done(object_id) = true;
+ to_keep(object_id) = true;
+ ++kept;
+ }
+ }
+ }
+ }
+
+ object_image(L) output;
+ if (kept == objects.nlabels())
+ {
+ trace::exiting("scribo::filter::objects_with_holes");
+ return objects;
+ }
+
+ output.init_from_(objects);
+ output.relabel(to_keep);
+
+ trace::exiting("scribo::filter::objects_with_holes");
+ return output;
+ }
+
+ }
+
+
+
+// template <typename L>
+// inline
+// object_image(L)
+// objects_with_holes(const object_image(L)& objects,
+// unsigned min_holes_count)
+// {
+// trace::entering("scribo::filter::objects_with_holes");
+
+// mln_precondition(objects.is_valid());
+
+
+// L bboxes_ima;
+// initialize(bboxes_ima, objects);
+// data::fill(bboxes_ima, literal::zero);
+
+// for_all_components(i, objects.bboxes())
+// mln::draw::box(bboxes_ima, objects.bbox(i), i);
+
+// util::array<util::set<mln_value(L)> > first_bg_comp(
+// static_cast<unsigned>(objects.nlabels()) + 1);
+
+// fun::i2v::array<bool>
+// to_keep(static_cast<unsigned>(objects.nlabels()) + 1,
+// false);
+// to_keep(0) = true;
+
+// mln_value(L) nbglabels;
+// L bg_lbl = labeling::background(objects, c8(), nbglabels);
+
+// unsigned kept;
+// mln_piter(L) p(bboxes_ima.domain());
+// for_all(p)
+// {
+// if (bboxes_ima(p) == literal::zero)
+// continue;
+
+// if (bg_lbl(p) != 0)
+// if (! first_bg_comp(bboxes_ima(p)).has(bg_lbl(p)))
+// if (first_bg_comp(bboxes_ima(p)).nelements() < min_holes_count - 1)
+// first_bg_comp(bboxes_ima(p)).insert(bg_lbl(p));
+// else
+// {
+// to_keep(bboxes_ima(p)) == true;
+// ++kept;
+// }
+// }
+
+// object_image(L) output;
+// if (kept == objects.nlabels())
+// output = objects;
+// else
+// output = internal::compute(objects, to_keep);
+
+// trace::exiting("scribo::filter::objects_with_holes");
+// return output;
+// }
+
+
+ template <typename L>
+ inline
+ object_image(L)
+ objects_with_holes_slow(const object_image(L)& objects,
+ unsigned min_holes_count)
+ {
+ trace::entering("scribo::filter::objects_with_holes");
+
+ mln_precondition(objects.is_valid());
+
+ fun::i2v::array<bool>
+ to_keep(static_cast<unsigned>(objects.nlabels()) + 1,
+ true);
+
+ bool to_remove = false;
+ for_all_components(i, objects.bboxes())
+ {
+ mln_domain(L) b = objects.bbox(i);
+ b.enlarge(1);
+
+ mln_ch_value(L, bool) tmp(b);
+ data::fill(tmp, true);
+ data::fill((tmp | ((objects | objects.bbox(i)) | (pw::value(objects) == pw::cst(i))).domain()).rw(), false);
+
+ typedef accu::math::count<mln_value(L)> accu_t;
+ mln_value(L) nlabels;
+ util::array<unsigned> counts
+ = labeling::blobs_and_compute(tmp,
+ c8(), nlabels,
+ accu_t()).second();
+ unsigned nholes = 0;
+ for_all_components(j, counts)
+ if (counts(j) > 4u)
+ ++nholes;
+
+ if (nholes < min_holes_count)
+ {
+ to_keep(i) = false;
+ to_remove = true;
+ }
+ }
+
+ object_image(L) output;
+ if (! to_remove)
+ output = objects;
+ else
+ output = internal::compute(objects, to_keep);
+
+ trace::exiting("scribo::filter::objects_with_holes");
+ return output;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::filter
+
+} // end of namespace scribo
+
+
+#endif // ! SCRIBO_FILTER_OBJECTS_WITH_HOLES_HH
--
1.5.6.5
1
0
11 Mar '10
* scribo/primitive/internal/find_left_link.hh,
* scribo/primitive/internal/find_right_link.hh,
* scribo/primitive/internal/is_invalid_link.hh: Remove.
* scribo/primitive/link/internal/compute_anchor.hh,
* scribo/primitive/link/internal/link_ms_dmax_base.hh,
* scribo/primitive/link/internal/link_ms_dmax_ratio_base.hh,
* scribo/primitive/link/internal/link_single_dmax_base.hh,
* scribo/primitive/link/internal/link_single_dmax_ratio_base.hh,
* scribo/primitive/link/with_single_down_link.hh,
* scribo/primitive/link/with_single_left_link.hh,
* scribo/primitive/link/with_single_left_link_dmax_ratio.hh,
* scribo/primitive/link/with_single_right_link.hh,
* scribo/primitive/link/with_single_right_link_dmax_ratio.hh,
* scribo/primitive/link/with_single_up_link.hh: Introduce the
anchor concept and make use of it.
---
scribo/ChangeLog | 21 +++
scribo/primitive/internal/find_left_link.hh | 108 ---------------
scribo/primitive/internal/find_right_link.hh | 108 ---------------
scribo/primitive/internal/is_invalid_link.hh | 100 --------------
scribo/primitive/link/internal/compute_anchor.hh | 143 +++++++++++++++++---
.../primitive/link/internal/link_ms_dmax_base.hh | 27 ++--
.../link/internal/link_ms_dmax_ratio_base.hh | 18 ++-
.../link/internal/link_single_dmax_base.hh | 21 ++--
.../link/internal/link_single_dmax_ratio_base.hh | 20 ++--
...ingle_left_link.hh => with_single_down_link.hh} | 68 +++++++---
scribo/primitive/link/with_single_left_link.hh | 2 +-
.../link/with_single_left_link_dmax_ratio.hh | 10 +-
scribo/primitive/link/with_single_right_link.hh | 4 +-
.../link/with_single_right_link_dmax_ratio.hh | 8 +-
...le_right_link_top.hh => with_single_up_link.hh} | 81 +++++++----
15 files changed, 296 insertions(+), 443 deletions(-)
delete mode 100644 scribo/primitive/internal/find_left_link.hh
delete mode 100644 scribo/primitive/internal/find_right_link.hh
delete mode 100644 scribo/primitive/internal/is_invalid_link.hh
copy scribo/primitive/link/{with_single_left_link.hh => with_single_down_link.hh} (60%)
copy scribo/primitive/link/{with_single_right_link_top.hh => with_single_up_link.hh} (60%)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 891cd30..45faa9f 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,26 @@
2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Improve object linking backend.
+
+ * scribo/primitive/internal/find_left_link.hh,
+ * scribo/primitive/internal/find_right_link.hh,
+ * scribo/primitive/internal/is_invalid_link.hh: Remove.
+
+ * scribo/primitive/link/internal/compute_anchor.hh,
+ * scribo/primitive/link/internal/link_ms_dmax_base.hh,
+ * scribo/primitive/link/internal/link_ms_dmax_ratio_base.hh,
+ * scribo/primitive/link/internal/link_single_dmax_base.hh,
+ * scribo/primitive/link/internal/link_single_dmax_ratio_base.hh,
+ * scribo/primitive/link/with_single_down_link.hh,
+ * scribo/primitive/link/with_single_left_link.hh,
+ * scribo/primitive/link/with_single_left_link_dmax_ratio.hh,
+ * scribo/primitive/link/with_single_right_link.hh,
+ * scribo/primitive/link/with_single_right_link_dmax_ratio.hh,
+ * scribo/primitive/link/with_single_up_link.hh: Introduce the
+ anchor concept and make use of it.
+
+2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+
* scribo/filter/objects_with_holes.hh: New component filter.
2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
diff --git a/scribo/primitive/internal/find_left_link.hh b/scribo/primitive/internal/find_left_link.hh
deleted file mode 100644
index 4f30e36..0000000
--- a/scribo/primitive/internal/find_left_link.hh
+++ /dev/null
@@ -1,108 +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.
-
-#ifndef SCRIBO_PRIMITIVE_INTERNAL_FIND_LEFT_LINK_HH
-# define SCRIBO_PRIMITIVE_INTERNAL_FIND_LEFT_LINK_HH
-
-/// \file
-///
-/// Find the left neighbor of a line of text if exists.
-///
-/// \todo To be deleted.
-
-# include <mln/core/concept/image.hh>
-
-# include <mln/math/abs.hh>
-
-# include <mln/util/array.hh>
-# include <mln/util/couple.hh>
-
-# include <scribo/core/object_image.hh>
-# include <scribo/primitive/internal/update_link_array.hh>
-# include <scribo/primitive/internal/is_invalid_link.hh>
-
-//FIXME: not generic.
-# include <mln/core/alias/dpoint2d.hh>
-
-namespace scribo
-{
-
- namespace primitive
- {
-
- namespace internal
- {
-
- /// Find the left neighbor of a line of text if exists.
- ///
- /// \param objects An image of objects.
- /// \param left_link The left neighbors.
- /// \param current_comp A text line id.
- /// \param dmax The maximum lookup distance.
- /// \param c The lookup start point.
- //
- template <typename L>
- mln::util::couple<bool, mln_site(L)>
- find_left_link(const object_image(L)& objects,
- mln::util::array<unsigned>& left_link,
- unsigned current_comp,
- float dmax,
- const mln_site(L)& c);
-
-
-# ifndef MLN_INCLUDE_ONLY
-
- template <typename L>
- mln::util::couple<bool, mln_site(L)>
- find_left_link(const object_image(L)& objects,
- mln::util::array<unsigned>& left_link,
- unsigned current_comp,
- float dmax,
- const mln_site(L)& c)
- {
- ///FIXME: the following code is not generic...
- /// First site on the right of the central site
- mln_site(L) p = c + mln::left;
-
- while (is_invalid_link(objects, left_link, p,
- current_comp, c, dmax))
- --p.col();
-
- bool
- b = update_link_array(objects, left_link, p, c, current_comp, dmax);
-
- return mln::make::couple(b, p);
- }
-
-# endif // MLN_INCLUDE_ONLY
-
- } // end of namespace scribo::primitive::internal
-
- } // end of namespace scribo::primitive
-
-} // end of namespace scribo
-
-
-#endif // ! SCRIBO_PRIMITIVE_INTERNAL_FIND_LEFT_LINK_HH
diff --git a/scribo/primitive/internal/find_right_link.hh b/scribo/primitive/internal/find_right_link.hh
deleted file mode 100644
index 09e60f9..0000000
--- a/scribo/primitive/internal/find_right_link.hh
+++ /dev/null
@@ -1,108 +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.
-
-#ifndef SCRIBO_PRIMITIVE_INTERNAL_FIND_RIGHT_LINK_HH
-# define SCRIBO_PRIMITIVE_INTERNAL_FIND_RIGHT_LINK_HH
-
-/// \file
-///
-/// Find the right neighbor of a line of text if exists.
-///
-/// \todo To be deleted.
-
-# include <mln/core/concept/image.hh>
-
-# include <mln/math/abs.hh>
-
-# include <mln/util/array.hh>
-# include <mln/util/couple.hh>
-
-# include <scribo/core/object_image.hh>
-# include <scribo/primitive/internal/update_link_array.hh>
-# include <scribo/primitive/internal/is_invalid_link.hh>
-
-//FIXME: not generic.
-# include <mln/core/alias/dpoint2d.hh>
-
-namespace scribo
-{
-
- namespace primitive
- {
-
- namespace internal
- {
-
- /// Find the right neighbor of a line of text if exists.
- ///
- /// \param objects An image of objects.
- /// \param right_link The right neighbors.
- /// \param current_comp A text line id.
- /// \param dmax The maximum lookup distance.
- /// \param c The lookup start point.
- //
- template <typename L>
- mln::util::couple<bool, mln_site(L)>
- find_right_link(const object_image(L)& objects,
- mln::util::array<unsigned>& right_link,
- unsigned current_comp,
- float dmax,
- const mln_site(L)& c);
-
-
-# ifndef MLN_INCLUDE_ONLY
-
- template <typename L>
- mln::util::couple<bool, mln_site(L)>
- find_right_link(const object_image(L)& objects,
- mln::util::array<unsigned>& right_link,
- unsigned current_comp,
- float dmax,
- const mln_site(L)& c)
- {
- /// FIXME: the following code is not generic...
- /// First site on the right of the central site
- mln_site(L) p = c + mln::right;
-
- while (is_invalid_link(objects, right_link, p,
- current_comp, c, dmax))
- ++p.col();
-
- bool
- b = update_link_array(objects, right_link, p, c, current_comp, dmax);
-
- return mln::make::couple(b, p);
- }
-
-# endif // MLN_INCLUDE_ONLY
-
- } // end of namespace scribo::primitive::internal
-
- } // end of namespace scribo::primitive
-
-} // end of namespace scribo
-
-
-#endif // ! SCRIBO_PRIMITIVE_INTERNAL_FIND_RIGHT_LINK_HH
diff --git a/scribo/primitive/internal/is_invalid_link.hh b/scribo/primitive/internal/is_invalid_link.hh
deleted file mode 100644
index e6343fd..0000000
--- a/scribo/primitive/internal/is_invalid_link.hh
+++ /dev/null
@@ -1,100 +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.
-
-#ifndef SCRIBO_PRIMITIVE_INTERNAL_IS_INVALID_LINK_HH
-# define SCRIBO_PRIMITIVE_INTERNAL_IS_INVALID_LINK_HH
-
-/// \file
-///
-/// Check whether an objects link is invalid or not.
-///
-/// \todo To be deleted.
-
-# include <mln/math/abs.hh>
-# include <mln/literal/zero.hh>
-
-# include <scribo/core/object_image.hh>
-
-namespace scribo
-{
-
- namespace primitive
- {
-
- namespace internal
- {
-
- using namespace mln;
-
-
- /// Check whether an objects link is invalid or not.
- ///
- /// \param objects An image of objects.
- /// \param left_link The left neighbors.
- /// \param p The current site.
- /// \param current_comp The current object id.
- /// \param c The left link start point.
- /// \param dmax The maximum lookup distance.
- //
- template <typename L>
- bool
- is_invalid_link(const object_image(L)& objects_,
- mln::util::array<unsigned>& link_array,
- const mln_site(L)& p,
- unsigned current_comp,
- const mln_site(L)& c,
- float dmax);
-
-# ifndef MLN_INCLUDE_ONLY
-
- template <typename L>
- inline
- bool
- is_invalid_link(const object_image(L)& objects,
- mln::util::array<unsigned>& link_array,
- const mln_site(L)& p,
- unsigned current_comp,
- const mln_site(L)& c,
- float dmax)
- {
- return (objects.domain().has(p) // Not outside image domain
- && (objects(p) == literal::zero // Is the background
- || objects(p) == current_comp // Is the current component
- || link_array[objects(p)] == current_comp) // Creates a loop
- && static_cast<float>(math::abs(p.col() - c.col())) < dmax); // Not too far
- }
-
-# endif // ! MLN_INCLUDE_ONLY
-
- } // end of namespace scribo::primitive::internal
-
- } // end of namespace scribo::primitive
-
-} // end of namespace scribo
-
-
-#endif // ! SCRIBO_PRIMITIVE_INTERNAL_IS_INVALID_LINK_HH
-
-
diff --git a/scribo/primitive/link/internal/compute_anchor.hh b/scribo/primitive/link/internal/compute_anchor.hh
index c7bae11..0d3b6f2 100644
--- a/scribo/primitive/link/internal/compute_anchor.hh
+++ b/scribo/primitive/link/internal/compute_anchor.hh
@@ -52,15 +52,11 @@ namespace scribo
/*! \brief Return the proper anchor used to find a neighbor.
\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:
- - anchor::MassCenter, mass center anchor.
- - anchor::Top, top anchor.
- - anchor::Bottom, bottom anchor.
- - anchor::Center, center anchor.
+ Anchor can take one of the values defined in the
+ scribo::anchor::Type enum.
Top and bottom anchors are respectively computed from the
@@ -76,64 +72,169 @@ namespace scribo
out.row = P.row - min(10, h /10)
*/
- template <typename L, typename P>
+ template <typename L>
mln_site(L)
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>
+ template <typename L>
mln_site(L)
compute_anchor(const object_image(L)& objects,
- const mln::util::array<P>& mass_centers,
unsigned current_object, anchor::Type anchor)
{
+ typedef mln_site(L) P;
+
unsigned h = objects.bbox(current_object).pmax().row()
- objects.bbox(current_object).pmin().row();
+ unsigned w = objects.bbox(current_object).pmax().col()
+ - objects.bbox(current_object).pmin().col();
mln_site(L) sp = objects.bbox(current_object).center();
- def::coord r = 0;
switch (anchor)
{
- // Masss Center
+ // Component masss center
case anchor::MassCenter:
- return mass_centers(current_object);
+ return objects.mass_center(current_object);
- // Top
+ // Bounding box top center
case anchor::Top:
if (h < 30)
- r = objects.bbox(current_object).pmin().row()
+ sp.row() = objects.bbox(current_object).pmin().row()
+ math::min(2u, (h + 1) / 2 - 1);
else
- r = objects.bbox(current_object).pmin().row()
+ sp.row() = objects.bbox(current_object).pmin().row()
+ math::min(10u, h /10);
break;
- // Bottom
+ // Bounding box bottom center
case anchor::Bottom:
if (h < 30)
- r = objects.bbox(current_object).pmax().row()
+ sp.row() = objects.bbox(current_object).pmax().row()
- math::min(2u, (h + 1) / 2 - 1);
else
- r = objects.bbox(current_object).pmax().row()
+ sp.row() = objects.bbox(current_object).pmax().row()
- math::min(10u, h /10);
break;
+
+ // Bounding box center
case anchor::Center:
return objects.bbox(current_object).center();
+
+ // Bounding box actual left center
+ case anchor::ActualLeft:
+ return P(objects.bbox(current_object).center().row(),
+ objects.bbox(current_object).pmin().col());
+
+
+ // Bounding box left center
+ case anchor::Left:
+ if (w < 30)
+ sp.col() = objects.bbox(current_object).pmin().col()
+ + math::min(2u, (w + 1) / 2 - 1);
+ else
+ sp.col() = objects.bbox(current_object).pmin().col()
+ + math::min(10u, w /10);
+ break;
+
+
+ // Bounding box actual right center
+ case anchor::ActualRight:
+ return P(objects.bbox(current_object).center().row(),
+ objects.bbox(current_object).pmax().col());
+
+
+ // Bounding box right center
+ case anchor::Right:
+ if (w < 30)
+ sp.col() = objects.bbox(current_object).pmax().col()
+ - math::min(2u, (w + 1) / 2 - 1);
+ else
+ sp.col() = objects.bbox(current_object).pmax().col()
+ - math::min(10u, w /10);
+ break;
+
+
+ // Bounding box top left
+ case anchor::TopLeft:
+ if (h < 30)
+ sp.row() = objects.bbox(current_object).pmin().row()
+ + math::min(2u, (h + 1) / 2 - 1);
+ else
+ sp.row() = objects.bbox(current_object).pmin().row()
+ + math::min(10u, h /10);
+ if (w < 30)
+ sp.col() = objects.bbox(current_object).pmin().col()
+ + math::min(2u, (w + 1) / 2 - 1);
+ else
+ sp.col() = objects.bbox(current_object).pmin().col()
+ + math::min(10u, w /10);
+ break;
+
+
+ // Bounding box top right
+ case anchor::TopRight:
+ if (h < 30)
+ sp.row() = objects.bbox(current_object).pmin().row()
+ + math::min(2u, (h + 1) / 2 - 1);
+ else
+ sp.row() = objects.bbox(current_object).pmin().row()
+ + math::min(10u, h /10);
+ if (w < 30)
+ sp.col() = objects.bbox(current_object).pmax().col()
+ - math::min(2u, (w + 1) / 2 - 1);
+ else
+ sp.col() = objects.bbox(current_object).pmax().col()
+ - math::min(10u, w /10);
+ break;
+
+
+ // Bounding box bottom left
+ case anchor::BottomLeft:
+ if (h < 30)
+ sp.row() = objects.bbox(current_object).pmax().row()
+ - math::min(2u, (h + 1) / 2 - 1);
+ else
+ sp.row() = objects.bbox(current_object).pmax().row()
+ - math::min(10u, h /10);
+ if (w < 30)
+ sp.col() = objects.bbox(current_object).pmin().col()
+ + math::min(2u, (w + 1) / 2 - 1);
+ else
+ sp.col() = objects.bbox(current_object).pmin().col()
+ + math::min(10u, w /10);
+ break;
+
+ // Bounding box bottom right
+ case anchor::BottomRight:
+ if (h < 30)
+ sp.row() = objects.bbox(current_object).pmax().row()
+ - math::min(2u, (h + 1) / 2 - 1);
+ else
+ sp.row() = objects.bbox(current_object).pmax().row()
+ - math::min(10u, h /10);
+ if (w < 30)
+ sp.col() = objects.bbox(current_object).pmax().col()
+ - math::min(2u, (w + 1) / 2 - 1);
+ else
+ sp.col() = objects.bbox(current_object).pmax().col()
+ - math::min(10u, w /10);
+ break;
+
+
+
default:
trace::warning("Non handled anchor");
- mln_assertion(anchor > 2);
+ mln_assertion(anchor < anchor::Invalid);
}
- sp.row() = r;
return sp;
}
diff --git a/scribo/primitive/link/internal/link_ms_dmax_base.hh b/scribo/primitive/link/internal/link_ms_dmax_base.hh
index 80a9a13..edb0941 100644
--- a/scribo/primitive/link/internal/link_ms_dmax_base.hh
+++ b/scribo/primitive/link/internal/link_ms_dmax_base.hh
@@ -75,12 +75,11 @@ namespace scribo
link_ms_dmax_base(const object_image(L)& objects,
- unsigned neighb_max_distance);
-
-
+ unsigned neighb_max_distance,
+ anchor::Direction direction);
bool verify_link_criterion_(unsigned current_object,
- const P& start_point, const P& p) const;
+ const P& start_point, const P& p) const;
mln_site(L) start_point_(unsigned current_object,
unsigned anchor);
@@ -88,9 +87,9 @@ namespace scribo
void start_processing_object_(unsigned current_object);
private:
- mln::util::array<ms_t> mass_centers_;
float dmax_;
float neighb_max_distance_;
+ anchor::Direction direction_;
};
@@ -101,17 +100,17 @@ namespace scribo
inline
link_ms_dmax_base<L, E>::link_ms_dmax_base(
const object_image(L)& objects,
- unsigned neighb_max_distance)
+ unsigned neighb_max_distance,
+ anchor::Direction direction)
: super_(objects),
dmax_(0),
- neighb_max_distance_(neighb_max_distance)
+ neighb_max_distance_(neighb_max_distance),
+ direction_(direction)
{
-
- mass_centers_ = labeling::compute(accu::meta::center(),
- objects, objects.nlabels());
}
+
template <typename L, typename E>
inline
bool
@@ -121,7 +120,7 @@ namespace scribo
{
(void) current_object;
- float dist = math::abs(p.col() - start_point.col());
+ float dist = math::abs(p[direction_] - start_point[direction_]);
return dist <= dmax_; // Not too far
}
@@ -133,7 +132,7 @@ namespace scribo
unsigned anchor)
{
(void) anchor;
- return mass_centers_(current_object);
+ return this->objects_.mass_center(current_object);
}
@@ -144,8 +143,8 @@ namespace scribo
unsigned current_object)
{
float
- midcol = (this->objects_.bbox(current_object).pmax().col()
- - this->objects_.bbox(current_object).pmin().col()) / 2;
+ midcol = (this->objects_.bbox(current_object).pmax()[direction_]
+ - this->objects_.bbox(current_object).pmin()[direction_]) / 2;
dmax_ = midcol + neighb_max_distance_;
}
diff --git a/scribo/primitive/link/internal/link_ms_dmax_ratio_base.hh b/scribo/primitive/link/internal/link_ms_dmax_ratio_base.hh
index 414e0b2..8eca53d 100644
--- a/scribo/primitive/link/internal/link_ms_dmax_ratio_base.hh
+++ b/scribo/primitive/link/internal/link_ms_dmax_ratio_base.hh
@@ -76,7 +76,8 @@ namespace scribo
link_ms_dmax_ratio_base(const object_image(L)& objects,
- float dmax_ratio);
+ float dmax_ratio,
+ anchor::Direction direction);
@@ -89,9 +90,9 @@ namespace scribo
void start_processing_object_(unsigned current_object);
private:
- mln::util::array<ms_t> mass_centers_;
float dmax_ratio_;
float dmax_;
+ anchor::Direction direction_;
};
@@ -102,14 +103,14 @@ namespace scribo
inline
link_ms_dmax_ratio_base<L, E>::link_ms_dmax_ratio_base(
const object_image(L)& objects,
- float dmax_ratio)
+ float dmax_ratio,
+ anchor::Direction direction)
: super_(objects),
dmax_ratio_(dmax_ratio),
- dmax_(0)
+ dmax_(0),
+ direction_(direction)
{
- mass_centers_ = labeling::compute(accu::meta::center(),
- objects, objects.nlabels());
}
template <typename L, typename E>
@@ -120,9 +121,10 @@ namespace scribo
const P& start_point,
const P& p) const
{
+ mln_assertion(dmax_ != 0);
(void) current_object;
- float dist = math::abs(p.col() - start_point.col());
+ float dist = math::abs(p[direction_] - start_point[direction_]);
return dist <= dmax_; // Not too far
}
@@ -134,7 +136,7 @@ namespace scribo
unsigned anchor)
{
(void) anchor;
- return mass_centers_(current_object);
+ return this->objects_.mass_center(current_object);
}
diff --git a/scribo/primitive/link/internal/link_single_dmax_base.hh b/scribo/primitive/link/internal/link_single_dmax_base.hh
index 4f571af..8d594f5 100644
--- a/scribo/primitive/link/internal/link_single_dmax_base.hh
+++ b/scribo/primitive/link/internal/link_single_dmax_base.hh
@@ -76,7 +76,8 @@ namespace scribo
typedef mln_site(L) P;
link_single_dmax_base(const object_image(L)& objects,
- unsigned neighb_max_distance);
+ unsigned neighb_max_distance,
+ anchor::Direction direction);
bool verify_link_criterion_(unsigned current_object,
@@ -90,7 +91,7 @@ namespace scribo
private:
float dmax_;
float neighb_max_distance_;
-// mln::util::array<ms_t> mass_centers_;
+ anchor::Direction direction_;
};
@@ -101,14 +102,14 @@ namespace scribo
inline
link_single_dmax_base<L, E>::link_single_dmax_base(
const object_image(L)& objects,
- unsigned neighb_max_distance)
+ unsigned neighb_max_distance,
+ anchor::Direction direction)
: super_(objects),
dmax_(0),
- neighb_max_distance_(neighb_max_distance)
+ neighb_max_distance_(neighb_max_distance),
+ direction_(direction)
{
-// mass_centers_ = labeling::compute(accu::meta::center(),
-// objects, objects.nlabels());
}
@@ -122,7 +123,7 @@ namespace scribo
{
(void) current_object;
- float dist = math::abs(p.col() - start_point.col());
+ float dist = math::abs(p[direction_] - start_point[direction_]);
return dist <= dmax_; // Not too far
}
@@ -133,7 +134,7 @@ namespace scribo
link_single_dmax_base<L, E>::start_point_(unsigned current_object,
anchor::Type anchor)
{
- return internal::compute_anchor(this->objects_, this->objects_.mass_centers(),//mass_centers_,
+ return internal::compute_anchor(this->objects_,
current_object, anchor);
}
@@ -145,8 +146,8 @@ namespace scribo
unsigned current_object)
{
float
- midcol = (this->objects_.bbox(current_object).pmax().col()
- - this->objects_.bbox(current_object).pmin().col()) / 2;
+ midcol = (this->objects_.bbox(current_object).pmax()[direction_]
+ - this->objects_.bbox(current_object).pmin()[direction_]) / 2;
dmax_ = midcol + neighb_max_distance_;
}
diff --git a/scribo/primitive/link/internal/link_single_dmax_ratio_base.hh b/scribo/primitive/link/internal/link_single_dmax_ratio_base.hh
index 9eadba7..ebe0b6a 100644
--- a/scribo/primitive/link/internal/link_single_dmax_ratio_base.hh
+++ b/scribo/primitive/link/internal/link_single_dmax_ratio_base.hh
@@ -78,8 +78,8 @@ namespace scribo
link_single_dmax_ratio_base(const object_image(L)& objects,
- float dmax_ratio,
- unsigned center_type_);
+ float dmax_ratio,
+ anchor::Direction direction);
@@ -94,7 +94,7 @@ namespace scribo
private:
float dmax_ratio_;
float dmax_;
- mln::util::array<ms_t> mass_centers_;
+ anchor::Direction direction_;
};
@@ -105,14 +105,14 @@ namespace scribo
inline
link_single_dmax_ratio_base<L, E>::link_single_dmax_ratio_base(
const object_image(L)& objects,
- float dmax_ratio)
+ float dmax_ratio,
+ anchor::Direction direction)
: super_(objects),
dmax_ratio_(dmax_ratio),
- dmax_(0)
+ dmax_(0),
+ direction_(direction)
{
- mass_centers_ = labeling::compute(accu::meta::center(),
- objects, objects.nlabels());
}
template <typename L, typename E>
@@ -125,7 +125,7 @@ namespace scribo
{
(void) current_object;
- float dist = math::abs(p.col() - start_point.col());
+ float dist = math::abs(p[direction_] - start_point[direction_]);
return dist <= dmax_; // Not too far
}
@@ -137,8 +137,8 @@ namespace scribo
anchor::Type anchor)
{
(void) anchor;
- return internal::compute_anchors(this->objects_, mass_centers_,
- current_object, anchor);
+ return internal::compute_anchor(this->objects_,
+ current_object, anchor);
}
diff --git a/scribo/primitive/link/with_single_left_link.hh b/scribo/primitive/link/with_single_down_link.hh
similarity index 60%
copy from scribo/primitive/link/with_single_left_link.hh
copy to scribo/primitive/link/with_single_down_link.hh
index 2cf0c5a..7e4e82c 100644
--- a/scribo/primitive/link/with_single_left_link.hh
+++ b/scribo/primitive/link/with_single_down_link.hh
@@ -23,12 +23,12 @@
// 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_WITH_SINGLE_LEFT_LINK_HH
-# define SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_LEFT_LINK_HH
+#ifndef SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_DOWN_LINK_HH
+# define SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_DOWN_LINK_HH
/// \file
///
-/// Link text objects with their left neighbor.
+/// Link text objects with their down neighbor.
# include <mln/core/concept/image.hh>
# include <mln/core/concept/neighborhood.hh>
@@ -61,17 +61,29 @@ namespace scribo
namespace link
{
- /// \brief Link objects with their left neighbor if exists.
+ /// \brief Link objects with their down neighbor if exists.
///
/// \param[in] objects An object image.
- /// \param[in] The maximum distance allowed to seach a neighbor object.
+ /// \param[in] neighb_max_distance The maximum distance allowed
+ /// to seach a neighbor object.
+ /// \param[in] anchor The neighborhod lookup start point.
///
/// \return Object links data.
//
template <typename L>
inline
object_links<L>
- with_single_left_link(const object_image(L)& objects,
+ with_single_down_link(const object_image(L)& objects,
+ unsigned neighb_max_distance,
+ anchor::Type anchor);
+
+ /// \overload
+ /// Anchor type is set to anchor::MassCenter
+ //
+ template <typename L>
+ inline
+ object_links<L>
+ with_single_down_link(const object_image(L)& objects,
unsigned neighb_max_distance);
@@ -80,7 +92,7 @@ namespace scribo
template <typename L>
inline
object_links<L>
- with_single_left_link(const object_image(L)& objects);
+ with_single_down_link(const object_image(L)& objects);
# ifndef MLN_INCLUDE_ONLY
@@ -92,23 +104,23 @@ namespace scribo
// Functor
template <typename L>
- class single_left_functor
- : public internal::link_single_dmax_base<L, single_left_functor<L> >
+ class single_down_functor
+ : public internal::link_single_dmax_base<L, single_down_functor<L> >
{
typedef
- internal::link_single_dmax_base<L, single_left_functor<L> > super_;
+ internal::link_single_dmax_base<L, single_down_functor<L> > sdowner_;
public:
typedef mln_site(L) P;
- single_left_functor(const object_image(L)& objects, unsigned dmax)
- : super_(objects, dmax)
+ single_down_functor(const object_image(L)& objects, unsigned dmax)
+ : sdowner_(objects, dmax, anchor::Vertical)
{
}
void compute_next_site_(P& p)
{
- --p.col();
+ ++p.row();
}
};
@@ -122,19 +134,20 @@ namespace scribo
template <typename L>
inline
object_links<L>
- with_single_left_link(const object_image(L)& objects,
- unsigned neighb_max_distance)
+ with_single_down_link(const object_image(L)& objects,
+ unsigned neighb_max_distance,
+ anchor::Type anchor)
{
- trace::entering("scribo::primitive::link::with_single_left_link");
+ trace::entering("scribo::primitive::link::with_single_down_link");
mln_precondition(objects.is_valid());
- internal::single_left_functor<L>
+ internal::single_down_functor<L>
functor(objects, neighb_max_distance);
- object_links<L> output = compute(functor);
+ object_links<L> output = compute(functor, anchor);
- trace::exiting("scribo::primitive::link::with_single_left_link");
+ trace::exiting("scribo::primitive::link::with_single_down_link");
return output;
}
@@ -142,9 +155,20 @@ namespace scribo
template <typename L>
inline
object_links<L>
- with_single_left_link(const object_image(L)& objects)
+ with_single_down_link(const object_image(L)& objects,
+ unsigned neighb_max_distance)
+ {
+ return with_single_down_link(objects, neighb_max_distance,
+ anchor::MassCenter);
+ }
+
+
+ template <typename L>
+ inline
+ object_links<L>
+ with_single_down_link(const object_image(L)& objects)
{
- return with_single_left_link(objects, mln_max(unsigned));
+ return with_single_down_link(objects, mln_max(unsigned));
}
@@ -156,4 +180,4 @@ namespace scribo
} // end of namespace scribo
-#endif // ! SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_LEFT_LINK_HH
+#endif // ! SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_DOWN_LINK_HH
diff --git a/scribo/primitive/link/with_single_left_link.hh b/scribo/primitive/link/with_single_left_link.hh
index 2cf0c5a..651f1f6 100644
--- a/scribo/primitive/link/with_single_left_link.hh
+++ b/scribo/primitive/link/with_single_left_link.hh
@@ -102,7 +102,7 @@ namespace scribo
typedef mln_site(L) P;
single_left_functor(const object_image(L)& objects, unsigned dmax)
- : super_(objects, dmax)
+ : super_(objects, dmax, anchor::Horizontal)
{
}
diff --git a/scribo/primitive/link/with_single_left_link_dmax_ratio.hh b/scribo/primitive/link/with_single_left_link_dmax_ratio.hh
index 587fb6c..d59bbc1 100644
--- a/scribo/primitive/link/with_single_left_link_dmax_ratio.hh
+++ b/scribo/primitive/link/with_single_left_link_dmax_ratio.hh
@@ -44,7 +44,7 @@
# include <scribo/core/object_links.hh>
# include <scribo/primitive/link/internal/find_link.hh>
-# include <scribo/primitive/link/internal/link_ms_dmax_ratio_base.hh>
+# include <scribo/primitive/link/internal/link_single_dmax_ratio_base.hh>
# include <scribo/primitive/link/compute.hh>
@@ -99,18 +99,18 @@ namespace scribo
template <typename L>
class single_left_dmax_ratio_functor
- : public internal::link_ms_dmax_ratio_base<L,
- single_left_dmax_ratio_functor<L> >
+ : public internal::link_single_dmax_ratio_base<L,
+ single_left_dmax_ratio_functor<L> >
{
typedef single_left_dmax_ratio_functor<L> self_t;
- typedef internal::link_ms_dmax_ratio_base<L, self_t> super_;
+ typedef internal::link_single_dmax_ratio_base<L, self_t> super_;
public:
typedef mln_site(L) P;
single_left_dmax_ratio_functor(const object_image(L)& objects,
unsigned dmax)
- : super_(objects, dmax)
+ : super_(objects, dmax, anchor::Horizontal)
{
}
diff --git a/scribo/primitive/link/with_single_right_link.hh b/scribo/primitive/link/with_single_right_link.hh
index f7272ee..22380ab 100644
--- a/scribo/primitive/link/with_single_right_link.hh
+++ b/scribo/primitive/link/with_single_right_link.hh
@@ -40,7 +40,7 @@
# include <mln/util/array.hh>
# include <scribo/core/macros.hh>
-# include <scribo/core/anchors.hh>
+# include <scribo/core/tag/anchor.hh>
# include <scribo/core/object_image.hh>
# include <scribo/core/object_links.hh>
@@ -102,7 +102,7 @@ namespace scribo
typedef mln_site(L) P;
single_right_functor(const object_image(L)& objects, unsigned dmax)
- : super_(objects, dmax)
+ : super_(objects, dmax, anchor::Horizontal)
{
}
diff --git a/scribo/primitive/link/with_single_right_link_dmax_ratio.hh b/scribo/primitive/link/with_single_right_link_dmax_ratio.hh
index ac6ef31..cd8360f 100644
--- a/scribo/primitive/link/with_single_right_link_dmax_ratio.hh
+++ b/scribo/primitive/link/with_single_right_link_dmax_ratio.hh
@@ -99,18 +99,18 @@ namespace scribo
template <typename L>
class single_right_dmax_ratio_functor
- : public link_ms_dmax_ratio_base<L,
- single_right_dmax_ratio_functor<L> >
+ : public link_single_dmax_ratio_base<L,
+ single_right_dmax_ratio_functor<L> >
{
typedef single_right_dmax_ratio_functor<L> self_t;
- typedef link_ms_dmax_ratio_base<L, self_t> super_;
+ typedef link_single_dmax_ratio_base<L, self_t> super_;
public:
typedef mln_site(L) P;
single_right_dmax_ratio_functor(const object_image(L)& objects,
unsigned dmax)
- : super_(objects, dmax)
+ : super_(objects, dmax, anchor::Horizontal)
{
}
diff --git a/scribo/primitive/link/with_single_right_link_top.hh b/scribo/primitive/link/with_single_up_link.hh
similarity index 60%
copy from scribo/primitive/link/with_single_right_link_top.hh
copy to scribo/primitive/link/with_single_up_link.hh
index 1e3e0df..8781128 100644
--- a/scribo/primitive/link/with_single_right_link_top.hh
+++ b/scribo/primitive/link/with_single_up_link.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_PRIMITIVE_LINK_WITH_SINGLE_RIGHT_LINK_TOP_HH
-# define SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_RIGHT_LINK_TOP_HH
+#ifndef SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_UP_LINK_HH
+# define SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_UP_LINK_HH
/// \file
///
-/// Link text objects with their right neighbor.
-
+/// Link text objects with their up neighbor.
# include <mln/core/concept/image.hh>
# include <mln/core/concept/neighborhood.hh>
# 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>
@@ -59,28 +61,39 @@ namespace scribo
namespace link
{
- /// \brief Link objects with their right neighbor if exists.
- /// Lookup startup point is the object top center.
+ /// \brief Link objects with their up neighbor if exists.
///
/// \param[in] objects An object image.
- /// \param[in] The maximum distance allowed to seach a neighbor object.
+ /// \param[in] neighb_max_distance The maximum distance allowed
+ /// to seach a neighbor object.
+ /// \param[in] anchor The neighborhod lookup start point.
///
/// \return Object links data.
//
template <typename L>
inline
object_links<L>
- with_single_right_link_top(const object_image(L)& objects,
- unsigned neighb_max_distance);
+ with_single_up_link(const object_image(L)& objects,
+ unsigned neighb_max_distance,
+ anchor::Type anchor);
+
+ /// \overload
+ /// Anchor type is set to anchor::Center
+ //
+ template <typename L>
+ inline
+ object_links<L>
+ with_single_up_link(const object_image(L)& objects,
+ unsigned neighb_max_distance);
/// \overload
/// Max distance is set to mln_max(unsigned).
+ //
template <typename L>
inline
object_links<L>
- with_single_right_link_top(const object_image(L)& objects);
-
+ with_single_up_link(const object_image(L)& objects);
# ifndef MLN_INCLUDE_ONLY
@@ -92,26 +105,23 @@ namespace scribo
// Functor
template <typename L>
- class single_right_top_functor
- : public link_single_dmax_base<L,
- single_right_top_functor<L> >
+ class single_up_functor
+ : public internal::link_single_dmax_base<L, single_up_functor<L> >
{
typedef
- link_single_dmax_base<L, single_right_top_functor<L> >
- super_;
+ internal::link_single_dmax_base<L, single_up_functor<L> > super_;
public:
typedef mln_site(L) P;
- single_right_top_functor(const object_image(L)& objects,
- unsigned dmax)
- : super_(objects, dmax)
+ single_up_functor(const object_image(L)& objects, unsigned dmax)
+ : super_(objects, dmax, anchor::Vertical)
{
}
void compute_next_site_(P& p)
{
- ++p.col();
+ --p.row();
}
};
@@ -125,29 +135,40 @@ namespace scribo
template <typename L>
inline
object_links<L>
- with_single_right_link_top(const object_image(L)& objects,
- unsigned neighb_max_distance)
+ with_single_up_link(const object_image(L)& objects,
+ unsigned neighb_max_distance,
+ anchor::Type anchor)
{
- trace::entering("scribo::primitive::link::with_single_right_link_top");
+ trace::entering("scribo::primitive::link::with_single_up_link");
mln_precondition(objects.is_valid());
- internal::single_right_top_functor<L>
+ internal::single_up_functor<L>
functor(objects, neighb_max_distance);
- object_links<L> output = compute(functor, anchor::Top);
+ object_links<L> output = compute(functor, anchor);
- trace::exiting("scribo::primitive::link::with_single_right_link_top");
+ trace::exiting("scribo::primitive::link::with_single_up_link");
return output;
}
+ template <typename L>
+ inline
+ object_links<L>
+ with_single_up_link(const object_image(L)& objects,
+ unsigned neighb_max_distance)
+ {
+ return with_single_up_link(objects, neighb_max_distance,
+ anchor::MassCenter);
+ }
+
template <typename L>
inline
object_links<L>
- with_single_right_link_top(const object_image(L)& objects)
+ with_single_up_link(const object_image(L)& objects)
{
- return with_single_right_link_top(objects, mln_max(unsigned));
+ return with_single_up_link(objects, mln_max(unsigned));
}
@@ -159,4 +180,4 @@ namespace scribo
} // end of namespace scribo
-#endif // ! SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_RIGHT_LINK_TOP_HH
+#endif // ! SCRIBO_PRIMITIVE_LINK_WITH_SINGLE_UP_LINK_HH
--
1.5.6.5
1
0
* scribo/filter/object_links_non_aligned_simple.hh: Handle new
cases.
* scribo/filter/object_links_left_aligned.hh,
* scribo/filter/object_links_right_aligned.hh: New filters.
---
scribo/ChangeLog | 10 +++++
...top_aligned.hh => object_links_left_aligned.hh} | 33 +++++++++---------
scribo/filter/object_links_non_aligned_simple.hh | 36 ++++++++++++++++++++
...op_aligned.hh => object_links_right_aligned.hh} | 30 ++++++++--------
4 files changed, 78 insertions(+), 31 deletions(-)
copy scribo/filter/{object_links_top_aligned.hh => object_links_left_aligned.hh} (76%)
copy scribo/filter/{object_links_top_aligned.hh => object_links_right_aligned.hh} (77%)
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 45faa9f..01ab3a1 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,15 @@
2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Add new link filters.
+
+ * scribo/filter/object_links_non_aligned_simple.hh: Handle new
+ cases.
+
+ * scribo/filter/object_links_left_aligned.hh,
+ * scribo/filter/object_links_right_aligned.hh: New filters.
+
+2010-02-19 Guillaume Lazzara <z(a)lrde.epita.fr>
+
Improve object linking backend.
* scribo/primitive/internal/find_left_link.hh,
diff --git a/scribo/filter/object_links_top_aligned.hh b/scribo/filter/object_links_left_aligned.hh
similarity index 76%
copy from scribo/filter/object_links_top_aligned.hh
copy to scribo/filter/object_links_left_aligned.hh
index 4a92c96..e69b110 100644
--- a/scribo/filter/object_links_top_aligned.hh
+++ b/scribo/filter/object_links_left_aligned.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_FILTER_OBJECT_LINKS_TOP_ALIGNED_HH
-# define SCRIBO_FILTER_OBJECT_LINKS_TOP_ALIGNED_HH
+#ifndef SCRIBO_FILTER_OBJECT_LINKS_LEFT_ALIGNED_HH
+# define SCRIBO_FILTER_OBJECT_LINKS_LEFT_ALIGNED_HH
/// \file
///
-/// Invalidate links between two objects if their top are not
+/// Invalidate links between two objects if their left are not
/// aligned.
-
+///
+/// \fixme UPDATE DOC!
# include <mln/util/array.hh>
@@ -48,7 +49,7 @@ namespace scribo
using namespace mln;
- /*! \brief Invalidate links between two objects if their top are not
+ /*! \brief Invalidate links between two objects if their left are not
aligned.
\param[in] objects An object image.
@@ -77,13 +78,13 @@ namespace scribo
\endverbatim
- The angle between the two tops must be lower than \p max_alpha.
+ The angle between the two lefts must be lower than \p max_alpha.
*/
template <typename L>
object_links<L>
- object_links_top_aligned(const object_image(L)& objects,
- const object_links<L>& links,
- float max_alpha);
+ object_links_left_aligned(const object_image(L)& objects,
+ const object_links<L>& links,
+ float max_alpha);
# ifndef MLN_INCLUDE_ONLY
@@ -91,21 +92,21 @@ namespace scribo
template <typename L>
object_links<L>
- object_links_top_aligned(const object_image(L)& objects,
- const object_links<L>& links,
- float max_alpha)
+ object_links_left_aligned(const object_image(L)& objects,
+ const object_links<L>& links,
+ float max_alpha)
{
- trace::entering("scribo::filter::object_links_top_aligned");
+ trace::entering("scribo::filter::object_links_left_aligned");
mln_precondition(objects.is_valid());
mln_precondition(links.is_valid());
object_links<L>
output = object_links_non_aligned_simple(objects, links,
- 1,
+ 3,
max_alpha);
- trace::exiting("scribo::filter::object_links_top_aligned");
+ trace::exiting("scribo::filter::object_links_left_aligned");
return output;
}
@@ -118,4 +119,4 @@ namespace scribo
} // end of namespace scribo
-#endif // ! SCRIBO_FILTER_OBJECT_LINKS_TOP_ALIGNED_HH
+#endif // ! SCRIBO_FILTER_OBJECT_LINKS_LEFT_ALIGNED_HH
diff --git a/scribo/filter/object_links_non_aligned_simple.hh b/scribo/filter/object_links_non_aligned_simple.hh
index 706497d..15be8e9 100644
--- a/scribo/filter/object_links_non_aligned_simple.hh
+++ b/scribo/filter/object_links_non_aligned_simple.hh
@@ -84,6 +84,8 @@ namespace scribo
0 = center
1 = top
2 = bottom
+ 3 = left
+ 4 = right
*/
template <typename L>
@@ -166,6 +168,40 @@ namespace scribo
}
}
}
+ // Left
+ else if (edge == 3)
+ {
+ for_all_components(i, objects.bboxes())
+ {
+ if (links[i] != i)
+ {
+ dr = math::abs(bboxes[i].center().row()
+ - bboxes[links[i]].center().row());
+ dc = math::abs(bboxes[i].pmin().col()
+ - bboxes[links[i]].pmin().col());
+
+ if (std::atan(dc / dr) > max_alpha_rad)
+ output[i] = i;
+ }
+ }
+ }
+ // Right
+ else if (edge == 4)
+ {
+ for_all_components(i, objects.bboxes())
+ {
+ if (links[i] != i)
+ {
+ dr = math::abs(bboxes[i].center().row()
+ - bboxes[links[i]].center().row());
+ dc = math::abs(bboxes[i].pmax().col()
+ - bboxes[links[i]].pmax().col());
+
+ if (std::atan(dc / dr) > max_alpha_rad)
+ 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_right_aligned.hh
similarity index 77%
copy from scribo/filter/object_links_top_aligned.hh
copy to scribo/filter/object_links_right_aligned.hh
index 4a92c96..2ee0280 100644
--- a/scribo/filter/object_links_top_aligned.hh
+++ b/scribo/filter/object_links_right_aligned.hh
@@ -23,12 +23,12 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-#ifndef SCRIBO_FILTER_OBJECT_LINKS_TOP_ALIGNED_HH
-# define SCRIBO_FILTER_OBJECT_LINKS_TOP_ALIGNED_HH
+#ifndef SCRIBO_FILTER_OBJECT_LINKS_RIGHT_ALIGNED_HH
+# define SCRIBO_FILTER_OBJECT_LINKS_RIGHT_ALIGNED_HH
/// \file
///
-/// Invalidate links between two objects if their top are not
+/// Invalidate links between two objects if their right are not
/// aligned.
@@ -48,7 +48,7 @@ namespace scribo
using namespace mln;
- /*! \brief Invalidate links between two objects if their top are not
+ /*! \brief Invalidate links between two objects if their right are not
aligned.
\param[in] objects An object image.
@@ -77,13 +77,13 @@ namespace scribo
\endverbatim
- The angle between the two tops must be lower than \p max_alpha.
+ The angle between the two rights must be lower than \p max_alpha.
*/
template <typename L>
object_links<L>
- object_links_top_aligned(const object_image(L)& objects,
- const object_links<L>& links,
- float max_alpha);
+ object_links_right_aligned(const object_image(L)& objects,
+ const object_links<L>& links,
+ float max_alpha);
# ifndef MLN_INCLUDE_ONLY
@@ -91,21 +91,21 @@ namespace scribo
template <typename L>
object_links<L>
- object_links_top_aligned(const object_image(L)& objects,
- const object_links<L>& links,
- float max_alpha)
+ object_links_right_aligned(const object_image(L)& objects,
+ const object_links<L>& links,
+ float max_alpha)
{
- trace::entering("scribo::filter::object_links_top_aligned");
+ trace::entering("scribo::filter::object_links_right_aligned");
mln_precondition(objects.is_valid());
mln_precondition(links.is_valid());
object_links<L>
output = object_links_non_aligned_simple(objects, links,
- 1,
+ 4,
max_alpha);
- trace::exiting("scribo::filter::object_links_top_aligned");
+ trace::exiting("scribo::filter::object_links_right_aligned");
return output;
}
@@ -118,4 +118,4 @@ namespace scribo
} // end of namespace scribo
-#endif // ! SCRIBO_FILTER_OBJECT_LINKS_TOP_ALIGNED_HH
+#endif // ! SCRIBO_FILTER_OBJECT_LINKS_RIGHT_ALIGNED_HH
--
1.5.6.5
1
0