olena-2.0-97-g44961f4 Improve Sauvola.

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