
* binarization/sauvola.hh: Revamp and now returns a threshold image. Move parts... * binarization/sauvola_threshold.hh: ... here. New file. * binarization/binarize.hh: New routine. --- scribo/ChangeLog | 11 + scribo/binarization/binarize.hh | 180 +++++++++++ scribo/binarization/sauvola.hh | 307 ++++++-------------- scribo/binarization/sauvola_threshold.hh | 478 ++++++++++++++++++++++++++++++ 4 files changed, 753 insertions(+), 223 deletions(-) create mode 100644 scribo/binarization/binarize.hh create mode 100644 scribo/binarization/sauvola_threshold.hh diff --git a/scribo/ChangeLog b/scribo/ChangeLog index f397523..deee412 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,3 +1,14 @@ +2009-10-22 Guillaume Lazzara <z@lrde.epita.fr> + + Revamp Sauvola binarization. + + * binarization/sauvola.hh: Revamp and now returns a threshold + image. Move parts... + + * binarization/sauvola_threshold.hh: ... here. New file. + + * binarization/binarize.hh: New routine. + 2009-10-12 Roland Levillain <roland@lrde.epita.fr> * headers.mk, tests/unit_test/unit-tests.mk: Regen. diff --git a/scribo/binarization/binarize.hh b/scribo/binarization/binarize.hh new file mode 100644 index 0000000..0f323bb --- /dev/null +++ b/scribo/binarization/binarize.hh @@ -0,0 +1,180 @@ +// Copyright (C) 2009 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_BINARIZE_HH +# define SCRIBO_BINARIZATION_BINARIZE_HH + +# include <mln/core/concept/image.hh> +# include <mln/value/concept/vectorial.hh> + +/// \file +/// +/// Binarize an image from a threshold image. + +namespace scribo +{ + + using namespace mln; + + + namespace binarization + { + + namespace internal + { + + template <typename I, typename T> + void + binarize_tests(const Image<I>& input, const Image<T>& threshold) + { + mln_precondition(exact(input).is_valid()); + mln_precondition(exact(threshold).is_valid()); + mln_precondition(exact(input).domain() == exact(threshold).domain()); + mlc_is_not_a(mln_value(I), value::Vectorial)::check(); + (void) input; + (void) threshold; + } + + } // end of namespace scribo::binarization::internal + + + namespace impl + { + + namespace generic + { + + template <typename I, typename T> + mln_ch_value(I, bool) + binarize(const Image<I>& input_, const Image<T>& threshold_) + { + trace::entering("scribo::binarization::impl::generic::binarize"); + + internal::binarize_tests(input_, threshold_); + + const I& input = exact(input_); + const T& threshold = exact(threshold_); + + mln_ch_value(I, bool) output; + initialize(output, input); + + mln_piter(I) p(input.domain()); + for_all(p) + output(p) = (input(p) <= threshold(p)); + + + trace::exiting("scribo::binarization::impl::generic::binarize"); + return output; + } + + + } // end of namespace scribo::binarization::impl::generic + + + template <typename I, typename T> + mln_ch_value(I, bool) + binarize_fastest(const Image<I>& input_, const Image<T>& threshold_) + { + trace::entering("scribo::binarization::impl::generic::binarize_fastest"); + internal::binarize_tests(input_, threshold_); + + const I& input = exact(input_); + const T& threshold = exact(threshold_); + + typedef mln_ch_value(I, bool) O; + O output; + initialize(output, input); + + mln_pixter(const I) pi(input); + mln_pixter(const T) pt(threshold); + mln_pixter(O) po(output); + for_all_3(pi, pt, po) + po.val() = pi.val() <= pt.val(); + + trace::exiting("scribo::binarization::impl::generic::binarize_fastest"); + return output; + } + + + + } // end of namespace scribo::binarization::impl + + + namespace internal + { + + template <typename I, typename T> + mln_ch_value(I, bool) + binarize_dispatch(trait::image::value_alignment::any, + trait::image::speed::any, + const Image<I>& input, const Image<T>& threshold) + { + return impl::generic::binarize(input, threshold); + } + + + template <typename I, typename T> + mln_ch_value(I, bool) + binarize_dispatch(trait::image::value_alignment::with_grid, + trait::image::speed::fastest, + const Image<I>& input, const Image<T>& threshold) + { + return impl::binarize_fastest(input, threshold); + } + + template <typename I, typename T> + mln_ch_value(I, bool) + binarize_dispatch(const Image<I>& input, const Image<T>& threshold) + { + return binarize_dispatch(mln_trait_image_value_alignment(I)(), + mln_trait_image_speed(I)(), + exact(input), exact(threshold)); + } + + } // end of namespace scribo::binarization::internal + + + template <typename I, typename T> + mln_ch_value(I, bool) + binarize(const Image<I>& input, const Image<T>& threshold) + { + trace::entering("scribo::binarization::binarize"); + + internal::binarize_tests(input, threshold); + + mln_ch_value(I, bool) + output = internal::binarize_dispatch(input, threshold); + + trace::exiting("scribo::binarization::binarize"); + return output; + } + + + } // end of namespace scribo::binarization + +} // end of namespace scribo + + +#endif // ! SCRIBO_BINARIZATION_BINARIZE_HH diff --git a/scribo/binarization/sauvola.hh b/scribo/binarization/sauvola.hh index b9f78f8..5323847 100644 --- a/scribo/binarization/sauvola.hh +++ b/scribo/binarization/sauvola.hh @@ -28,21 +28,15 @@ /// \file /// -/// Convert an image into a binary image. - -# 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/core/concept/image.hh> # include <mln/data/transform.hh> -# include <mln/pw/all.hh> -# include <mln/core/routine/duplicate.hh> - +# include <mln/value/int_u8.hh> +# include <mln/value/rgb8.hh> +# include <scribo/binarization/sauvola_threshold.hh> +# include <scribo/binarization/binarize.hh> namespace scribo @@ -53,104 +47,31 @@ namespace scribo using namespace mln; + /*! \brief Convert an image into a binary image. - \input[in] An image. + \input[in] input An image. + \input[in] window_size The window size. \return A binary image. */ template <typename I> - mln_ch_value(I,bool) - sauvola(const Image<I>& input); - - - -# ifndef MLN_INCLUDE_ONLY - - - namespace internal - { - - template <typename T> - class integral_image - { - public: - - template<class F> - integral_image(const image2d<T>& i, F func) - : img_(0), - nrows_(i.nrows()), - ncols_(i.ncols()) - { - img_ = (unsigned long long**)malloc(sizeof(unsigned long long*) * nrows_); - for (int n = 0; n < nrows_; ++n) - img_[n] = (unsigned long long*)malloc(sizeof(unsigned long long) * ncols_); - - img_[0][0] = func(i.at_(0, 0)); - - for (int row = 1; row < nrows_; ++row) - img_[row][0] = (*this)(row - 1, 0) + func(i.at_(row, 0)); - - for (int col = 1; col < ncols_; ++col) - img_[0][col] = (*this)(0, col - 1) - + func(i.at_(0, col)); - - for (int row = 1; row < nrows_; ++row) - for (int col = 1; col < ncols_; ++col) - img_[row][col] = (*this)(row - 1, col) - + (*this)(row, col - 1) - - (*this)(row - 1, col - 1) - + func(i.at_(row, col)); - } - - ~integral_image() - { - for (int n = 0; n < nrows_; ++n) - free(img_[n]); - free(img_); - } - - unsigned long long operator()(int row, int col) const - { - return img_[row][col]; - } - - private: - unsigned long long** img_; - int nrows_; - int ncols_; - }; - - - struct rgb8_to_int_u8 : Function_v2v< rgb8_to_int_u8 > - { - typedef value::int_u8 result; - result operator()(const value::rgb8& c) const - { - return (c.red() + c.green() + c.blue()) / 3; - } - }; - - - unsigned long long square_(const value::int_u8& val) - { - unsigned long long v = static_cast<unsigned long long>(val); - return v * v; - } - - unsigned long long identity_(const value::int_u8& val) - { - return static_cast<unsigned long long>(val); - } - - } // end of namespace scribo::binarization::internal + mln_ch_value(I, bool) + sauvola(const Image<I>& input, unsigned window_size); + /// \overload + /// The window size is set to 11. + // + template <typename I> + mln_ch_value(I, bool) + sauvola(const Image<I>& input); - // Implementation +# ifndef MLN_INCLUDE_ONLY + // Implementations. namespace impl { @@ -159,73 +80,16 @@ namespace scribo { template <typename I> - inline mln_ch_value(I, bool) - sauvola(const I& input) + sauvola(const Image<I>& input, unsigned window_size) { trace::entering("scribo::binarization::impl::generic::sauvola"); + mln_precondition(exact(input).is_valid()); - typedef mln_value(I) V; - - // Value of the window size - const unsigned int w = 11; - - // Control the threshold value in the local window - // The higher, the lower the threshold form the local - // mean m(x, y). Badekas et al. said 0.34 was best. - const double k = 0.34; - - // Maximum value of the standard deviation (128 for - // grayscale documents). - const double R = 128; - - // Compute the sum of all intensities of input - internal::integral_image<V> simple(input, internal::identity_); - - // Compute the sum of all squared intensities of input - internal::integral_image<V> squared(input, internal::square_); - - int w_2 = w >> 1; - - // Savaula Algorithm with I.I. - - image2d<bool> 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) - { - int row_min = std::max(0, row - w_2); - int col_min = std::max(0, col - w_2); - int row_max = std::min(nrows - 1, row + w_2); - int col_max = std::min(ncols - 1, col + w_2); - - double wh = (row_max - row_min + 1) * (col_max - col_min + 1); - - // Mean. - double m_x_y_tmp = (simple(row_max, col_max) - + simple(row_min, col_min) - - simple(row_max, col_min) - - simple(row_min, col_max)); - - double m_x_y = m_x_y_tmp / wh; - - // Standard deviation. - double s_x_y_tmp = (squared(row_max, col_max) - + squared(row_min, col_min) - - squared(row_max, col_min) - - squared(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. - double t_x_y = m_x_y * (1.0 + k * ((s_x_y / R) - 1.0)); - - output.at_(row, col) = (input.at_(row, col) < t_x_y); - } + mln_ch_value(I, bool) + output = binarize(input, + binarization::sauvola_threshold(input, + window_size)); trace::exiting("scribo::binarization::impl::generic::sauvola"); return output; @@ -234,98 +98,95 @@ namespace scribo } // end of namespace scribo::binarization::impl::generic - template <typename I> - inline - mln_ch_value(I, bool) - sauvola_gl(const I& input) - { - return impl::generic::sauvola(input); - } + template <typename I> + mln_ch_value(I, bool) + sauvola_rgb8(const Image<I>& input, unsigned window_size) + { + 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, internal::rgb8_to_int_u8()); - template <typename I> - inline mln_ch_value(I, bool) - sauvola_rgb8(const I& input) - { - trace::entering("scribo::binarization::impl::sauvola_rgb8"); + output = binarize(gima, + binarization::sauvola_threshold(gima, + window_size)); - mln_ch_value(I, value::int_u8) gima; - gima = data::transform(input, - internal::rgb8_to_int_u8()); + trace::exiting("scribo::binarization::impl::generic::sauvola"); + return output; + } - mln_ch_value(I, bool) output = impl::generic::sauvola(gima); + } // end of namespace scribo::binarization::impl - trace::exiting("scribo::binarization::impl::sauvola_rgb8"); - return output; - } - } // end of namespace scribo::binarization::impl + // Dispatch + namespace internal + { + template <typename I> + mln_ch_value(I, bool) + sauvola_dispatch(const mln_value(I)&, + const Image<I>& input, unsigned window_size) + { + return impl::generic::sauvola(input, window_size); + } + template <typename I> + mln_ch_value(I, bool) + sauvola_dispatch(const value::rgb8&, + const Image<I>& input, unsigned window_size) + { + return impl::sauvola_rgb8(input, window_size); + } - // Dispatch - namespace internal + template <typename I> + mln_ch_value(I, bool) + sauvola_dispatch(const Image<I>& input, unsigned window_size) { + typedef mln_value(I) V; + return sauvola_dispatch(V(), input, window_size); + } - template <typename I, unsigned n> - inline - mln_ch_value(I, bool) - sauvola_dispatch(const value::int_u<n>&, const I& input) - { - return impl::sauvola_gl(input); - } - - template <typename I> - inline - mln_ch_value(I, bool) - sauvola_dispatch(const value::rgb8&, const I& input) - { - return impl::sauvola_rgb8(input); - } + } // end of namespace scribo::binarization::internal - template <typename I> - inline - mln_ch_value(I, bool) - sauvola_dispatch(const mln_value(I)&, const I& input) - { - // No dispatch for this kind of value type. - mlc_abort(I)::check(); - typedef mln_ch_value(I,bool) output_t; - return output_t(); - } + // Facades - } // end of namespace scribo::binarization::internal + template <typename I> + mln_ch_value(I, bool) + sauvola(const Image<I>& input, unsigned window_size) + { + trace::entering("scribo::binarization::sauvola"); + mln_precondition(exact(input).is_valid()); - template <typename I> - inline mln_ch_value(I, bool) - sauvola(const Image<I>& input) - { - trace::entering("scribo::binarization::sauvola"); + output = internal::sauvola_dispatch(input, window_size); - mln_precondition(mln_site_(I)::dim == 2); - mln_precondition(exact(input).is_valid()); + trace::exiting("scribo::binarization::sauvola"); + return output; + } - typedef mln_value(I) value_t; - mln_ch_value(I, bool) - output = internal::sauvola_dispatch(value_t(), exact(input)); - trace::exiting("scribo::text::ppm2pbm"); - return output; - } + template <typename I> + mln_ch_value(I, bool) + sauvola(const Image<I>& input) + { + return sauvola(input, 11); + } + # endif // ! MLN_INCLUDE_ONLY + } // end of namespace scribo::binarization } // end of namespace scribo -#endif // ! SCRIBO_TEXT_PPM2PBM_HH +#endif // ! SCRIBO_BINARIZATION_SAUVOLA_HH diff --git a/scribo/binarization/sauvola_threshold.hh b/scribo/binarization/sauvola_threshold.hh new file mode 100644 index 0000000..9a9e439 --- /dev/null +++ b/scribo/binarization/sauvola_threshold.hh @@ -0,0 +1,478 @@ +// Copyright (C) 2009 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_HH +# define SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_HH + +/// \file +/// +/// Convert an image into a binary image. + +/// \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> + + +// Forward declaration. +namespace mln { template <typename T> class integral_image; } + + +namespace scribo +{ + + namespace binarization + { + + using namespace mln; + + /*! \brief Compute a threshold image with Sauvola's algorithm. + + \input[in] input An image. + \input[in] window_size The window size.x + \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 T> + mln_ch_value(I, value::int_u8) + sauvola_threshold(const Image<I>& input, unsigned window_size, + integral_image<T>& simple, + integral_image<T>& squared); + + + /// \overload + template <typename I> + mln_ch_value(I, value::int_u8) + sauvola_threshold(const Image<I>& input, unsigned window_size); + + + /// \overload + /// The window size is set to 11. + // + template <typename I> + mln_ch_value(I, value::int_u8) + sauvola_threshold(const Image<I>& input); + + + +# ifndef MLN_INCLUDE_ONLY + + + namespace internal + { + + struct rgb8_to_int_u8 : Function_v2v< rgb8_to_int_u8 > + { + typedef value::int_u8 result; + result operator()(const value::rgb8& c) const + { + return (c.red() + c.green() + c.blue()) / 3; + } + }; + + + unsigned long long square_(const value::int_u8& val) + { + unsigned long long v = static_cast<unsigned long long>(val); + return v * v; + } + + unsigned long long identity_(const value::int_u8& val) + { + return static_cast<unsigned long long>(val); + } + + + /// \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). + + template <typename P, typename T> + double + compute_sauvola_threshold(const P& p, + const integral_image<T>& simple, + const integral_image<T>& 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); + int col_min = std::max(0, p.col() - w_2); + int row_max = std::min(simple.nrows() - 1, p.row() + w_2); + int col_max = std::min(simple.ncols() - 1, p.col() + w_2); + + double wh = (row_max - row_min + 1) * (col_max - col_min + 1); + + // Mean. + double m_x_y_tmp = (simple(row_max, col_max) + + simple(row_min, col_min) + - simple(row_max, col_min) + - simple(row_min, col_max)); + + double m_x_y = m_x_y_tmp / wh; + + // Standard deviation. + double s_x_y_tmp = (squared(row_max, col_max) + + squared(row_min, col_min) + - squared(row_max, col_min) + - squared(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. + double t_x_y = m_x_y * (1.0 + k * ((s_x_y / R) - 1.0)); + + return t_x_y; + } + + + template <typename P, typename T> + double + compute_sauvola_threshold(const P& p, + const integral_image<T>& simple, + const integral_image<T>& squared, + int win_width) + { + // Badekas et al. said 0.34 was best. + const double k = 0.34; + + // 128 is best for grayscale documents. + const double R = 128; + + return compute_sauvola_threshold(p, simple, squared, win_width, k, R); + } + + + } // end of namespace scribo::binarization::internal + + } // end of namespace scribo::binarization + +} // end of namespace scribo + + +namespace mln +{ + + template <typename T> + class integral_image + { + public: + + integral_image() + : img_(0), nrows_(0), ncols_(0) + {} + + template<class F> + integral_image(const image2d<T>& i, F func) + : img_(0), + nrows_(0), + ncols_(0) + { + init_(i, func); + } + + template<class F> + void init_(const image2d<T>& i, F func) + { + nrows_ = i.nrows(); + ncols_ = i.ncols(); + + img_ = (unsigned long long**)malloc(sizeof(unsigned long long*) * nrows_); + for (int n = 0; n < nrows_; ++n) + img_[n] = (unsigned long long*)malloc(sizeof(unsigned long long) * ncols_); + + img_[0][0] = func(i.at_(0, 0)); + + for (int row = 1; row < nrows_; ++row) + img_[row][0] = (*this)(row - 1, 0) + func(i.at_(row, 0)); + + for (int col = 1; col < ncols_; ++col) + img_[0][col] = (*this)(0, col - 1) + + func(i.at_(0, col)); + + for (int row = 1; row < nrows_; ++row) + for (int col = 1; col < ncols_; ++col) + img_[row][col] = (*this)(row - 1, col) + + (*this)(row, col - 1) + - (*this)(row - 1, col - 1) + + func(i.at_(row, col)); + } + + + ~integral_image() + { + for (int n = 0; n < nrows_; ++n) + free(img_[n]); + free(img_); + } + + bool is_valid() const + { + return img_ != 0; + } + + unsigned long long operator()(int row, int col) const + { + return img_[row][col]; + } + + int nrows() const + { + return nrows_; + } + + int ncols() const + { + return ncols_; + } + + + private: + unsigned long long** img_; + int nrows_; + int ncols_; + }; + +} // end of namespace mln + + + +namespace scribo +{ + + namespace binarization + { + + // Implementation + + + namespace impl + { + + namespace generic + { + + template <typename I, typename T> + inline + mln_concrete(I) + sauvola_threshold(const I& input, unsigned window_size, + integral_image<T>& simple, + integral_image<T>& squared) + { + trace::entering("scribo::binarization::impl::generic::sauvola_threshold"); + + typedef mln_value(I) V; + typedef mln_site(I) P; + + // Compute the sum of all intensities of input + simple.init_(input, internal::identity_); + + // Compute the sum of all squared intensities of input + squared.init_(input, internal::square_); + + // 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) + output.at_(row, col) + = internal::compute_sauvola_threshold(P(row, col), simple, + squared, window_size); + + trace::exiting("scribo::binarization::impl::generic::sauvola_threshold"); + return output; + } + + } // end of namespace scribo::binarization::impl::generic + + + + template <typename I, typename T> + inline + mln_concrete(I) + sauvola_threshold_gl(const I& input, unsigned window_size, + integral_image<T>& simple, + integral_image<T>& squared) + { + return impl::generic::sauvola_threshold(input, window_size, + simple, squared); + } + + + template <typename I, typename T> + inline + mln_ch_value(I, value::int_u8) + sauvola_threshold_rgb8(const I& input, unsigned window_size, + integral_image<T>& simple, + integral_image<T>& squared) + { + trace::entering("scribo::binarization::impl::sauvola_threshold_rgb8"); + + mln_ch_value(I, value::int_u8) gima; + gima = data::transform(input, + internal::rgb8_to_int_u8()); + + mln_ch_value(I, value::int_u8) + output = impl::generic::sauvola_threshold(gima, window_size, + simple, squared); + + trace::exiting("scribo::binarization::impl::sauvola_threshold_rgb8"); + return output; + } + + + } // end of namespace scribo::binarization::impl + + + + + // Dispatch + + namespace internal + { + + template <unsigned n, typename I, typename T> + inline + mln_ch_value(I, value::int_u<n>) + sauvola_threshold_dispatch(const value::int_u<n>&, const I& input, + unsigned window_size, + integral_image<T>& simple, + integral_image<T>& squared) + { + return impl::sauvola_threshold_gl(input, window_size, simple, squared); + } + + template <typename I, typename T> + inline + mln_ch_value(I, value::int_u8) + sauvola_threshold_dispatch(const value::rgb8&, const I& input, + unsigned window_size, + integral_image<T>& simple, + integral_image<T>& squared) + { + return impl::sauvola_threshold_rgb8(input, window_size, + simple, squared); + } + + template <typename I, typename T> + inline + mln_ch_value(I, value::int_u8) + sauvola_threshold_dispatch(const mln_value(I)&, const I& input, + unsigned window_size, + integral_image<T>& simple, + integral_image<T>& 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 T> + mln_ch_value(I, value::int_u8) + sauvola_threshold(const Image<I>& input, unsigned window_size, + integral_image<T>& simple, + integral_image<T>& squared) + { + trace::entering("scribo::binarization::sauvola_threshold"); + + 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_dispatch(value_t(), exact(input), + window_size, simple, + squared); + + trace::exiting("scribo::text::ppm2pbm"); + return output; + } + + + template <typename I> + inline + mln_ch_value(I, value::int_u8) + sauvola_threshold(const Image<I>& input, unsigned window_size) + { + mln::integral_image<value::int_u8> simple, squared; + return sauvola_threshold(input, window_size, simple, squared); + } + + + template <typename I> + inline + mln_ch_value(I, value::int_u8) + sauvola_threshold(const Image<I>& input) + { + return sauvola_threshold(input, 11); + } + + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace scribo::binarization + +} // end of namespace scribo + + +#endif // ! SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_HH -- 1.5.6.5
participants (1)
-
Guillaume Lazzara