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
June 2012
- 6 participants
- 147 discussions
* src/binarization/global_threshold.cc,
* src/binarization/kim.cc,
* src/binarization/niblack.cc,
* src/binarization/otsu.cc,
* src/binarization/sauvola.cc,
* src/binarization/sauvola_ms.cc,
* src/binarization/sauvola_ms_debug.cc,
* src/binarization/sauvola_ms_fg.cc,
* src/binarization/sauvola_ms_split.cc,
* src/binarization/wolf.cc: Make use of operator<<.
---
scribo/src/binarization/global_threshold.cc | 10 +++++-----
scribo/src/binarization/kim.cc | 13 +++++--------
scribo/src/binarization/niblack.cc | 10 +++++-----
scribo/src/binarization/otsu.cc | 9 ++++-----
scribo/src/binarization/sauvola.cc | 18 ++++++------------
scribo/src/binarization/sauvola_ms.cc | 21 ++++++++-------------
scribo/src/binarization/sauvola_ms_debug.cc | 20 +++++++-------------
scribo/src/binarization/sauvola_ms_fg.cc | 11 +++++------
scribo/src/binarization/sauvola_ms_split.cc | 15 ++++++---------
scribo/src/binarization/wolf.cc | 9 ++++-----
10 files changed, 55 insertions(+), 81 deletions(-)
diff --git a/scribo/src/binarization/global_threshold.cc b/scribo/src/binarization/global_threshold.cc
index 276ec2e..eaf11c7 100644
--- a/scribo/src/binarization/global_threshold.cc
+++ b/scribo/src/binarization/global_threshold.cc
@@ -1,4 +1,5 @@
-// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2011, 2012 EPITA Research and Development Laboratory
+// (LRDE)
//
// This file is part of Olena.
//
@@ -57,7 +58,8 @@ 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 },
- { "verbose", "Enable verbose mode", 0, 0, 0, 0 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{0, 0, 0, 0, 0, 0}
};
@@ -83,11 +85,9 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
unsigned threshold = atoi(options.arg("threshold_value"));
- if (verbose)
- std::cout << "Using threshold=" << threshold << std::endl;
+ scribo::debug::logger() << "Using threshold=" << threshold << std::endl;
image2d<value::rgb8> input;
io::magick::load(input, options.arg("input.*"));
diff --git a/scribo/src/binarization/kim.cc b/scribo/src/binarization/kim.cc
index 9f9c38f..0a064d8 100644
--- a/scribo/src/binarization/kim.cc
+++ b/scribo/src/binarization/kim.cc
@@ -59,7 +59,8 @@ 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" },
- { "verbose", "Enable verbose mode", 0, 0, 0, 0 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{ "win-size", "Window size at scale 1", "<size>", 0, 1, "101" },
{0, 0, 0, 0, 0, 0}
};
@@ -90,13 +91,9 @@ int main(int argc, char *argv[])
unsigned w_1 = atoi(options.opt_value("win-size").c_str());
double k = atof(options.opt_value("k").c_str());
- if (options.is_set("verbose"))
- {
- scribo::debug::logger().set_verbose_mode(
- scribo::debug::txt_to_verbose_mode(options.opt_value("verbose")));
- scribo::debug::logger().log(Low, std::string("Using w_1=") + w_1
- + std::string(" - k=") + k);
- }
+ scribo::debug::logger() << "Using w_1=" << w_1
+ << " - k=" << k << std::endl;
+
// Load
image2d<value::rgb8> input_1;
diff --git a/scribo/src/binarization/niblack.cc b/scribo/src/binarization/niblack.cc
index 58074fc..7c14c45 100644
--- a/scribo/src/binarization/niblack.cc
+++ b/scribo/src/binarization/niblack.cc
@@ -1,4 +1,5 @@
-// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2011, 2012 EPITA Research and Development Laboratory
+// (LRDE)
//
// This file is part of Olena.
//
@@ -59,7 +60,8 @@ 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", "Niblack's formulae parameter", "<value>", 0, 1, "-0.2" },
- { "verbose", "Enable verbose mode", 0, 0, 0, 0 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{ "win-size", "Window size", "<size>", 0, 1, "101" },
{0, 0, 0, 0, 0, 0}
};
@@ -86,12 +88,10 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
unsigned w = atoi(options.opt_value("win-size").c_str());
double k = atof(options.opt_value("k").c_str());
- if (verbose)
- std::cout << "Using w=" << w << " and k=" << k << std::endl;
+ scribo::debug::logger() << "Using w=" << w << " and k=" << k << std::endl;
image2d<value::rgb8> input;
io::magick::load(input, options.arg("input.*"));
diff --git a/scribo/src/binarization/otsu.cc b/scribo/src/binarization/otsu.cc
index eb60973..dcdae1d 100644
--- a/scribo/src/binarization/otsu.cc
+++ b/scribo/src/binarization/otsu.cc
@@ -1,4 +1,5 @@
-// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2011, 2012 EPITA Research and Development Laboratory
+// (LRDE)
//
// This file is part of Olena.
//
@@ -60,7 +61,8 @@ 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 },
- { "verbose", "Enable verbose mode", 0, 0, 0, 0 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{0, 0, 0, 0, 0, 0}
};
@@ -86,9 +88,6 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
- (void) verbose;
-
image2d<value::rgb8> input;
io::magick::load(input, options.arg("input.*"));
diff --git a/scribo/src/binarization/sauvola.cc b/scribo/src/binarization/sauvola.cc
index 6ea224c..3549585 100644
--- a/scribo/src/binarization/sauvola.cc
+++ b/scribo/src/binarization/sauvola.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Copyright (C) 2009, 2010, 2011, 2012 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
@@ -58,7 +58,8 @@ 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" },
- { "verbose", "Enable verbose mode", 0, 0, 0, 0 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{ "win-size", "Window size", "<size>", 0, 1, "101" },
{0, 0, 0, 0, 0, 0}
};
@@ -85,12 +86,10 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
unsigned w = atoi(options.opt_value("win-size").c_str());
double k = atof(options.opt_value("k").c_str());
- if (verbose)
- std::cout << "Using w=" << w << " and k=" << k << std::endl;
+ scribo::debug::logger() << "Using w=" << w << " and k=" << k << std::endl;
image2d<value::rgb8> input;
io::magick::load(input, options.arg("input.*"));
@@ -99,17 +98,12 @@ 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>());
- mln::util::timer t;
- t.start();
+ scribo::debug::logger().start_local_time_logging();
// Binarize
image2d<bool> out = scribo::binarization::sauvola(input_1_gl, w, k);
- if (verbose)
- {
- t.stop();
- std::cout << "binarized in " << t << "s" << std::endl;
- }
+ scribo::debug::logger().stop_local_time_logging("Binarized in");
io::pbm::save(out, options.arg("output.pbm"));
diff --git a/scribo/src/binarization/sauvola_ms.cc b/scribo/src/binarization/sauvola_ms.cc
index d07de72..c5ab3e4 100644
--- a/scribo/src/binarization/sauvola_ms.cc
+++ b/scribo/src/binarization/sauvola_ms.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Copyright (C) 2009, 2010, 2011, 2012 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
@@ -70,7 +70,8 @@ static const scribo::debug::opt_data opt_desc[] =
{ "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 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{ "win-size", "Window size at scale 1", "<size>", 0, 1, "101" },
{0, 0, 0, 0, 0, 0}
};
@@ -102,7 +103,6 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
// Window size
unsigned w_1 = atoi(options.opt_value("win-size").c_str());
// First subsampling scale.
@@ -122,9 +122,8 @@ int main(int argc, char *argv[])
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;
+ scribo::debug::logger() << "Using w_1=" << w_1 << " - s=" << s
+ << " - k=" << k << std::endl;
@@ -137,18 +136,14 @@ int main(int argc, char *argv[])
input_1_gl = data::transform(input_1,
mln::fun::v2v::rgb_to_luma<value::int_u8>());
- mln::util::timer t;
- t.start();
+
+ scribo::debug::logger().start_local_time_logging();
// Binarize
image2d<bool>
output = scribo::binarization::sauvola_ms(input_1_gl, w_1, s, k);
- if (verbose)
- {
- t.stop();
- std::cout << "binarized in " << t << "s" << std::endl;
- }
+ scribo::debug::logger().stop_local_time_logging("Binarized in");
io::pbm::save(output, options.arg("output.pbm"));
}
diff --git a/scribo/src/binarization/sauvola_ms_debug.cc b/scribo/src/binarization/sauvola_ms_debug.cc
index d89e9f4..251f0e8 100644
--- a/scribo/src/binarization/sauvola_ms_debug.cc
+++ b/scribo/src/binarization/sauvola_ms_debug.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Copyright (C) 2009, 2010, 2011, 2012 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
@@ -72,7 +72,8 @@ static const scribo::debug::opt_data opt_desc[] =
{ "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 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{ "win-size", "Window size at scale 1", "<size>", 0, 1, "101" },
{0, 0, 0, 0, 0, 0}
};
@@ -131,7 +132,6 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
// Window size
unsigned w_1 = atoi(options.opt_value("win-size").c_str());
// First subsampling scale.
@@ -142,9 +142,8 @@ int main(int argc, char *argv[])
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;
+ scribo::debug::logger() << "Using w_1=" << w_1 << " - s=" << s
+ << " - k=" << k << std::endl;
scribo::binarization::internal::scale_image_output = "scale_image.pgm";
scribo::binarization::internal::threshold_image_output = "threshold_image.pbm";
@@ -162,18 +161,13 @@ int main(int argc, char *argv[])
input_1_gl = data::transform(input_1,
mln::fun::v2v::rgb_to_luma<value::int_u8>());
- mln::util::timer t;
- t.start();
+ scribo::debug::logger().start_local_time_logging();
// Binarize.
image2d<bool>
output = scribo::binarization::sauvola_ms(input_1_gl, w_1, s, k);
- if (verbose)
- {
- t.stop();
- std::cout << "binarized in " << t << "s" << std::endl;
- }
+ scribo::debug::logger().stop_local_time_logging("Binarized in");
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
{
diff --git a/scribo/src/binarization/sauvola_ms_fg.cc b/scribo/src/binarization/sauvola_ms_fg.cc
index 83a48af..98206a8 100644
--- a/scribo/src/binarization/sauvola_ms_fg.cc
+++ b/scribo/src/binarization/sauvola_ms_fg.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Copyright (C) 2009, 2010, 2011, 2012 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
@@ -65,7 +65,8 @@ static const scribo::debug::opt_data opt_desc[] =
"useful if fg-extraction is enabled.", "<size>", 0, 1, "1024" },
{ "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 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{ "win-size", "Window size at scale 1", "<size>", 0, 1, "101" },
{0, 0, 0, 0, 0, 0}
};
@@ -92,7 +93,6 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
unsigned lambda = atoi(options.opt_value("lambda").c_str());
// Window size
@@ -102,9 +102,8 @@ 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 (verbose)
- std::cout << "Using w_1=" << w_1 << " - s=" << s << " - k="
- << k << " - lambda=" << lambda << std::endl;
+ scribo::debug::logger() << "Using w_1=" << w_1 << " - s=" << s << " - k="
+ << k << " - lambda=" << lambda << std::endl;
Magick::InitializeMagick(0);
diff --git a/scribo/src/binarization/sauvola_ms_split.cc b/scribo/src/binarization/sauvola_ms_split.cc
index f71f734..f1cc490 100644
--- a/scribo/src/binarization/sauvola_ms_split.cc
+++ b/scribo/src/binarization/sauvola_ms_split.cc
@@ -1,5 +1,5 @@
-// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory
-// (LRDE)
+// Copyright (C) 2009, 2010, 2012 EPITA Research and Development
+// Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -67,7 +67,8 @@ static const scribo::debug::opt_data opt_desc[] =
"<num>", scribo::debug::check_sauvola_split_ntrue, 1, "2" },
{ "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 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{ "win-size", "Window size at scale 1", "<size>", 0, 1, "101" },
{0, 0, 0, 0, 0, 0}
};
@@ -92,7 +93,6 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
// Window size
unsigned w_1 = atoi(options.opt_value("win-size").c_str()); // Scale 1
@@ -105,11 +105,8 @@ int main(int argc, char *argv[])
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;
-
+ scribo::debug::logger() << "Using w_1=" << w_1 << " - s=" << s << " - k="
+ << k << " - min_ntrue=" << min_ntrue << std::endl;
Magick::InitializeMagick(0);
diff --git a/scribo/src/binarization/wolf.cc b/scribo/src/binarization/wolf.cc
index c481e09..4495f64 100644
--- a/scribo/src/binarization/wolf.cc
+++ b/scribo/src/binarization/wolf.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Copyright (C) 2009, 2010, 2011, 2012 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
@@ -58,7 +58,8 @@ 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", "Wolf's formulae parameter", "<value>", 0, 1, "0.34" },
- { "verbose", "Enable verbose mode", 0, 0, 0, 0 },
+ { "verbose", "Enable verbose mode (mute, time, low, medium, full)",
+ "<mode>", scribo::debug::check_verbose_mode, 1, "mute" },
{ "win-size", "Window size", "<size>", 0, 1, "101" },
{0, 0, 0, 0, 0, 0}
};
@@ -85,12 +86,10 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
unsigned w = atoi(options.opt_value("win-size").c_str());
double k = atof(options.opt_value("k").c_str());
- if (verbose)
- std::cout << "Using w=" << w << " and k=" << k << std::endl;
+ scribo::debug::logger() << "Using w=" << w << " and k=" << k << std::endl;
image2d<value::rgb8> input;
io::magick::load(input, options.arg("input.*"));
--
1.7.2.5
1
0
* src/binarization/kim.cc: Move code...
* scribo/binarization/kim.hh: ... here.
* tests/binarization/Makefile.am: Add new target.
* tests/binarization/kim.cc,
* tests/binarization/kim.ref.pbm,
* tests/binarization/kim_weven_hodd.ref.pbm,
* tests/binarization/kim_wodd_heven.ref.pbm,
* tests/binarization/kim_wodd_hodd.ref.pbm: New.
---
scribo/scribo/binarization/kim.hh | 262 ++++++++++++++++++++++
scribo/src/binarization/kim.cc | 199 +---------------
scribo/tests/binarization/Makefile.am | 6 +
scribo/tests/binarization/{sauvola.cc => kim.cc} | 18 +-
scribo/tests/binarization/kim.ref.pbm | Bin 0 -> 32884 bytes
scribo/tests/binarization/kim_weven_hodd.ref.pbm | Bin 0 -> 32820 bytes
scribo/tests/binarization/kim_wodd_heven.ref.pbm | Bin 0 -> 32884 bytes
scribo/tests/binarization/kim_wodd_hodd.ref.pbm | Bin 0 -> 32820 bytes
8 files changed, 289 insertions(+), 196 deletions(-)
create mode 100644 scribo/scribo/binarization/kim.hh
copy scribo/tests/binarization/{sauvola.cc => kim.cc} (77%)
create mode 100644 scribo/tests/binarization/kim.ref.pbm
create mode 100644 scribo/tests/binarization/kim_weven_hodd.ref.pbm
create mode 100644 scribo/tests/binarization/kim_wodd_heven.ref.pbm
create mode 100644 scribo/tests/binarization/kim_wodd_hodd.ref.pbm
diff --git a/scribo/scribo/binarization/kim.hh b/scribo/scribo/binarization/kim.hh
new file mode 100644
index 0000000..0d31a1d
--- /dev/null
+++ b/scribo/scribo/binarization/kim.hh
@@ -0,0 +1,262 @@
+// Copyright (C) 2012 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_KIM_HH
+# define SCRIBO_BINARIZATION_KIM_HH
+
+/// \file
+///
+///
+
+#include <cmath>
+#include <map>
+#include <scribo/binarization/sauvola.hh>
+#include <scribo/util/integral_sum_sum2_functor.hh>
+#include <scribo/text/extract_lines.hh>
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ using namespace mln;
+
+ /*! \brief Kim's binarization
+
+ This algorithms performs a first rough binarization on the input
+ (here we use Sauvola's method). Then text lines are roughly
+ detected by grouping connected components. For each text lines,
+ character thickness and x height is computed. Finally, each
+ lines is binarized again, using text features as parameters for
+ adjusting the final threshold.
+
+ This algorithms considers that global and local statistics
+ should be used to compute a threshold in text areas.
+
+ This is an improvement of Sauvola's method.
+
+ \param[in] input A gray-level image.
+ \param[in] window_size the window size to be used for the first
+ binarization.
+ \param[in] k Sauvola's formula parameter.
+
+ This implementation is based on the paper "Multi-Window
+ Binarization of Camera Image for Document Recognition", In-Jung
+ Kim, Proceedings of the 9th International Workshop on Frontiers
+ in Handwriting Recognition (IWFHR-9 2004)
+ */
+ template <typename I>
+ mln_ch_value(I, bool)
+ kim(const Image<I>& input, unsigned window_size, double k);
+
+ /*! \overload
+ k is set to SCRIBO_DEFAULT_SAUVOLA_K.
+ */
+ template <typename I>
+ mln_ch_value(I, bool)
+ kim(const Image<I>& input, unsigned window_size);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+
+ 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);
+ }
+
+ } // end of namespace scribo::binarization::internal
+
+
+ template <typename I>
+ mln_ch_value(I, bool)
+ kim(const Image<I>& input_, unsigned window_size, double k)
+ {
+ trace::entering("scribo::binarization::kim");
+
+ const I& input = exact(input_);
+
+ mln_precondition(input.is_valid());
+
+ // 1st simple binarization
+ image2d<bool>
+ output = scribo::binarization::sauvola(input, window_size, k);
+
+ // Compute integral image
+ scribo::util::integral_sum_sum2_functor<mln_value(I),double> f_sum_sum2;
+ image2d<mln::util::couple<double,double> >
+ integral_sum_sum_2 = scribo::util::init_integral_image(input, 1, f_sum_sum2);
+
+ // Find text lines
+ line_set<image2d<scribo::def::lbl_type> >
+ lines = scribo::text::extract_lines(output, c8());
+
+ typedef scribo::def::lbl_type V;
+ typedef image2d<V> L;
+ mln::util::array<unsigned> thickness(lines.nelements() + 1, 0);
+ const component_set<L>& comp_set = lines.components();
+ const L& lbl = comp_set.labeled_image();
+
+ // Compute run-lengths histogram in order to compute character
+ // thickness for each line.
+ for_all_lines(i, lines)
+ {
+ if (!lines(i).is_textline())
+ continue;
+
+ std::map<unsigned, unsigned> histo;
+ int count = 0;
+ for (int l = lines(i).bbox().pmin().row(); l <= lines(i).bbox().pmax().row(); ++l)
+ {
+ const V* end_ptr = &lbl.at_(l, lines(i).bbox().pmax().col() + 1);
+ for (const V* run_ptr = &lbl.at_(l, lines(i).bbox().pmin().col()); run_ptr != end_ptr; ++run_ptr)
+ if (*run_ptr)
+ ++count;
+ else
+ if (count)
+ {
+ if (histo.find(count) != histo.end())
+ histo[count]++;
+ else
+ histo.insert(std::make_pair(count, 1));
+ count = 0;
+ }
+ }
+
+ unsigned max = 0;
+ unsigned thick = 0;
+ for (std::map<unsigned, unsigned>::const_iterator it = histo.begin(); it != histo.end(); ++it)
+ if (it->second > max)
+ {
+ max = it->second;
+ thick = it->first;
+ }
+
+ thickness(lines(i).id()) = thick;
+ }
+
+ // Compute thresholds for each pixel of each line and binarize again!
+ for_all_lines(i, lines)
+ {
+ if (!lines(i).is_textline())
+ continue;
+
+ double
+ win_min = thickness(lines(i).id()),
+ win_max = lines(i).bbox().height();;
+
+ mln_assertion(win_min != 0);
+ mln_assertion(win_max != 0);
+
+ scribo::binarization::internal::sauvola_formula formula;
+
+ double teta = 0.3; // Good results from 0.1 to 0.3 according
+ // to the paper.
+ 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());
+ const mln_value(I)* in_ptr = &input.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);
+
+ // Max case
+ double T_max = compute_thres(integral_sum_sum_2, row, col, win_max, formula);
+
+ // Final threshold
+ double T = teta * T_max + (1 - teta) * T_min;
+
+ mln_assertion(T_min <= 255);
+ mln_assertion(T_max <= 255);
+ mln_assertion(T <= 255);
+
+ *out_ptr++ = *in_ptr++ <= T;
+ }
+ }
+ }
+
+ trace::exiting("scribo::binarization::kim");
+ return output;
+ }
+
+
+ template <typename I>
+ mln_ch_value(I, bool)
+ kim(const Image<I>& input, unsigned window_size)
+ {
+ return kim(input, window_size, SCRIBO_DEFAULT_SAUVOLA_K);
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_BINARIZATION_KIM_HH
diff --git a/scribo/src/binarization/kim.cc b/scribo/src/binarization/kim.cc
index aa81f50..9f9c38f 100644
--- a/scribo/src/binarization/kim.cc
+++ b/scribo/src/binarization/kim.cc
@@ -28,26 +28,18 @@
#include <cmath>
#include <mln/core/image/image2d.hh>
#include <mln/value/int_u8.hh>
-#include <mln/io/magick/load.hh>
-#include <mln/io/pbm/save.hh>
+#include <mln/io/magick/all.hh>
#include <mln/data/transform.hh>
#include <mln/fun/v2v/rgb_to_luma.hh>
-
-#include <scribo/binarization/sauvola_ms.hh>
+#include <scribo/binarization/kim.hh>
#include <scribo/debug/option_parser.hh>
#include <scribo/debug/logger.hh>
-#include <scribo/util/integral_sum_sum2_functor.hh>
-
-#include <scribo/text/extract_lines.hh>
-#include <scribo/debug/bboxes_enlarged_image.hh>
-#include <algorithm>
-
static const scribo::debug::arg_data arg_desc[] =
{
{ "input.*", "An image." },
- { "output.pbm", "A binary image." },
+ { "output.*", "A binary image." },
{0, 0}
};
@@ -67,59 +59,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" },
- { "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 },
{ "win-size", "Window size at scale 1", "<size>", 0, 1, "101" },
{0, 0, 0, 0, 0, 0}
};
-
-
-
-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[])
{
using namespace mln;
@@ -142,16 +86,17 @@ int main(int argc, char *argv[])
trace::entering("main");
- bool verbose = options.is_set("verbose");
// Window size
unsigned w_1 = atoi(options.opt_value("win-size").c_str());
- // First subsampling scale.
- unsigned s = atoi(options.opt_value("s").c_str());
double k = atof(options.opt_value("k").c_str());
- if (verbose)
- std::cout << "Using w_1=" << w_1 << " - s=" << s
- << " - k=" << k << std::endl;
+ if (options.is_set("verbose"))
+ {
+ scribo::debug::logger().set_verbose_mode(
+ scribo::debug::txt_to_verbose_mode(options.opt_value("verbose")));
+ scribo::debug::logger().log(Low, std::string("Using w_1=") + w_1
+ + std::string(" - k=") + k);
+ }
// Load
image2d<value::rgb8> input_1;
@@ -165,128 +110,8 @@ int main(int argc, char *argv[])
input_1_gl = data::transform(input_1,
mln::fun::v2v::rgb_to_luma<value::int_u8>());
- // 1st simple binarization
image2d<bool>
- output = scribo::binarization::sauvola_ms(input_1_gl, w_1, s, k);
-
- mln::util::timer lt;
- lt.start();
-
- // Compute integral image
- scribo::util::integral_sum_sum2_functor<value::int_u8,double> f_sum_sum2;
- image2d<mln::util::couple<double,double> >
- integral_sum_sum_2 = scribo::util::init_integral_image(input_1_gl, 1, f_sum_sum2);
-
- lt.stop();
- std::cout << "integral image - " << lt << std::endl;
- lt.start();
-
- // Find text lines
- line_set<image2d<scribo::def::lbl_type> >
- lines = scribo::text::extract_lines(output, c8());
-
- typedef scribo::def::lbl_type V;
- typedef image2d<V> L;
- mln::util::array<unsigned> thickness(lines.nelements() + 1, 0);
- const component_set<L>& comp_set = lines.components();
- const L& lbl = comp_set.labeled_image();
-
- lt.stop();
- std::cout << "Text line finding - " << lt << std::endl;
- lt.start();
-
- // Compute run-lengths histogram in order to compute character
- // thickness for each line.
- for_all_lines(i, lines)
- {
- if (!lines(i).is_textline())
- continue;
-
- std::map<unsigned, unsigned> histo;
- int count = 0;
- for (int l = lines(i).bbox().pmin().row(); l <= lines(i).bbox().pmax().row(); ++l)
- {
- const V* end_ptr = &lbl.at_(l, lines(i).bbox().pmax().col() + 1);
- for (const V* run_ptr = &lbl.at_(l, lines(i).bbox().pmin().col()); run_ptr != end_ptr; ++run_ptr)
- if (*run_ptr)
- ++count;
- else
- if (count)
- {
- if (histo.find(count) != histo.end())
- histo[count]++;
- else
- histo.insert(std::make_pair(count, 1));
- count = 0;
- }
- }
-
- unsigned max = 0;
- unsigned thick = 0;
- for (std::map<unsigned, unsigned>::const_iterator it = histo.begin(); it != histo.end(); ++it)
- if (it->second > max)
- {
- max = it->second;
- thick = it->first;
- }
-
- thickness(lines(i).id()) = thick;
- }
-
- lt.stop();
- std::cout << "run-lengths histogram - " << lt << std::endl;
-
- lt.start();
- // Compute thresholds for each pixel of each line and binarize again!
- for_all_lines(i, lines)
- {
- if (!lines(i).is_textline())
- continue;
-
- double
- win_min = thickness(lines(i).id()),
- win_max = lines(i).bbox().height();;
-
- mln_assertion(win_min != 0);
- mln_assertion(win_max != 0);
-
- scribo::binarization::internal::sauvola_formula formula;
-
- 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);
-
- // Max case
- double T_max = compute_thres(integral_sum_sum_2, row, col, win_max, formula);
-
- // 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);
-
- *out_ptr++ = *in_ptr++ <= T;
- }
- }
- }
-
- lt.stop();
- std::cout << "Last binarization - " << lt << std::endl;
-
- t.stop();
- std::cout << "Total time = " << t << std::endl;
+ output = scribo::binarization::kim(input_1_gl, w_1, k);
- io::pbm::save(output, options.arg("output.pbm"));
+ io::magick::save(output, options.arg("output.*"));
}
diff --git a/scribo/tests/binarization/Makefile.am b/scribo/tests/binarization/Makefile.am
index bac5a24..714bf93 100644
--- a/scribo/tests/binarization/Makefile.am
+++ b/scribo/tests/binarization/Makefile.am
@@ -21,6 +21,10 @@
include $(top_srcdir)/scribo/tests/tests.mk
EXTRA_DIST = \
+ kim.res.pbm \
+ kim_wodd_heven.ref.pbm \
+ kim_weven_hodd.ref.pbm \
+ kim_wodd_hodd.ref.pbm \
niblack.res.pbm \
niblack_wodd_heven.ref.pbm \
niblack_weven_hodd.ref.pbm \
@@ -41,6 +45,7 @@ EXTRA_DIST = \
check_PROGRAMS = \
global_threshold \
+ kim \
local_threshold \
niblack \
otsu \
@@ -50,6 +55,7 @@ check_PROGRAMS = \
global_threshold_SOURCES = global_threshold.cc
+kim_SOURCES = kim.cc
local_threshold_SOURCES = local_threshold.cc
niblack_SOURCES = niblack.cc
otsu_SOURCES = otsu.cc
diff --git a/scribo/tests/binarization/sauvola.cc b/scribo/tests/binarization/kim.cc
similarity index 77%
copy from scribo/tests/binarization/sauvola.cc
copy to scribo/tests/binarization/kim.cc
index 54e8bbd..74e0eef 100644
--- a/scribo/tests/binarization/sauvola.cc
+++ b/scribo/tests/binarization/kim.cc
@@ -31,7 +31,7 @@
#include <mln/io/pgm/load.hh>
#include <mln/io/pbm/load.hh>
-#include <scribo/binarization/sauvola.hh>
+#include <scribo/binarization/kim.hh>
#include "tests/data.hh"
@@ -44,10 +44,10 @@ int main()
image2d<value::int_u8> input;
io::pgm::load(input, MILENA_IMG_DIR "/lena.pgm");
- image2d<bool> bin = scribo::binarization::sauvola(input, 101);
+ image2d<bool> bin = scribo::binarization::kim(input, 101);
image2d<bool> ref;
- io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/sauvola.ref.pbm");
+ io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/kim.ref.pbm");
mln_assertion(bin == ref);
}
@@ -57,10 +57,10 @@ int main()
image2d<value::int_u8> input;
io::pgm::load(input, SCRIBO_IMG_DIR "/lena_wodd_heven.pgm");
- image2d<bool> bin = scribo::binarization::sauvola(input, 101);
+ image2d<bool> bin = scribo::binarization::kim(input, 101);
image2d<bool> ref;
- io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/sauvola_wodd_heven.ref.pbm");
+ io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/kim_wodd_heven.ref.pbm");
mln_assertion(bin == ref);
}
@@ -70,10 +70,10 @@ int main()
image2d<value::int_u8> input;
io::pgm::load(input, SCRIBO_IMG_DIR "/lena_weven_hodd.pgm");
- image2d<bool> bin = scribo::binarization::sauvola(input, 101);
+ image2d<bool> bin = scribo::binarization::kim(input, 101);
image2d<bool> ref;
- io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/sauvola_weven_hodd.ref.pbm");
+ io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/kim_weven_hodd.ref.pbm");
mln_assertion(bin == ref);
}
@@ -83,10 +83,10 @@ int main()
image2d<value::int_u8> input;
io::pgm::load(input, SCRIBO_IMG_DIR "/lena_wodd_hodd.pgm");
- image2d<bool> bin = scribo::binarization::sauvola(input, 101);
+ image2d<bool> bin = scribo::binarization::kim(input, 101);
image2d<bool> ref;
- io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/sauvola_wodd_hodd.ref.pbm");
+ io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/kim_wodd_hodd.ref.pbm");
mln_assertion(bin == ref);
}
diff --git a/scribo/tests/binarization/kim.ref.pbm b/scribo/tests/binarization/kim.ref.pbm
new file mode 100644
index 0000000..d792130
Binary files /dev/null and b/scribo/tests/binarization/kim.ref.pbm differ
diff --git a/scribo/tests/binarization/kim_weven_hodd.ref.pbm b/scribo/tests/binarization/kim_weven_hodd.ref.pbm
new file mode 100644
index 0000000..45eab1d
Binary files /dev/null and b/scribo/tests/binarization/kim_weven_hodd.ref.pbm differ
diff --git a/scribo/tests/binarization/kim_wodd_heven.ref.pbm b/scribo/tests/binarization/kim_wodd_heven.ref.pbm
new file mode 100644
index 0000000..1dc805f
Binary files /dev/null and b/scribo/tests/binarization/kim_wodd_heven.ref.pbm differ
diff --git a/scribo/tests/binarization/kim_wodd_hodd.ref.pbm b/scribo/tests/binarization/kim_wodd_hodd.ref.pbm
new file mode 100644
index 0000000..5598763
Binary files /dev/null and b/scribo/tests/binarization/kim_wodd_hodd.ref.pbm differ
--
1.7.2.5
1
0
olena-2.0-96-g00db91c Make integral browsing canvas robust to large windows.
by Guillaume Lazzara 22 Jun '12
by Guillaume Lazzara 22 Jun '12
22 Jun '12
* scribo/binarization/sauvola_ms.hh: remove tests on window size.
* scribo/canvas/integral_browsing.hh: Check window size.
---
scribo/scribo/binarization/sauvola_ms.hh | 28 ----------------------------
scribo/scribo/canvas/integral_browsing.hh | 19 +++++++++++++++++++
2 files changed, 19 insertions(+), 28 deletions(-)
diff --git a/scribo/scribo/binarization/sauvola_ms.hh b/scribo/scribo/binarization/sauvola_ms.hh
index ba58207..5f0f963 100644
--- a/scribo/scribo/binarization/sauvola_ms.hh
+++ b/scribo/scribo/binarization/sauvola_ms.hh
@@ -169,34 +169,6 @@ namespace scribo
w_local_h = w_local,
w_local_w = w_local;
- //std::cout << "scale " << i << " - w = " << w << " - lambda_min = " << lambda_min << " - lambda_max = " << lambda_max << std::endl;
-
- // Make sure the window fits in the image domain.
- if (w_local_w >= static_cast<const unsigned>(integral_sum_sum_2.ncols()))
- {
- w_local_w = std::min(integral_sum_sum_2.ncols(),
- integral_sum_sum_2.nrows()) - integral_sum_sum_2.border();
- w_local_h = w_local_w;
- trace::warning("integral_browsing - Adjusting window width since it"
- " was larger than image width.");
- }
- if (w_local_h >= static_cast<const unsigned>(integral_sum_sum_2.nrows()))
- {
- w_local_h = std::min(integral_sum_sum_2.nrows(),
- integral_sum_sum_2.ncols()) - integral_sum_sum_2.border();
- w_local_w = w_local_h;
- trace::warning("integral_browsing - Adjusting window height since it"
- " was larger than image height.");
- }
-
- if (! (w_local % 2))
- {
- --w_local_w;
- ++w_local_h;
- }
-
- //std::cout << "Scale " << i << " - w_h = " << w_local_h << " - w_w = " << w_local_w << " - w = " << w << std::endl;
-
// 1st pass
scribo::binarization::internal::sauvola_ms_functor< image2d<int_u8> >
f(sub, K, SCRIBO_DEFAULT_SAUVOLA_R, e_2, i, q);
diff --git a/scribo/scribo/canvas/integral_browsing.hh b/scribo/scribo/canvas/integral_browsing.hh
index da13fe7..5328a5a 100644
--- a/scribo/scribo/canvas/integral_browsing.hh
+++ b/scribo/scribo/canvas/integral_browsing.hh
@@ -88,6 +88,25 @@ namespace scribo
// mln_precondition((h/2) < ima.nrows());
// mln_precondition((w/2) < ima.ncols());
+ // Adjust window size to image.
+ if (w > (ima.domain().ncols() - ima.border()))
+ {
+ w = std::min(ima.domain().ncols(), ima.domain().nrows()) - ima.border();
+ if (! (w % 2))
+ --w;
+ trace::warning("integral_browsing - Adjusting window width since it"
+ " was larger than image height.");
+ }
+ if (h > (ima.domain().nrows() - ima.border()))
+ {
+ h = std::min(ima.domain().ncols(), ima.domain().nrows()) - ima.border();
+ if (! (h % 2))
+ --h;
+ trace::warning("integral_browsing - Adjusting window height since it"
+ " was larger than image width.");
+ }
+
+
const int
nrows = ima.nrows(),
ncols = ima.ncols(),
--
1.7.2.5
1
0
---
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
1
0
---
scribo/src/binarization/kim.cc | 102 ++++++++++++----------------------------
1 files changed, 30 insertions(+), 72 deletions(-)
diff --git a/scribo/src/binarization/kim.cc b/scribo/src/binarization/kim.cc
index 4596990..7294a9c 100644
--- a/scribo/src/binarization/kim.cc
+++ b/scribo/src/binarization/kim.cc
@@ -116,6 +116,9 @@ int main(int argc, char *argv[])
image2d<value::rgb8> input_1;
io::magick::load(input_1, options.arg("input.*"));
+ mln::util::timer t;
+ t.start();
+
// Convert to Gray level image.
image2d<value::int_u8>
input_1_gl = data::transform(input_1,
@@ -125,13 +128,18 @@ int main(int argc, char *argv[])
image2d<bool>
output = scribo::binarization::sauvola_ms(input_1_gl, w_1, s, k);
- io::pbm::save(output, "debug_bin.pbm");
+ mln::util::timer lt;
+ lt.start();
// Compute integral image
scribo::util::integral_sum_sum2_functor<value::int_u8,double> f_sum_sum2;
image2d<mln::util::couple<double,double> >
integral_sum_sum_2 = scribo::util::init_integral_image(input_1_gl, 1, f_sum_sum2);
+ lt.stop();
+ std::cout << "integral image - " << lt << std::endl;
+ lt.start();
+
// Find text lines
line_set<image2d<scribo::def::lbl_type> >
lines = scribo::text::extract_lines(output, c8());
@@ -142,6 +150,10 @@ int main(int argc, char *argv[])
const component_set<L>& comp_set = lines.components();
const L& lbl = comp_set.labeled_image();
+ lt.stop();
+ std::cout << "Text line finding - " << lt << std::endl;
+ lt.start();
+
// Compute run-lengths histogram in order to compute character
// thickness for each line.
for_all_lines(i, lines)
@@ -178,14 +190,13 @@ int main(int argc, char *argv[])
}
thickness(lines(i).id()) = thick;
- std::cout << "line " << i << " - thickness = " << thick << " - height = " << lines(i).x_height() << std::endl;
}
- // std::cout << "integral_sum_sum_2.domain() = " << integral_sum_sum_2.domain() << std::endl;
-
- // FIXME: To be removed.
- extension::adjust_duplicate(integral_sum_sum_2, 50);
+ lt.stop();
+ std::cout << "run-lengths histogram - " << lt << std::endl;
+ lt.start();
+ // Compute thresholds for each pixel of each line and binarize again!
for_all_lines(i, lines)
{
if (!lines(i).is_textline())
@@ -193,34 +204,20 @@ int main(int argc, char *argv[])
math::round<double> round;
double
- win_min = round(std::max(thickness(lines(i).id()),2u) / 2.0),
- win_max = round(std::max(lines(i).x_height(),2u) / 2.0),
+ win_min = thickness(lines(i).id()),
+ win_max = lines(i).bbox().height(),
card_min,
card_max;
- if (win_min == 0)
- {
- std::cout << "win_min == 0 - thickness = " << thickness(lines(i).id()) << std::endl;
- abort();
- }
-
- if (win_max == 0)
- {
- std::cout << "win_max == 0 - x_height = " << lines(i).x_height() << std::endl;
- abort();
- }
-
+ mln_assertion(win_min != 0);
+ mln_assertion(win_max != 0);
binarization::internal::sauvola_formula compute_thres;
-
-
- // std::cout << "<<<<<<<<<<<<<< New line" << std::endl;
+ point2d tl, br;
mln_piter(L) p(lines(i).bbox());
for_all(p)
{
- accu::shape::bbox<point2d> accu;
- point2d tl, br;
// Min case
tl.row() = (p.row() - win_min - 1);
@@ -229,9 +226,7 @@ int main(int argc, char *argv[])
br.row() = (p.row() + win_min);
br.col() = (p.col() + win_min);
- accu.take(tl);
- accu.take(br);
- box2d b = accu.to_result();
+ box2d b(tl, br);
b.crop_wrt(integral_sum_sum_2.domain());
point2d tr = b.pmax();
@@ -239,24 +234,7 @@ int main(int argc, char *argv[])
point2d bl = b.pmin();
bl.row() = b.pmax().row();
- {
- accu::shape::bbox<point2d> accu;
- point2d tl, br;
-
- tl.row() = (p.row() - win_min);
- tl.col() = (p.col() - win_min);
-
- br.row() = (p.row() + win_min);
- br.col() = (p.col() + win_min);
-
- accu.take(tl);
- accu.take(br);
- box2d b = accu.to_result();
- b.crop_wrt(input_1_gl.domain());
- card_min = b.nsites();
- }
-
- // std::cout << "p = " << p << " - box = " << b << " - nsites = " << b.nsites() << " - card_min = " << card_min << std::endl;
+ 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();
@@ -273,16 +251,13 @@ int main(int argc, char *argv[])
double T_min = compute_thres(mean, stddev);
// Max case
- accu.init();
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);
- accu.take(tl);
- accu.take(br);
- b = accu.to_result();
+ b = box2d(tl, br);
b.crop_wrt(integral_sum_sum_2.domain());
tr = b.pmax();
@@ -290,24 +265,7 @@ int main(int argc, char *argv[])
bl = b.pmin();
bl.row() = b.pmax().row();
- {
- accu::shape::bbox<point2d> accu;
- point2d tl, br;
-
- tl.row() = (p.row() - win_max);
- tl.col() = (p.col() - win_max);
-
- br.row() = (p.row() + win_max);
- br.col() = (p.col() + win_max);
-
- accu.take(tl);
- accu.take(br);
- box2d b = accu.to_result();
- b.crop_wrt(input_1_gl.domain());
- card_max = b.nsites();
-
- // std::cout << "card_max = " << card_max << " - b = " << b << std::endl;
- }
+ 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();
@@ -328,7 +286,6 @@ int main(int argc, char *argv[])
double teta = 0.3;
double T = teta * T_max + (1 - teta) * T_min;
-// std::cout << "bbox = " << lines(i).bbox() << " - box = " << b << " - T_max = " << T_max << " - T_min = " << T_min << " - T = " << T << std::endl;
mln_assertion(T_min <= 255);
mln_assertion(T_max <= 255);
mln_assertion(T <= 255);
@@ -338,10 +295,11 @@ int main(int argc, char *argv[])
}
+ lt.stop();
+ std::cout << "Last binarization - " << lt << std::endl;
- image2d<value::rgb8> bbox = scribo::debug::bboxes_enlarged_image(output, lines);
- io::ppm::save(bbox, "debug_bbox.ppm");
-
+ t.stop();
+ std::cout << "Total time = " << t << std::endl;
io::pbm::save(output, options.arg("output.pbm"));
}
--
1.7.2.5
1
0
---
scribo/src/binarization/kim.cc | 347 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 347 insertions(+), 0 deletions(-)
create mode 100644 scribo/src/binarization/kim.cc
diff --git a/scribo/src/binarization/kim.cc b/scribo/src/binarization/kim.cc
new file mode 100644
index 0000000..4596990
--- /dev/null
+++ b/scribo/src/binarization/kim.cc
@@ -0,0 +1,347 @@
+// Copyright (C) 2012 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.
+
+/// \file
+
+#include <cmath>
+#include <mln/core/image/image2d.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/io/magick/load.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/data/transform.hh>
+#include <mln/fun/v2v/rgb_to_luma.hh>
+
+#include <scribo/binarization/sauvola_ms.hh>
+#include <scribo/debug/option_parser.hh>
+#include <scribo/debug/logger.hh>
+
+#include <scribo/util/integral_sum_sum2_functor.hh>
+
+#include <scribo/text/extract_lines.hh>
+#include <scribo/debug/bboxes_enlarged_image.hh>
+#include <algorithm>
+
+
+static const scribo::debug::arg_data arg_desc[] =
+{
+ { "input.*", "An image." },
+ { "output.pbm", "A binary image." },
+ {0, 0}
+};
+
+
+// --enable/disable-<name>
+static const scribo::debug::toggle_data toggle_desc[] =
+{
+ // name, description, default value
+ {0, 0, false}
+};
+
+
+// --<name> <args>
+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" },
+ { "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 },
+ { "win-size", "Window size at scale 1", "<size>", 0, 1, "101" },
+ {0, 0, 0, 0, 0, 0}
+};
+
+
+
+
+
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+ using namespace scribo;
+
+ scribo::debug::option_parser options(arg_desc, toggle_desc, opt_desc);
+
+ if (!options.parse(argc, argv))
+ return 1;
+
+ // Enable debug output.
+ if (options.is_set("debug-prefix"))
+ {
+ scribo::debug::logger().set_filename_prefix(options.opt_value("debug-prefix").c_str());
+ scribo::debug::logger().set_level(scribo::debug::All);
+ }
+
+ Magick::InitializeMagick(*argv);
+
+ trace::entering("main");
+
+
+ bool verbose = options.is_set("verbose");
+ // Window size
+ unsigned w_1 = atoi(options.opt_value("win-size").c_str());
+ // First subsampling scale.
+ unsigned s = atoi(options.opt_value("s").c_str());
+ double k = atof(options.opt_value("k").c_str());
+
+ if (verbose)
+ std::cout << "Using w_1=" << w_1 << " - s=" << s
+ << " - k=" << k << std::endl;
+
+ // Load
+ image2d<value::rgb8> input_1;
+ io::magick::load(input_1, options.arg("input.*"));
+
+ // Convert to Gray level image.
+ image2d<value::int_u8>
+ input_1_gl = data::transform(input_1,
+ mln::fun::v2v::rgb_to_luma<value::int_u8>());
+
+ // 1st simple binarization
+ image2d<bool>
+ output = scribo::binarization::sauvola_ms(input_1_gl, w_1, s, k);
+
+ io::pbm::save(output, "debug_bin.pbm");
+
+ // Compute integral image
+ scribo::util::integral_sum_sum2_functor<value::int_u8,double> f_sum_sum2;
+ image2d<mln::util::couple<double,double> >
+ integral_sum_sum_2 = scribo::util::init_integral_image(input_1_gl, 1, f_sum_sum2);
+
+ // Find text lines
+ line_set<image2d<scribo::def::lbl_type> >
+ lines = scribo::text::extract_lines(output, c8());
+
+ typedef scribo::def::lbl_type V;
+ typedef image2d<V> L;
+ mln::util::array<unsigned> thickness(lines.nelements() + 1, 0);
+ const component_set<L>& comp_set = lines.components();
+ const L& lbl = comp_set.labeled_image();
+
+ // Compute run-lengths histogram in order to compute character
+ // thickness for each line.
+ for_all_lines(i, lines)
+ {
+ if (!lines(i).is_textline())
+ continue;
+
+ std::map<unsigned, unsigned> histo;
+ int count = 0;
+ for (int l = lines(i).bbox().pmin().row(); l <= lines(i).bbox().pmax().row(); ++l)
+ {
+ const V* end_ptr = &lbl.at_(l, lines(i).bbox().pmax().col() + 1);
+ for (const V* run_ptr = &lbl.at_(l, lines(i).bbox().pmin().col()); run_ptr != end_ptr; ++run_ptr)
+ if (*run_ptr)
+ ++count;
+ else
+ if (count)
+ {
+ if (histo.find(count) != histo.end())
+ histo[count]++;
+ else
+ histo.insert(std::make_pair(count, 1));
+ count = 0;
+ }
+ }
+
+ unsigned max = 0;
+ unsigned thick = 0;
+ for (std::map<unsigned, unsigned>::const_iterator it = histo.begin(); it != histo.end(); ++it)
+ if (it->second > max)
+ {
+ max = it->second;
+ thick = it->first;
+ }
+
+ thickness(lines(i).id()) = thick;
+ std::cout << "line " << i << " - thickness = " << thick << " - height = " << lines(i).x_height() << std::endl;
+ }
+
+ // std::cout << "integral_sum_sum_2.domain() = " << integral_sum_sum_2.domain() << std::endl;
+
+ // FIXME: To be removed.
+ extension::adjust_duplicate(integral_sum_sum_2, 50);
+
+ for_all_lines(i, lines)
+ {
+ if (!lines(i).is_textline())
+ continue;
+
+ math::round<double> round;
+ double
+ win_min = round(std::max(thickness(lines(i).id()),2u) / 2.0),
+ win_max = round(std::max(lines(i).x_height(),2u) / 2.0),
+ card_min,
+ card_max;
+
+ if (win_min == 0)
+ {
+ std::cout << "win_min == 0 - thickness = " << thickness(lines(i).id()) << std::endl;
+ abort();
+ }
+
+ if (win_max == 0)
+ {
+ std::cout << "win_max == 0 - x_height = " << lines(i).x_height() << std::endl;
+ abort();
+ }
+
+
+ binarization::internal::sauvola_formula compute_thres;
+
+
+ // std::cout << "<<<<<<<<<<<<<< New line" << std::endl;
+
+ mln_piter(L) p(lines(i).bbox());
+ for_all(p)
+ {
+ accu::shape::bbox<point2d> accu;
+ point2d tl, br;
+
+ // 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);
+
+ accu.take(tl);
+ accu.take(br);
+ box2d b = accu.to_result();
+ 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();
+
+ {
+ accu::shape::bbox<point2d> accu;
+ point2d tl, br;
+
+ tl.row() = (p.row() - win_min);
+ tl.col() = (p.col() - win_min);
+
+ br.row() = (p.row() + win_min);
+ br.col() = (p.col() + win_min);
+
+ accu.take(tl);
+ accu.take(br);
+ box2d b = accu.to_result();
+ b.crop_wrt(input_1_gl.domain());
+ card_min = b.nsites();
+ }
+
+ // std::cout << "p = " << p << " - box = " << b << " - nsites = " << b.nsites() << " - card_min = " << card_min << std::endl;
+
+ 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
+ accu.init();
+ 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);
+
+ accu.take(tl);
+ accu.take(br);
+ b = accu.to_result();
+ b.crop_wrt(integral_sum_sum_2.domain());
+
+ tr = b.pmax();
+ tr.row() = b.pmin().row();
+ bl = b.pmin();
+ bl.row() = b.pmax().row();
+
+ {
+ accu::shape::bbox<point2d> accu;
+ point2d tl, br;
+
+ tl.row() = (p.row() - win_max);
+ tl.col() = (p.col() - win_max);
+
+ br.row() = (p.row() + win_max);
+ br.col() = (p.col() + win_max);
+
+ accu.take(tl);
+ accu.take(br);
+ box2d b = accu.to_result();
+ b.crop_wrt(input_1_gl.domain());
+ card_max = b.nsites();
+
+ // std::cout << "card_max = " << card_max << " - b = " << b << std::endl;
+ }
+
+ 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
+
+ double teta = 0.3;
+ double T = teta * T_max + (1 - teta) * T_min;
+
+// std::cout << "bbox = " << lines(i).bbox() << " - box = " << b << " - T_max = " << T_max << " - T_min = " << T_min << " - T = " << T << std::endl;
+ mln_assertion(T_min <= 255);
+ mln_assertion(T_max <= 255);
+ mln_assertion(T <= 255);
+
+ output(p) = input_1_gl(p) <= T;
+ }
+
+ }
+
+
+ image2d<value::rgb8> bbox = scribo::debug::bboxes_enlarged_image(output, lines);
+ io::ppm::save(bbox, "debug_bbox.ppm");
+
+
+ io::pbm::save(output, options.arg("output.pbm"));
+}
--
1.7.2.5
1
0
---
.../binarization/internal/sauvola_ms_functor.hh | 3 +--
scribo/scribo/binarization/sauvola_ms.hh | 7 ++++---
scribo/src/binarization/otsu.cc | 10 ++++++++++
scribo/src/binarization/sauvola.cc | 10 ++++++++++
4 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/scribo/scribo/binarization/internal/sauvola_ms_functor.hh b/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
index cbace88..3411d1b 100644
--- a/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
+++ b/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Copyright (C) 2009, 2010, 2011, 2012 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
@@ -205,7 +205,6 @@ 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 a740ec0..96064e9 100644
--- a/scribo/scribo/binarization/sauvola_ms.hh
+++ b/scribo/scribo/binarization/sauvola_ms.hh
@@ -159,7 +159,7 @@ namespace scribo
w_local_h = w_local,
w_local_w = w_local;
- std::cout << "scale " << i << " - w = " << w << " - lambda_min = " << lambda_min << " - lambda_max = " << lambda_max << std::endl;
+ //std::cout << "scale " << i << " - w = " << w << " - lambda_min = " << lambda_min << " - lambda_max = " << lambda_max << std::endl;
// Make sure the window fits in the image domain.
if (w_local_w >= static_cast<const unsigned>(integral_sum_sum_2.ncols()))
@@ -185,7 +185,7 @@ namespace scribo
++w_local_h;
}
- std::cout << "Scale " << i << " - w_h = " << w_local_h << " - w_w = " << w_local_w << " - w = " << w << std::endl;
+ //std::cout << "Scale " << i << " - w_h = " << w_local_h << " - w_w = " << w_local_w << " - w = " << w << std::endl;
// 1st pass
scribo::binarization::internal::sauvola_ms_functor< image2d<int_u8> >
@@ -196,7 +196,7 @@ namespace scribo
s,
f);
- std::cout << " i = " << i << " - ratio = " << ratio << std::endl;
+ //std::cout << " i = " << i << " - ratio = " << ratio << std::endl;
// 2nd pass
{
@@ -807,6 +807,7 @@ namespace scribo
trace::entering("scribo::binarization::sauvola_ms");
const I& input_1 = exact(input_1_);
+ typedef mln_value(I) V;
mlc_is_a(mln_value(I), value::Scalar)::check();
mln_precondition(input_1.is_valid());
diff --git a/scribo/src/binarization/otsu.cc b/scribo/src/binarization/otsu.cc
index ebd5da4..eb60973 100644
--- a/scribo/src/binarization/otsu.cc
+++ b/scribo/src/binarization/otsu.cc
@@ -28,7 +28,9 @@
#include <mln/io/magick/load.hh>
#include <mln/io/pbm/save.hh>
#include <mln/data/transform.hh>
+#include <mln/arith/revert.hh>
#include <mln/fun/v2v/rgb_to_luma.hh>
+#include <mln/logical/not.hh>
#include <scribo/binarization/otsu.hh>
#include <scribo/debug/option_parser.hh>
@@ -46,6 +48,8 @@ static const scribo::debug::arg_data arg_desc[] =
static const scribo::debug::toggle_data toggle_desc[] =
{
// name, description, default value
+ { "negate-input", "Negate input image before binarizing.", false },
+ { "negate-output", "Negate output image before binarizing.", false },
{0, 0, false}
};
@@ -92,8 +96,14 @@ 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>());
+ if (options.is_enabled("negate-input"))
+ input_1_gl = arith::revert(input_1_gl);
+
image2d<bool> out = scribo::binarization::otsu(input_1_gl);
+ if (options.is_enabled("negate-output"))
+ logical::not_inplace(out);
+
io::pbm::save(out, options.arg("output.pbm"));
trace::exiting("main");
diff --git a/scribo/src/binarization/sauvola.cc b/scribo/src/binarization/sauvola.cc
index 518937b..6ea224c 100644
--- a/scribo/src/binarization/sauvola.cc
+++ b/scribo/src/binarization/sauvola.cc
@@ -99,8 +99,18 @@ 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>());
+ mln::util::timer t;
+ t.start();
+
+ // Binarize
image2d<bool> out = scribo::binarization::sauvola(input_1_gl, w, k);
+ if (verbose)
+ {
+ t.stop();
+ std::cout << "binarized in " << t << "s" << std::endl;
+ }
+
io::pbm::save(out, options.arg("output.pbm"));
trace::exiting("main");
--
1.7.2.5
1
0
---
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 +++-
8 files changed, 161 insertions(+), 127 deletions(-)
delete mode 100644 scribo/sauvola_fast.cc
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
1
0
* scribo/binarization/internal/wolf_formula.hh,
* scribo/binarization/internal/wolf_functor.hh,
* scribo/binarization/wolf.hh,
* scribo/util/integral_sum_sum2_global_min_functor.hh,
* src/binarization/wolf.cc,
* tests/binarization/wolf.cc,
* tests/binarization/wolf.ref.pbm,
* tests/binarization/wolf_weven_hodd.ref.pbm,
* tests/binarization/wolf_wodd_heven.ref.pbm,
* tests/binarization/wolf_wodd_hodd.ref.pbm: New.
* src/binarization/Makefile.am,
* tests/binarization/Makefile.am: Add new target.
---
.../scribo/binarization/internal/wolf_formula.hh | 95 ++++++++++
.../scribo/binarization/internal/wolf_functor.hh | 176 +++++++++++++++++
scribo/scribo/binarization/wolf.hh | 197 ++++++++++++++++++++
.../util/integral_sum_sum2_global_min_functor.hh | 156 ++++++++++++++++
scribo/src/binarization/Makefile.am | 9 +-
scribo/src/binarization/wolf.cc | 107 +++++++++++
scribo/tests/binarization/Makefile.am | 19 ++-
scribo/tests/binarization/wolf.cc | 93 +++++++++
scribo/tests/binarization/wolf.ref.pbm | Bin 0 -> 32884 bytes
scribo/tests/binarization/wolf_weven_hodd.ref.pbm | Bin 0 -> 32820 bytes
scribo/tests/binarization/wolf_wodd_heven.ref.pbm | Bin 0 -> 32884 bytes
scribo/tests/binarization/wolf_wodd_hodd.ref.pbm | Bin 0 -> 32820 bytes
12 files changed, 849 insertions(+), 3 deletions(-)
create mode 100644 scribo/scribo/binarization/internal/wolf_formula.hh
create mode 100644 scribo/scribo/binarization/internal/wolf_functor.hh
create mode 100644 scribo/scribo/binarization/wolf.hh
create mode 100644 scribo/scribo/util/integral_sum_sum2_global_min_functor.hh
create mode 100644 scribo/src/binarization/wolf.cc
create mode 100644 scribo/tests/binarization/wolf.cc
create mode 100644 scribo/tests/binarization/wolf.ref.pbm
create mode 100644 scribo/tests/binarization/wolf_weven_hodd.ref.pbm
create mode 100644 scribo/tests/binarization/wolf_wodd_heven.ref.pbm
create mode 100644 scribo/tests/binarization/wolf_wodd_hodd.ref.pbm
diff --git a/scribo/scribo/binarization/internal/wolf_formula.hh b/scribo/scribo/binarization/internal/wolf_formula.hh
new file mode 100644
index 0000000..a3084a7
--- /dev/null
+++ b/scribo/scribo/binarization/internal/wolf_formula.hh
@@ -0,0 +1,95 @@
+// Copyright (C) 2012 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_INTERNAL_WOLF_FORMULA_HH
+# define SCRIBO_BINARIZATION_INTERNAL_WOLF_FORMULA_HH
+
+
+/// \file
+///
+/// \brief Routines computing a threshold using Wolf's binarization
+/// formula.
+
+
+// Setup default Wolf's formula parameters values.
+// These macros may be used in other variant of Wolf's algorithms.
+//
+// Values are set according to the following reference: <FIXME>
+
+# define SCRIBO_DEFAULT_WOLF_K 0.34
+
+
+#include <mln/core/alias/point2d.hh>
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ namespace internal
+ {
+
+ using namespace mln;
+
+ template <typename V>
+ struct wolf_formula
+ {
+
+ /*! \brief Compute a threshold using Wolf's formula.
+
+ \todo doc!
+
+ \return A threshold.
+ */
+ double operator()(const double m_x_y, const double s_x_y,
+ const double K, const double global_max_stddev,
+ const V& global_min) const;
+
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ template <typename V>
+ inline
+ double
+ wolf_formula<V>::operator()(const double m_x_y, const double s_x_y,
+ const double K, const double global_max_stddev,
+ const V& global_min) const
+ {
+ return m_x_y - K * (1 - s_x_y / global_max_stddev) * (m_x_y - global_min);
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization::internal
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_BINARIZATION_INTERNAL_WOLF_FORMULA_HH
diff --git a/scribo/scribo/binarization/internal/wolf_functor.hh b/scribo/scribo/binarization/internal/wolf_functor.hh
new file mode 100644
index 0000000..d394c21
--- /dev/null
+++ b/scribo/scribo/binarization/internal/wolf_functor.hh
@@ -0,0 +1,176 @@
+// Copyright (C) 2012 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_INTERNAL_WOLF_FUNCTOR_HH
+# define SCRIBO_BINARIZATION_INTERNAL_WOLF_FUNCTOR_HH
+
+/// \file
+///
+///
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/extension/fill.hh>
+
+# include <scribo/binarization/internal/wolf_formula.hh>
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+# include <scribo/binarization/internal/local_threshold_debug.hh>
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ namespace internal
+ {
+
+ using namespace mln;
+
+
+ template <typename I>
+ struct wolf_functor
+ {
+ typedef mln_value(I) V;
+
+ wolf_functor(const Image<I>& input, double K,
+ const mln_value(I)& global_min,
+ double global_max_stddev);
+
+ // Run every 4 pixels.
+ void exec(double mean, double stddev);
+
+ void end_of_row(int);
+
+ void finalize();
+
+
+ const I input;
+ mln_ch_value(I,bool) output;
+
+ const mln_value(I)* pi;
+ bool* po;
+
+ double K_;
+
+ V global_min_;
+ double global_max_stddev_;
+
+ scribo::binarization::internal::wolf_formula<V> formula_;
+
+ int step_;
+ unsigned next_line3;
+ unsigned offset1;
+ unsigned offset2;
+ };
+
+#ifndef MLN_INCLUDE_ONLY
+
+ template <typename I>
+ wolf_functor<I>::wolf_functor(const Image<I>& input_,
+ double K,
+ const mln_value(I)& global_min,
+ double global_max_stddev)
+ : input(exact(input_)),
+ pi(&input(input.domain().pmin())),
+ K_(K),
+ global_min_(global_min),
+ global_max_stddev_(global_max_stddev)
+ {
+ step_ = 3;
+
+ // 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 3, some sites in the border may not be
+ // processed and we must skip them.
+ int more_offset = - (3 - input.ncols() % 3);
+ if (more_offset == - 3)
+ more_offset = 0; // No offset needed.
+
+ next_line3 = input.delta_index(dpoint2d(+2,0))
+ + 2 * input.border() + more_offset;
+
+ offset1 = input.delta_index(dpoint2d(+1,0));
+ offset2 = input.delta_index(dpoint2d(+2,0));
+
+ initialize(output, input);
+ po = &output(output.domain().pmin());
+ }
+
+ template <typename I>
+ void
+ wolf_functor<I>::exec(double mean, double stddev)
+ {
+ double th = formula_(mean, stddev, K_,
+ global_max_stddev_, global_min_);
+
+ for (int i = 0; i < step_; ++i, ++po, ++pi)
+ {
+ *po = (*pi <= th);
+ *(po + offset1) = (*(pi + offset1) <= th);
+ *(po + offset2) = (*(pi + offset2) <= th);
+ }
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ // Store local mean
+ unsigned index = pi - input.buffer();
+
+ debug_mean.element(index) = mean * mean_debug_factor;
+ debug_stddev.element(index) = stddev * stddev_debug_factor;
+ debug_threshold.element(index) = th;
+
+ double alpha = K_ * (1 - stddev / R_);
+ debug_alpham.element(index) = alpha * mean * alpham_debug_factor;
+ debug_alphacond.element(index) = (stddev < (alpha * mean / 2.));
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+ }
+
+ template <typename I>
+ void
+ wolf_functor<I>::end_of_row(int)
+ {
+ po += next_line3;
+ pi += next_line3;
+ }
+
+ template <typename I>
+ void
+ wolf_functor<I>::finalize()
+ {
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization::internal
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+#endif // SCRIBO_BINARIZATION_INTERNAL_WOLF_FUNCTOR_HH
diff --git a/scribo/scribo/binarization/wolf.hh b/scribo/scribo/binarization/wolf.hh
new file mode 100644
index 0000000..25b4531
--- /dev/null
+++ b/scribo/scribo/binarization/wolf.hh
@@ -0,0 +1,197 @@
+// Copyright (C) 2012 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_WOLF_HH
+# define SCRIBO_BINARIZATION_WOLF_HH
+
+/// \file
+///
+///
+
+# include <mln/core/concept/image.hh>
+# include <scribo/binarization/internal/wolf_functor.hh>
+# include <scribo/binarization/internal/local_threshold_core.hh>
+# include <scribo/util/integral_sum_sum2_global_min_functor.hh>
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ using namespace mln;
+
+
+ /*! \brief Convert an image into a binary image.
+
+ \input[in] input An image.
+ \input[in] window_size The window size.
+ \input[in] K Wolf's formulae constant.
+
+ \return A binary image.
+
+ This implementation is based on article "Text Localization,
+ Enhancement and Binarization in Multimedia Documents", Christian
+ Wolf, Jean-Michel Jolion, Françoise Chassaing, ICPR 2002.
+
+ */
+ template <typename I>
+ mln_ch_value(I, bool)
+ wolf(const Image<I>& input, unsigned window_size, double K);
+
+
+
+ /*! \brief Convert an image into a binary image.
+
+ Wolf's formulae constant K is set to 0.34.
+
+ \input[in] input An image.
+ \input[in] window_size The window size.
+
+ \return A binary image.
+
+ */
+ template <typename I>
+ mln_ch_value(I, bool)
+ wolf(const Image<I>& input, unsigned window_size);
+
+
+ /// \overload
+ /// The window size is set to 11.
+ //
+ template <typename I>
+ mln_ch_value(I, bool)
+ wolf(const Image<I>& input);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+
+ template <typename I>
+ struct global_max_stddev
+ {
+ global_max_stddev()
+ : max_stddev(0)
+ {
+ }
+
+ // Run every 4 pixels.
+ void exec(double mean, double stddev)
+ {
+ (void) mean;
+ if (max_stddev < stddev)
+ max_stddev = stddev;
+ }
+
+ void end_of_row(int)
+ {
+ }
+
+ void finalize()
+ {
+ }
+
+ double max_stddev;
+ };
+
+ } // end of namespace scribo::binarization::internal
+
+
+ // Facades
+
+ template <typename I>
+ mln_ch_value(I, bool)
+ wolf(const Image<I>& input, unsigned window_size, double K)
+ {
+ trace::entering("scribo::binarization::wolf");
+
+ mln_precondition(exact(input).is_valid());
+
+
+ // Make sure the image sizes are a multiple of 3 in each
+ // dimension. (browsing while binarizing relies on that
+ // property).
+ 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_global_min_functor<value::int_u8, double> fi;
+ image2d<mln::util::couple<double,double> >
+ integral = scribo::util::init_integral_image(input, 3, fi,
+ sub_domains[2].first(),
+ sub_domains[2].second());
+
+ window_size /= 3;
+ if (window_size % 2)
+ window_size += 2;
+ else
+ window_size += 1;
+
+
+ // Compute max(stddev) of all windows.
+ internal::global_max_stddev<I> f_max_stddev;
+ scribo::canvas::integral_browsing(integral, 1, window_size,
+ window_size, 3, f_max_stddev);
+
+ // Binarize !
+ internal::wolf_functor<I>
+ f(input, K, fi.global_min(), f_max_stddev.max_stddev);
+ scribo::canvas::integral_browsing(integral, 1, window_size,
+ window_size, 3, f);
+
+ trace::exiting("scribo::binarization::wolf");
+ return f.output;
+ }
+
+
+ template <typename I>
+ mln_ch_value(I, bool)
+ wolf(const Image<I>& input, unsigned window_size)
+ {
+ return wolf(input, window_size, SCRIBO_DEFAULT_WOLF_K);
+ }
+
+
+ template <typename I>
+ mln_ch_value(I, bool)
+ wolf(const Image<I>& input)
+ {
+ return wolf(input, 11);
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+
+#endif // ! SCRIBO_BINARIZATION_WOLF_HH
diff --git a/scribo/scribo/util/integral_sum_sum2_global_min_functor.hh b/scribo/scribo/util/integral_sum_sum2_global_min_functor.hh
new file mode 100644
index 0000000..20a61c0
--- /dev/null
+++ b/scribo/scribo/util/integral_sum_sum2_global_min_functor.hh
@@ -0,0 +1,156 @@
+// Copyright (C) 2012 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_UTIL_INTEGRAL_SUM_SUM2_GLOBAL_MIN_FUNCTOR_HH
+# define SCRIBO_UTIL_INTEGRAL_SUM_SUM2_GLOBAL_MIN_FUNCTOR_HH
+
+/// \file
+///
+///
+
+# include <mln/util/couple.hh>
+
+namespace scribo
+{
+
+ namespace util
+ {
+
+ template <typename V, typename S = mln_sum(V)>
+ class integral_sum_sum2_global_min_functor
+ {
+ public:
+ typedef mln::util::couple<S, S> result;
+
+ void begin_of_first_row();
+ void begin_of_row();
+ void end_of_row();
+
+ void begin_of_col();
+ void end_of_col();
+
+
+ void take(const V& v);
+
+ result to_result_first_row() const;
+ result to_result(const result& up_result) const;
+
+ const V& global_min() const;
+
+ private:
+ S h_sum_;
+ S h_sum_2_;
+
+ V global_min_;
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_global_min_functor<V,S>::begin_of_first_row()
+ {
+ h_sum_ = 0;
+ h_sum_2_ = 0;
+ global_min_ = 0;
+ }
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_global_min_functor<V,S>::begin_of_row()
+ {
+ h_sum_ = 0;
+ h_sum_2_ = 0;
+ }
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_global_min_functor<V,S>::take(const V& v)
+ {
+ if (global_min_ > v)
+ global_min_ = v;
+
+ h_sum_ += v;
+ h_sum_2_ += v * v;
+ }
+
+ template <typename V, typename S>
+ inline
+ typename integral_sum_sum2_global_min_functor<V,S>::result
+ integral_sum_sum2_global_min_functor<V,S>::to_result_first_row() const
+ {
+ return result(h_sum_, h_sum_2_);
+ }
+
+ template <typename V, typename S>
+ inline
+ typename integral_sum_sum2_global_min_functor<V,S>::result
+ integral_sum_sum2_global_min_functor<V,S>::to_result(const result& up_result) const
+ {
+ return result(h_sum_ + up_result.first(),
+ h_sum_2_ + up_result.second());
+ }
+
+ template <typename V, typename S>
+ inline
+ const V&
+ integral_sum_sum2_global_min_functor<V,S>::global_min() const
+ {
+ return global_min_;
+ }
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_global_min_functor<V,S>::begin_of_col()
+ {
+ }
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_global_min_functor<V,S>::end_of_col()
+ {
+ }
+
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_global_min_functor<V,S>::end_of_row()
+ {
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::util
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_UTIL_INTEGRAL_SUM_SUM2_GLOBAL_MIN_FUNCTOR_HH
diff --git a/scribo/src/binarization/Makefile.am b/scribo/src/binarization/Makefile.am
index a0a4378..68b83dc 100644
--- a/scribo/src/binarization/Makefile.am
+++ b/scribo/src/binarization/Makefile.am
@@ -35,7 +35,8 @@ if HAVE_MAGICKXX
sauvola \
sauvola_ms \
sauvola_ms_fg \
- sauvola_ms_split
+ sauvola_ms_split \
+ wolf
global_threshold_SOURCES = global_threshold.cc
@@ -70,6 +71,12 @@ if HAVE_MAGICKXX
sauvola_LDFLAGS = $(AM_LDFLAGS) \
$(MAGICKXX_LDFLAGS)
+ wolf_SOURCES = wolf.cc
+ wolf_CPPFLAGS = $(AM_CPPFLAGS) \
+ $(MAGICKXX_CPPFLAGS)
+ wolf_LDFLAGS = $(AM_LDFLAGS) \
+ $(MAGICKXX_LDFLAGS)
+
sauvola_debug_SOURCES = sauvola_debug.cc
sauvola_debug_CPPFLAGS = $(AM_CPPFLAGS) \
-DSCRIBO_LOCAL_THRESHOLD_DEBUG \
diff --git a/scribo/src/binarization/wolf.cc b/scribo/src/binarization/wolf.cc
new file mode 100644
index 0000000..c481e09
--- /dev/null
+++ b/scribo/src/binarization/wolf.cc
@@ -0,0 +1,107 @@
+// Copyright (C) 2009, 2010, 2011 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/value/int_u8.hh>
+#include <mln/io/magick/load.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/data/transform.hh>
+#include <mln/fun/v2v/rgb_to_luma.hh>
+
+#include <scribo/binarization/wolf.hh>
+#include <scribo/debug/option_parser.hh>
+#include <scribo/debug/logger.hh>
+
+static const scribo::debug::arg_data arg_desc[] =
+{
+ { "input.*", "An image." },
+ { "output.pbm", "A binary image." },
+ {0, 0}
+};
+
+
+// --enable/disable-<name>
+static const scribo::debug::toggle_data toggle_desc[] =
+{
+ // name, description, default value
+ {0, 0, false}
+};
+
+
+// --<name> <args>
+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", "Wolf's formulae parameter", "<value>", 0, 1, "0.34" },
+ { "verbose", "Enable verbose mode", 0, 0, 0, 0 },
+ { "win-size", "Window size", "<size>", 0, 1, "101" },
+ {0, 0, 0, 0, 0, 0}
+};
+
+
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+
+ scribo::debug::option_parser options(arg_desc, toggle_desc, opt_desc);
+
+ if (!options.parse(argc, argv))
+ return 1;
+
+ // Enable debug output.
+ if (options.is_set("debug-prefix"))
+ {
+ scribo::debug::logger().set_filename_prefix(options.opt_value("debug-prefix").c_str());
+ scribo::debug::logger().set_level(scribo::debug::All);
+ }
+
+ Magick::InitializeMagick(*argv);
+
+ trace::entering("main");
+
+ bool verbose = options.is_set("verbose");
+ unsigned w = atoi(options.opt_value("win-size").c_str());
+ double k = atof(options.opt_value("k").c_str());
+
+ if (verbose)
+ std::cout << "Using w=" << w << " and k=" << k << std::endl;
+
+ image2d<value::rgb8> input;
+ io::magick::load(input, options.arg("input.*"));
+
+ // Convert to Gray level image.
+ image2d<value::int_u8>
+ input_1_gl = data::transform(input, mln::fun::v2v::rgb_to_luma<value::int_u8>());
+
+ image2d<bool> out = scribo::binarization::wolf(input_1_gl, w, k);
+
+ io::pbm::save(out, options.arg("output.pbm"));
+
+ trace::exiting("main");
+}
diff --git a/scribo/tests/binarization/Makefile.am b/scribo/tests/binarization/Makefile.am
index a2962bb..bac5a24 100644
--- a/scribo/tests/binarization/Makefile.am
+++ b/scribo/tests/binarization/Makefile.am
@@ -22,9 +22,22 @@ include $(top_srcdir)/scribo/tests/tests.mk
EXTRA_DIST = \
niblack.res.pbm \
+ niblack_wodd_heven.ref.pbm \
+ niblack_weven_hodd.ref.pbm \
+ niblack_wodd_hodd.ref.pbm \
sauvola_ms.ref.pbm \
+ sauvola_ms_wodd_heven.ref.pbm \
+ sauvola_ms_weven_hodd.ref.pbm \
+ sauvola_ms_wodd_hodd.ref.pbm \
sauvola.ref.pbm \
- otsu.ref.pbm
+ sauvola_wodd_heven.ref.pbm \
+ sauvola_weven_hodd.ref.pbm \
+ sauvola_wodd_hodd.ref.pbm \
+ otsu.ref.pbm \
+ wolf.ref.pbm \
+ wolf_wodd_heven.ref.pbm \
+ wolf_weven_hodd.ref.pbm \
+ wolf_wodd_hodd.ref.pbm
check_PROGRAMS = \
global_threshold \
@@ -32,7 +45,8 @@ check_PROGRAMS = \
niblack \
otsu \
sauvola \
- sauvola_ms
+ sauvola_ms \
+ wolf
global_threshold_SOURCES = global_threshold.cc
@@ -41,6 +55,7 @@ niblack_SOURCES = niblack.cc
otsu_SOURCES = otsu.cc
sauvola_SOURCES = sauvola.cc
sauvola_ms_SOURCES = sauvola_ms.cc
+wolf_SOURCES = wolf.cc
TESTS = $(check_PROGRAMS)
diff --git a/scribo/tests/binarization/wolf.cc b/scribo/tests/binarization/wolf.cc
new file mode 100644
index 0000000..27d7cd2
--- /dev/null
+++ b/scribo/tests/binarization/wolf.cc
@@ -0,0 +1,93 @@
+// Copyright (C) 2012 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.
+
+/// \file
+
+#include <mln/core/image/image2d.hh>
+#include <mln/data/compare.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pbm/load.hh>
+
+#include <scribo/binarization/wolf.hh>
+
+#include "tests/data.hh"
+
+int main()
+{
+ using namespace mln;
+
+ // even height and width
+ {
+ image2d<value::int_u8> input;
+ io::pgm::load(input, MILENA_IMG_DIR "/lena.pgm");
+
+ image2d<bool> bin = scribo::binarization::wolf(input, 101);
+
+ image2d<bool> ref;
+ io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/wolf.ref.pbm");
+
+ mln_assertion(bin == ref);
+ }
+
+ // even height and odd width
+ {
+ image2d<value::int_u8> input;
+ io::pgm::load(input, SCRIBO_IMG_DIR "/lena_wodd_heven.pgm");
+
+ image2d<bool> bin = scribo::binarization::wolf(input, 101);
+
+ image2d<bool> ref;
+ io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/wolf_wodd_heven.ref.pbm");
+
+ mln_assertion(bin == ref);
+ }
+
+ // odd height and even width
+ {
+ image2d<value::int_u8> input;
+ io::pgm::load(input, SCRIBO_IMG_DIR "/lena_weven_hodd.pgm");
+
+ image2d<bool> bin = scribo::binarization::wolf(input, 101);
+
+ image2d<bool> ref;
+ io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/wolf_weven_hodd.ref.pbm");
+
+ mln_assertion(bin == ref);
+ }
+
+ // odd height and width
+ {
+ image2d<value::int_u8> input;
+ io::pgm::load(input, SCRIBO_IMG_DIR "/lena_wodd_hodd.pgm");
+
+ image2d<bool> bin = scribo::binarization::wolf(input, 101);
+
+ image2d<bool> ref;
+ io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/wolf_wodd_hodd.ref.pbm");
+
+ mln_assertion(bin == ref);
+ }
+}
diff --git a/scribo/tests/binarization/wolf.ref.pbm b/scribo/tests/binarization/wolf.ref.pbm
new file mode 100644
index 0000000..9b8a367
Binary files /dev/null and b/scribo/tests/binarization/wolf.ref.pbm differ
diff --git a/scribo/tests/binarization/wolf_weven_hodd.ref.pbm b/scribo/tests/binarization/wolf_weven_hodd.ref.pbm
new file mode 100644
index 0000000..d2281ed
Binary files /dev/null and b/scribo/tests/binarization/wolf_weven_hodd.ref.pbm differ
diff --git a/scribo/tests/binarization/wolf_wodd_heven.ref.pbm b/scribo/tests/binarization/wolf_wodd_heven.ref.pbm
new file mode 100644
index 0000000..c29fffa
Binary files /dev/null and b/scribo/tests/binarization/wolf_wodd_heven.ref.pbm differ
diff --git a/scribo/tests/binarization/wolf_wodd_hodd.ref.pbm b/scribo/tests/binarization/wolf_wodd_hodd.ref.pbm
new file mode 100644
index 0000000..9dce37a
Binary files /dev/null and b/scribo/tests/binarization/wolf_wodd_hodd.ref.pbm differ
--
1.7.2.5
1
0
---
.../{pgm_color_diff.cc => pbm_color_diff.cc} | 17 +++--
scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc | 2 +-
.../binarization/internal/local_threshold_debug.hh | 3 +
.../binarization/internal/sauvola_ms_functor.hh | 55 ++++++++++++++++-
scribo/scribo/binarization/sauvola_ms.hh | 63 +++++++++++++++++---
scribo/src/binarization/sauvola_ms_debug.cc | 1 +
6 files changed, 122 insertions(+), 19 deletions(-)
copy scribo/sandbox/z/sauvola_ms_rv/{pgm_color_diff.cc => pbm_color_diff.cc} (72%)
diff --git a/scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc b/scribo/sandbox/z/sauvola_ms_rv/pbm_color_diff.cc
similarity index 72%
copy from scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc
copy to scribo/sandbox/z/sauvola_ms_rv/pbm_color_diff.cc
index 7474c46..b49f40b 100644
--- a/scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc
+++ b/scribo/sandbox/z/sauvola_ms_rv/pbm_color_diff.cc
@@ -2,10 +2,11 @@
#include <mln/core/image/image2d.hh>
#include <mln/value/rgb8.hh>
#include <mln/value/int_u8.hh>
-#include <mln/io/pgm/load.hh>
+#include <mln/io/pbm/load.hh>
#include <mln/io/ppm/save.hh>
#include <mln/data/transform.hh>
#include <mln/arith/minus.hh>
+#include <mln/data/convert.hh>
namespace mln
{
@@ -21,7 +22,7 @@ namespace mln
int v_d2 = std::abs(v / 2);
if (v >= -threshold_ && v <= threshold_)
- return value::rgb8(255, 255, 255);
+ return value::rgb8(0, 0, 0);
else if (v > threshold_)
return value::rgb8(v_d2, 128 + v_d2, v_d2);
else
@@ -42,16 +43,18 @@ int main(int argc, char *argv[])
if (argc != 5)
{
- std::cout << "Usage: " << argv[0] << " in.pgm ref.pgm threshold out.ppm" << std::endl;
+ std::cout << "Usage: " << argv[0] << " in.pbm ref.pbm threshold out.ppm" << std::endl;
return 1;
}
- image2d<value::int_u8> input, ref;
+ image2d<bool> input, ref;
- io::pgm::load(input, argv[1]);
- io::pgm::load(ref, argv[2]);
+ io::pbm::load(input, argv[1]);
+ io::pbm::load(ref, argv[2]);
- image2d<int> diff = input - ref;
+ image2d<int>
+ diff = data::convert(value::int_u8(), input)
+ - data::convert(value::int_u8(), ref);
color_diff f(atoi(argv[3]));
image2d<value::rgb8> result = data::transform(diff, f);
diff --git a/scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc b/scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc
index 7474c46..d9c677a 100644
--- a/scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc
+++ b/scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc
@@ -21,7 +21,7 @@ namespace mln
int v_d2 = std::abs(v / 2);
if (v >= -threshold_ && v <= threshold_)
- return value::rgb8(255, 255, 255);
+ return value::rgb8(0, 0, 0);
else if (v > threshold_)
return value::rgb8(v_d2, 128 + v_d2, v_d2);
else
diff --git a/scribo/scribo/binarization/internal/local_threshold_debug.hh b/scribo/scribo/binarization/internal/local_threshold_debug.hh
index 6b2263f..46503f6 100644
--- a/scribo/scribo/binarization/internal/local_threshold_debug.hh
+++ b/scribo/scribo/binarization/internal/local_threshold_debug.hh
@@ -56,6 +56,7 @@ namespace scribo
const char* mean_image_output = 0;
const char* threshold_image_output = 0;
const char* full_threshold_image_output = 0;
+ const char * scale_proba_output = 0;
const char* scale_image_output = 0;
const char* scale_iz_image_output = 0;
@@ -68,6 +69,8 @@ namespace scribo
image2d<double> debug_mean;
image2d<double> debug_threshold;
+ image3d<double> debug_scale_proba;
+
image2d<double> debug_alpham;
image2d<bool> debug_alphacond;
diff --git a/scribo/scribo/binarization/internal/sauvola_ms_functor.hh b/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
index d72fc26..d0e6200 100644
--- a/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
+++ b/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
@@ -43,6 +43,7 @@
# include <scribo/binarization/internal/local_threshold_debug.hh>
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+#include <mln/value/int_u8.hh>
namespace scribo
{
@@ -60,6 +61,11 @@ namespace scribo
struct sauvola_ms_functor
{
const I& input;
+
+ const image2d<value::int_u8>& e_2;
+ unsigned i;
+ unsigned q;
+
mln_fwd_pixter(const I) pxl;
double res;
image2d<unsigned> parent;
@@ -79,7 +85,7 @@ namespace scribo
sauvola_formula formula_;
- sauvola_ms_functor(const I& input, double K, double R);
+ sauvola_ms_functor(const I& input, double K, double R, const image2d<value::int_u8>&e_2, unsigned i, unsigned q);
void exec(double mean, double stddev);
void end_of_row(int row);
@@ -101,8 +107,11 @@ namespace scribo
template <typename I>
- sauvola_ms_functor<I>::sauvola_ms_functor(const I& input, double K, double R)
+ sauvola_ms_functor<I>::sauvola_ms_functor(const I& input, double K, double R, const image2d<value::int_u8>&e_2, unsigned i, unsigned q)
: input(input),
+ e_2(e_2),
+ i(i),
+ q(q),
pxl(input),
K_(K),
R_(R)
@@ -142,7 +151,49 @@ 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
full_msk.element(p) = msk.element(p);
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
diff --git a/scribo/scribo/binarization/sauvola_ms.hh b/scribo/scribo/binarization/sauvola_ms.hh
index 63ea38f..e6297bd 100644
--- a/scribo/scribo/binarization/sauvola_ms.hh
+++ b/scribo/scribo/binarization/sauvola_ms.hh
@@ -72,6 +72,7 @@
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
# include <scribo/binarization/internal/local_threshold_debug.hh>
# include <mln/io/pgm/save.hh>
+# include <mln/io/dump/save.hh>
# include <mln/debug/filename.hh>
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
@@ -186,13 +187,15 @@ namespace scribo
// 1st pass
scribo::binarization::internal::sauvola_ms_functor< image2d<int_u8> >
- f(sub, K, SCRIBO_DEFAULT_SAUVOLA_R);
+ f(sub, K, SCRIBO_DEFAULT_SAUVOLA_R, e_2, i, q);
scribo::canvas::integral_browsing(integral_sum_sum_2,
ratio,
w_local_w, w_local_h,
s,
f);
+ std::cout << " i = " << i << " - ratio = " << ratio << std::endl;
+
// 2nd pass
{
mln::util::array<mln_value_(I) *> ptr(ratio);
@@ -235,6 +238,10 @@ namespace scribo
&& f.card.element(p) < lambda_max;
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
f.full_msk.element(p) = true;
+
+ 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);
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
if (f.msk.element(p) && e_2(sq) == 0u)
@@ -250,6 +257,13 @@ namespace scribo
f.msk.element(p) = f.msk.element(f.parent.element(p));
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
f.full_msk.element(p) = f.full_msk.element(f.parent.element(p));
+
+ point2d sqp = f.parent.point_at_index(f.parent.element(p)) * ratio;
+ unsigned v = debug_scale_proba(point3d(i - 2, sqp.row(), sqp.col()));
+
+ 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)) = v;
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
if (f.msk.element(p) && e_2(sq) == 0u)
@@ -868,10 +882,10 @@ namespace scribo
data::fill(e_2, 0u);
// Computing optimal object area for each scale.
- unsigned w_1_sq = w_1 * w_1;
- unsigned q_2 = std::pow(float(q), float(2));
- unsigned min_area = (5 * w_1_sq) / (4 * q_2);
- unsigned max_area = (w_1_sq + (q_2) * w_1_sq) / 4;
+ // unsigned w_1_sq = w_1 * w_1;
+ // unsigned q_2 = std::pow(float(q), float(2));
+ // unsigned min_area = (5 * w_1_sq) / (4 * q_2);
+ // unsigned max_area = (w_1_sq + (q_2) * w_1_sq) / 4;
// mln::util::array<unsigned> area(sub_ima.size(), 0);
@@ -879,11 +893,33 @@ namespace scribo
// for (unsigned i = 3; i < area.nelements(); ++i)
// area[i] = std::pow(float(q), float(i * 2 - 4)) * area[2];
+ mln::util::array<unsigned> win_w(sub_ima.size(), 0);
+ win_w[2] = s * w_1;
+ for (unsigned i = 3; i < win_w.nelements(); ++i)
+ {
+ win_w[i] = q * win_w[i - 1];
+ if (!(win_w[i] % 2))
+ ++win_w[i];
+ }
+
+ float coeff = 1.4;
+
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ internal::debug_scale_proba = image3d<double>(3,
+ integral_sum_sum_2.nrows(),
+ integral_sum_sum_2.ncols(),
+ integral_sum_sum_2.border());
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+
// Highest scale -> no maximum component size.
{
int i = sub_ima.size() - 1;
t_ima[i] = internal::compute_t_n_and_e_2(sub_ima[i], e_2,
- min_area,
+// (8096 / 144) / coeff,
+// 44 / coeff,
+ win_w[i] / 3 / coeff,
mln_max(unsigned),
s,
q, i, w_work,
@@ -896,8 +932,12 @@ namespace scribo
for (int i = sub_ima.size() - 2; i > 2; --i)
{
t_ima[i] = internal::compute_t_n_and_e_2(sub_ima[i], e_2,
- min_area,
- max_area,
+// 22 / coeff,
+// 201 * coeff,
+ win_w[i] / 3 / coeff,
+ win_w[i] * 3 * coeff,
+// (810 / 36) / coeff,
+// (8096 / 36) * coeff,
s,
q, i, w_work,
integral_sum_sum_2,
@@ -909,7 +949,9 @@ namespace scribo
{
t_ima[2] = internal::compute_t_n_and_e_2(sub_ima[2], e_2,
0,
- max_area,
+// 99 * coeff,
+ win_w[2] * 3 * coeff,
+// (810 / 9) * coeff,
s, 1, 2, w_work,
integral_sum_sum_2,
K);
@@ -938,6 +980,9 @@ namespace scribo
if (internal::scale_iz_image_output)
io::pgm::save(e_2,
mln::debug::filename(internal::scale_iz_image_output));
+ if (internal::scale_proba_output)
+ io::dump::save(internal::debug_scale_proba,
+ mln::debug::filename(internal::scale_proba_output));
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
// Binarize
diff --git a/scribo/src/binarization/sauvola_ms_debug.cc b/scribo/src/binarization/sauvola_ms_debug.cc
index 63fbefe..c04e58b 100644
--- a/scribo/src/binarization/sauvola_ms_debug.cc
+++ b/scribo/src/binarization/sauvola_ms_debug.cc
@@ -105,6 +105,7 @@ int main(int argc, char *argv[])
scribo::binarization::internal::threshold_image_output = "threshold_image.pbm";
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";
// Load
image2d<value::rgb8> input_1;
--
1.7.2.5
1
0