* sauvola_fast.cc: Remove.
* scribo/binarization/internal/local_threshold_debug.hh: Add more
debug.
* scribo/binarization/internal/sauvola_ms_functor.hh,
* scribo/binarization/sauvola_ms.hh: Introduce k for each scale.
* src/binarization/Makefile.am,
* src/binarization/sauvola_ms.cc,
* src/binarization/sauvola_ms_debug.cc,
* src/binarization/sauvola_ms_split.cc: Take several k into
account.
---
scribo/ChangeLog | 18 ++++
scribo/sauvola_fast.cc | 81 -------------------
.../binarization/internal/local_threshold_debug.hh | 4 +
.../binarization/internal/sauvola_ms_functor.hh | 60 ++++----------
scribo/scribo/binarization/sauvola_ms.hh | 23 +++++-
scribo/src/binarization/Makefile.am | 7 ++
scribo/src/binarization/sauvola_ms.cc | 15 +++-
scribo/src/binarization/sauvola_ms_debug.cc | 84 ++++++++++++++++++++
scribo/src/binarization/sauvola_ms_split.cc | 14 +++-
9 files changed, 179 insertions(+), 127 deletions(-)
delete mode 100644 scribo/sauvola_fast.cc
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index ff7d1fa..4bc842f 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,23 @@
2012-08-23 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Improve Sauvola.
+
+ * sauvola_fast.cc: Remove.
+
+ * scribo/binarization/internal/local_threshold_debug.hh: Add more
+ debug.
+
+ * scribo/binarization/internal/sauvola_ms_functor.hh,
+ * scribo/binarization/sauvola_ms.hh: Introduce k for each scale.
+
+ * src/binarization/Makefile.am,
+ * src/binarization/sauvola_ms.cc,
+ * src/binarization/sauvola_ms_debug.cc,
+ * src/binarization/sauvola_ms_split.cc: Take several k into
+ account.
+
+2012-08-23 Guillaume Lazzara <z(a)lrde.epita.fr>
+
Add Wolf's binarization algorithm.
* scribo/binarization/internal/wolf_formula.hh,
diff --git a/scribo/sauvola_fast.cc b/scribo/sauvola_fast.cc
deleted file mode 100644
index f412bbe..0000000
--- a/scribo/sauvola_fast.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-#include <mln/core/image/image2d.hh>
-#include <scribo/canvas/integral_browsing.hh>
-#include <mln/io/pgm/load.hh>
-#include <mln/io/pbm/save.hh>
-#include <mln/util/couple.hh>
-#include <mln/util/timer.hh>
-#include <scribo/binarization/internal/sauvola_formula.hh>
-#include <scribo/binarization/internal/sauvola_functor.hh>
-#include <scribo/util/init_integral_image.hh>
-#include <scribo/util/integral_sum_sum2_functor.hh>
-#include <scribo/util/compute_sub_domains.hh>
-
-#include <mln/io/dump/save.hh>
-
-#include <mln/border/mirror.hh>
-#include <mln/border/adjust.hh>
-
-namespace mln
-{
-
- image2d<bool>
- sauvola_fast(const image2d<value::int_u8>& input, unsigned win)
- {
- util::timer t;
- t.start();
-
- mln::util::array<mln::util::couple<box2d, unsigned> >
- sub_domains = scribo::util::compute_sub_domains(input, 1, 3);
-
- border::adjust(input, sub_domains(1).second());
- border::mirror(input);
-
- scribo::util::integral_sum_sum2_functor<value::int_u8, double> fi;
- image2d<util::couple<double,double> >
- integral = scribo::util::init_integral_image(input, 3, fi, sub_domains[2].first(),
- sub_domains[2].second());
-
- t.stop();
- std::cout << "image integrale - " << t << std::endl;
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- initialize(internal::debug_mean, input);
- initialize(internal::debug_stddev, input);
-
- initialize(internal::debug_threshold, input);
- initialize(internal::debug_alpham, input);
- initialize(internal::debug_alphacond, input);
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
- t.restart();
- scribo::binarization::internal::sauvola_functor<image2d<value::int_u8> >
f(input,
- SCRIBO_DEFAULT_SAUVOLA_K,
- SCRIBO_DEFAULT_SAUVOLA_R);
- scribo::canvas::integral_browsing(integral, 1, win / 3, win / 3, 3, f);
- t.stop();
- std::cout << "Binarization - " << t << std::endl;
-
- return f.bin;
- }
-
-}
-
-
-int main(int argc, char *argv[])
-{
- using namespace mln;
-
- image2d<value::int_u8> input;
- io::pgm::load(input, argv[1]);
-
- unsigned win = atoi(argv[2]);
-
- util::timer t;
- t.start();
- image2d<bool> output = sauvola_fast(input, win);
- t.stop();
- std::cout << t << std::endl;
-
- io::pbm::save(output, argv[3]);
-}
-
diff --git a/scribo/scribo/binarization/internal/local_threshold_debug.hh
b/scribo/scribo/binarization/internal/local_threshold_debug.hh
index 46503f6..19310f2 100644
--- a/scribo/scribo/binarization/internal/local_threshold_debug.hh
+++ b/scribo/scribo/binarization/internal/local_threshold_debug.hh
@@ -71,6 +71,8 @@ namespace scribo
image3d<double> debug_scale_proba;
+ image2d<value::int_u8> debug_e_2;
+
image2d<double> debug_alpham;
image2d<bool> debug_alphacond;
@@ -78,6 +80,8 @@ namespace scribo
double stddev_debug_factor = 1.0;
double alpham_debug_factor = 2.0;
+ mln::util::array<std::map<unsigned, unsigned> > area_histo(3);
+
} // end of namespace scribo::binarization::internal
} // end of namespace scribo::binarization
diff --git a/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
b/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
index d0e6200..cbace88 100644
--- a/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
+++ b/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
@@ -54,6 +54,11 @@ namespace scribo
namespace internal
{
+ double k2;
+ double k3;
+ double k4;
+
+
using namespace mln;
@@ -82,6 +87,7 @@ namespace scribo
double K_;
double R_;
+ int i_;
sauvola_formula formula_;
@@ -113,8 +119,9 @@ namespace scribo
i(i),
q(q),
pxl(input),
- K_(K),
- R_(R)
+ //K_(K),
+ R_(R),
+ i_(i)
{
res = 0;
pxl.start();
@@ -137,6 +144,13 @@ namespace scribo
dp = negative_offsets_wrt(input, c8());
n_nbhs = dp.nelements();
+
+ if (i == 2)
+ K_ = binarization::internal::k2;
+ else if (i == 3)
+ K_ = binarization::internal::k3;
+ else
+ K_ = binarization::internal::k4;
}
@@ -151,47 +165,6 @@ namespace scribo
value::int_u8 t_p;
mln::convert::from_to(formula_(mean, stddev, K_, R_), t_p);
- // point2d pi = input.point_at_index(p);
- // pi.row() *= std::pow(q, i - 2);
- // pi.col() *= std::pow(q, i - 2);
-
- // point2d pi_up = pi;
- // pi_up.row() -= std::pow(q, i - 2);
-
- // point2d pi_up_left = pi;
- // pi_up_left.row() -= std::pow(q, i - 2);
- // pi_up_left.col() -= std::pow(q, i - 2);
-
- // point2d pi_up_right = pi;
- // pi_up_right.row() -= std::pow(q, i - 2);
- // pi_up_right.col() += std::pow(q, i - 2);
-
- // point2d pi_down = pi;
- // pi_down.row() += std::pow(q, i - 2);
-
- // point2d pi_down_left = pi;
- // pi_down_left.row() += std::pow(q, i - 2);
- // pi_down_left.col() -= std::pow(q, i - 2);
-
- // point2d pi_down_right = pi;
- // pi_down_right.row() += std::pow(q, i - 2);
- // pi_down_right.col() += std::pow(q, i - 2);
-
- // point2d pi_left = pi;
- // pi_left.col() -= std::pow(q, i - 2);
-
- // point2d pi_right = pi;
- // pi_right.col() += std::pow(q, i - 2);
-
-
-
-
-
-// if (e_2(pi) != 0) // Already retrieved from another scale.
-// // || e_2(pi_up) != 0 || e_2(pi_down) != 0 || e_2(pi_left) != 0 || e_2(pi_right)
!= 0
-// // || e_2(pi_up_left) != 0 || e_2(pi_up_right) != 0 || e_2(pi_down_left) != 0 ||
e_2(pi_down_right) != 0)
-// msk.element(p) = false;
-// else
msk.element(p) = input.element(p) < t_p;
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
@@ -232,6 +205,7 @@ namespace scribo
template <typename I>
void sauvola_ms_functor<I>::finalize()
{
+ std::cout << "Scale " << i_ << " - K = " <<
K_ << std::endl;
mln_assertion(! pxl.is_valid());
}
diff --git a/scribo/scribo/binarization/sauvola_ms.hh
b/scribo/scribo/binarization/sauvola_ms.hh
index e6297bd..a740ec0 100644
--- a/scribo/scribo/binarization/sauvola_ms.hh
+++ b/scribo/scribo/binarization/sauvola_ms.hh
@@ -74,6 +74,8 @@
# include <mln/io/pgm/save.hh>
# include <mln/io/dump/save.hh>
# include <mln/debug/filename.hh>
+# include <mln/labeling/compute.hh>
+# include <mln/accu/math/count.hh>
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
# include <mln/util/timer.hh>
@@ -239,6 +241,13 @@ namespace scribo
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
f.full_msk.element(p) = true;
+
+ unsigned area = f.card.element(p) * ratio * s;
+ if (area_histo[i - 2].find(area) != area_histo[i - 2].end())
+ ++area_histo[i - 2][area];
+ else
+ area_histo[i - 2][area] = 1;
+
for (unsigned l = 0; l < ratio; ++l)
for (unsigned k = 0; k < ratio; ++k)
debug_scale_proba(point3d(i - 2, sq.row() + l, sq.col() + k)) =
f.card.element(p);
@@ -948,7 +957,8 @@ namespace scribo
// Lowest scale -> no minimum component size.
{
t_ima[2] = internal::compute_t_n_and_e_2(sub_ima[2], e_2,
- 0,
+ // FIXME: was '0'. '2' is to avoid too much noise with
k=0.2.
+ 2,
// 99 * coeff,
win_w[2] * 3 * coeff,
// (810 / 9) * coeff,
@@ -977,9 +987,20 @@ namespace scribo
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ internal::debug_e_2 = e_2;
if (internal::scale_iz_image_output)
io::pgm::save(e_2,
mln::debug::filename(internal::scale_iz_image_output));
+
+ // Computing scale ratios.
+ mln::util::array<unsigned>
+ count = labeling::compute(accu::meta::math::count(), e_2, 4);
+ unsigned npixels = e_2.domain().nsites();
+ std::cout << "Scale ratios: 2 (" << count[2] / (float)npixels *
100
+ << ") - 3 (" << count[3] / (float)npixels * 100
+ << ") - 4 (" << count[4] / (float)npixels * 100 <<
")"
+ << std::endl;
+
if (internal::scale_proba_output)
io::dump::save(internal::debug_scale_proba,
mln::debug::filename(internal::scale_proba_output));
diff --git a/scribo/src/binarization/Makefile.am b/scribo/src/binarization/Makefile.am
index 68b83dc..b29ac30 100644
--- a/scribo/src/binarization/Makefile.am
+++ b/scribo/src/binarization/Makefile.am
@@ -36,6 +36,7 @@ if HAVE_MAGICKXX
sauvola_ms \
sauvola_ms_fg \
sauvola_ms_split \
+ singh \
wolf
@@ -71,6 +72,12 @@ if HAVE_MAGICKXX
sauvola_LDFLAGS = $(AM_LDFLAGS) \
$(MAGICKXX_LDFLAGS)
+ singh_SOURCES = singh.cc
+ singh_CPPFLAGS = $(AM_CPPFLAGS) \
+ $(MAGICKXX_CPPFLAGS)
+ singh_LDFLAGS = $(AM_LDFLAGS) \
+ $(MAGICKXX_LDFLAGS)
+
wolf_SOURCES = wolf.cc
wolf_CPPFLAGS = $(AM_CPPFLAGS) \
$(MAGICKXX_CPPFLAGS)
diff --git a/scribo/src/binarization/sauvola_ms.cc
b/scribo/src/binarization/sauvola_ms.cc
index 77f839d..483a35b 100644
--- a/scribo/src/binarization/sauvola_ms.cc
+++ b/scribo/src/binarization/sauvola_ms.cc
@@ -60,7 +60,14 @@ static const scribo::debug::opt_data opt_desc[] =
// name, description, arguments, check args function, number of args, default arg
{ "debug-prefix", "Enable debug image outputs. Prefix image name with
that "
"given prefix.", "<prefix>", 0, 1, 0 },
- { "k", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.34" },
+ { "k", "Sauvola's formulae parameter. Set it globally for all
scales.",
+ "<value>", 0, 1, "0.34" },
+
+ { "k2", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.20" },
+ { "k3", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.30" },
+ { "k4", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.50" },
+
+
{ "s", "First subsampling ratio. Possible values: 2 or 3.",
"ratio",
scribo::debug::check_sauvola_first_subsampling, 1, "3" },
{ "verbose", "Enable verbose mode", 0, 0, 0, 0 },
@@ -106,6 +113,12 @@ int main(int argc, char *argv[])
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;
io::magick::load(input_1, options.arg("input.*"));
diff --git a/scribo/src/binarization/sauvola_ms_debug.cc
b/scribo/src/binarization/sauvola_ms_debug.cc
index c04e58b..d89e9f4 100644
--- a/scribo/src/binarization/sauvola_ms_debug.cc
+++ b/scribo/src/binarization/sauvola_ms_debug.cc
@@ -30,6 +30,13 @@
#include <mln/io/pbm/save.hh>
#include <mln/data/transform.hh>
#include <mln/fun/v2v/rgb_to_luma.hh>
+#include <mln/data/paste.hh>
+#include <mln/pw/all.hh>
+#include <mln/core/image/dmorph/sub_image.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/data/convert.hh>
+#include <mln/labeling/foreground.hh>
+#include <mln/literal/colors.hh>
#include <scribo/binarization/sauvola_ms.hh>
#include <scribo/debug/option_parser.hh>
@@ -58,6 +65,11 @@ static const scribo::debug::opt_data opt_desc[] =
{ "debug-prefix", "Enable debug image outputs. Prefix image name with
that "
"given prefix.", "<prefix>", 0, 1, 0 },
{ "k", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.34" },
+
+ { "k2", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.20" },
+ { "k3", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.30" },
+ { "k4", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.50" },
+
{ "s", "First subsampling ratio. Possible values: 2 or 3.",
"ratio",
scribo::debug::check_sauvola_first_subsampling, 1, "3" },
{ "verbose", "Enable verbose mode", 0, 0, 0, 0 },
@@ -66,6 +78,35 @@ static const scribo::debug::opt_data opt_desc[] =
};
+namespace mln
+{
+
+ struct scale_to_color : public Function_v2v<scale_to_color>
+ {
+ typedef value::rgb8 result;
+
+ value::rgb8 operator()(const value::int_u8& v) const
+ {
+ switch (v)
+ {
+ default:
+ case 0:
+ return literal::black;
+
+ case 2:
+ return literal::green;
+
+ case 3:
+ return literal::blue;
+
+ case 4:
+ return literal::red;
+ }
+ }
+
+ };
+
+}
int main(int argc, char *argv[])
@@ -97,6 +138,10 @@ int main(int argc, char *argv[])
unsigned s = atoi(options.opt_value("s").c_str());
double k = atof(options.opt_value("k").c_str());
+ 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;
@@ -106,6 +151,7 @@ int main(int argc, char *argv[])
scribo::binarization::internal::full_threshold_image_output =
"full_threshold_image.pbm";
scribo::binarization::internal::scale_iz_image_output = "scale_iz.pgm";
scribo::binarization::internal::scale_proba_output = "scale_proba.dump";
+ const char *scale_bin_output = "scale_bin.ppm";
// Load
image2d<value::rgb8> input_1;
@@ -129,6 +175,44 @@ int main(int argc, char *argv[])
std::cout << "binarized in " << t << "s"
<< std::endl;
}
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ {
+ image2d<value::int_u8> scale_bin;
+ initialize(scale_bin, output);
+
+ for (unsigned i = 0; i < geom::nrows(output); ++i)
+ for (unsigned j = 0; j < geom::ncols(output); ++j)
+ if (output.at_(i,j))
+ scale_bin.at_(i,j) = binarization::internal::debug_e_2.at_(i/3, j/3);
+ else
+ scale_bin.at_(i,j) = 0;
+
+ scale_to_color f;
+ io::ppm::save(data::transform(scale_bin, f),
+ mln::debug::filename(scale_bin_output));
+
+ // Computing size of retrieved objects for each scale.
+ unsigned max = 15000;
+ std::ofstream ostr(mln::debug::filename("area_per_scale.tsv").c_str());
+ for (unsigned j = 0; j < max; ++j)
+ {
+ ostr << j;
+ for (unsigned i = 0; i < 3; ++i)
+ {
+ if (binarization::internal::area_histo[i].find(j) !=
binarization::internal::area_histo[i].end())
+ ostr << " " << binarization::internal::area_histo[i][j];
+ else
+ ostr << " " << 0;
+ }
+ ostr << std::endl;
+ }
+ ostr.close();
+
+
+ }
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+
io::pbm::save(output, options.arg("output.pbm"));
}
diff --git a/scribo/src/binarization/sauvola_ms_split.cc
b/scribo/src/binarization/sauvola_ms_split.cc
index 8206a20..f71f734 100644
--- a/scribo/src/binarization/sauvola_ms_split.cc
+++ b/scribo/src/binarization/sauvola_ms_split.cc
@@ -55,7 +55,13 @@ static const scribo::debug::opt_data opt_desc[] =
// name, description, arguments, check args function, number of args, default arg
{ "debug-prefix", "Enable debug image outputs. Prefix image name with
that "
"given prefix.", "<prefix>", 0, 1, 0 },
- { "k", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.34" },
+ { "k", "Sauvola's formulae parameter. Set it globally for all
scales.",
+ "<value>", 0, 1, "0.34" },
+
+ { "k2", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.20" },
+ { "k3", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.30" },
+ { "k4", "Sauvola's formulae parameter",
"<value>", 0, 1, "0.50" },
+
{ "min-ntrue", "The number of components in which a site must be set to
'True' in"
" order to be set to 'True' in the output (Possible values: 1, 2,
3).",
"<num>", scribo::debug::check_sauvola_split_ntrue, 1, "2"
},
@@ -95,10 +101,16 @@ int main(int argc, char *argv[])
double k = atof(options.opt_value("k").c_str());
unsigned min_ntrue = atoi(options.opt_value("min-ntrue").c_str());
+ 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 << " - min_ntrue=" << min_ntrue <<
std::endl;
+
Magick::InitializeMagick(0);
image2d<value::rgb8> input_1;
--
1.7.2.5