* 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 -> 16498 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(a)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(a)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..adbef13
--- /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 0000000000000000000000000000000000000000..7a3435193f1961f8161b71f8f60f3102d5ebbf87
GIT binary patch
literal 16498
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
literal 0
HcmV?d00001
--
1.7.2.5