* binarization/sauvola.hh: Revamp and now returns a threshold
image. Move parts...
* binarization/sauvola_threshold.hh: ... here. New file.
* binarization/binarize.hh: New routine.
---
scribo/ChangeLog | 11 +
scribo/binarization/binarize.hh | 180 +++++++++++
scribo/binarization/sauvola.hh | 307 ++++++--------------
scribo/binarization/sauvola_threshold.hh | 478 ++++++++++++++++++++++++++++++
4 files changed, 753 insertions(+), 223 deletions(-)
create mode 100644 scribo/binarization/binarize.hh
create mode 100644 scribo/binarization/sauvola_threshold.hh
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index f397523..deee412 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,3 +1,14 @@
+2009-10-22 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Revamp Sauvola binarization.
+
+ * binarization/sauvola.hh: Revamp and now returns a threshold
+ image. Move parts...
+
+ * binarization/sauvola_threshold.hh: ... here. New file.
+
+ * binarization/binarize.hh: New routine.
+
2009-10-12 Roland Levillain <roland(a)lrde.epita.fr>
* headers.mk, tests/unit_test/unit-tests.mk: Regen.
diff --git a/scribo/binarization/binarize.hh b/scribo/binarization/binarize.hh
new file mode 100644
index 0000000..0f323bb
--- /dev/null
+++ b/scribo/binarization/binarize.hh
@@ -0,0 +1,180 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_BINARIZE_HH
+# define SCRIBO_BINARIZATION_BINARIZE_HH
+
+# include <mln/core/concept/image.hh>
+# include <mln/value/concept/vectorial.hh>
+
+/// \file
+///
+/// Binarize an image from a threshold image.
+
+namespace scribo
+{
+
+ using namespace mln;
+
+
+ namespace binarization
+ {
+
+ namespace internal
+ {
+
+ template <typename I, typename T>
+ void
+ binarize_tests(const Image<I>& input, const Image<T>&
threshold)
+ {
+ mln_precondition(exact(input).is_valid());
+ mln_precondition(exact(threshold).is_valid());
+ mln_precondition(exact(input).domain() == exact(threshold).domain());
+ mlc_is_not_a(mln_value(I), value::Vectorial)::check();
+ (void) input;
+ (void) threshold;
+ }
+
+ } // end of namespace scribo::binarization::internal
+
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+ template <typename I, typename T>
+ mln_ch_value(I, bool)
+ binarize(const Image<I>& input_, const Image<T>& threshold_)
+ {
+ trace::entering("scribo::binarization::impl::generic::binarize");
+
+ internal::binarize_tests(input_, threshold_);
+
+ const I& input = exact(input_);
+ const T& threshold = exact(threshold_);
+
+ mln_ch_value(I, bool) output;
+ initialize(output, input);
+
+ mln_piter(I) p(input.domain());
+ for_all(p)
+ output(p) = (input(p) <= threshold(p));
+
+
+ trace::exiting("scribo::binarization::impl::generic::binarize");
+ return output;
+ }
+
+
+ } // end of namespace scribo::binarization::impl::generic
+
+
+ template <typename I, typename T>
+ mln_ch_value(I, bool)
+ binarize_fastest(const Image<I>& input_, const Image<T>&
threshold_)
+ {
+ trace::entering("scribo::binarization::impl::generic::binarize_fastest");
+ internal::binarize_tests(input_, threshold_);
+
+ const I& input = exact(input_);
+ const T& threshold = exact(threshold_);
+
+ typedef mln_ch_value(I, bool) O;
+ O output;
+ initialize(output, input);
+
+ mln_pixter(const I) pi(input);
+ mln_pixter(const T) pt(threshold);
+ mln_pixter(O) po(output);
+ for_all_3(pi, pt, po)
+ po.val() = pi.val() <= pt.val();
+
+ trace::exiting("scribo::binarization::impl::generic::binarize_fastest");
+ return output;
+ }
+
+
+
+ } // end of namespace scribo::binarization::impl
+
+
+ namespace internal
+ {
+
+ template <typename I, typename T>
+ mln_ch_value(I, bool)
+ binarize_dispatch(trait::image::value_alignment::any,
+ trait::image::speed::any,
+ const Image<I>& input, const Image<T>& threshold)
+ {
+ return impl::generic::binarize(input, threshold);
+ }
+
+
+ template <typename I, typename T>
+ mln_ch_value(I, bool)
+ binarize_dispatch(trait::image::value_alignment::with_grid,
+ trait::image::speed::fastest,
+ const Image<I>& input, const Image<T>& threshold)
+ {
+ return impl::binarize_fastest(input, threshold);
+ }
+
+ template <typename I, typename T>
+ mln_ch_value(I, bool)
+ binarize_dispatch(const Image<I>& input, const Image<T>&
threshold)
+ {
+ return binarize_dispatch(mln_trait_image_value_alignment(I)(),
+ mln_trait_image_speed(I)(),
+ exact(input), exact(threshold));
+ }
+
+ } // end of namespace scribo::binarization::internal
+
+
+ template <typename I, typename T>
+ mln_ch_value(I, bool)
+ binarize(const Image<I>& input, const Image<T>& threshold)
+ {
+ trace::entering("scribo::binarization::binarize");
+
+ internal::binarize_tests(input, threshold);
+
+ mln_ch_value(I, bool)
+ output = internal::binarize_dispatch(input, threshold);
+
+ trace::exiting("scribo::binarization::binarize");
+ return output;
+ }
+
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+
+#endif // ! SCRIBO_BINARIZATION_BINARIZE_HH
diff --git a/scribo/binarization/sauvola.hh b/scribo/binarization/sauvola.hh
index b9f78f8..5323847 100644
--- a/scribo/binarization/sauvola.hh
+++ b/scribo/binarization/sauvola.hh
@@ -28,21 +28,15 @@
/// \file
///
-/// Convert an image into a binary image.
-
-# include <algorithm>
-# include <cmath>
-
-# include <mln/core/image/image2d.hh>
-# include <mln/value/rgb8.hh>
-# include <mln/value/int_u.hh>
-# include <mln/value/int_u8.hh>
+///
+# include <mln/core/concept/image.hh>
# include <mln/data/transform.hh>
-# include <mln/pw/all.hh>
-# include <mln/core/routine/duplicate.hh>
-
+# include <mln/value/int_u8.hh>
+# include <mln/value/rgb8.hh>
+# include <scribo/binarization/sauvola_threshold.hh>
+# include <scribo/binarization/binarize.hh>
namespace scribo
@@ -53,104 +47,31 @@ namespace scribo
using namespace mln;
+
/*! \brief Convert an image into a binary image.
- \input[in] An image.
+ \input[in] input An image.
+ \input[in] window_size The window size.
\return A binary image.
*/
template <typename I>
- mln_ch_value(I,bool)
- sauvola(const Image<I>& input);
-
-
-
-# ifndef MLN_INCLUDE_ONLY
-
-
- namespace internal
- {
-
- template <typename T>
- class integral_image
- {
- public:
-
- template<class F>
- integral_image(const image2d<T>& i, F func)
- : img_(0),
- nrows_(i.nrows()),
- ncols_(i.ncols())
- {
- img_ = (unsigned long long**)malloc(sizeof(unsigned long long*) * nrows_);
- for (int n = 0; n < nrows_; ++n)
- img_[n] = (unsigned long long*)malloc(sizeof(unsigned long long) * ncols_);
-
- img_[0][0] = func(i.at_(0, 0));
-
- for (int row = 1; row < nrows_; ++row)
- img_[row][0] = (*this)(row - 1, 0) + func(i.at_(row, 0));
-
- for (int col = 1; col < ncols_; ++col)
- img_[0][col] = (*this)(0, col - 1)
- + func(i.at_(0, col));
-
- for (int row = 1; row < nrows_; ++row)
- for (int col = 1; col < ncols_; ++col)
- img_[row][col] = (*this)(row - 1, col)
- + (*this)(row, col - 1)
- - (*this)(row - 1, col - 1)
- + func(i.at_(row, col));
- }
-
- ~integral_image()
- {
- for (int n = 0; n < nrows_; ++n)
- free(img_[n]);
- free(img_);
- }
-
- unsigned long long operator()(int row, int col) const
- {
- return img_[row][col];
- }
-
- private:
- unsigned long long** img_;
- int nrows_;
- int ncols_;
- };
-
-
- struct rgb8_to_int_u8 : Function_v2v< rgb8_to_int_u8 >
- {
- typedef value::int_u8 result;
- result operator()(const value::rgb8& c) const
- {
- return (c.red() + c.green() + c.blue()) / 3;
- }
- };
-
-
- unsigned long long square_(const value::int_u8& val)
- {
- unsigned long long v = static_cast<unsigned long long>(val);
- return v * v;
- }
-
- unsigned long long identity_(const value::int_u8& val)
- {
- return static_cast<unsigned long long>(val);
- }
-
- } // end of namespace scribo::binarization::internal
+ mln_ch_value(I, bool)
+ sauvola(const Image<I>& input, unsigned window_size);
+ /// \overload
+ /// The window size is set to 11.
+ //
+ template <typename I>
+ mln_ch_value(I, bool)
+ sauvola(const Image<I>& input);
- // Implementation
+# ifndef MLN_INCLUDE_ONLY
+ // Implementations.
namespace impl
{
@@ -159,73 +80,16 @@ namespace scribo
{
template <typename I>
- inline
mln_ch_value(I, bool)
- sauvola(const I& input)
+ sauvola(const Image<I>& input, unsigned window_size)
{
trace::entering("scribo::binarization::impl::generic::sauvola");
+ mln_precondition(exact(input).is_valid());
- typedef mln_value(I) V;
-
- // Value of the window size
- const unsigned int w = 11;
-
- // Control the threshold value in the local window
- // The higher, the lower the threshold form the local
- // mean m(x, y). Badekas et al. said 0.34 was best.
- const double k = 0.34;
-
- // Maximum value of the standard deviation (128 for
- // grayscale documents).
- const double R = 128;
-
- // Compute the sum of all intensities of input
- internal::integral_image<V> simple(input, internal::identity_);
-
- // Compute the sum of all squared intensities of input
- internal::integral_image<V> squared(input, internal::square_);
-
- int w_2 = w >> 1;
-
- // Savaula Algorithm with I.I.
-
- image2d<bool> output;
- initialize(output, input);
-
- const def::coord nrows = static_cast<def::coord>(input.nrows());
- const def::coord ncols = static_cast<def::coord>(input.ncols());
-
- for(def::coord row = 0; row < nrows; ++row)
- for(def::coord col = 0; col < ncols; ++col)
- {
- int row_min = std::max(0, row - w_2);
- int col_min = std::max(0, col - w_2);
- int row_max = std::min(nrows - 1, row + w_2);
- int col_max = std::min(ncols - 1, col + w_2);
-
- double wh = (row_max - row_min + 1) * (col_max - col_min + 1);
-
- // Mean.
- double m_x_y_tmp = (simple(row_max, col_max)
- + simple(row_min, col_min)
- - simple(row_max, col_min)
- - simple(row_min, col_max));
-
- double m_x_y = m_x_y_tmp / wh;
-
- // Standard deviation.
- double s_x_y_tmp = (squared(row_max, col_max)
- + squared(row_min, col_min)
- - squared(row_max, col_min)
- - squared(row_min, col_max));
-
- double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh -
1.f));
-
- // Thresholding.
- double t_x_y = m_x_y * (1.0 + k * ((s_x_y / R) - 1.0));
-
- output.at_(row, col) = (input.at_(row, col) < t_x_y);
- }
+ mln_ch_value(I, bool)
+ output = binarize(input,
+ binarization::sauvola_threshold(input,
+ window_size));
trace::exiting("scribo::binarization::impl::generic::sauvola");
return output;
@@ -234,98 +98,95 @@ namespace scribo
} // end of namespace scribo::binarization::impl::generic
- template <typename I>
- inline
- mln_ch_value(I, bool)
- sauvola_gl(const I& input)
- {
- return impl::generic::sauvola(input);
- }
+ template <typename I>
+ mln_ch_value(I, bool)
+ sauvola_rgb8(const Image<I>& input, unsigned window_size)
+ {
+ trace::entering("scribo::binarization::impl::generic::sauvola");
+ mln_precondition(exact(input).is_valid());
+ mln_ch_value(I, value::int_u8) gima;
+ gima = data::transform(input, internal::rgb8_to_int_u8());
- template <typename I>
- inline
mln_ch_value(I, bool)
- sauvola_rgb8(const I& input)
- {
- trace::entering("scribo::binarization::impl::sauvola_rgb8");
+ output = binarize(gima,
+ binarization::sauvola_threshold(gima,
+ window_size));
- mln_ch_value(I, value::int_u8) gima;
- gima = data::transform(input,
- internal::rgb8_to_int_u8());
+ trace::exiting("scribo::binarization::impl::generic::sauvola");
+ return output;
+ }
- mln_ch_value(I, bool) output = impl::generic::sauvola(gima);
+ } // end of namespace scribo::binarization::impl
- trace::exiting("scribo::binarization::impl::sauvola_rgb8");
- return output;
- }
- } // end of namespace scribo::binarization::impl
+ // Dispatch
+ namespace internal
+ {
+ template <typename I>
+ mln_ch_value(I, bool)
+ sauvola_dispatch(const mln_value(I)&,
+ const Image<I>& input, unsigned window_size)
+ {
+ return impl::generic::sauvola(input, window_size);
+ }
+ template <typename I>
+ mln_ch_value(I, bool)
+ sauvola_dispatch(const value::rgb8&,
+ const Image<I>& input, unsigned window_size)
+ {
+ return impl::sauvola_rgb8(input, window_size);
+ }
- // Dispatch
- namespace internal
+ template <typename I>
+ mln_ch_value(I, bool)
+ sauvola_dispatch(const Image<I>& input, unsigned window_size)
{
+ typedef mln_value(I) V;
+ return sauvola_dispatch(V(), input, window_size);
+ }
- template <typename I, unsigned n>
- inline
- mln_ch_value(I, bool)
- sauvola_dispatch(const value::int_u<n>&, const I& input)
- {
- return impl::sauvola_gl(input);
- }
-
- template <typename I>
- inline
- mln_ch_value(I, bool)
- sauvola_dispatch(const value::rgb8&, const I& input)
- {
- return impl::sauvola_rgb8(input);
- }
+ } // end of namespace scribo::binarization::internal
- template <typename I>
- inline
- mln_ch_value(I, bool)
- sauvola_dispatch(const mln_value(I)&, const I& input)
- {
- // No dispatch for this kind of value type.
- mlc_abort(I)::check();
- typedef mln_ch_value(I,bool) output_t;
- return output_t();
- }
+ // Facades
- } // end of namespace scribo::binarization::internal
+ template <typename I>
+ mln_ch_value(I, bool)
+ sauvola(const Image<I>& input, unsigned window_size)
+ {
+ trace::entering("scribo::binarization::sauvola");
+ mln_precondition(exact(input).is_valid());
- template <typename I>
- inline
mln_ch_value(I, bool)
- sauvola(const Image<I>& input)
- {
- trace::entering("scribo::binarization::sauvola");
+ output = internal::sauvola_dispatch(input, window_size);
- mln_precondition(mln_site_(I)::dim == 2);
- mln_precondition(exact(input).is_valid());
+ trace::exiting("scribo::binarization::sauvola");
+ return output;
+ }
- typedef mln_value(I) value_t;
- mln_ch_value(I, bool)
- output = internal::sauvola_dispatch(value_t(), exact(input));
- trace::exiting("scribo::text::ppm2pbm");
- return output;
- }
+ template <typename I>
+ mln_ch_value(I, bool)
+ sauvola(const Image<I>& input)
+ {
+ return sauvola(input, 11);
+ }
+
# endif // ! MLN_INCLUDE_ONLY
+
} // end of namespace scribo::binarization
} // end of namespace scribo
-#endif // ! SCRIBO_TEXT_PPM2PBM_HH
+#endif // ! SCRIBO_BINARIZATION_SAUVOLA_HH
diff --git a/scribo/binarization/sauvola_threshold.hh
b/scribo/binarization/sauvola_threshold.hh
new file mode 100644
index 0000000..9a9e439
--- /dev/null
+++ b/scribo/binarization/sauvola_threshold.hh
@@ -0,0 +1,478 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_HH
+# define SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_HH
+
+/// \file
+///
+/// Convert an image into a binary image.
+
+/// \fixme return type too restrictive!
+
+# include <algorithm>
+# include <cmath>
+
+# include <mln/core/image/image2d.hh>
+# include <mln/value/rgb8.hh>
+# include <mln/value/int_u.hh>
+# include <mln/value/int_u8.hh>
+
+# include <mln/data/transform.hh>
+# include <mln/pw/all.hh>
+# include <mln/core/routine/duplicate.hh>
+
+
+// Forward declaration.
+namespace mln { template <typename T> class integral_image; }
+
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ using namespace mln;
+
+ /*! \brief Compute a threshold image with Sauvola's algorithm.
+
+ \input[in] input An image.
+ \input[in] window_size The window size.x
+ \input[out] simple The sum of all intensities of \p input.
+ \input[out] squared The sum of all squared intensities of \p
+ input.
+
+ \return An image of local thresholds.
+
+ */
+ template <typename I, typename T>
+ mln_ch_value(I, value::int_u8)
+ sauvola_threshold(const Image<I>& input, unsigned window_size,
+ integral_image<T>& simple,
+ integral_image<T>& squared);
+
+
+ /// \overload
+ template <typename I>
+ mln_ch_value(I, value::int_u8)
+ sauvola_threshold(const Image<I>& input, unsigned window_size);
+
+
+ /// \overload
+ /// The window size is set to 11.
+ //
+ template <typename I>
+ mln_ch_value(I, value::int_u8)
+ sauvola_threshold(const Image<I>& input);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ namespace internal
+ {
+
+ struct rgb8_to_int_u8 : Function_v2v< rgb8_to_int_u8 >
+ {
+ typedef value::int_u8 result;
+ result operator()(const value::rgb8& c) const
+ {
+ return (c.red() + c.green() + c.blue()) / 3;
+ }
+ };
+
+
+ unsigned long long square_(const value::int_u8& val)
+ {
+ unsigned long long v = static_cast<unsigned long long>(val);
+ return v * v;
+ }
+
+ unsigned long long identity_(const value::int_u8& val)
+ {
+ return static_cast<unsigned long long>(val);
+ }
+
+
+ /// \brief Compute a point wise threshold according Sauvola's
+ /// binarization.
+ ///
+ /// \param[in] p A site.
+ /// \param[in] simple An integral image of mean values.
+ /// \param[in] squared An integral image of squared mean values.
+ /// \param[in] win_width Window width.
+ /// \param[in] k Control the threshold value in the local
+ /// window. The higher, the lower the threshold
+ /// form the local mean m(x, y).
+ /// \param[in] R Maximum value of the standard deviation (128
+ /// for grayscale documents).
+
+ template <typename P, typename T>
+ double
+ compute_sauvola_threshold(const P& p,
+ const integral_image<T>& simple,
+ const integral_image<T>& squared,
+ int win_width, double k, double R)
+ {
+ mln_precondition(simple.nrows() == squared.nrows());
+ mln_precondition(simple.ncols() == squared.ncols());
+
+ // Window half width.
+ int w_2 = win_width >> 1;
+
+ int row_min = std::max(0, p.row() - w_2);
+ int col_min = std::max(0, p.col() - w_2);
+ int row_max = std::min(simple.nrows() - 1, p.row() + w_2);
+ int col_max = std::min(simple.ncols() - 1, p.col() + w_2);
+
+ double wh = (row_max - row_min + 1) * (col_max - col_min + 1);
+
+ // Mean.
+ double m_x_y_tmp = (simple(row_max, col_max)
+ + simple(row_min, col_min)
+ - simple(row_max, col_min)
+ - simple(row_min, col_max));
+
+ double m_x_y = m_x_y_tmp / wh;
+
+ // Standard deviation.
+ double s_x_y_tmp = (squared(row_max, col_max)
+ + squared(row_min, col_min)
+ - squared(row_max, col_min)
+ - squared(row_min, col_max));
+
+ double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh - 1.f));
+
+ // Thresholding.
+ double t_x_y = m_x_y * (1.0 + k * ((s_x_y / R) - 1.0));
+
+ return t_x_y;
+ }
+
+
+ template <typename P, typename T>
+ double
+ compute_sauvola_threshold(const P& p,
+ const integral_image<T>& simple,
+ const integral_image<T>& squared,
+ int win_width)
+ {
+ // Badekas et al. said 0.34 was best.
+ const double k = 0.34;
+
+ // 128 is best for grayscale documents.
+ const double R = 128;
+
+ return compute_sauvola_threshold(p, simple, squared, win_width, k, R);
+ }
+
+
+ } // end of namespace scribo::binarization::internal
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+
+namespace mln
+{
+
+ template <typename T>
+ class integral_image
+ {
+ public:
+
+ integral_image()
+ : img_(0), nrows_(0), ncols_(0)
+ {}
+
+ template<class F>
+ integral_image(const image2d<T>& i, F func)
+ : img_(0),
+ nrows_(0),
+ ncols_(0)
+ {
+ init_(i, func);
+ }
+
+ template<class F>
+ void init_(const image2d<T>& i, F func)
+ {
+ nrows_ = i.nrows();
+ ncols_ = i.ncols();
+
+ img_ = (unsigned long long**)malloc(sizeof(unsigned long long*) * nrows_);
+ for (int n = 0; n < nrows_; ++n)
+ img_[n] = (unsigned long long*)malloc(sizeof(unsigned long long) * ncols_);
+
+ img_[0][0] = func(i.at_(0, 0));
+
+ for (int row = 1; row < nrows_; ++row)
+ img_[row][0] = (*this)(row - 1, 0) + func(i.at_(row, 0));
+
+ for (int col = 1; col < ncols_; ++col)
+ img_[0][col] = (*this)(0, col - 1)
+ + func(i.at_(0, col));
+
+ for (int row = 1; row < nrows_; ++row)
+ for (int col = 1; col < ncols_; ++col)
+ img_[row][col] = (*this)(row - 1, col)
+ + (*this)(row, col - 1)
+ - (*this)(row - 1, col - 1)
+ + func(i.at_(row, col));
+ }
+
+
+ ~integral_image()
+ {
+ for (int n = 0; n < nrows_; ++n)
+ free(img_[n]);
+ free(img_);
+ }
+
+ bool is_valid() const
+ {
+ return img_ != 0;
+ }
+
+ unsigned long long operator()(int row, int col) const
+ {
+ return img_[row][col];
+ }
+
+ int nrows() const
+ {
+ return nrows_;
+ }
+
+ int ncols() const
+ {
+ return ncols_;
+ }
+
+
+ private:
+ unsigned long long** img_;
+ int nrows_;
+ int ncols_;
+ };
+
+} // end of namespace mln
+
+
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ // Implementation
+
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+ template <typename I, typename T>
+ inline
+ mln_concrete(I)
+ sauvola_threshold(const I& input, unsigned window_size,
+ integral_image<T>& simple,
+ integral_image<T>& squared)
+ {
+ trace::entering("scribo::binarization::impl::generic::sauvola_threshold");
+
+ typedef mln_value(I) V;
+ typedef mln_site(I) P;
+
+ // Compute the sum of all intensities of input
+ simple.init_(input, internal::identity_);
+
+ // Compute the sum of all squared intensities of input
+ squared.init_(input, internal::square_);
+
+ // Savaula Algorithm with I.I.
+
+ mln_concrete(I) output;
+ initialize(output, input);
+
+ const def::coord nrows = static_cast<def::coord>(input.nrows());
+ const def::coord ncols = static_cast<def::coord>(input.ncols());
+
+ for(def::coord row = 0; row < nrows; ++row)
+ for(def::coord col = 0; col < ncols; ++col)
+ output.at_(row, col)
+ = internal::compute_sauvola_threshold(P(row, col), simple,
+ squared, window_size);
+
+ trace::exiting("scribo::binarization::impl::generic::sauvola_threshold");
+ return output;
+ }
+
+ } // end of namespace scribo::binarization::impl::generic
+
+
+
+ template <typename I, typename T>
+ inline
+ mln_concrete(I)
+ sauvola_threshold_gl(const I& input, unsigned window_size,
+ integral_image<T>& simple,
+ integral_image<T>& squared)
+ {
+ return impl::generic::sauvola_threshold(input, window_size,
+ simple, squared);
+ }
+
+
+ template <typename I, typename T>
+ inline
+ mln_ch_value(I, value::int_u8)
+ sauvola_threshold_rgb8(const I& input, unsigned window_size,
+ integral_image<T>& simple,
+ integral_image<T>& squared)
+ {
+ trace::entering("scribo::binarization::impl::sauvola_threshold_rgb8");
+
+ mln_ch_value(I, value::int_u8) gima;
+ gima = data::transform(input,
+ internal::rgb8_to_int_u8());
+
+ mln_ch_value(I, value::int_u8)
+ output = impl::generic::sauvola_threshold(gima, window_size,
+ simple, squared);
+
+ trace::exiting("scribo::binarization::impl::sauvola_threshold_rgb8");
+ return output;
+ }
+
+
+ } // end of namespace scribo::binarization::impl
+
+
+
+
+ // Dispatch
+
+ namespace internal
+ {
+
+ template <unsigned n, typename I, typename T>
+ inline
+ mln_ch_value(I, value::int_u<n>)
+ sauvola_threshold_dispatch(const value::int_u<n>&, const I& input,
+ unsigned window_size,
+ integral_image<T>& simple,
+ integral_image<T>& squared)
+ {
+ return impl::sauvola_threshold_gl(input, window_size, simple, squared);
+ }
+
+ template <typename I, typename T>
+ inline
+ mln_ch_value(I, value::int_u8)
+ sauvola_threshold_dispatch(const value::rgb8&, const I& input,
+ unsigned window_size,
+ integral_image<T>& simple,
+ integral_image<T>& squared)
+ {
+ return impl::sauvola_threshold_rgb8(input, window_size,
+ simple, squared);
+ }
+
+ template <typename I, typename T>
+ inline
+ mln_ch_value(I, value::int_u8)
+ sauvola_threshold_dispatch(const mln_value(I)&, const I& input,
+ unsigned window_size,
+ integral_image<T>& simple,
+ integral_image<T>& squared)
+ {
+ // No dispatch for this kind of value type.
+ mlc_abort(I)::check();
+
+ typedef mln_ch_value(I,bool) output_t;
+ return output_t();
+ }
+
+
+ } // end of namespace scribo::binarization::internal
+
+
+
+ template <typename I, typename T>
+ mln_ch_value(I, value::int_u8)
+ sauvola_threshold(const Image<I>& input, unsigned window_size,
+ integral_image<T>& simple,
+ integral_image<T>& squared)
+ {
+ trace::entering("scribo::binarization::sauvola_threshold");
+
+ mln_precondition(mln_site_(I)::dim == 2);
+ mln_precondition(exact(input).is_valid());
+
+ typedef mln_value(I) value_t;
+ mln_ch_value(I, value::int_u8)
+ output = internal::sauvola_threshold_dispatch(value_t(), exact(input),
+ window_size, simple,
+ squared);
+
+ trace::exiting("scribo::text::ppm2pbm");
+ return output;
+ }
+
+
+ template <typename I>
+ inline
+ mln_ch_value(I, value::int_u8)
+ sauvola_threshold(const Image<I>& input, unsigned window_size)
+ {
+ mln::integral_image<value::int_u8> simple, squared;
+ return sauvola_threshold(input, window_size, simple, squared);
+ }
+
+
+ template <typename I>
+ inline
+ mln_ch_value(I, value::int_u8)
+ sauvola_threshold(const Image<I>& input)
+ {
+ return sauvola_threshold(input, 11);
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+
+#endif // ! SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_HH
--
1.5.6.5