Commit 39901400 authored by Guillaume Lazzara's avatar Guillaume Lazzara
Browse files

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.
parent fcf3c159
2010-11-15 Guillaume Lazzara <z@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@lrde.epita.fr>
Add arrows shortcuts.
......
// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory
// (LRDE)
// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
......@@ -24,31 +23,21 @@
// 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
#ifndef SCRIBO_BINARIZATION_INTERNAL_COMPUTE_SAUVOLA_THRESHOLD_HH
# define SCRIBO_BINARIZATION_INTERNAL_COMPUTE_SAUVOLA_THRESHOLD_HH
/// \file
///
/// Compute an image of local threshold using Sauvola algorithm.
/// \fixme return type too restrictive!
/// \brief Compute a threshold with Sauvola's binarization formula.
# 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>
# include <scribo/binarization/internal/sauvola_debug.hh>
// Setup default Sauvola's formulae parameters values.
......@@ -64,49 +53,17 @@
# 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;
using namespace mln;
/*! \brief Compute a point wise threshold according Sauvola's
binarization.
......@@ -123,10 +80,66 @@ namespace scribo
\return A threshold.
*/
template <typename P, typename M, typename J>
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,
M& mean, M& stddev, M& thres,
const J& simple,
const J& squared,
int win_width, double K, double R)
......@@ -156,7 +169,10 @@ namespace scribo
double m_x_y = m_x_y_tmp / wh;
mean(p) = m_x_y;// * mean_debug_factor;
# 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)
......@@ -166,256 +182,104 @@ namespace scribo
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;
# 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);
thres(p) = t_x_y;
# 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;
}
} // 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 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;
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);
int row_min = std::max(0, p.row() - w_2);
int col_min = std::max(0, p.col() - w_2);
const def::coord nrows = static_cast<def::coord>(input.nrows());
const def::coord ncols = static_cast<def::coord>(input.ncols());
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);
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;
}
double wh = (row_max - row_min + 1) * (col_max - col_min + 1);
} // end of namespace scribo::binarization::impl::generic
// 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
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);
}
// 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));
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");
# ifdef SCRIBO_SAUVOLA_DEBUG
// Store local standard deviation
debug_stddev(p) = s_x_y * stddev_debug_factor;
# endif // !SCRIBO_SAUVOLA_DEBUG
mln_ch_value(I, value::int_u8) gima;
gima = data::transform(input,
mln::fun::v2v::rgb_to_int_u<8>());
// Thresholding.
double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R);
mln_ch_value(I, value::int_u8)
output = impl::generic::sauvola_threshold_image_debug(gima, window_size,
K,
mean, stddev, thres,
simple, squared);
# 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
trace::exiting("scribo::binarization::impl::sauvola_threshold_image_debug_rgb8");
return output;
return t_x_y;
}
} // 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)
template <typename P, typename J>
double
compute_sauvola_threshold(const P& p,
const J& simple,
const J& squared,
int win_width)
{
return impl::sauvola_threshold_image_debug_gl(input, window_size, K,
mean, stddev, thres,
simple, squared);
return compute_sauvola_threshold(p, simple, squared, win_width,
SCRIBO_DEFAULT_SAUVOLA_K,
SCRIBO_DEFAULT_SAUVOLA_R);
}
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();
}
#endif // ! MLN_INCLUDE_ONLY
} // 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::binarization
} // end of namespace scribo
#endif // ! SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_DEBUG_HH
#endif // ! SCRIBO_BINARIZATION_INTERNAL_COMPUTE_SAUVOLA_THRESHOLD_HH
// 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;
......
// 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.
//