olena-2.0-11-g2fb4b79 Add Niblack's binarization algorithm.
* scribo/binarization/all.hh: Update includes. * scribo/binarization/internal/compute_local_threshold.hh, * scribo/binarization/internal/compute_sauvola_threshold.hh, * scribo/binarization/internal/first_pass_functor.hh, * scribo/binarization/internal/local_threshold_debug.hh, * scribo/binarization/internal/sauvola_debug.hh, * scribo/binarization/internal/sauvola_formula.hh, * scribo/binarization/sauvola.hh, * scribo/binarization/sauvola_ms.hh, * scribo/binarization/sauvola_threshold.hh, * scribo/binarization/sauvola_threshold_image.hh: Revamp code in order to share some parts with Niblack's algorithm. * scribo/binarization/internal/niblack_formula.hh, * scribo/binarization/niblack.hh, * scribo/binarization/niblack_threshold.hh: New. * src/binarization/Makefile.am * tests/binarization/Makefile.am: Add new targets. * src/binarization/niblack.cc: New tool. * tests/binarization/niblack.cc: New test. * tests/binarization/niblack.ref.pbm: New test data. --- scribo/ChangeLog | 31 ++ scribo/scribo/binarization/all.hh | 5 +- .../internal/compute_local_threshold.hh | 224 +++++++++++++++ .../internal/compute_sauvola_threshold.hh | 285 ------------------ .../binarization/internal/first_pass_functor.hh | 24 +- .../binarization/internal/local_threshold_debug.hh | 88 ++++++ .../binarization/internal/niblack_formula.hh | 105 +++++++ .../scribo/binarization/internal/sauvola_debug.hh | 87 ------ .../binarization/internal/sauvola_formula.hh | 121 ++++++++ scribo/scribo/binarization/niblack.hh | 218 ++++++++++++++ scribo/scribo/binarization/niblack_threshold.hh | 299 +++++++++++++++++++ scribo/scribo/binarization/sauvola.hh | 24 +- scribo/scribo/binarization/sauvola_ms.hh | 21 +- scribo/scribo/binarization/sauvola_threshold.hh | 296 +++++++++++++++++++ .../scribo/binarization/sauvola_threshold_image.hh | 301 -------------------- scribo/src/binarization/Makefile.am | 12 +- scribo/src/binarization/niblack.cc | 106 +++++++ .../binarization/pgm_sauvola_threshold_image.cc | 7 +- scribo/tests/binarization/Makefile.am | 3 + scribo/tests/binarization/niblack.cc | 52 ++++ scribo/tests/binarization/niblack.ref.pbm | Bin 0 -> 32884 bytes 21 files changed, 1597 insertions(+), 712 deletions(-) create mode 100644 scribo/scribo/binarization/internal/compute_local_threshold.hh delete mode 100644 scribo/scribo/binarization/internal/compute_sauvola_threshold.hh create mode 100644 scribo/scribo/binarization/internal/local_threshold_debug.hh create mode 100644 scribo/scribo/binarization/internal/niblack_formula.hh delete mode 100644 scribo/scribo/binarization/internal/sauvola_debug.hh create mode 100644 scribo/scribo/binarization/internal/sauvola_formula.hh create mode 100644 scribo/scribo/binarization/niblack.hh create mode 100644 scribo/scribo/binarization/niblack_threshold.hh create mode 100644 scribo/scribo/binarization/sauvola_threshold.hh delete mode 100644 scribo/scribo/binarization/sauvola_threshold_image.hh create mode 100644 scribo/src/binarization/niblack.cc create mode 100644 scribo/tests/binarization/niblack.cc create mode 100644 scribo/tests/binarization/niblack.ref.pbm diff --git a/scribo/ChangeLog b/scribo/ChangeLog index 5aa2a06..0923b28 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,3 +1,34 @@ +2011-10-17 Guillaume Lazzara <z@lrde.epita.fr> + + Add Niblack's binarization algorithm. + + * scribo/binarization/all.hh: Update includes. + + * scribo/binarization/internal/compute_local_threshold.hh, + * scribo/binarization/internal/compute_sauvola_threshold.hh, + * scribo/binarization/internal/first_pass_functor.hh, + * scribo/binarization/internal/local_threshold_debug.hh, + * scribo/binarization/internal/sauvola_debug.hh, + * scribo/binarization/internal/sauvola_formula.hh, + * scribo/binarization/sauvola.hh, + * scribo/binarization/sauvola_ms.hh, + * scribo/binarization/sauvola_threshold.hh, + * scribo/binarization/sauvola_threshold_image.hh: Revamp code in + order to share some parts with Niblack's algorithm. + + * scribo/binarization/internal/niblack_formula.hh, + * scribo/binarization/niblack.hh, + * scribo/binarization/niblack_threshold.hh: New. + + * src/binarization/Makefile.am + * tests/binarization/Makefile.am: Add new targets. + + * src/binarization/niblack.cc: New tool. + + * tests/binarization/niblack.cc: New test. + + * tests/binarization/niblack.ref.pbm: New test data. + 2011-10-14 Guillaume Lazzara <z@lrde.epita.fr> Add a new tool for global thresholding. diff --git a/scribo/scribo/binarization/all.hh b/scribo/scribo/binarization/all.hh index 6f40505..5530861 100644 --- a/scribo/scribo/binarization/all.hh +++ b/scribo/scribo/binarization/all.hh @@ -1,4 +1,5 @@ -// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -50,6 +51,6 @@ namespace scribo # 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> +# include <scribo/binarization/sauvola_threshold.hh> #endif // ! SCRIBO_BINARIZATION_ALL_HH diff --git a/scribo/scribo/binarization/internal/compute_local_threshold.hh b/scribo/scribo/binarization/internal/compute_local_threshold.hh new file mode 100644 index 0000000..147ef0f --- /dev/null +++ b/scribo/scribo/binarization/internal/compute_local_threshold.hh @@ -0,0 +1,224 @@ +// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory +// (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_BINARIZATION_INTERNAL_COMPUTE_LOCAL_THRESHOLD_HH +# define SCRIBO_BINARIZATION_INTERNAL_COMPUTE_LOCAL_THRESHOLD_HH + + +/// \file +/// +/// \brief Compute a threshold with Local's binarization formula. + +# include <algorithm> +# include <cmath> + +# include <mln/core/image/image2d.hh> +# include <mln/value/int_u8.hh> + +# include <scribo/binarization/internal/local_threshold_debug.hh> + + + +// extern mln::image2d<double> skewness; + +namespace scribo +{ + + namespace binarization + { + + namespace internal + { + + using namespace mln; + + + /*! \brief Compute a point wise threshold according to a local + binarization formula. + + \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). + \param[in] formula The function to use to compute the local + threshold. + + \return A threshold. + */ + template <typename P, typename J, typename F> + double + compute_local_threshold(const P& p, + const J& simple, + const J& squared, + int win_width, double K, double R, + const F& formula); + + + +# ifndef MLN_INCLUDE_ONLY + + + template <typename P, typename J, typename F> + double + compute_local_threshold(const P& p, + const J& simple, + const J& squared, + int win_width, double K, double R, + const F& formula) + { + 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_LOCAL_THRESHOLD_DEBUG + // Store local mean + debug_mean(p) = m_x_y * mean_debug_factor; +# endif // ! SCRIBO_LOCAL_THRESHOLD_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_LOCAL_THRESHOLD_DEBUG + // Store local standard deviation + debug_stddev(p) = s_x_y * stddev_debug_factor; +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG + + // Thresholding. + // skewness_ = skewness(p); + // b = (p == point2d(5,5)); + double t_x_y = formula(m_x_y, s_x_y, K, R); + +# ifdef SCRIBO_LOCAL_THRESHOLD_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_LOCAL_THRESHOLD_DEBUG + + return t_x_y; + } + + + template <typename P, typename J, typename F> + double + compute_local_threshold_single_image(const P& p, + const J& integral, + int win_width, + double K, double R, + const F& formula) + { + // 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_LOCAL_THRESHOLD_DEBUG + // Store local mean + debug_mean(p) = m_x_y * mean_debug_factor; +# endif // ! SCRIBO_LOCAL_THRESHOLD_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_LOCAL_THRESHOLD_DEBUG + // Store local standard deviation + debug_stddev(p) = s_x_y * stddev_debug_factor; +# endif // !SCRIBO_LOCAL_THRESHOLD_DEBUG + + // Thresholding. + double t_x_y = formula(m_x_y, s_x_y, K, R); + +# ifdef SCRIBO_LOCAL_THRESHOLD_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_LOCAL_THRESHOLD_DEBUG + + return t_x_y; + } + + +#endif // ! MLN_INCLUDE_ONLY + + } // end of namespace scribo::binarization::internal + + } // end of namespace scribo::binarization + +} // end of namespace scribo + +#endif // ! SCRIBO_BINARIZATION_INTERNAL_COMPUTE_LOCAL_THRESHOLD_HH diff --git a/scribo/scribo/binarization/internal/compute_sauvola_threshold.hh b/scribo/scribo/binarization/internal/compute_sauvola_threshold.hh deleted file mode 100644 index d3ca07f..0000000 --- a/scribo/scribo/binarization/internal/compute_sauvola_threshold.hh +++ /dev/null @@ -1,285 +0,0 @@ -// 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 0b1a7ac..8da401b 100644 --- a/scribo/scribo/binarization/internal/first_pass_functor.hh +++ b/scribo/scribo/binarization/internal/first_pass_functor.hh @@ -37,7 +37,11 @@ # include <mln/value/int_u8.hh> # include <mln/data/fill.hh> -# include <scribo/binarization/sauvola_threshold_image.hh> +# include <scribo/binarization/internal/sauvola_formula.hh> + +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG +# include <scribo/binarization/internal/local_threshold_debug.hh> +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG namespace scribo @@ -67,8 +71,11 @@ namespace scribo mln::util::array<int> dp; double K_; + double R_; + + sauvola_formula formula_; - first_pass_functor(const I& input, double K); + first_pass_functor(const I& input, double K, double R); void exec(double mean, double stddev); void finalize(); @@ -88,10 +95,11 @@ namespace scribo template <typename I> - first_pass_functor<I>::first_pass_functor(const I& input, double K) + first_pass_functor<I>::first_pass_functor(const I& input, double K, double R) : input(input), pxl(input), - K_(K) + K_(K), + R_(R) { res = 0; pxl.start(); @@ -100,10 +108,10 @@ namespace scribo initialize(parent, input); initialize(msk, input); -# ifdef SCRIBO_SAUVOLA_DEBUG +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG initialize(debug_mean, input); initialize(debug_stddev, input); -# endif // ! SCRIBO_SAUVOLA_DEBUG +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG mln::extension::fill(msk, false); @@ -124,9 +132,7 @@ namespace scribo unsigned p = pxl.offset(); value::int_u8 t_p; - mln::convert::from_to(sauvola_threshold_formula(mean, stddev, - K_, - SCRIBO_DEFAULT_SAUVOLA_R), + mln::convert::from_to(formula_(mean, stddev, K_, R_), t_p); msk.element(p) = input.element(p) < t_p; diff --git a/scribo/scribo/binarization/internal/local_threshold_debug.hh b/scribo/scribo/binarization/internal/local_threshold_debug.hh new file mode 100644 index 0000000..a9da06c --- /dev/null +++ b/scribo/scribo/binarization/internal/local_threshold_debug.hh @@ -0,0 +1,88 @@ +// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory +// (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_BINARIZATION_INTERNAL_LOCAL_THRESHOLD_DEBUG_HH +# define SCRIBO_BINARIZATION_INTERNAL_LOCAL_THRESHOLD_DEBUG_HH + +/// \file +/// +/// \brief Declare all debug related variables for local based +/// algorithms. + + +/// FIXME: A struct may be a bit better... + + +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG + +# ifndef MLN_INCLUDE_ONLY + + +namespace scribo +{ + + 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 + + +# endif // ! MLN_INCLUDE_ONLY + +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG + + +#endif // ! SCRIBO_BINARIZATION_INTERNAL_LOCAL_THRESHOLD_DEBUG_HH diff --git a/scribo/scribo/binarization/internal/niblack_formula.hh b/scribo/scribo/binarization/internal/niblack_formula.hh new file mode 100644 index 0000000..54dbc9b --- /dev/null +++ b/scribo/scribo/binarization/internal/niblack_formula.hh @@ -0,0 +1,105 @@ +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_BINARIZATION_INTERNAL_NIBLACK_FORMULA_HH +# define SCRIBO_BINARIZATION_INTERNAL_NIBLACK_FORMULA_HH + + +/// \file +/// +/// \brief Routines computing a threshold using Niblack's binarization +/// formula. + +// \fixme Having an unused parameter to fulfill the required interface +// may not be the best solution... + +// Setup default Niblack's formula parameters values. +# define SCRIBO_DEFAULT_NIBLACK_K -0.2 + + + +namespace scribo +{ + + namespace binarization + { + + namespace internal + { + + struct niblack_formula + { + + /*! \brief compute a threshold using Niblack's 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). Unused in this formula. + + \return A threshold. + */ + double operator()(const double m_x_y, const double s_x_y, + const double K, const double R) const; + + /*! + \overload K = 0.34. + */ + double operator()(const double m_x_y, const double s_x_y) const; + + }; + + +# ifndef MLN_INCLUDE_ONLY + + inline + double + niblack_formula::operator()(const double m_x_y, const double s_x_y, + const double K, const double /*R*/) const + { + return m_x_y + K * s_x_y; + } + + inline + double + niblack_formula::operator()(const double m_x_y, const double s_x_y) const + { + return (*this)(m_x_y, s_x_y, + SCRIBO_DEFAULT_NIBLACK_K, 128); + } + + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace scribo::binarization::internal + + } // end of namespace scribo::binarization + +} // end of namespace scribo + +#endif // ! SCRIBO_BINARIZATION_INTERNAL_NIBLACK_FORMULA_HH diff --git a/scribo/scribo/binarization/internal/sauvola_debug.hh b/scribo/scribo/binarization/internal/sauvola_debug.hh deleted file mode 100644 index 0f8ccf0..0000000 --- a/scribo/scribo/binarization/internal/sauvola_debug.hh +++ /dev/null @@ -1,87 +0,0 @@ -// 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_SAUVOLA_DEBUG_HH -# define SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_DEBUG_HH - -/// \file -/// -/// \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 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 - - -# endif // ! MLN_INCLUDE_ONLY - -# endif // ! SCRIBO_SAUVOLA_DEBUG - - -#endif // ! SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_DEBUG_HH diff --git a/scribo/scribo/binarization/internal/sauvola_formula.hh b/scribo/scribo/binarization/internal/sauvola_formula.hh new file mode 100644 index 0000000..3251abd --- /dev/null +++ b/scribo/scribo/binarization/internal/sauvola_formula.hh @@ -0,0 +1,121 @@ +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_FORMULA_HH +# define SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_FORMULA_HH + + +/// \file +/// +/// \brief Routines computing a threshold using Sauvola's binarization +/// formula. + + +// Setup default Sauvola's formula parameters values. +// These macros may be used in other variant of Sauvola's algorithms. +// +// 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 for Sauvola. +# 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 + { + + struct sauvola_formula + { + + /*! \brief Compute a threshold using Sauvola's 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. + */ + double operator()(const double m_x_y, const double s_x_y, + const double K, const double R) const; + + /*! + \overload K = 0.34 and R = 128. + */ + double operator()(const double m_x_y, const double s_x_y) const; + + }; + + +# ifndef MLN_INCLUDE_ONLY + + bool b; + double skewness_; + + inline + double + sauvola_formula::operator()(const double m_x_y, const double s_x_y, + const double K, const double R) const + { + // if (b) + // std::cout << skewness_ << " - " << (K * -1 * skewness_) << std::endl; + // volatile double new_t = ((skewness_ < 0) ? -skewness_ : 1 * m_x_y * (1.0 + K * ((s_x_y / R) - 1.0))); + // volatile double old_t = (m_x_y * (1.0 + K * ((s_x_y / R) - 1.0))); + // if (skewness_ > 0) + // if (new_t != old_t) + // std::cout << skewness_ << " - " << new_t << " vs " << old_t << std::endl; + + return m_x_y * (1.0 + K * ((s_x_y / R) - 1.0)); + } + + inline + double + sauvola_formula::operator()(const double m_x_y, const double s_x_y) const + { + return (*this)(m_x_y, s_x_y, + 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_SAUVOLA_FORMULA_HH diff --git a/scribo/scribo/binarization/niblack.hh b/scribo/scribo/binarization/niblack.hh new file mode 100644 index 0000000..e66e7b4 --- /dev/null +++ b/scribo/scribo/binarization/niblack.hh @@ -0,0 +1,218 @@ +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_BINARIZATION_NIBLACK_HH +# define SCRIBO_BINARIZATION_NIBLACK_HH + +/// \file +/// +/// + +# include <mln/core/concept/image.hh> +# include <mln/data/transform.hh> +# include <mln/value/int_u8.hh> + +# include <scribo/binarization/niblack_threshold.hh> +# include <scribo/binarization/local_threshold.hh> +# include <scribo/binarization/internal/local_threshold_debug.hh> + +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG +# include <mln/io/pgm/save.hh> +# include <mln/io/pbm/save.hh> +# include <mln/data/saturate.hh> +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG + +namespace scribo +{ + + namespace binarization + { + + using namespace mln; + + + /*! \brief Convert an image into a binary image. + + \input[in] input An image. + \input[in] window_size The window size. + \input[in] K Niblack's formulae constant. + + \return A binary image. + + */ + template <typename I> + mln_ch_value(I, bool) + niblack(const Image<I>& input, unsigned window_size, double K); + + + + /*! \brief Convert an image into a binary image. + + Niblack's formulae constant K is set to 0.34. + + \input[in] input An image. + \input[in] window_size The window size. + + \return A binary image. + + */ + template <typename I> + mln_ch_value(I, bool) + niblack(const Image<I>& input, unsigned window_size); + + + /// \overload + /// The window size is set to 11. + // + template <typename I> + mln_ch_value(I, bool) + niblack(const Image<I>& input); + + +# ifndef MLN_INCLUDE_ONLY + + + // Implementations. + + namespace impl + { + + namespace generic + { + + template <typename I> + mln_ch_value(I, bool) + niblack(const Image<I>& input, unsigned window_size, double K) + { + trace::entering("scribo::binarization::impl::generic::niblack"); + mln_precondition(exact(input).is_valid()); + + mln_ch_value(I,value::int_u8) + threshold_image = binarization::niblack_threshold(input, window_size, K); + + mln_ch_value(I, bool) + output = local_threshold(input, threshold_image); + + trace::exiting("scribo::binarization::impl::generic::niblack"); + return output; + } + + } // end of namespace scribo::binarization::impl::generic + + + } // end of namespace scribo::binarization::impl + + + + // Dispatch + + namespace internal + { + + template <typename I> + mln_ch_value(I, bool) + niblack_dispatch(const mln_value(I)&, + const Image<I>& input, unsigned window_size, + double K) + { + return impl::generic::niblack(input, window_size, K); + } + + + template <typename I> + mln_ch_value(I, bool) + niblack_dispatch(const Image<I>& input, unsigned window_size, + double K) + { + typedef mln_value(I) V; + return niblack_dispatch(V(), input, window_size, K); + } + + } // end of namespace scribo::binarization::internal + + + + // Facades + + template <typename I> + mln_ch_value(I, bool) + niblack(const Image<I>& input, unsigned window_size, double K) + { + trace::entering("scribo::binarization::niblack"); + + mln_precondition(exact(input).is_valid()); + + mln_ch_value(I, bool) + output = internal::niblack_dispatch(input, window_size, K); + +# ifdef SCRIBO_LOCAL_THRESHOLD_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_LOCAL_THRESHOLD_DEBUG + + + trace::exiting("scribo::binarization::niblack"); + return output; + } + + + template <typename I> + mln_ch_value(I, bool) + niblack(const Image<I>& input, unsigned window_size) + { + return niblack(input, window_size, SCRIBO_DEFAULT_NIBLACK_K); + } + + + template <typename I> + mln_ch_value(I, bool) + niblack(const Image<I>& input) + { + return niblack(input, 11); + } + + +# endif // ! MLN_INCLUDE_ONLY + + + } // end of namespace scribo::binarization + +} // end of namespace scribo + + +#endif // ! SCRIBO_BINARIZATION_NIBLACK_HH diff --git a/scribo/scribo/binarization/niblack_threshold.hh b/scribo/scribo/binarization/niblack_threshold.hh new file mode 100644 index 0000000..db4a74e --- /dev/null +++ b/scribo/scribo/binarization/niblack_threshold.hh @@ -0,0 +1,299 @@ +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_BINARIZATION_NIBLACK_THRESHOLD_HH +# define SCRIBO_BINARIZATION_NIBLACK_THRESHOLD_HH + +/// \file +/// +/// Compute an image of local threshold using Niblack algorithm. + +/// \fixme return type too restrictive! +/// \fixme Revamp code and merge with sauvola_threshold.hh. + +# include <algorithm> +# include <cmath> + +# include <mln/core/image/image2d.hh> +# include <mln/value/int_u.hh> +# include <mln/value/int_u8.hh> + +# include <scribo/core/init_integral_image.hh> +# include <scribo/binarization/internal/compute_local_threshold.hh> +# include <scribo/binarization/internal/niblack_formula.hh> + + + +namespace scribo +{ + + namespace binarization + { + + using namespace mln; + + /*! \brief Compute an image of local threshold using Niblack algorithm. + + \input[in] input A gray level 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) + niblack_threshold(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) + niblack_threshold(const Image<I>& input, unsigned window_size, + double K); + + /// \overload + /// K is set to 0.34 + template <typename I> + mln_ch_value(I, value::int_u8) + niblack_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) + niblack_threshold(const Image<I>& input); + + + +# ifndef MLN_INCLUDE_ONLY + + + // Implementation + + + namespace impl + { + + namespace generic + { + + template <typename I, typename J> + inline + mln_concrete(I) + niblack_threshold(const Image<I>& input_, unsigned window_size, + double K, + Image<J>& simple_, + Image<J>& squared_) + { + trace::entering("scribo::binarization::impl::generic::niblack_threshold"); + + const I& input = exact(input_); + 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; + +# 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 + + mln_concrete(I) output; + initialize(output, input); + + const mln::def::coord + nrows = static_cast<mln::def::coord>(input.nrows()), + ncols = static_cast<mln::def::coord>(input.ncols()); + + + internal::niblack_formula formula; + for(mln::def::coord row = 0; row < nrows; ++row) + for(mln::def::coord col = 0; col < ncols; ++col) + { + // FIXME: Setting R parameter to 128 should not be + // hard-coded. Even though it is not used in Niblack's + // formula, this parameter is used for debug images and + // should be adapted to the data range values. + double t = internal::compute_local_threshold(P(row, col), simple, + squared, window_size, + K, + 128, + formula); + mln::convert::from_to(t, output.at_(row, col)); + +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG + internal::debug_threshold.at_(row, col) = t; +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG + } + + trace::exiting("scribo::binarization::impl::generic::niblack_threshold"); + return output; + } + + } // end of namespace scribo::binarization::impl::generic + + + + template <typename I, typename J> + inline + mln_concrete(I) + niblack_threshold_gl(const I& input, unsigned window_size, + double K, + Image<J>& simple, + Image<J>& squared) + { + return impl::generic::niblack_threshold(input, window_size, K, + simple, squared); + } + + + } // end of namespace scribo::binarization::impl + + + + + // Dispatch + + namespace internal + { + + template <unsigned n, typename I, typename J> + inline + mln_ch_value(I, value::int_u<n>) + niblack_threshold_dispatch(const value::int_u<n>&, const I& input, + unsigned window_size, + double K, + J& simple, + J& squared) + { + return impl::niblack_threshold_gl(input, window_size, K, + simple, squared); + } + + + template <typename I, typename J> + inline + mln_ch_value(I, value::int_u8) + niblack_threshold_dispatch(const mln_value(I)&, const I& input, + 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 J> + mln_ch_value(I, value::int_u8) + niblack_threshold(const Image<I>& input, unsigned window_size, + double K, + Image<J>& simple, + Image<J>& squared) + { + trace::entering("scribo::binarization::niblack_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::niblack_threshold_dispatch(value_t(), + exact(input), + window_size, + K, + exact(simple), + exact(squared)); + + trace::exiting("scribo::text::ppm2pbm"); + return output; + } + + + template <typename I> + inline + mln_ch_value(I, value::int_u8) + niblack_threshold(const Image<I>& input, unsigned window_size, + double K) + { + mln_ch_value(I, double) + simple = init_integral_image(input, scribo::internal::identity_), + squared = init_integral_image(input, scribo::internal::square_); + + return niblack_threshold(input, window_size, + K, simple, squared); + } + + + template <typename I> + inline + mln_ch_value(I, value::int_u8) + niblack_threshold(const Image<I>& input, unsigned window_size) + { + return niblack_threshold(input, window_size, + SCRIBO_DEFAULT_NIBLACK_K); + } + + + template <typename I> + inline + mln_ch_value(I, value::int_u8) + niblack_threshold(const Image<I>& input) + { + return niblack_threshold(input, 11); + } + + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace scribo::binarization + +} // end of namespace scribo + + +#endif // ! SCRIBO_BINARIZATION_NIBLACK_THRESHOLD_HH diff --git a/scribo/scribo/binarization/sauvola.hh b/scribo/scribo/binarization/sauvola.hh index 45891c3..fc3e104 100644 --- a/scribo/scribo/binarization/sauvola.hh +++ b/scribo/scribo/binarization/sauvola.hh @@ -1,5 +1,5 @@ -// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory -// (LRDE) +// Copyright (C) 2009, 2010, 2011 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of Olena. // @@ -35,15 +35,15 @@ # include <mln/data/transform.hh> # include <mln/value/int_u8.hh> -# include <scribo/binarization/sauvola_threshold_image.hh> +# include <scribo/binarization/sauvola_threshold.hh> # include <scribo/binarization/local_threshold.hh> -# include <scribo/binarization/internal/sauvola_debug.hh> +# include <scribo/binarization/internal/local_threshold_debug.hh> -# ifdef SCRIBO_SAUVOLA_DEBUG +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG # include <mln/io/pgm/save.hh> # include <mln/io/pbm/save.hh> # include <mln/data/saturate.hh> -# endif // ! SCRIBO_SAUVOLA_DEBUG +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG namespace scribo { @@ -110,11 +110,11 @@ namespace scribo trace::entering("scribo::binarization::impl::generic::sauvola"); mln_precondition(exact(input).is_valid()); + mln_ch_value(I,value::int_u8) + threshold_image = binarization::sauvola_threshold(input, window_size, K); + mln_ch_value(I, bool) - output = local_threshold(input, - binarization::sauvola_threshold_image(input, - window_size, - K)); + output = local_threshold(input, threshold_image); trace::exiting("scribo::binarization::impl::generic::sauvola"); return output; @@ -168,7 +168,7 @@ namespace scribo mln_ch_value(I, bool) output = internal::sauvola_dispatch(input, window_size, K); -# ifdef SCRIBO_SAUVOLA_DEBUG +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG if (internal::stddev_image_output) io::pgm::save(data::saturate(value::int_u8(), internal::debug_stddev), internal::stddev_image_output); @@ -184,7 +184,7 @@ namespace scribo internal::alpham_image_output); if (internal::alphacond_image_output) io::pbm::save(internal::debug_alphacond, internal::alphacond_image_output); -# endif // ! SCRIBO_SAUVOLA_DEBUG +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG trace::exiting("scribo::binarization::sauvola"); diff --git a/scribo/scribo/binarization/sauvola_ms.hh b/scribo/scribo/binarization/sauvola_ms.hh index c1a3414..36629f9 100644 --- a/scribo/scribo/binarization/sauvola_ms.hh +++ b/scribo/scribo/binarization/sauvola_ms.hh @@ -60,16 +60,15 @@ # include <scribo/core/macros.hh> -# include <scribo/binarization/sauvola_threshold_image.hh> # include <scribo/binarization/internal/first_pass_functor.hh> # include <scribo/canvas/integral_browsing.hh> -# ifdef SCRIBO_SAUVOLA_DEBUG -# include <scribo/binarization/internal/sauvola_debug.hh> +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG +# include <scribo/binarization/internal/local_threshold_debug.hh> # include <mln/io/pgm/save.hh> # include <scribo/make/debug_filename.hh> -# endif // ! SCRIBO_SAUVOLA_DEBUG +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG @@ -179,7 +178,7 @@ namespace scribo // 1st pass scribo::binarization::internal::first_pass_functor< image2d<int_u8> > - f(sub, K); + f(sub, K, SCRIBO_DEFAULT_SAUVOLA_R); scribo::canvas::integral_browsing(integral_sum_sum_2, ratio, w_local_w, w_local_h, @@ -259,10 +258,10 @@ namespace scribo } // end of 2nd pass -# ifdef SCRIBO_SAUVOLA_DEBUG +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG io::pbm::save(f.msk, scribo::make::debug_filename(internal::threshold_image_output).c_str()); -# endif // ! SCRIBO_SAUVOLA_DEBUG +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG return f.t_sub; } @@ -923,18 +922,18 @@ namespace scribo } -# ifdef SCRIBO_SAUVOLA_DEBUG +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG if (internal::scale_image_output) io::pgm::save(e_2, internal::scale_image_output); -# endif // ! SCRIBO_SAUVOLA_DEBUG +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG // Propagate scale values. e_2 = transform::influence_zone_geodesic(e_2, c8()); -// # ifdef SCRIBO_SAUVOLA_DEBUG +// # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG // if (internal::scale_image_output) // io::pgm::save(e_2, internal::scale_image_output); -// # endif // ! SCRIBO_SAUVOLA_DEBUG +// # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG // Binarize image2d<bool> diff --git a/scribo/scribo/binarization/sauvola_threshold.hh b/scribo/scribo/binarization/sauvola_threshold.hh new file mode 100644 index 0000000..df46e95 --- /dev/null +++ b/scribo/scribo/binarization/sauvola_threshold.hh @@ -0,0 +1,296 @@ +// Copyright (C) 2009, 2010, 2011 EPITA Research and Development +// Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_HH +# define SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_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/int_u.hh> +# include <mln/value/int_u8.hh> + +# include <scribo/core/init_integral_image.hh> +# include <scribo/binarization/internal/compute_local_threshold.hh> +# include <scribo/binarization/internal/sauvola_formula.hh> + + + +namespace scribo +{ + + namespace binarization + { + + using namespace mln; + + /*! \brief Compute an image of local threshold using Sauvola algorithm. + + \input[in] input A gray level 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(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(const Image<I>& input, unsigned window_size, + double K); + + /// \overload + /// K is set to 0.34 + 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 + + + // Implementation + + + namespace impl + { + + namespace generic + { + + template <typename I, typename J> + inline + mln_concrete(I) + sauvola_threshold(const Image<I>& input_, unsigned window_size, + double K, + Image<J>& simple_, + Image<J>& squared_) + { + trace::entering("scribo::binarization::impl::generic::sauvola_threshold"); + + const I& input = exact(input_); + 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; + +# 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 + + // Sauvola Algorithm with I.I. + + mln_concrete(I) output; + initialize(output, input); + + const mln::def::coord + nrows = static_cast<mln::def::coord>(input.nrows()), + ncols = static_cast<mln::def::coord>(input.ncols()); + + internal::sauvola_formula formula; + for(mln::def::coord row = 0; row < nrows; ++row) + for(mln::def::coord col = 0; col < ncols; ++col) + { + double t = internal::compute_local_threshold(P(row, col), simple, + squared, window_size, + K, + SCRIBO_DEFAULT_SAUVOLA_R, + formula); + mln::convert::from_to(t, output.at_(row, col)); + +# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG + internal::debug_threshold.at_(row, col) = t; +# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG + } + + trace::exiting("scribo::binarization::impl::generic::sauvola_threshold"); + return output; + } + + } // end of namespace scribo::binarization::impl::generic + + + + template <typename I, typename J> + inline + mln_concrete(I) + sauvola_threshold_gl(const I& input, unsigned window_size, + double K, + Image<J>& simple, + Image<J>& squared) + { + return impl::generic::sauvola_threshold(input, window_size, K, + simple, squared); + } + + + } // end of namespace scribo::binarization::impl + + + + + // Dispatch + + namespace internal + { + + template <unsigned n, typename I, typename J> + inline + mln_ch_value(I, value::int_u<n>) + sauvola_threshold_dispatch(const value::int_u<n>&, const I& input, + unsigned window_size, + double K, + J& simple, + J& squared) + { + return impl::sauvola_threshold_gl(input, window_size, K, + simple, squared); + } + + + template <typename I, typename J> + inline + mln_ch_value(I, value::int_u8) + sauvola_threshold_dispatch(const mln_value(I)&, const I& input, + 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 J> + mln_ch_value(I, value::int_u8) + sauvola_threshold(const Image<I>& input, unsigned window_size, + double K, + Image<J>& simple, + Image<J>& 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, + K, + exact(simple), + exact(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, + double K) + { + mln_ch_value(I, double) + simple = init_integral_image(input, scribo::internal::identity_), + squared = init_integral_image(input, scribo::internal::square_); + + return sauvola_threshold(input, window_size, + K, simple, squared); + } + + + template <typename I> + inline + mln_ch_value(I, value::int_u8) + sauvola_threshold(const Image<I>& input, unsigned window_size) + { + return sauvola_threshold(input, window_size, + SCRIBO_DEFAULT_SAUVOLA_K); + } + + + 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 diff --git a/scribo/scribo/binarization/sauvola_threshold_image.hh b/scribo/scribo/binarization/sauvola_threshold_image.hh deleted file mode 100644 index 94cd688..0000000 --- a/scribo/scribo/binarization/sauvola_threshold_image.hh +++ /dev/null @@ -1,301 +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_HH -# define SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_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/int_u.hh> -# include <mln/value/int_u8.hh> - -# include <scribo/core/init_integral_image.hh> -# include <scribo/binarization/internal/compute_sauvola_threshold.hh> - - - -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(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(const Image<I>& input, unsigned window_size, - double K); - - /// \overload - /// K is set to 0.34 - template <typename I> - mln_ch_value(I, value::int_u8) - sauvola_threshold_image(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_image(const Image<I>& input); - - - -# ifndef MLN_INCLUDE_ONLY - - - // Implementation - - - namespace impl - { - - namespace generic - { - - template <typename I, typename J> - inline - mln_concrete(I) - sauvola_threshold_image(const Image<I>& input_, unsigned window_size, - double K, - Image<J>& simple_, - Image<J>& squared_) - { - trace::entering("scribo::binarization::impl::generic::sauvola_threshold_image"); - - const I& input = exact(input_); - 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; - -# 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); - - const mln::def::coord - nrows = static_cast<mln::def::coord>(input.nrows()), - ncols = static_cast<mln::def::coord>(input.ncols()); - - - for(mln::def::coord row = 0; row < nrows; ++row) - for(mln::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; - } - - } // end of namespace scribo::binarization::impl::generic - - - - template <typename I, typename J> - inline - mln_concrete(I) - sauvola_threshold_image_gl(const I& input, unsigned window_size, - double K, - Image<J>& simple, - Image<J>& squared) - { - return impl::generic::sauvola_threshold_image(input, window_size, K, - simple, squared); - } - - - } // end of namespace scribo::binarization::impl - - - - - // Dispatch - - namespace internal - { - - template <unsigned n, typename I, typename J> - inline - mln_ch_value(I, value::int_u<n>) - sauvola_threshold_image_dispatch(const value::int_u<n>&, const I& input, - unsigned window_size, - double K, - J& simple, - J& squared) - { - return impl::sauvola_threshold_image_gl(input, window_size, K, - simple, squared); - } - - - template <typename I, typename J> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image_dispatch(const mln_value(I)&, const I& input, - 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 J> - mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input, unsigned window_size, - double K, - Image<J>& simple, - Image<J>& squared) - { - trace::entering("scribo::binarization::sauvola_threshold_image"); - - 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_dispatch(value_t(), - exact(input), - window_size, - K, - exact(simple), - exact(squared)); - - trace::exiting("scribo::text::ppm2pbm"); - return output; - } - - - template <typename I> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input, unsigned window_size, - double K) - { - 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(input, window_size, - K, simple, squared); - } - - - template <typename I> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input, unsigned window_size) - { - return sauvola_threshold_image(input, window_size, - SCRIBO_DEFAULT_SAUVOLA_K); - } - - - template <typename I> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input) - { - return sauvola_threshold_image(input, 11); - } - - -# endif // ! MLN_INCLUDE_ONLY - - } // end of namespace scribo::binarization - -} // end of namespace scribo - - -#endif // ! SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_HH diff --git a/scribo/src/binarization/Makefile.am b/scribo/src/binarization/Makefile.am index 315e621..567972a 100644 --- a/scribo/src/binarization/Makefile.am +++ b/scribo/src/binarization/Makefile.am @@ -46,6 +46,7 @@ if HAVE_MAGICKXX sauvola_ms_debug utilexec_PROGRAMS = \ + niblack \ otsu \ sauvola \ sauvola_ms \ @@ -60,6 +61,13 @@ if HAVE_MAGICKXX $(MAGICKXX_LDFLAGS) + niblack_SOURCES = niblack.cc + niblack_CPPFLAGS = $(AM_CPPFLAGS) \ + $(MAGICKXX_CPPFLAGS) + niblack_LDFLAGS = $(AM_LDFLAGS) \ + $(MAGICKXX_LDFLAGS) + + otsu_SOURCES = otsu.cc otsu_CPPFLAGS = $(AM_CPPFLAGS) \ $(MAGICKXX_CPPFLAGS) @@ -80,7 +88,7 @@ if HAVE_MAGICKXX sauvola_debug_SOURCES = sauvola_debug.cc sauvola_debug_CPPFLAGS = $(AM_CPPFLAGS) \ - -DSCRIBO_SAUVOLA_DEBUG \ + -DSCRIBO_LOCAL_THRESHOLD_DEBUG \ $(MAGICKXX_CPPFLAGS) sauvola_debug_LDFLAGS = $(AM_LDFLAGS) \ $(MAGICKXX_LDFLAGS) @@ -94,7 +102,7 @@ if HAVE_MAGICKXX sauvola_ms_debug_SOURCES = sauvola_ms_debug.cc sauvola_ms_debug_CPPFLAGS = $(AM_CPPFLAGS) \ - -DSCRIBO_SAUVOLA_DEBUG \ + -DSCRIBO_LOCAL_THRESHOLD_DEBUG \ $(MAGICKXX_CPPFLAGS) sauvola_ms_debug_LDFLAGS = $(AM_LDFLAGS) \ $(MAGICKXX_LDFLAGS) diff --git a/scribo/src/binarization/niblack.cc b/scribo/src/binarization/niblack.cc new file mode 100644 index 0000000..4b7ed91 --- /dev/null +++ b/scribo/src/binarization/niblack.cc @@ -0,0 +1,106 @@ +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#include <mln/core/image/image2d.hh> +#include <mln/value/int_u8.hh> +#include <mln/io/magick/load.hh> +#include <mln/io/pbm/save.hh> +#include <mln/data/transform.hh> +#include <mln/fun/v2v/rgb_to_luma.hh> + +#include <scribo/binarization/niblack.hh> +#include <scribo/debug/option_parser.hh> +#include <scribo/debug/logger.hh> + +static const scribo::debug::arg_data arg_desc[] = +{ + { "input.*", "An image." }, + { "output.pbm", "A binary image." }, + {0, 0} +}; + + +// --enable/disable-<name> +static const scribo::debug::toggle_data toggle_desc[] = +{ + // name, description, default value + {0, 0, false} +}; + + +// --<name> <args> +static const scribo::debug::opt_data opt_desc[] = +{ + // name, description, arguments, check args function, number of args, default arg + { "debug-prefix", "Enable debug image outputs. Prefix image name with that " + "given prefix.", "<prefix>", 0, 1, 0 }, + { "k", "Niblack's formulae parameter", "<value>", 0, 1, "-0.2" }, + { "verbose", "Enable verbose mode", 0, 0, 0, 0 }, + { "win-size", "Window size", "<size>", 0, 1, "101" }, + {0, 0, 0, 0, 0, 0} +}; + + + +int main(int argc, char *argv[]) +{ + using namespace mln; + + scribo::debug::option_parser options(arg_desc, toggle_desc, opt_desc); + + if (!options.parse(argc, argv)) + return 1; + + // Enable debug output. + if (options.is_set("debug-prefix")) + { + scribo::debug::logger().set_filename_prefix(options.opt_value("debug-prefix").c_str()); + scribo::debug::logger().set_level(scribo::debug::All); + } + + Magick::InitializeMagick(*argv); + + trace::entering("main"); + + bool verbose = options.is_set("verbose"); + unsigned w = atoi(options.opt_value("win-size").c_str()); + double k = atof(options.opt_value("k").c_str()); + + if (verbose) + std::cout << "Using w=" << w << " and k=" << k << std::endl; + + image2d<value::rgb8> input; + io::magick::load(input, options.arg("input.*")); + + // Convert to Gray level image. + image2d<value::int_u8> + input_1_gl = data::transform(input, mln::fun::v2v::rgb_to_luma<value::int_u8>()); + + image2d<bool> out = scribo::binarization::niblack(input_1_gl, w, k); + + io::pbm::save(out, options.arg("output.pbm")); + + trace::exiting("main"); +} diff --git a/scribo/src/binarization/pgm_sauvola_threshold_image.cc b/scribo/src/binarization/pgm_sauvola_threshold_image.cc index a38784a..69e2e15 100644 --- a/scribo/src/binarization/pgm_sauvola_threshold_image.cc +++ b/scribo/src/binarization/pgm_sauvola_threshold_image.cc @@ -1,4 +1,5 @@ -// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -25,7 +26,7 @@ #include <mln/io/pgm/all.hh> -#include <scribo/binarization/sauvola.hh> +#include <scribo/binarization/sauvola_threshold.hh> #include <scribo/debug/usage.hh> const char *args_desc[][2] = @@ -67,7 +68,7 @@ int main(int argc, char *argv[]) image2d<value::int_u8> input; io::pgm::load(input, argv[1]); - image2d<value::int_u8> out = scribo::binarization::sauvola_threshold_image(input, w, k); + image2d<value::int_u8> out = scribo::binarization::sauvola_threshold(input, w, k); io::pgm::save(out, argv[2]); diff --git a/scribo/tests/binarization/Makefile.am b/scribo/tests/binarization/Makefile.am index b8ab2d9..a2962bb 100644 --- a/scribo/tests/binarization/Makefile.am +++ b/scribo/tests/binarization/Makefile.am @@ -21,6 +21,7 @@ include $(top_srcdir)/scribo/tests/tests.mk EXTRA_DIST = \ + niblack.res.pbm \ sauvola_ms.ref.pbm \ sauvola.ref.pbm \ otsu.ref.pbm @@ -28,6 +29,7 @@ EXTRA_DIST = \ check_PROGRAMS = \ global_threshold \ local_threshold \ + niblack \ otsu \ sauvola \ sauvola_ms @@ -35,6 +37,7 @@ check_PROGRAMS = \ global_threshold_SOURCES = global_threshold.cc local_threshold_SOURCES = local_threshold.cc +niblack_SOURCES = niblack.cc otsu_SOURCES = otsu.cc sauvola_SOURCES = sauvola.cc sauvola_ms_SOURCES = sauvola_ms.cc diff --git a/scribo/tests/binarization/niblack.cc b/scribo/tests/binarization/niblack.cc new file mode 100644 index 0000000..99a58e2 --- /dev/null +++ b/scribo/tests/binarization/niblack.cc @@ -0,0 +1,52 @@ +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +/// \file + +#include <mln/core/image/image2d.hh> +#include <mln/data/compare.hh> +#include <mln/value/int_u8.hh> +#include <mln/io/pgm/load.hh> +#include <mln/io/pbm/load.hh> +#include <mln/io/pbm/save.hh> + +#include <scribo/binarization/niblack.hh> + +#include "tests/data.hh" + +int main() +{ + using namespace mln; + + image2d<value::int_u8> input; + io::pgm::load(input, MILENA_IMG_DIR "/lena.pgm"); + + image2d<bool> bin = scribo::binarization::niblack(input, 101); + + image2d<bool> ref; + io::pbm::load(ref, SCRIBO_TESTS_DIR "binarization/niblack.ref.pbm"); + + mln_assertion(bin == ref); +} diff --git a/scribo/tests/binarization/niblack.ref.pbm b/scribo/tests/binarization/niblack.ref.pbm new file mode 100644 index 0000000..83cf4fb Binary files /dev/null and b/scribo/tests/binarization/niblack.ref.pbm differ -- 1.7.2.5
participants (1)
-
Guillaume Lazzara