last-svn-commit-581-g3990140 Improve debug management and outputs for Sauvola.

* scribo/binarization/internal/compute_sauvola_threshold.hh: New. Move sauvola_threshold related routines here. * scribo/binarization/internal/first_pass_functor.hh, * scribo/binarization/sauvola.hh, * scribo/binarization/sauvola_ms.hh, * scribo/binarization/sauvola_threshold_image.hh: Move debug variables... * scribo/binarization/internal/sauvola_debug.hh: ... here. New. * scribo/binarization/sauvola_threshold_image_debug.hh: Remove. * src/binarization/Makefile.am, * src/binarization/sauvola_debug.cc, * src/binarization/sauvola_ms_debug.cc: Improve debug outputs. --- scribo/ChangeLog | 21 + .../internal/compute_sauvola_threshold.hh | 285 +++++++++++++ .../binarization/internal/first_pass_functor.hh | 30 +-- .../{all.hh => internal/sauvola_debug.hh} | 56 ++- scribo/scribo/binarization/sauvola.hh | 69 ++-- scribo/scribo/binarization/sauvola_ms.hh | 61 ++-- .../scribo/binarization/sauvola_threshold_image.hh | 361 +---------------- .../binarization/sauvola_threshold_image_debug.hh | 421 -------------------- scribo/src/binarization/Makefile.am | 5 +- scribo/src/binarization/sauvola_debug.cc | 68 ++-- scribo/src/binarization/sauvola_ms_debug.cc | 40 +-- 11 files changed, 493 insertions(+), 924 deletions(-) create mode 100644 scribo/scribo/binarization/internal/compute_sauvola_threshold.hh copy scribo/scribo/binarization/{all.hh => internal/sauvola_debug.hh} (56%) delete mode 100644 scribo/scribo/binarization/sauvola_threshold_image_debug.hh diff --git a/scribo/ChangeLog b/scribo/ChangeLog index 49dc324..eceb1ba 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,3 +1,24 @@ +2010-11-15 Guillaume Lazzara <z@lrde.epita.fr> + + Improve debug management and outputs for Sauvola. + + * scribo/binarization/internal/compute_sauvola_threshold.hh: + New. Move sauvola_threshold related routines here. + + * scribo/binarization/internal/first_pass_functor.hh, + * scribo/binarization/sauvola.hh, + * scribo/binarization/sauvola_ms.hh, + * scribo/binarization/sauvola_threshold_image.hh: Move debug + variables... + + * scribo/binarization/internal/sauvola_debug.hh: ... here. New. + + * scribo/binarization/sauvola_threshold_image_debug.hh: Remove. + + * src/binarization/Makefile.am, + * src/binarization/sauvola_debug.cc, + * src/binarization/sauvola_ms_debug.cc: Improve debug outputs. + 2010-08-06 Arthur Crepin-Leblond <crepin@lrde.epita.fr> Add arrows shortcuts. diff --git a/scribo/scribo/binarization/internal/compute_sauvola_threshold.hh b/scribo/scribo/binarization/internal/compute_sauvola_threshold.hh new file mode 100644 index 0000000..d3ca07f --- /dev/null +++ b/scribo/scribo/binarization/internal/compute_sauvola_threshold.hh @@ -0,0 +1,285 @@ +// Copyright (C) 2010 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_COMPUTE_SAUVOLA_THRESHOLD_HH +# define SCRIBO_BINARIZATION_INTERNAL_COMPUTE_SAUVOLA_THRESHOLD_HH + + +/// \file +/// +/// \brief Compute a threshold with Sauvola's binarization formula. + +# include <algorithm> +# include <cmath> + +# include <mln/core/image/image2d.hh> +# include <mln/value/int_u8.hh> + +# include <scribo/binarization/internal/sauvola_debug.hh> + + +// Setup default Sauvola's formulae parameters values. +// These macros may be used in other variant of Sauvola's algorithm. +// +// Values are set according to the following reference: "Automatic +// Evaluation of Document Binarization Results", Badekas and al, 2005 +// +// Badekas et al. said 0.34 was best. +# define SCRIBO_DEFAULT_SAUVOLA_K 0.34 +// +// 128 is best for grayscale documents. +# define SCRIBO_DEFAULT_SAUVOLA_R 128 + + +namespace scribo +{ + + namespace binarization + { + + namespace internal + { + + using namespace mln; + + + /*! \brief Compute a point wise threshold according Sauvola's + binarization. + + \param[in] p A site. + \param[in] simple An integral image of mean values. + \param[in] squared An integral image of squared mean values. + \param[in] win_width Window width. + \param[in] k Control the threshold value in the local + window. The higher, the lower the threshold + form the local mean m(x, y). + \param[in] R Maximum value of the standard deviation (128 + for grayscale documents). + + \return A threshold. + */ + template <typename P, typename J> + double + compute_sauvola_threshold(const P& p, + const J& simple, + const J& squared, + int win_width, double K, double R); + + /// \overload + /// K is set to 0.34 and R to 128. + // + template <typename P, typename J> + double + compute_sauvola_threshold(const P& p, + const J& simple, + const J& squared, + int win_width); + + + +# ifndef MLN_INCLUDE_ONLY + + + + /*! \brief compute Sauvola's threshold applying directly the formula. + + \param[in] m_x_y Mean value. + \param[in] s_x_y Standard deviation. + \param[in] k Control the threshold value in the local + window. The higher, the lower the threshold + form the local mean m(x, y). + \param[in] R Maximum value of the standard deviation (128 + for grayscale documents). + + \return A threshold. + */ + inline + double + sauvola_threshold_formula(const double m_x_y, const double s_x_y, + const double K, const double R) + { + return m_x_y * (1.0 + K * ((s_x_y / R) - 1.0)); + } + + /// \overload + /// K is set to 0.34 and R to 128. + // + inline + double + sauvola_threshold_formula(double m_x_y, double s_x_y) + { + return sauvola_threshold_formula(m_x_y, s_x_y, + SCRIBO_DEFAULT_SAUVOLA_K, + SCRIBO_DEFAULT_SAUVOLA_R); + } + + + + template <typename P, typename J> + double + compute_sauvola_threshold(const P& p, + const J& simple, + const J& squared, + int win_width, double K, double R) + { + mln_precondition(simple.nrows() == squared.nrows()); + mln_precondition(simple.ncols() == squared.ncols()); + + // Window half width. + int w_2 = win_width >> 1; + + int row_min = std::max(0, p.row() - w_2 - 1); + int col_min = std::max(0, p.col() - w_2 - 1); + + int row_max = std::min(static_cast<int>(simple.nrows()) - 1, + p.row() + w_2); + int col_max = std::min(static_cast<int>(simple.ncols()) - 1, + p.col() + w_2); + + + double wh = (row_max - row_min) * (col_max - col_min); + + // Mean. + double m_x_y_tmp = (simple.at_(row_max, col_max) + + simple.at_(row_min, col_min) + - simple.at_(row_max, col_min) + - simple.at_(row_min, col_max)); + + double m_x_y = m_x_y_tmp / wh; + +# ifdef SCRIBO_SAUVOLA_DEBUG + // Store local mean + debug_mean(p) = m_x_y * mean_debug_factor; +# endif // ! SCRIBO_SAUVOLA_DEBUG + + // Standard deviation. + double s_x_y_tmp = (squared.at_(row_max, col_max) + + squared.at_(row_min, col_min) + - squared.at_(row_max, col_min) + - squared.at_(row_min, col_max)); + + double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh - 1.f)); + +# ifdef SCRIBO_SAUVOLA_DEBUG + // Store local standard deviation + debug_stddev(p) = s_x_y * stddev_debug_factor; +# endif // ! SCRIBO_SAUVOLA_DEBUG + + // Thresholding. + double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R); + +# ifdef SCRIBO_SAUVOLA_DEBUG + double alpha = K * (1 - s_x_y / R); + debug_alpham(p) = alpha * m_x_y * alpham_debug_factor; + debug_alphacond(p) = (s_x_y < (alpha * m_x_y / 2.)); +# endif // !SCRIBO_SAUVOLA_DEBUG + + return t_x_y; + } + + + template <typename P, typename J> + double + compute_sauvola_threshold_single_image(const P& p, + const J& integral, + int win_width, + double K, double R) + { + // Window half width. + int w_2 = win_width >> 1; + + int row_min = std::max(0, p.row() - w_2); + int col_min = std::max(0, p.col() - w_2); + + int row_max = std::min(static_cast<int>(integral.nrows()) - 1, + p.row() + w_2); + int col_max = std::min(static_cast<int>(integral.ncols()) - 1, + p.col() + w_2); + + + double wh = (row_max - row_min + 1) * (col_max - col_min + 1); + + // Mean. + double m_x_y_tmp = (integral.at_(row_max, col_max).first() + + integral.at_(row_min, col_min).first() + - integral.at_(row_max, col_min).first() + - integral.at_(row_min, col_max).first()); + + double m_x_y = m_x_y_tmp / wh; + +# ifdef SCRIBO_SAUVOLA_DEBUG + // Store local mean + debug_mean(p) = m_x_y * mean_debug_factor; +# endif // ! SCRIBO_SAUVOLA_DEBUG + + // Standard deviation. + double s_x_y_tmp = (integral.at_(row_max, col_max).second() + + integral.at_(row_min, col_min).second() + - integral.at_(row_max, col_min).second() + - integral.at_(row_min, col_max).second()); + + double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh - 1.f)); + +# ifdef SCRIBO_SAUVOLA_DEBUG + // Store local standard deviation + debug_stddev(p) = s_x_y * stddev_debug_factor; +# endif // !SCRIBO_SAUVOLA_DEBUG + + // Thresholding. + double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R); + +# ifdef SCRIBO_SAUVOLA_DEBUG + double alpha = K * (1 - s_x_y / R); + debug_alpham(p) = alpha * m_x_y * alpham_debug_factor; + debug_alphacond(p) = (s_x_y < (alpha * m_x_y / 2.)); +# endif // !SCRIBO_SAUVOLA_DEBUG + + return t_x_y; + } + + + + template <typename P, typename J> + double + compute_sauvola_threshold(const P& p, + const J& simple, + const J& squared, + int win_width) + { + return compute_sauvola_threshold(p, simple, squared, win_width, + SCRIBO_DEFAULT_SAUVOLA_K, + SCRIBO_DEFAULT_SAUVOLA_R); + } + + +#endif // ! MLN_INCLUDE_ONLY + + } // end of namespace scribo::binarization::internal + + } // end of namespace scribo::binarization + +} // end of namespace scribo + +#endif // ! SCRIBO_BINARIZATION_INTERNAL_COMPUTE_SAUVOLA_THRESHOLD_HH diff --git a/scribo/scribo/binarization/internal/first_pass_functor.hh b/scribo/scribo/binarization/internal/first_pass_functor.hh index 694779f..637ff39 100644 --- a/scribo/scribo/binarization/internal/first_pass_functor.hh +++ b/scribo/scribo/binarization/internal/first_pass_functor.hh @@ -1,4 +1,5 @@ -// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -35,8 +36,6 @@ # include <scribo/binarization/sauvola_threshold_image.hh> -// #include <mln/border/adjust.hh> - namespace scribo { @@ -46,13 +45,6 @@ namespace scribo namespace internal { -# ifdef SCRIBO_SAUVOLA_DEBUG - // Global debug images. - extern image2d<value::int_u8> debug_k; - extern image2d<float> debug_s_n; - extern image2d<float> debug_k_l; -# endif // ! SCRIBO_SAUVOLA_DEBUG - using namespace mln; @@ -94,9 +86,8 @@ namespace scribo initialize(msk, input); # ifdef SCRIBO_SAUVOLA_DEBUG - initialize(debug_k, input); - initialize(debug_s_n, input); - initialize(debug_k_l, input); + initialize(debug_mean, input); + initialize(debug_stddev, input); # endif // ! SCRIBO_SAUVOLA_DEBUG mln::extension::fill(msk, false); @@ -114,24 +105,11 @@ namespace scribo unsigned p = pxl.offset(); -# ifdef SCRIBO_SAUVOLA_DEBUG - value::int_u8 t_p; - convert::from_to( - sauvola_threshold_formula(mean, stddev, - K_, - SCRIBO_DEFAULT_SAUVOLA_R, - debug_k.element(p), - debug_s_n.element(p), - debug_k_l.element(p)), - t_p); -# else value::int_u8 t_p; mln::convert::from_to(sauvola_threshold_formula(mean, stddev, K_, SCRIBO_DEFAULT_SAUVOLA_R), t_p); -# endif // SCRIBO_SAUVOLA_DEBUG - msk.element(p) = input.element(p) < t_p; t_sub.element(p) = t_p; diff --git a/scribo/scribo/binarization/all.hh b/scribo/scribo/binarization/internal/sauvola_debug.hh similarity index 56% copy from scribo/scribo/binarization/all.hh copy to scribo/scribo/binarization/internal/sauvola_debug.hh index 6f40505..0f8ccf0 100644 --- a/scribo/scribo/binarization/all.hh +++ b/scribo/scribo/binarization/internal/sauvola_debug.hh @@ -23,33 +23,65 @@ // exception does not however invalidate any other reasons why the // executable file might be covered by the GNU General Public License. -#ifndef SCRIBO_BINARIZATION_ALL_HH -# define SCRIBO_BINARIZATION_ALL_HH +#ifndef SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_DEBUG_HH +# define SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_DEBUG_HH /// \file /// -/// Include all headers located in scribo/binarization. +/// \brief Declare all debug related variables for Sauvola* +/// algorithms. + + +/// FIXME: A struct may be a bit better... + + +# ifdef SCRIBO_SAUVOLA_DEBUG + +# ifndef MLN_INCLUDE_ONLY + namespace scribo { - /// Namespace of binarization routines. namespace binarization { + using namespace mln; + + namespace internal + { + + char* stddev_image_output = 0; + char* mean_image_output = 0; + char* threshold_image_output = 0; + + char* scale_image_output = 0; + + char* alpham_image_output = 0; + char* alphacond_image_output = 0; + + // Declare debug images. + image2d<double> debug_stddev; + image2d<double> debug_mean; + image2d<double> debug_threshold; + + image2d<double> debug_alpham; + image2d<bool> debug_alphacond; + + double mean_debug_factor = 1.0; + double stddev_debug_factor = 1.0; + double alpham_debug_factor = 2.0; + + } // end of namespace scribo::binarization::internal + } // end of namespace scribo::binarization } // end of namespace scribo -# include <scribo/binarization/global_threshold.hh> -# include <scribo/binarization/global_threshold_auto.hh> +# endif // ! MLN_INCLUDE_ONLY -# include <scribo/binarization/local_threshold.hh> +# endif // ! SCRIBO_SAUVOLA_DEBUG -# include <scribo/binarization/sauvola.hh> -# include <scribo/binarization/sauvola_ms.hh> -# include <scribo/binarization/sauvola_ms_split.hh> -# include <scribo/binarization/sauvola_threshold_image.hh> -#endif // ! SCRIBO_BINARIZATION_ALL_HH +#endif // ! SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_DEBUG_HH diff --git a/scribo/scribo/binarization/sauvola.hh b/scribo/scribo/binarization/sauvola.hh index 6dd812b..45891c3 100644 --- a/scribo/scribo/binarization/sauvola.hh +++ b/scribo/scribo/binarization/sauvola.hh @@ -34,13 +34,16 @@ # include <mln/core/concept/image.hh> # include <mln/data/transform.hh> # include <mln/value/int_u8.hh> -# include <mln/value/rgb8.hh> - -# include <mln/fun/v2v/rgb_to_int_u.hh> # include <scribo/binarization/sauvola_threshold_image.hh> # include <scribo/binarization/local_threshold.hh> +# include <scribo/binarization/internal/sauvola_debug.hh> +# ifdef SCRIBO_SAUVOLA_DEBUG +# include <mln/io/pgm/save.hh> +# include <mln/io/pbm/save.hh> +# include <mln/data/saturate.hh> +# endif // ! SCRIBO_SAUVOLA_DEBUG namespace scribo { @@ -91,6 +94,7 @@ namespace scribo # ifndef MLN_INCLUDE_ONLY + // Implementations. namespace impl @@ -119,26 +123,6 @@ namespace scribo } // end of namespace scribo::binarization::impl::generic - template <typename I> - mln_ch_value(I, bool) - sauvola_rgb8(const Image<I>& input, unsigned window_size, double K) - { - trace::entering("scribo::binarization::impl::generic::sauvola"); - mln_precondition(exact(input).is_valid()); - - mln_ch_value(I, value::int_u8) gima; - gima = data::transform(input, mln::fun::v2v::rgb_to_int_u<8>()); - - mln_ch_value(I, bool) - output = local_threshold(gima, - binarization::sauvola_threshold_image(gima, - window_size, - K)); - - trace::exiting("scribo::binarization::impl::generic::sauvola"); - return output; - } - } // end of namespace scribo::binarization::impl @@ -157,15 +141,6 @@ namespace scribo return impl::generic::sauvola(input, window_size, K); } - template <typename I> - mln_ch_value(I, bool) - sauvola_dispatch(const value::rgb8&, - const Image<I>& input, unsigned window_size, - double K) - { - return impl::sauvola_rgb8(input, window_size, K); - } - template <typename I> mln_ch_value(I, bool) @@ -193,6 +168,25 @@ namespace scribo mln_ch_value(I, bool) output = internal::sauvola_dispatch(input, window_size, K); +# ifdef SCRIBO_SAUVOLA_DEBUG + if (internal::stddev_image_output) + io::pgm::save(data::saturate(value::int_u8(), internal::debug_stddev), + internal::stddev_image_output); + if (internal::mean_image_output) + io::pgm::save(data::saturate(value::int_u8(), internal::debug_mean), + internal::mean_image_output); + if (internal::threshold_image_output) + io::pgm::save(data::saturate(value::int_u8(), internal::debug_threshold), + internal::threshold_image_output); + + if (internal::alpham_image_output) + io::pgm::save(data::saturate(value::int_u8(), internal::debug_alpham), + internal::alpham_image_output); + if (internal::alphacond_image_output) + io::pbm::save(internal::debug_alphacond, internal::alphacond_image_output); +# endif // ! SCRIBO_SAUVOLA_DEBUG + + trace::exiting("scribo::binarization::sauvola"); return output; } @@ -202,16 +196,7 @@ namespace scribo mln_ch_value(I, bool) sauvola(const Image<I>& input, unsigned window_size) { - trace::entering("scribo::binarization::sauvola"); - - mln_precondition(exact(input).is_valid()); - - mln_ch_value(I, bool) - output = internal::sauvola_dispatch(input, window_size, - SCRIBO_DEFAULT_SAUVOLA_K); - - trace::exiting("scribo::binarization::sauvola"); - return output; + return sauvola(input, window_size, SCRIBO_DEFAULT_SAUVOLA_K); } diff --git a/scribo/scribo/binarization/sauvola_ms.hh b/scribo/scribo/binarization/sauvola_ms.hh index c526e69..a6b3aba 100644 --- a/scribo/scribo/binarization/sauvola_ms.hh +++ b/scribo/scribo/binarization/sauvola_ms.hh @@ -32,6 +32,8 @@ /// /// \brief Binarize an image using a multi-scale implementation of /// Sauvola's algoritm. +/// +/// \fixme Use the integral image for successive subsampling. # include <mln/core/alias/neighb2d.hh> @@ -64,10 +66,9 @@ # include <scribo/canvas/integral_browsing.hh> # ifdef SCRIBO_SAUVOLA_DEBUG +# include <scribo/binarization/internal/sauvola_debug.hh> # include <mln/io/pgm/save.hh> -# include <mln/data/saturate.hh> -# include <mln/data/convert.hh> -# include <mln/arith/times.hh> +# include <scribo/make/debug_filename.hh> # endif // ! SCRIBO_SAUVOLA_DEBUG @@ -121,13 +122,6 @@ namespace scribo using namespace mln; -# ifdef SCRIBO_SAUVOLA_DEBUG - char* scale_image_output = 0; - char* k_image_output = 0; - char* s_n_image_output = 0; - char* k_l_image_output = 0; -# endif // ! SCRIBO_SAUVOLA_DEBUG - template <typename V> V my_find_root(image2d<V>& parent, const V& x) { @@ -160,15 +154,19 @@ namespace scribo // 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_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."); + 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_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."); + trace::warning("integral_browsing - Adjusting window height since it" + " was larger than image height."); } if (! (w_local % 2)) @@ -259,6 +257,12 @@ namespace scribo } } // end of 2nd pass + +# ifdef SCRIBO_SAUVOLA_DEBUG + io::pbm::save(f.msk, + scribo::make::debug_filename(internal::threshold_image_output).c_str()); +# endif // ! SCRIBO_SAUVOLA_DEBUG + return f.t_sub; } @@ -860,8 +864,10 @@ namespace scribo sub_domains[2].first(), sub_domains[2].second())); - // Subsampling to scale 3 and 4. + // + // FIXME: we may use the integral image to compute + // subsampled images -> faster and more precise. for (unsigned i = 3; i <= nb_subscale + 1; ++i) sub_ima.append(mln::subsampling::antialiased(sub_ima[i - 1], q, sub_domains[i].first(), @@ -913,14 +919,19 @@ namespace scribo } - // Propagate scale values. - e_2 = transform::influence_zone_geodesic(e_2, c8()); - # ifdef SCRIBO_SAUVOLA_DEBUG if (internal::scale_image_output) io::pgm::save(e_2, internal::scale_image_output); # endif // ! SCRIBO_SAUVOLA_DEBUG + // Propagate scale values. + e_2 = transform::influence_zone_geodesic(e_2, c8()); + +// # ifdef SCRIBO_SAUVOLA_DEBUG +// if (internal::scale_image_output) +// io::pgm::save(e_2, internal::scale_image_output); +// # endif // ! SCRIBO_SAUVOLA_DEBUG + // Binarize image2d<bool> output = internal::multi_scale_binarization(input_1, e_2, t_ima, s); @@ -952,20 +963,6 @@ namespace scribo mln_ch_value(I,bool) output = impl::generic::sauvola_ms(exact(input_1_), w_1, s, K); - -# ifdef SCRIBO_SAUVOLA_DEBUG - if (internal::k_image_output) - io::pgm::save(internal::debug_k, internal::k_image_output); - - if (internal::s_n_image_output) - io::pgm::save(data::saturate(value::int_u8(), internal::debug_s_n * 100), - internal::s_n_image_output); - if (internal::k_l_image_output) - io::pgm::save(data::saturate(value::int_u8(), internal::debug_k_l * 10), - internal::k_l_image_output); -# endif // ! SCRIBO_SAUVOLA_DEBUG - - trace::exiting("scribo::binarization::sauvola_ms"); return output; } diff --git a/scribo/scribo/binarization/sauvola_threshold_image.hh b/scribo/scribo/binarization/sauvola_threshold_image.hh index bdb032c..05a7064 100644 --- a/scribo/scribo/binarization/sauvola_threshold_image.hh +++ b/scribo/scribo/binarization/sauvola_threshold_image.hh @@ -37,31 +37,11 @@ # include <cmath> # include <mln/core/image/image2d.hh> -# include <mln/value/rgb8.hh> # include <mln/value/int_u.hh> # include <mln/value/int_u8.hh> -# include <mln/data/transform.hh> -# include <mln/pw/all.hh> -# include <mln/core/routine/duplicate.hh> - -# include <mln/fun/v2v/rgb_to_int_u.hh> - # include <scribo/core/init_integral_image.hh> - - - -// Setup default Sauvola's formulae parameters values. -// These macros may be used in other variant of Sauvola's algorithm. -// -// Values are set according to the following reference: "Automatic -// Evaluation of Document Binarization Results", Badekas and al, 2005 -// -// Badekas et al. said 0.34 was best. -# define SCRIBO_DEFAULT_SAUVOLA_K 0.34 -// -// 128 is best for grayscale documents. -# define SCRIBO_DEFAULT_SAUVOLA_R 128 +# include <scribo/binarization/internal/compute_sauvola_threshold.hh> @@ -116,287 +96,6 @@ namespace scribo # ifndef MLN_INCLUDE_ONLY - namespace internal - { - -# ifdef SCRIBO_SAUVOLA_DEBUG - // Declare debug images. - image2d<value::int_u8> debug_k; - image2d<float> debug_s_n; - image2d<float> debug_k_l; -# endif // ! SCRIBO_SAUVOLA_DEBUG - - - /*! \brief compute Sauvola's threshold applying directly the formula. - - \param[in] m_x_y Mean value. - \param[in] s_x_y Standard deviation. - \param[in] k Control the threshold value in the local - window. The higher, the lower the threshold - form the local mean m(x, y). - \param[in] R Maximum value of the standard deviation (128 - for grayscale documents). - - \return A threshold. - */ -# ifdef SCRIBO_SAUVOLA_DEBUG - inline - double - sauvola_threshold_formula(const double m_x_y, const double s_x_y, - const double K, const double R, - value::int_u8& dbg_k, float& dbg_s_n, - float& dbg_k_l) -# else - inline - double - sauvola_threshold_formula(const double m_x_y, const double s_x_y, - const double K, const double R) -# endif // ! SCRIBO_SAUVOLA_DEBUG - { -// double s_N = s_x_y / 256; - double K_2 = K; -// double K_2 = exp(K * log(s_x_y / 256)); -// if (s_x_y < 30) -// K_2 = 0.01; -// else if (s_x_y < 80) -// K_2 = 0.1; -// else if (s_x_y > 80) -// K_2 = K; - - -// Results_0.1_0.34 -// -// if (s_N < 0.1f) -// { -// K_2 = 0.1f; -// # ifdef SCRIBO_SAUVOLA_DEBUG -// dbg_k = 0; -// dbg_s_n = s_N; -// # endif // !SCRIBO_SAUVOLA_DEBUG -// } -// else if (s_N > 0.34) -// { -// K_2 = 0.34; -// # ifdef SCRIBO_SAUVOLA_DEBUG -// dbg_k = 255; -// dbg_s_n = s_N; -// # endif // !SCRIBO_SAUVOLA_DEBUG -// } -// else -// { -// K_2 = s_N; -// # ifdef SCRIBO_SAUVOLA_DEBUG -// dbg_k = 150; -// dbg_s_n = s_N; -// # endif // !SCRIBO_SAUVOLA_DEBUG -// } - - -// const double k_min = 0.1f; -// const double k_max = 1.0f; -// const double s_1 = 0.05f; -// const double s_2 = 0.50f; - -// double k_b = (k_max - k_min) / (double)(s_2 - s_1); -// double k_a = 0.1f - s_1 * k_b; -// K_2 = k_a + k_b * s_N; - -// dbg_s_n = s_N; -// if (K_2 < k_min) -// dbg_k = 0; -// else if (K_2 > k_max) -// dbg_k = 255; -// else -// dbg_k = 150; - - - -// if (s_N < 0.1f) -// { -// K_2 = 0.1f; -// dbg_k = 0; -// dbg_s_n = s_N; -// dbg_k_l = 0.1; -// } -// else -// { -// // double K_L = ((long int)((s_N * 11) + 0.49999)) * s_N; -// double K_L = s_N * K / 3.0f; -// // K_2 = std::min(K_L, (double) 1.0); -// K_2 = K_L; -// if (K_L > 1.0f) -// dbg_k = 255; -// else -// dbg_k = 150; - -// dbg_s_n = s_N; -// dbg_k_l = K_L; -// } - - - return m_x_y * (1.0 + K_2 * ((s_x_y / R) - 1.0)); - } - - - /// \overload - // - inline - double - sauvola_threshold_formula(double m_x_y, double s_x_y) - { -# ifdef SCRIBO_SAUVOLA_DEBUG - std::cout << "This overload of sauvola_threshold_formula is disabled in debug mode!" << std::endl; - return 0; -# else - return sauvola_threshold_formula(m_x_y, s_x_y, - SCRIBO_DEFAULT_SAUVOLA_K, - SCRIBO_DEFAULT_SAUVOLA_R); -# endif // !SCRIBO_SAUVOLA_DEBUG - } - - - /*! \brief Compute a point wise threshold according Sauvola's - binarization. - - \param[in] p A site. - \param[in] simple An integral image of mean values. - \param[in] squared An integral image of squared mean values. - \param[in] win_width Window width. - \param[in] k Control the threshold value in the local - window. The higher, the lower the threshold - form the local mean m(x, y). - \param[in] R Maximum value of the standard deviation (128 - for grayscale documents). - - \return A threshold. - */ - template <typename P, typename J> - double - compute_sauvola_threshold(const P& p, - const J& simple, - const J& squared, - int win_width, double K, double R) - { - mln_precondition(simple.nrows() == squared.nrows()); - mln_precondition(simple.ncols() == squared.ncols()); - - // Window half width. - int w_2 = win_width >> 1; - - int row_min = std::max(0, p.row() - w_2 - 1); - int col_min = std::max(0, p.col() - w_2 - 1); - - int row_max = std::min(static_cast<int>(simple.nrows()) - 1, - p.row() + w_2); - int col_max = std::min(static_cast<int>(simple.ncols()) - 1, - p.col() + w_2); - - - double wh = (row_max - row_min) * (col_max - col_min); - - // Mean. - double m_x_y_tmp = (simple.at_(row_max, col_max) - + simple.at_(row_min, col_min) - - simple.at_(row_max, col_min) - - simple.at_(row_min, col_max)); - - double m_x_y = m_x_y_tmp / wh; - - // Standard deviation. - double s_x_y_tmp = (squared.at_(row_max, col_max) - + squared.at_(row_min, col_min) - - squared.at_(row_max, col_min) - - squared.at_(row_min, col_max)); - - double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh - 1.f)); - - // Thresholding. -# ifdef SCRIBO_SAUVOLA_DEBUG - double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R, debug_k(p), debug_s_n(p), debug_k_l(p)); -# else - double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R); -# endif // ! SCRIBO_SAUVOLA_DEBUG - - return t_x_y; - } - - - template <typename P, typename J> - double - compute_sauvola_threshold_single_image(const P& p, - const J& integral, - int win_width, - double K, double R) - { - // Window half width. - int w_2 = win_width >> 1; - - int row_min = std::max(0, p.row() - w_2); - int col_min = std::max(0, p.col() - w_2); - - int row_max = std::min(static_cast<int>(integral.nrows()) - 1, - p.row() + w_2); - int col_max = std::min(static_cast<int>(integral.ncols()) - 1, - p.col() + w_2); - - - double wh = (row_max - row_min + 1) * (col_max - col_min + 1); - - // Mean. - double m_x_y_tmp = (integral.at_(row_max, col_max).first() - + integral.at_(row_min, col_min).first() - - integral.at_(row_max, col_min).first() - - integral.at_(row_min, col_max).first()); - - double m_x_y = m_x_y_tmp / wh; - - // Standard deviation. - double s_x_y_tmp = (integral.at_(row_max, col_max).second() - + integral.at_(row_min, col_min).second() - - integral.at_(row_max, col_min).second() - - integral.at_(row_min, col_max).second()); - - double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh - 1.f)); - - // Thresholding. -# ifdef SCRIBO_SAUVOLA_DEBUG - double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R, debug_k(p), debug_s_n(p), debug_k_l(p)); -# else - double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R); -# endif // !SCRIBO_SAUVOLA_DEBUG - - return t_x_y; - } - - - - template <typename P, typename J> - double - compute_sauvola_threshold(const P& p, - const J& simple, - const J& squared, - int win_width) - { - return compute_sauvola_threshold(p, simple, squared, win_width, - SCRIBO_DEFAULT_SAUVOLA_K, - SCRIBO_DEFAULT_SAUVOLA_R); - } - - - } // end of namespace scribo::binarization::internal - - } // end of namespace scribo::binarization - -} // end of namespace scribo - - - -namespace scribo -{ - - namespace binarization - { - // Implementation @@ -427,7 +126,15 @@ namespace scribo typedef mln_value(I) V; typedef mln_site(I) P; - // Savaula Algorithm with I.I. +# ifdef SCRIBO_SAUVOLA_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_SAUVOLA_DEBUG + + // Sauvola Algorithm with I.I. mln_concrete(I) output; initialize(output, input); @@ -439,12 +146,24 @@ namespace scribo for(def::coord row = 0; row < nrows; ++row) for(def::coord col = 0; col < ncols; ++col) + { +# ifdef SCRIBO_SAUVOLA_DEBUG + + double t = internal::compute_sauvola_threshold(P(row, col), simple, + squared, window_size, + K, + SCRIBO_DEFAULT_SAUVOLA_R); + mln::convert::from_to(t, output.at_(row, col)); + internal::debug_threshold.at_(row, col) = t; +# else mln::convert::from_to( internal::compute_sauvola_threshold(P(row, col), simple, squared, window_size, K, SCRIBO_DEFAULT_SAUVOLA_R), output.at_(row, col)); +# endif // ! SCRIBO_SAUVOLA_DEBUG + } trace::exiting("scribo::binarization::impl::generic::sauvola_threshold"); return output; @@ -467,30 +186,6 @@ namespace scribo } - template <typename I, typename J> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_rgb8(const I& input, unsigned window_size, - double K, - Image<J>& simple, - Image<J>& squared) - { - trace::entering("scribo::binarization::impl::sauvola_threshold_image_rgb8"); - - mln_ch_value(I, value::int_u8) gima; - gima = data::transform(input, - mln::fun::v2v::rgb_to_int_u<8>()); - - mln_ch_value(I, value::int_u8) - output = impl::generic::sauvola_threshold_image(gima, window_size, - K, - simple, squared); - - trace::exiting("scribo::binarization::impl::sauvola_threshold_image_rgb8"); - return output; - } - - } // end of namespace scribo::binarization::impl @@ -514,18 +209,6 @@ namespace scribo simple, squared); } - template <typename I, typename J> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_dispatch(const value::rgb8&, const I& input, - unsigned window_size, - double K, - J& simple, - J& squared) - { - return impl::sauvola_threshold_image_rgb8(input, window_size, - K, simple, squared); - } template <typename I, typename J> inline diff --git a/scribo/scribo/binarization/sauvola_threshold_image_debug.hh b/scribo/scribo/binarization/sauvola_threshold_image_debug.hh deleted file mode 100644 index fd317bc..0000000 --- a/scribo/scribo/binarization/sauvola_threshold_image_debug.hh +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright (C) 2009, 2010 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_SAUVOLA_THRESHOLD_IMAGE_DEBUG_HH -# define SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_DEBUG_HH - -/// \file -/// -/// Compute an image of local threshold using Sauvola algorithm. - -/// \fixme return type too restrictive! - -# include <algorithm> -# include <cmath> - -# include <mln/core/image/image2d.hh> -# include <mln/value/rgb8.hh> -# include <mln/value/int_u.hh> -# include <mln/value/int_u8.hh> - -# include <mln/data/transform.hh> -# include <mln/pw/all.hh> -# include <mln/core/routine/duplicate.hh> - -# include <mln/fun/v2v/rgb_to_int_u.hh> - -# include <scribo/core/init_integral_image.hh> -# include <scribo/binarization/sauvola_threshold_image.hh> - - -// Setup default Sauvola's formulae parameters values. -// These macros may be used in other variant of Sauvola's algorithm. -// -// Values are set according to the following reference: "Automatic -// Evaluation of Document Binarization Results", Badekas and al, 2005 -// -// Badekas et al. said 0.34 was best. -# define SCRIBO_DEFAULT_SAUVOLA_K 0.34 -// -// 128 is best for grayscale documents. -# define SCRIBO_DEFAULT_SAUVOLA_R 128 - - - -namespace scribo -{ - - namespace binarization - { - - using namespace mln; - - /*! \brief Compute an image of local threshold using Sauvola algorithm. - - \input[in] input An image. - \input[in] window_size The window size. - \input[out] simple The sum of all intensities of \p input. - \input[out] squared The sum of all squared intensities of \p - input. - - \return An image of local thresholds. - - */ - template <typename I, typename J> - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_debug(const Image<I>& input, unsigned window_size, - double K, - Image<J>& simple, - Image<J>& squared); - - /// \overload - template <typename I> - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_debug(const Image<I>& input, unsigned window_size, - double K); - - - -# ifndef MLN_INCLUDE_ONLY - - - namespace internal - { - - unsigned mean_debug_factor = 1; - unsigned stddev_debug_factor = 10; - - /*! \brief Compute a point wise threshold according Sauvola's - binarization. - - \param[in] p A site. - \param[in] simple An integral image of mean values. - \param[in] squared An integral image of squared mean values. - \param[in] win_width Window width. - \param[in] k Control the threshold value in the local - window. The higher, the lower the threshold - form the local mean m(x, y). - \param[in] R Maximum value of the standard deviation (128 - for grayscale documents). - - \return A threshold. - */ - template <typename P, typename M, typename J> - double - compute_sauvola_threshold(const P& p, - M& mean, M& stddev, M& thres, - const J& simple, - const J& squared, - int win_width, double K, double R) - { - mln_precondition(simple.nrows() == squared.nrows()); - mln_precondition(simple.ncols() == squared.ncols()); - - // Window half width. - int w_2 = win_width >> 1; - - int row_min = std::max(0, p.row() - w_2 - 1); - int col_min = std::max(0, p.col() - w_2 - 1); - - int row_max = std::min(static_cast<int>(simple.nrows()) - 1, - p.row() + w_2); - int col_max = std::min(static_cast<int>(simple.ncols()) - 1, - p.col() + w_2); - - - double wh = (row_max - row_min) * (col_max - col_min); - - // Mean. - double m_x_y_tmp = (simple.at_(row_max, col_max) - + simple.at_(row_min, col_min) - - simple.at_(row_max, col_min) - - simple.at_(row_min, col_max)); - - double m_x_y = m_x_y_tmp / wh; - - mean(p) = m_x_y;// * mean_debug_factor; - - // Standard deviation. - double s_x_y_tmp = (squared.at_(row_max, col_max) - + squared.at_(row_min, col_min) - - squared.at_(row_max, col_min) - - squared.at_(row_min, col_max)); - - double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh - 1.f)); - - stddev(p) = s_x_y;// * stddev_debug_factor; - - // Thresholding. - double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R); - - thres(p) = t_x_y; - - return t_x_y; - } - - - } // end of namespace scribo::binarization::internal - - } // end of namespace scribo::binarization - -} // end of namespace scribo - - - -namespace scribo -{ - - namespace binarization - { - - // Implementation - - - namespace impl - { - - namespace generic - { - - template <typename I, typename M, typename J> - inline - mln_concrete(I) - sauvola_threshold_image_debug(const Image<I>& input_, - unsigned window_size, - double K, - Image<M>& mean_, Image<M>& stddev_, - Image<M>& thres_, - Image<J>& simple_, - Image<J>& squared_) - { - trace::entering("scribo::binarization::impl::generic::sauvola_threshold_image_debug"); - - const I& input = exact(input_); - M& mean = exact(mean_); - M& stddev = exact(stddev_); - M& thres = exact(thres_); - J& simple = exact(simple_); - J& squared = exact(squared_); - - mln_assertion(input.is_valid()); - mln_assertion(simple.is_valid()); - mln_assertion(squared.is_valid()); - - typedef mln_value(I) V; - typedef mln_site(I) P; - - // Savaula Algorithm with I.I. - - mln_concrete(I) output; - initialize(output, input); - - const def::coord nrows = static_cast<def::coord>(input.nrows()); - const def::coord ncols = static_cast<def::coord>(input.ncols()); - - for(def::coord row = 0; row < nrows; ++row) - for(def::coord col = 0; col < ncols; ++col) - convert::from_to( - internal::compute_sauvola_threshold(P(row, col), - mean, stddev, thres, - simple, squared, - window_size, K, - SCRIBO_DEFAULT_SAUVOLA_R), - output.at_(row, col)); - - trace::exiting("scribo::binarization::impl::generic::sauvola_threshold"); - return output; - } - - } // end of namespace scribo::binarization::impl::generic - - - - template <typename I, typename M, typename J> - inline - mln_concrete(I) - sauvola_threshold_image_debug_gl(const Image<I>& input, - unsigned window_size, - double K, - Image<M>& mean, Image<M>& stddev, - Image<M>& thres, - Image<J>& simple, - Image<J>& squared) - { - return impl::generic::sauvola_threshold_image_debug(input, window_size, - K, - mean, stddev, thres, - simple, squared); - } - - - template <typename I, typename M, typename J> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_debug_rgb8(const Image<I>& input, - unsigned window_size, - double K, - Image<M>& mean, Image<M>& stddev, - Image<M>& thres, - Image<J>& simple, - Image<J>& squared) - { - trace::entering("scribo::binarization::impl::sauvola_threshold_image_debug_rgb8"); - - mln_ch_value(I, value::int_u8) gima; - gima = data::transform(input, - mln::fun::v2v::rgb_to_int_u<8>()); - - mln_ch_value(I, value::int_u8) - output = impl::generic::sauvola_threshold_image_debug(gima, window_size, - K, - mean, stddev, thres, - simple, squared); - - trace::exiting("scribo::binarization::impl::sauvola_threshold_image_debug_rgb8"); - return output; - } - - - } // end of namespace scribo::binarization::impl - - - - - // Dispatch - - namespace internal - { - - template <unsigned n, typename I, typename M, typename J> - inline - mln_ch_value(I, value::int_u<n>) - sauvola_threshold_image_debug_dispatch(const value::int_u<n>&, - const I& input, - unsigned window_size, - double K, - M& mean, M& stddev, M& thres, - J& simple, - J& squared) - { - return impl::sauvola_threshold_image_debug_gl(input, window_size, K, - mean, stddev, thres, - simple, squared); - } - - template <typename I, typename M, typename J> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_debug_dispatch(const value::rgb8&, const I& input, - unsigned window_size, - double K, - M& mean, M& stddev, M& thres, - J& simple, - J& squared) - { - return impl::sauvola_threshold_image_debug_rgb8(input, window_size, - K, mean, stddev, - simple, squared); - } - - template <typename I, typename M, typename J> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_debug_dispatch(const mln_value(I)&, const I& input, - M& mean, M& stddev, M& thres, - unsigned window_size, - double K, - J& simple, - J& squared) - { - // No dispatch for this kind of value type. - mlc_abort(I)::check(); - - typedef mln_ch_value(I,bool) output_t; - return output_t(); - } - - - } // end of namespace scribo::binarization::internal - - - - template <typename I, typename M, typename J> - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_debug(const Image<I>& input, unsigned window_size, - double K, - Image<M>& mean, Image<M>& stddev, - Image<M>& thres, - Image<J>& simple, - Image<J>& squared) - { - trace::entering("scribo::binarization::sauvola_threshold_image_debug"); - - mln_precondition(mln_site_(I)::dim == 2); - mln_precondition(exact(input).is_valid()); - - typedef mln_value(I) value_t; - mln_ch_value(I, value::int_u8) - output = internal::sauvola_threshold_image_debug_dispatch(value_t(), - exact(input), - window_size, - K, - exact(mean), - exact(stddev), - exact(thres), - exact(simple), - exact(squared)); - - trace::exiting("scribo::text::ppm2pbm"); - return output; - } - - - template <typename I, typename M> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_debug(const Image<I>& input, unsigned window_size, - double K, - Image<M>& mean, Image<M>& stddev, - Image<M>& thres) - { - mln_ch_value(I, double) - simple = init_integral_image(input, scribo::internal::identity_), - squared = init_integral_image(input, scribo::internal::square_); - - return sauvola_threshold_image_debug(input, window_size, K, - mean, stddev, thres, - simple, squared); - } - - -# endif // ! MLN_INCLUDE_ONLY - - } // end of namespace scribo::binarization - -} // end of namespace scribo - - -#endif // ! SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_DEBUG_HH diff --git a/scribo/src/binarization/Makefile.am b/scribo/src/binarization/Makefile.am index 2b01a74..557a30a 100644 --- a/scribo/src/binarization/Makefile.am +++ b/scribo/src/binarization/Makefile.am @@ -21,6 +21,7 @@ noinst_PROGRAMS = \ pgm_global_threshold_auto \ pgm_sauvola \ pgm_sauvola_ms \ + pgm_sauvola_threshold_image \ ppm_sauvola \ ppm_sauvola_ms_fg \ ppm_sauvola_ms \ @@ -30,6 +31,7 @@ noinst_PROGRAMS = \ pgm_global_threshold_auto_SOURCES = pgm_global_threshold_auto.cc pgm_sauvola_SOURCES = pgm_sauvola.cc pgm_sauvola_ms_SOURCES = pgm_sauvola_ms.cc +pgm_sauvola_threshold_image_SOURCES = pgm_sauvola_threshold_image.cc ppm_sauvola_SOURCES = ppm_sauvola.cc ppm_sauvola_ms_fg_SOURCES = ppm_sauvola_ms_fg.cc ppm_sauvola_ms_SOURCES = ppm_sauvola_ms.cc @@ -62,7 +64,8 @@ if HAVE_MAGICKXX $(MAGICKXX_LDFLAGS) sauvola_debug_SOURCES = sauvola_debug.cc - sauvola_debug_CPPFLAGS = $(AM_CPPFLAGS) \ + sauvola_debug_CPPFLAGS = $(AM_CPPFLAGS) \ + -DSCRIBO_SAUVOLA_DEBUG \ $(MAGICKXX_CPPFLAGS) sauvola_debug_LDFLAGS = $(AM_LDFLAGS) \ $(MAGICKXX_LDFLAGS) diff --git a/scribo/src/binarization/sauvola_debug.cc b/scribo/src/binarization/sauvola_debug.cc index b17dd13..f723851 100644 --- a/scribo/src/binarization/sauvola_debug.cc +++ b/scribo/src/binarization/sauvola_debug.cc @@ -32,8 +32,10 @@ #include <mln/data/convert.hh> #include <mln/data/saturate.hh> +#include <mln/fun/v2v/rgb_to_int_u.hh> + #include <scribo/binarization/local_threshold.hh> -#include <scribo/binarization/sauvola_threshold_image_debug.hh> +#include <scribo/binarization/sauvola.hh> #include <scribo/debug/usage.hh> const char *args_desc[][2] = @@ -42,9 +44,15 @@ const char *args_desc[][2] = { "output.pbm", "A binary image." }, { "mean.pgm", "The local mean image." }, { "stddev.pgm", "The local standard deviation image." }, + { "threshold.pgm", "Threshold image." }, + { "alpham.pgm", "alpha * m values" }, + { "alphacond.pbm", "Boolean image. True if s < (alpha * m / 2)" }, + { "mean_factor", "Mean value factor (default 1)." }, - { "stddev_factor", "Standard deviation value factor (default 10)." }, - { "w", "Window size (default 51)." }, + { "stddev_factor", "Standard deviation value factor (default 2)." }, + { "alphamfact", "" }, + + { "w", "Window size (default 101)." }, { "k", "Sauvola's formulae parameter (default 0.34)." }, {0, 0} }; @@ -55,62 +63,70 @@ int main(int argc, char *argv[]) using namespace mln; using namespace scribo::binarization; - if (argc < 5 || argc >= 9) + if (argc < 5 || argc >= 13) return scribo::debug::usage(argv, "Binarization based on Sauvola's algorithm.", - "input.* output.pbm mean.pgm stddev.pgm <mean_factor> <stddev_factor> <w> <k>", + "input.* output.pbm mean.pgm stddev.pgm threshold.pgm alpham.pgm " + "alphacond.pbm <mean_factor> <stddev_factor> <alphamfact> <w> <k>", args_desc); trace::entering("main"); unsigned w; - if (argc >= 8) - w = atoi(argv[7]); + if (argc >= 12) + w = atoi(argv[11]); else - w = 51; + w = 101; double k; - if (argc >= 9) - k = atof(argv[8]); + if (argc >= 13) + k = atof(argv[12]); else k = 0.34f; std::cout << "Using w=" << w << " and k=" << k << std::endl; + if (argc >= 4) + scribo::binarization::internal::mean_image_output = argv[3]; + if (argc >= 5) + scribo::binarization::internal::stddev_image_output = argv[4]; if (argc >= 6) - scribo::binarization::internal::mean_debug_factor = atoi(argv[5]); + scribo::binarization::internal::threshold_image_output = argv[5]; if (argc >= 7) - scribo::binarization::internal::stddev_debug_factor = atoi(argv[6]); + scribo::binarization::internal::alpham_image_output = argv[6]; + if (argc >= 8) + scribo::binarization::internal::alphacond_image_output = argv[7]; + + if (argc >= 9) + scribo::binarization::internal::mean_debug_factor = atof(argv[8]); + else + scribo::binarization::internal::mean_debug_factor = 1; + if (argc >= 10) + scribo::binarization::internal::stddev_debug_factor = atof(argv[9]); + else + scribo::binarization::internal::stddev_debug_factor = 2; + if (argc >= 11) + scribo::binarization::internal::alpham_debug_factor = atof(argv[10]); + else + scribo::binarization::internal::alpham_debug_factor = 2; image2d<value::rgb8> input; io::magick::load(input, argv[1]); - image2d<float> mean, stddev, thres; - initialize(mean, input); - initialize(stddev, input); - initialize(thres, input); - image2d<value::int_u8> gima = data::transform(input, mln::fun::v2v::rgb_to_int_u<8>()); image2d<bool> - out = local_threshold(gima, - sauvola_threshold_image_debug(gima, w, k, - mean, stddev, thres)); + out = scribo::binarization::sauvola(gima, w, k); io::pbm::save(out, argv[2]); - io::pgm::save(data::stretch(value::int_u8(), mean), argv[3]); - io::pgm::save(data::stretch(value::int_u8(), stddev), argv[4]); - - io::pgm::save(data::saturate(value::int_u8(), mean), "mean_saturated.pgm"); - io::pgm::save(data::saturate(value::int_u8(), stddev), "stddev_saturated.pgm"); - io::pgm::save(data::saturate(value::int_u8(), thres), "thres_saturated.pgm"); +//io::pgm::save(data::saturate(value::int_u8(), thres), "thres_saturated.pgm"); trace::exiting("main"); } diff --git a/scribo/src/binarization/sauvola_ms_debug.cc b/scribo/src/binarization/sauvola_ms_debug.cc index 80594dd..6bf9837 100644 --- a/scribo/src/binarization/sauvola_ms_debug.cc +++ b/scribo/src/binarization/sauvola_ms_debug.cc @@ -28,18 +28,20 @@ #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_int_u.hh> #include <scribo/binarization/sauvola_ms.hh> #include <scribo/debug/usage.hh> bool check_args(int argc, char * argv[]) { - if (argc < 3 || argc > 10) + if (argc < 3 || argc > 7) return false; - if (argc >= 5) + if (argc >= 6) { - int s = atoi(argv[4]); + int s = atoi(argv[5]); if (s < 1 || s > 3) { @@ -57,13 +59,10 @@ const char *args_desc[][2] = { { "input.*", "An image." }, { "out.pbm", "A binary image." }, + { "scale.pgm", "Image of scales used for binarization." }, { "w", "Window size at scale 1. (default: 101)" }, { "s", "First subsampling ratio (default: 3)." }, { "k", "Sauvola's formuale parameter (default: 0.34)" }, - { "scale.pgm", "Image of scales used for binarization." }, - { "k_image.pgm", "Image of the parameter K used in the image." }, - { "sn_image.pgm", "Image of the parameter normalized standard deviation." }, - { "k_l_image.pgm", "Precise image of the parameter K used for each site." }, {0, 0} }; @@ -89,42 +88,33 @@ int main(int argc, char *argv[]) if (!check_args(argc, argv)) return scribo::debug::usage(argv, "Multi-Scale Binarization based on Sauvola's algorithm.", - "input.* output.pbm <w> <s> <k> <scale.pgm> <k_image.pgm> <sn_image.pgm> <k_l_image.pgm", + "input.* output.pbm <scale.pgm> <w> <s> <k>", args_desc); trace::entering("main"); // Window size unsigned w_1; - if (argc >= 4) - w_1 = atoi(argv[3]); // Scale 1 + if (argc >= 5) + w_1 = atoi(argv[4]); // Scale 1 else w_1 = 101u; // First subsampling scale. unsigned s; - if (argc >= 5) - s = atoi(argv[4]); + if (argc >= 6) + s = atoi(argv[5]); else s = 3u; double k; - if (argc >= 6) - k = atof(argv[5]); + if (argc >= 7) + k = atof(argv[6]); else k = 0.34f; - if (argc >= 7) - scribo::binarization::internal::scale_image_output = argv[6]; - - if (argc >= 8) - scribo::binarization::internal::k_image_output = argv[7]; - - if (argc >= 9) - scribo::binarization::internal::s_n_image_output = argv[8]; - - if (argc >= 10) - scribo::binarization::internal::k_l_image_output = argv[9]; + if (argc >= 4) + scribo::binarization::internal::scale_image_output = argv[3]; // Load -- 1.5.6.5
participants (1)
-
Guillaume Lazzara