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