---
milena/mln/core/internal/image_base.hh | 33 ++++---
scribo/scribo/binarization/sauvola_ms.hh | 43 ++++++++-
scribo/scribo/canvas/integral_browsing.hh | 8 ++-
scribo/scribo/estim/font_color.hh | 4 +-
scribo/src/binarization/Makefile.am | 7 ++
scribo/src/binarization/kim.cc | 143 +++++++++++++----------------
scribo/src/binarization/niblack.cc | 5 +-
scribo/src/binarization/sauvola_ms.cc | 17 +++-
8 files changed, 156 insertions(+), 104 deletions(-)
diff --git a/milena/mln/core/internal/image_base.hh
b/milena/mln/core/internal/image_base.hh
index f1ba4f9..6b60121 100644
--- a/milena/mln/core/internal/image_base.hh
+++ b/milena/mln/core/internal/image_base.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2007, 2008, 2009 EPITA Research and Development
+// Copyright (C) 2007, 2008, 2009, 2012 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
@@ -43,18 +43,6 @@
# include <mln/value/set.hh>
# include <mln/value/super_value.hh>
-// image_base
-// ^
-// |
-// ---------------------------
-// | |
-// image_primary image_morpher
-// ^ ^
-// | |
-// | -----------------------------------------
-// | | | |
-// pw_image_base image_domain_morpher image_value_morpher image_identity
-
namespace mln
{
@@ -73,10 +61,27 @@ namespace mln
- /// A base class for images.
+ /// \brief A base class for images.
///
/// Parameter \p T is the image value type.
/// Parameter \p S is the image site set type.
+ ///
+ /// \internal
+ ///
+ /// \verbatim
+ /// image_base
+ /// ^
+ /// |
+ /// ---------------------------
+ /// | |
+ /// image_primary image_morpher
+ /// ^ ^
+ /// | |
+ /// | -----------------------------------------
+ /// | | | |
+ /// pw_image_base image_domain_morpher image_value_morpher image_identity
+ ///
+ /// \endverbatim
//
template <typename T, typename S, typename E>
struct image_base
diff --git a/scribo/scribo/binarization/sauvola_ms.hh
b/scribo/scribo/binarization/sauvola_ms.hh
index 96064e9..ba58207 100644
--- a/scribo/scribo/binarization/sauvola_ms.hh
+++ b/scribo/scribo/binarization/sauvola_ms.hh
@@ -98,7 +98,8 @@ namespace scribo
\param[in] s The scale factor used for the first subscaling.
\param[in] lambda_min_1 Size of the objects kept at scale 1.
\param[in] K Sauvola's formulae parameter.
-
+ \param[out] integral_sum_sum_2 Integral image of sum and squared
+ sum.
\p w_1 and \p lambda_min_1 are expressed according to the image
at scale 0, i.e. the original size.
@@ -107,6 +108,15 @@ namespace scribo
*/
template <typename I>
mln_ch_value(I,bool)
+ sauvola_ms(const Image<I>& input_1_, unsigned w_1,
+ unsigned s, double K,
+ image2d<mln::util::couple<double,double> >& integral_sum_sum_2);
+
+ /// \overload
+ /// The integral image is not returned.
+ //
+ template <typename I>
+ mln_ch_value(I,bool)
sauvola_ms(const Image<I>& input_1_, unsigned w_1, unsigned s, double K);
/// \overload
@@ -802,7 +812,8 @@ namespace scribo
template <typename I>
mln_ch_value(I,bool)
sauvola_ms(const Image<I>& input_1_, unsigned w_1,
- unsigned s, double K)
+ unsigned s, double K,
+ image2d<mln::util::couple<double,double> >& integral_sum_sum_2)
{
trace::entering("scribo::binarization::sauvola_ms");
@@ -853,7 +864,7 @@ namespace scribo
// Resize input and compute integral images.
typedef image2d<mln::util::couple<double,double> > integral_t;
- integral_t integral_sum_sum_2;
+// integral_t integral_sum_sum_2;
mln::util::timer t;
t.start();
@@ -1030,6 +1041,27 @@ namespace scribo
template <typename I>
mln_ch_value(I,bool)
sauvola_ms(const Image<I>& input_1_, unsigned w_1,
+ unsigned s, double K,
+ image2d<mln::util::couple<double,double> >& integral_sum_sum_2)
+ {
+ trace::entering("scribo::binarization::sauvola_ms");
+
+ mln_precondition(exact(input_1_).is_valid());
+ // Gray level images ONLY.
+ mlc_is_not_a(mln_value(I), value::Vectorial)::check();
+ mlc_is_not(mln_value(I), bool)::check();
+
+ mln_ch_value(I,bool)
+ output = impl::generic::sauvola_ms(exact(input_1_), w_1, s, K,
+ integral_sum_sum_2);
+
+ trace::exiting("scribo::binarization::sauvola_ms");
+ return output;
+ }
+
+ template <typename I>
+ mln_ch_value(I,bool)
+ sauvola_ms(const Image<I>& input_1_, unsigned w_1,
unsigned s, double K)
{
trace::entering("scribo::binarization::sauvola_ms");
@@ -1039,8 +1071,11 @@ namespace scribo
mlc_is_not_a(mln_value(I), value::Vectorial)::check();
mlc_is_not(mln_value(I), bool)::check();
+ typedef image2d<mln::util::couple<double,double> > integral_t;
+ integral_t integral_sum_sum_2;
+
mln_ch_value(I,bool)
- output = impl::generic::sauvola_ms(exact(input_1_), w_1, s, K);
+ output = sauvola_ms(exact(input_1_), w_1, s, K, integral_sum_sum_2);
trace::exiting("scribo::binarization::sauvola_ms");
return output;
diff --git a/scribo/scribo/canvas/integral_browsing.hh
b/scribo/scribo/canvas/integral_browsing.hh
index 89e0019..da13fe7 100644
--- a/scribo/scribo/canvas/integral_browsing.hh
+++ b/scribo/scribo/canvas/integral_browsing.hh
@@ -116,6 +116,12 @@ namespace scribo
for (col = col_0; col <= max_col_mid; col += step) ;
int w_right = ncols - col + w/2;
+ // tl: top left
+ // tr: top right
+ // ml: middle left
+ // mr: middle right
+ // bl: bottom left
+ // br: bottom right
Ptr
d_tl_start, d_tr_start,
b_ml_start = 0, d_ml_start = 0, b_mr_start = 0, d_mr_start = 0,
@@ -176,7 +182,7 @@ namespace scribo
for (; col <= max_col_mid; col += step)
{
// D - C
- internal::compute_stats(d_ima->first() - c_ima->first(),
+ internal::compute_stats(d_ima->first() - c_ima->first(),
d_ima->second() - c_ima->second(),
size_tc * s_2,
mean, stddev);
diff --git a/scribo/scribo/estim/font_color.hh b/scribo/scribo/estim/font_color.hh
index 9a3c429..78e8c83 100644
--- a/scribo/scribo/estim/font_color.hh
+++ b/scribo/scribo/estim/font_color.hh
@@ -83,7 +83,7 @@ namespace scribo
mln_ch_value(I,value::int_u8)
lbl = labeling::blobs(skel, c8(), nlabels);
- util::array<algebra::vec<3u, float> > res =
+ mln::util::array<algebra::vec<3u, float> > res =
labeling::compute(accu::meta::stat::mean(), text_ima, lbl, nlabels);
accu::stat::median_h<value::int_u12> m_red;
@@ -131,7 +131,7 @@ namespace scribo
value::int_u8 nlabels = 0;
mln_ch_value(J,value::int_u8) lbl = labeling::blobs(skel, c8(), nlabels);
- util::array<algebra::vec<3u, float> > res =
+ mln::util::array<algebra::vec<3u, float> > res =
labeling::compute(accu::meta::stat::mean(), text_ima, lbl, nlabels);
accu::stat::median_h<value::int_u12> m_val;
diff --git a/scribo/src/binarization/Makefile.am b/scribo/src/binarization/Makefile.am
index b29ac30..db168fa 100644
--- a/scribo/src/binarization/Makefile.am
+++ b/scribo/src/binarization/Makefile.am
@@ -30,6 +30,7 @@ if HAVE_MAGICKXX
sauvola_ms_debug
utilexec_PROGRAMS = \
+ kim \
niblack \
otsu \
sauvola \
@@ -66,6 +67,12 @@ if HAVE_MAGICKXX
sauvola_ms_fg_LDFLAGS = $(AM_LDFLAGS) \
$(MAGICKXX_LDFLAGS)
+ kim_SOURCES = kim.cc
+ kim_CPPFLAGS = $(AM_CPPFLAGS) \
+ $(MAGICKXX_CPPFLAGS)
+ kim_LDFLAGS = $(AM_LDFLAGS) \
+ $(MAGICKXX_LDFLAGS)
+
sauvola_SOURCES = sauvola.cc
sauvola_CPPFLAGS = $(AM_CPPFLAGS) \
$(MAGICKXX_CPPFLAGS)
diff --git a/scribo/src/binarization/kim.cc b/scribo/src/binarization/kim.cc
index 7294a9c..aa81f50 100644
--- a/scribo/src/binarization/kim.cc
+++ b/scribo/src/binarization/kim.cc
@@ -77,6 +77,47 @@ static const scribo::debug::opt_data opt_desc[] =
+double
+compute_thres(const mln::image2d<mln::util::couple<double,double> >&
integral_sum_sum_2,
+ int row, int col, unsigned win_size,
+ const scribo::binarization::internal::sauvola_formula& formula)
+{
+ point2d
+ tl(row - win_size - 1,
+ col - win_size - 1),
+ br(row + win_size,
+ col + win_size);
+
+ box2d b(tl, br);
+ b.crop_wrt(integral_sum_sum_2.domain());
+
+ point2d tr = b.pmax();
+ tr.row() = b.pmin().row();
+ point2d bl = b.pmin();
+ bl.row() = b.pmax().row();
+
+ unsigned card_min = b.nsites() - b.height() - b.width() + 1;
+
+ const mln::util::couple<double,double>&
+ D = integral_sum_sum_2(b.pmax()),
+ B = integral_sum_sum_2(tr),
+ C = integral_sum_sum_2(bl),
+ A = integral_sum_sum_2(b.pmin());
+
+ double sum = D.first() - B.first() - C.first() + A.first();
+ double sum_2 = D.second() - B.second() - C.second() + A.second();
+ double mean = sum / card_min;
+
+ double num = (sum_2 - sum * sum / card_min);
+ double stddev;
+ if (num > 0)
+ stddev = std::sqrt(num / (card_min - 1));
+ else
+ stddev = 0;
+
+ return formula(mean, stddev);
+}
+
int main(int argc, char *argv[])
@@ -202,97 +243,43 @@ int main(int argc, char *argv[])
if (!lines(i).is_textline())
continue;
- math::round<double> round;
double
win_min = thickness(lines(i).id()),
- win_max = lines(i).bbox().height(),
- card_min,
- card_max;
+ win_max = lines(i).bbox().height();;
mln_assertion(win_min != 0);
mln_assertion(win_max != 0);
- binarization::internal::sauvola_formula compute_thres;
- point2d tl, br;
+ scribo::binarization::internal::sauvola_formula formula;
- mln_piter(L) p(lines(i).bbox());
- for_all(p)
+ for (int row = lines(i).bbox().pmin().row();
+ row <= lines(i).bbox().pmax().row();
+ ++row)
{
+ bool* out_ptr = &output.at_(row, lines(i).bbox().pmin().col());
+ value::int_u8* in_ptr = &input_1_gl.at_(row, lines(i).bbox().pmin().col());
+ for (int col = lines(i).bbox().pmin().col();
+ col <= lines(i).bbox().pmax().col();
+ ++col)
+ {
+ // Min case
+ double T_min = compute_thres(integral_sum_sum_2, row, col, win_min, formula);
- // Min case
- tl.row() = (p.row() - win_min - 1);
- tl.col() = (p.col() - win_min - 1);
-
- br.row() = (p.row() + win_min);
- br.col() = (p.col() + win_min);
-
- box2d b(tl, br);
- b.crop_wrt(integral_sum_sum_2.domain());
-
- point2d tr = b.pmax();
- tr.row() = b.pmin().row();
- point2d bl = b.pmin();
- bl.row() = b.pmax().row();
-
- card_min = b.nsites() - b.height() - b.width() + 1;
-
- double sum = integral_sum_sum_2(b.pmax()).first() - integral_sum_sum_2(tr).first()
- integral_sum_sum_2(bl).first() + integral_sum_sum_2(b.pmin()).first();
- double sum_2 = integral_sum_sum_2(b.pmax()).second() -
integral_sum_sum_2(tr).second() - integral_sum_sum_2(bl).second() +
integral_sum_sum_2(b.pmin()).second();
- double mean = sum / card_min;
-
- double num = (sum_2 - sum * sum / card_min);
- double stddev = 0;
- if (num > 0)
- stddev = std::sqrt(num / (card_min - 1));
- else
- stddev = 0;
-
-
- double T_min = compute_thres(mean, stddev);
-
- // Max case
- tl.row() = (p.row() - win_max - 1);
- tl.col() = (p.col() - win_max - 1);
-
- br.row() = (p.row() + win_max);
- br.col() = (p.col() + win_max);
-
- b = box2d(tl, br);
- b.crop_wrt(integral_sum_sum_2.domain());
-
- tr = b.pmax();
- tr.row() = b.pmin().row();
- bl = b.pmin();
- bl.row() = b.pmax().row();
-
- card_max = b.nsites() - b.height() - b.width() + 1;
-
- sum = integral_sum_sum_2(b.pmax()).first() - integral_sum_sum_2(tr).first() -
integral_sum_sum_2(bl).first() + integral_sum_sum_2(b.pmin()).first();
- sum_2 = integral_sum_sum_2(b.pmax()).second() - integral_sum_sum_2(tr).second() -
integral_sum_sum_2(bl).second() + integral_sum_sum_2(b.pmin()).second();
- mean = sum / card_max;
-
- num = (sum_2 - sum * sum / card_max);
- stddev = 0;
- if (num > 0)
- stddev = std::sqrt(num / (card_max - 1));
- else
- stddev = 0;
-
- double T_max = compute_thres(mean, stddev);
-
-
- // Final threshold
+ // Max case
+ double T_max = compute_thres(integral_sum_sum_2, row, col, win_max, formula);
- double teta = 0.3;
- double T = teta * T_max + (1 - teta) * T_min;
+ // Final threshold
+ double teta = 0.3; // Good results from 0.1 to 0.3 according
+ // to the paper.
+ double T = teta * T_max + (1 - teta) * T_min;
- mln_assertion(T_min <= 255);
- mln_assertion(T_max <= 255);
- mln_assertion(T <= 255);
+ mln_assertion(T_min <= 255);
+ mln_assertion(T_max <= 255);
+ mln_assertion(T <= 255);
- output(p) = input_1_gl(p) <= T;
+ *out_ptr++ = *in_ptr++ <= T;
+ }
}
-
}
lt.stop();
diff --git a/scribo/src/binarization/niblack.cc b/scribo/src/binarization/niblack.cc
index 4b7ed91..58074fc 100644
--- a/scribo/src/binarization/niblack.cc
+++ b/scribo/src/binarization/niblack.cc
@@ -29,6 +29,8 @@
#include <mln/io/pbm/save.hh>
#include <mln/data/transform.hh>
#include <mln/fun/v2v/rgb_to_luma.hh>
+#include <mln/arith/revert.hh>
+#include <mln/logical/not.hh>
#include <scribo/binarization/niblack.hh>
#include <scribo/debug/option_parser.hh>
@@ -98,8 +100,9 @@ int main(int argc, char *argv[])
image2d<value::int_u8>
input_1_gl = data::transform(input,
mln::fun::v2v::rgb_to_luma<value::int_u8>());
+ arith::revert_inplace(input_1_gl);
image2d<bool> out = scribo::binarization::niblack(input_1_gl, w, k);
-
+ logical::not_inplace(out);
io::pbm::save(out, options.arg("output.pbm"));
trace::exiting("main");
diff --git a/scribo/src/binarization/sauvola_ms.cc
b/scribo/src/binarization/sauvola_ms.cc
index 483a35b..d07de72 100644
--- a/scribo/src/binarization/sauvola_ms.cc
+++ b/scribo/src/binarization/sauvola_ms.cc
@@ -109,15 +109,24 @@ int main(int argc, char *argv[])
unsigned s = atoi(options.opt_value("s").c_str());
double k = atof(options.opt_value("k").c_str());
+ if (options.is_set("k"))
+ {
+ binarization::internal::k2 = k;
+ binarization::internal::k3 = k;
+ binarization::internal::k4 = k;
+ }
+ else
+ {
+ binarization::internal::k2 = atof(options.opt_value("k2").c_str());
+ binarization::internal::k3 = atof(options.opt_value("k3").c_str());
+ binarization::internal::k4 = atof(options.opt_value("k4").c_str());
+ }
+
if (verbose)
std::cout << "Using w_1=" << w_1 << " - s="
<< s
<< " - k=" << k << std::endl;
- binarization::internal::k2 = atof(options.opt_value("k2").c_str());
- binarization::internal::k3 = atof(options.opt_value("k3").c_str());
- binarization::internal::k4 = atof(options.opt_value("k4").c_str());
-
// Load
image2d<value::rgb8> input_1;
--
1.7.2.5