This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Olena, a generic and efficient image processing platform".
The branch apps-morphers has been created
at 6b931cc6d218c25448e7bf3479c98c16acd7daa1 (commit)
- Log -----------------------------------------------------------------
6b931cc configure.ac: Configure milena/apps/morphers/Makefile.
1e58a78 Add examples of morphers.
-----------------------------------------------------------------------
hooks/post-receive
--
Olena, a generic and efficient image processing platform
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Olena, a generic and efficient image processing platform".
The branch unstable/scribo has been updated
via b340c526ae583ce7be9ea28b63bf98f25aae1add (commit)
via 3b03179e7f4d5bd9354bdfbcc897dfd47968fe05 (commit)
from 6982d67f5d2c708ed42648e039ad0b1cfcc959ab (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
b340c52 m4/oln-with-lib.m4: Lookup for multiple AND single libraries while checking Tesseract availability.
3b03179 scribo/text/recognition.hh: Fix code for Tesseract 3.01 compatibility.
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 5 +++++
m4/oln-with-lib.m4 | 28 ++++++++++++++++++----------
scribo/ChangeLog | 5 +++++
scribo/scribo/text/recognition.hh | 4 ++--
4 files changed, 30 insertions(+), 12 deletions(-)
hooks/post-receive
--
Olena, a generic and efficient image processing platform
* 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