* scribo/binarization/internal/first_pass_functor.hh, * scribo/binarization/local_threshold.hh, * scribo/binarization/sauvola.hh, * scribo/binarization/sauvola_ms.hh, * scribo/binarization/sauvola_ms_split.hh, * scribo/binarization/sauvola_threshold_image.hh, * scribo/canvas/integral_browsing.hh: Add more parameters to Sauvola routines.
* scribo/binarization/sauvola_threshold_image_debug.hh: New. New overload providing debug outputs.
* scribo/debug/usage.hh: Remove a parameter.
* scribo/src/binarization/Makefile.am, * scribo/src/binarization/pgm_global_threshold_auto.cc, * scribo/src/binarization/pgm_sauvola.cc, * scribo/src/binarization/pgm_sauvola_ms.cc, * scribo/src/binarization/ppm_fg_sauvola_ms.cc, * scribo/src/binarization/ppm_sauvola.cc, * scribo/src/binarization/ppm_sauvola_ms.cc, * scribo/src/binarization/ppm_sauvola_ms_split.cc: Add new program arguments.
* scribo/src/binarization/fg_sauvola_ms.cc, * scribo/src/binarization/sauvola.cc, * scribo/src/binarization/sauvola_ms.cc, * scribo/src/binarization/sauvola_ms_split.cc, * scribo/src/binarization/sauvola_debug.cc: New. --- scribo/ChangeLog | 34 +++ scribo/binarization/internal/first_pass_functor.hh | 22 +- scribo/binarization/local_threshold.hh | 3 - scribo/binarization/sauvola.hh | 61 ++++- scribo/binarization/sauvola_ms.hh | 132 +++++---- scribo/binarization/sauvola_ms_split.hh | 29 ++- scribo/binarization/sauvola_threshold_image.hh | 128 +++++---- ...d_image.hh => sauvola_threshold_image_debug.hh} | 309 ++++++++------------ scribo/canvas/integral_browsing.hh | 13 - scribo/debug/usage.hh | 13 +- .../{ppm_fg_sauvola_ms.cc => fg_sauvola_ms.cc} | 15 +- .../src/binarization/pgm_global_threshold_auto.cc | 3 +- scribo/src/binarization/pgm_sauvola.cc | 28 ++- scribo/src/binarization/pgm_sauvola_ms.cc | 53 +++- scribo/src/binarization/ppm_fg_sauvola_ms.cc | 58 +++-- scribo/src/binarization/ppm_sauvola.cc | 38 ++- scribo/src/binarization/ppm_sauvola_ms.cc | 57 +++-- scribo/src/binarization/ppm_sauvola_ms_split.cc | 65 +++-- .../binarization/{pgm_sauvola.cc => sauvola.cc} | 39 ++- scribo/src/binarization/sauvola_debug.cc | 105 +++++++ .../{ppm_sauvola_ms.cc => sauvola_ms.cc} | 64 +++-- ...ppm_sauvola_ms_split.cc => sauvola_ms_split.cc} | 71 ++++-- scribo/src/preprocessing/to_pgm.cc | 46 +++ 23 files changed, 863 insertions(+), 523 deletions(-) copy scribo/binarization/{sauvola_threshold_image.hh => sauvola_threshold_image_debug.hh} (55%) copy scribo/src/binarization/{ppm_fg_sauvola_ms.cc => fg_sauvola_ms.cc} (87%) copy scribo/src/binarization/{pgm_sauvola.cc => sauvola.cc} (68%) create mode 100644 scribo/src/binarization/sauvola_debug.cc copy scribo/src/binarization/{ppm_sauvola_ms.cc => sauvola_ms.cc} (61%) copy scribo/src/binarization/{ppm_sauvola_ms_split.cc => sauvola_ms_split.cc} (64%) create mode 100644 scribo/src/preprocessing/to_pgm.cc
diff --git a/scribo/ChangeLog b/scribo/ChangeLog index 50f9d86..34a258f 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,3 +1,37 @@ +2010-04-13 Guillaume Lazzara z@lrde.epita.fr + + Add new Sauvola overloads and update examples. + + * scribo/binarization/internal/first_pass_functor.hh, + * scribo/binarization/local_threshold.hh, + * scribo/binarization/sauvola.hh, + * scribo/binarization/sauvola_ms.hh, + * scribo/binarization/sauvola_ms_split.hh, + * scribo/binarization/sauvola_threshold_image.hh, + * scribo/canvas/integral_browsing.hh: Add more parameters to + Sauvola routines. + + * scribo/binarization/sauvola_threshold_image_debug.hh: New. New + overload providing debug outputs. + + * scribo/debug/usage.hh: Remove a parameter. + + * scribo/src/binarization/Makefile.am, + * scribo/src/binarization/pgm_global_threshold_auto.cc, + * scribo/src/binarization/pgm_sauvola.cc, + * scribo/src/binarization/pgm_sauvola_ms.cc, + * scribo/src/binarization/ppm_fg_sauvola_ms.cc, + * scribo/src/binarization/ppm_sauvola.cc, + * scribo/src/binarization/ppm_sauvola_ms.cc, + * scribo/src/binarization/ppm_sauvola_ms_split.cc: Add new + program arguments. + + * scribo/src/binarization/fg_sauvola_ms.cc, + * scribo/src/binarization/sauvola.cc, + * scribo/src/binarization/sauvola_ms.cc, + * scribo/src/binarization/sauvola_ms_split.cc, + * scribo/src/binarization/sauvola_debug.cc: New. + 2010-03-29 Guillaume Lazzara z@lrde.epita.fr
Add support for various image types in text_in_photo_fast. diff --git a/scribo/binarization/internal/first_pass_functor.hh b/scribo/binarization/internal/first_pass_functor.hh index df4c025..3455060 100644 --- a/scribo/binarization/internal/first_pass_functor.hh +++ b/scribo/binarization/internal/first_pass_functor.hh @@ -68,12 +68,12 @@ namespace scribo unsigned n_nbhs; util::array<int> dp;
- static const double one_k = 1 - 0.34; - static const double k_R = 0.34 / 128.0; + double K_;
- first_pass_functor(const I& input) + first_pass_functor(const I& input, double K) : input(input), - pxl(input) + pxl(input), + K_(K) { res = 0; pxl.start(); @@ -96,17 +96,9 @@ namespace scribo
unsigned p = pxl.offset();
- // Use an inlined and developed version of sauvola's - // threshold formula. -// value::int_u8 t_p = mean * (one_k + k_R * stddev); - -// std::cout << t_p << ", "; - -// std::cout << input.element(p) << " - " << t_p << std::endl; - value::int_u8 t_p = sauvola_threshold_formula(mean, stddev); - -// std::cout << input.point_at_index(p) -// << " - " << sauvola_threshold_formula(mean, stddev); + value::int_u8 t_p = sauvola_threshold_formula(mean, stddev, + K_, + SCRIBO_DEFAULT_SAUVOLA_R);
msk.element(p) = input.element(p) < t_p; diff --git a/scribo/binarization/local_threshold.hh b/scribo/binarization/local_threshold.hh index ea5b34e..aa53664 100644 --- a/scribo/binarization/local_threshold.hh +++ b/scribo/binarization/local_threshold.hh @@ -200,9 +200,6 @@ namespace scribo
internal::local_threshold_tests(input, threshold);
- - - mln_ch_value(I, bool) output = internal::local_threshold_dispatch(input, threshold);
diff --git a/scribo/binarization/sauvola.hh b/scribo/binarization/sauvola.hh index c3a0cce..6dd812b 100644 --- a/scribo/binarization/sauvola.hh +++ b/scribo/binarization/sauvola.hh @@ -55,6 +55,23 @@ namespace scribo
\input[in] input An image. \input[in] window_size The window size. + \input[in] K Sauvola's formulae constant. + + \return A binary image. + + */ + template <typename I> + mln_ch_value(I, bool) + sauvola(const Image<I>& input, unsigned window_size, double K); + + + + /*! \brief Convert an image into a binary image. + + Sauvola's formulae constant K is set to 0.34. + + \input[in] input An image. + \input[in] window_size The window size.
\return A binary image.
@@ -84,7 +101,7 @@ namespace scribo
template <typename I> mln_ch_value(I, bool) - sauvola(const Image<I>& input, unsigned window_size) + sauvola(const Image<I>& input, unsigned window_size, double K) { trace::entering("scribo::binarization::impl::generic::sauvola"); mln_precondition(exact(input).is_valid()); @@ -92,7 +109,8 @@ namespace scribo mln_ch_value(I, bool) output = local_threshold(input, binarization::sauvola_threshold_image(input, - window_size)); + window_size, + K));
trace::exiting("scribo::binarization::impl::generic::sauvola"); return output; @@ -103,7 +121,7 @@ namespace scribo
template <typename I> mln_ch_value(I, bool) - sauvola_rgb8(const Image<I>& input, unsigned window_size) + sauvola_rgb8(const Image<I>& input, unsigned window_size, double K) { trace::entering("scribo::binarization::impl::generic::sauvola"); mln_precondition(exact(input).is_valid()); @@ -114,7 +132,8 @@ namespace scribo mln_ch_value(I, bool) output = local_threshold(gima, binarization::sauvola_threshold_image(gima, - window_size)); + window_size, + K));
trace::exiting("scribo::binarization::impl::generic::sauvola"); return output; @@ -132,26 +151,29 @@ namespace scribo template <typename I> mln_ch_value(I, bool) sauvola_dispatch(const mln_value(I)&, - const Image<I>& input, unsigned window_size) + const Image<I>& input, unsigned window_size, + double K) { - return impl::generic::sauvola(input, window_size); + 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) + const Image<I>& input, unsigned window_size, + double K) { - return impl::sauvola_rgb8(input, window_size); + return impl::sauvola_rgb8(input, window_size, K); }
template <typename I> mln_ch_value(I, bool) - sauvola_dispatch(const Image<I>& input, unsigned window_size) + sauvola_dispatch(const Image<I>& input, unsigned window_size, + double K) { typedef mln_value(I) V; - return sauvola_dispatch(V(), input, window_size); + return sauvola_dispatch(V(), input, window_size, K); }
} // end of namespace scribo::binarization::internal @@ -162,6 +184,22 @@ namespace scribo
template <typename I> mln_ch_value(I, bool) + sauvola(const Image<I>& input, unsigned window_size, double K) + { + trace::entering("scribo::binarization::sauvola"); + + mln_precondition(exact(input).is_valid()); + + mln_ch_value(I, bool) + output = internal::sauvola_dispatch(input, window_size, K); + + trace::exiting("scribo::binarization::sauvola"); + return output; + } + + + template <typename I> + mln_ch_value(I, bool) sauvola(const Image<I>& input, unsigned window_size) { trace::entering("scribo::binarization::sauvola"); @@ -169,7 +207,8 @@ namespace scribo mln_precondition(exact(input).is_valid());
mln_ch_value(I, bool) - output = internal::sauvola_dispatch(input, window_size); + output = internal::sauvola_dispatch(input, window_size, + SCRIBO_DEFAULT_SAUVOLA_K);
trace::exiting("scribo::binarization::sauvola"); return output; diff --git a/scribo/binarization/sauvola_ms.hh b/scribo/binarization/sauvola_ms.hh index 2717770..6e70e04 100644 --- a/scribo/binarization/sauvola_ms.hh +++ b/scribo/binarization/sauvola_ms.hh @@ -54,6 +54,9 @@
# include <mln/extension/adjust.hh>
+// FIXME: to be removed later... +# include <mln/io/pgm/save.hh> + # include <scribo/subsampling/integral_single_image.hh>
# include <scribo/core/macros.hh> @@ -81,6 +84,7 @@ namespace scribo \param[in] w_1 The window size used to compute stats. \param[in] s The scale factor used for the first subscaling. \param[in] lambda_min_1 Size of the objects kept at scale 1. + \param[in] K Sauvola's formulae parameter.
\p w_1 and \p lambda_min_1 are expressed according to the image @@ -90,6 +94,14 @@ namespace scribo */ template <typename I> mln_ch_value(I,bool) + sauvola_ms(const Image<I>& input_1_, unsigned w_1, + unsigned s, unsigned lambda_min_1, double K); + + /// \overload + /// K is set to 0.34. + // + template <typename I> + mln_ch_value(I,bool) sauvola_ms(const Image<I>& input_1, unsigned w_1, unsigned s, unsigned lambda_min_1);
@@ -105,6 +117,11 @@ namespace scribo
using namespace mln;
+ + // FIXME: to be removed later... + char* scale_image_output = 0; + + template <typename V> V my_find_root(image2d<V>& parent, const V& x) { @@ -120,7 +137,8 @@ namespace scribo unsigned lambda_min, unsigned lambda_max, unsigned s, unsigned q, unsigned i, unsigned w, - const image2d<util::couple<double,double> >& integral_sum_sum_2) + const image2d<util::couple<double,double> >& integral_sum_sum_2, + double K) { typedef image2d<int_u8> I; typedef point2d P; @@ -133,15 +151,30 @@ namespace scribo w_local_h = w_local, w_local_w = w_local;
+ // Make sure the window fits in the image domain. + if (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_h = w_local_w; + 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_w = w_local_h; + trace::warning("integral_browsing - Adjusting window height since it was larger than image height."); + } + if (! (w_local % 2)) { --w_local_w; ++w_local_h; }
+ // 1st pass scribo::binarization::internal::first_pass_functor< image2d<int_u8> > - f(sub); + f(sub, K); scribo::canvas::integral_browsing(integral_sum_sum_2, ratio, w_local_w, w_local_h, @@ -757,7 +790,7 @@ namespace scribo template <typename I> mln_ch_value(I,bool) sauvola_ms(const Image<I>& input_1_, unsigned w_1, - unsigned s, unsigned lambda_min_1) + unsigned s, double K) { trace::entering("scribo::binarization::sauvola_ms");
@@ -768,6 +801,8 @@ namespace scribo
dpoint2d none(0, 0);
+ unsigned lambda_min_1 = w_1 / 2; + // Number of subscales. unsigned nb_subscale = 3;
@@ -820,7 +855,7 @@ namespace scribo
// Subsampling to scale 3 and 4. for (unsigned i = 3; i <= nb_subscale + 1; ++i) - sub_ima.append(mln::subsampling::antialiased(sub_ima[i - 1], q, none, + sub_ima.append(mln::subsampling::antialiased(sub_ima[i - 1], q, sub_domains[i].first(), sub_domains[i].second()));
@@ -840,7 +875,8 @@ namespace scribo mln_max(unsigned), s, q, i, w_work, - integral_sum_sum_2); + integral_sum_sum_2, + K); }
// Other scales -> maximum and minimum component size. @@ -854,7 +890,8 @@ namespace scribo lambda_max_2 / ratio, s, q, i, w_work, - integral_sum_sum_2); + integral_sum_sum_2, + K); } }
@@ -863,13 +900,17 @@ namespace scribo t_ima[2] = internal::compute_t_n_and_e_2(sub_ima[2], e_2, 0, lambda_max_2, s, 1, 2, w_work, - integral_sum_sum_2); + integral_sum_sum_2, + K); }
// Propagate scale values. e_2 = transform::influence_zone_geodesic(e_2, c8());
+ // FIXME: Remove or make it better... + if (internal::scale_image_output) + io::pgm::save(e_2, internal::scale_image_output);
// Binarize image2d<bool> @@ -885,7 +926,7 @@ namespace scribo template <typename I> mln_ch_value(I,bool) sauvola_ms_rgb8(const Image<I>& input_1_, unsigned w_1, - unsigned s, unsigned lambda_min_1) + unsigned s, double K) { const I& input_1 = exact(input_1_);
@@ -893,54 +934,7 @@ namespace scribo gima = data::transform(input_1, mln::fun::v2v::rgb_to_int_u<8>());
mln_ch_value(I, bool) - output = generic::sauvola_ms(gima, w_1, s, lambda_min_1); - - -// typedef mln_ch_value(I,bool) bin_t; - - -// mln_ch_value(I, value::int_u8) r_i, g_i, b_i; - -// // Split the rgb8 image into 3 intensity images. -// mln::data::split(input_1, r_i, g_i, b_i); - -// bin_t r_b, g_b, b_b; - -// r_b = generic::sauvola_ms(r_i, w_1, s, lambda_min_1); -// g_b = generic::sauvola_ms(g_i, w_1, s, lambda_min_1); -// b_b = generic::sauvola_ms(b_i, w_1, s, lambda_min_1); - -// border::resize(r_b, input_1.border()); -// border::resize(g_b, input_1.border()); -// border::resize(b_b, input_1.border()); - -// bin_t output; -// initialize(output, input_1); - -// typedef bool * b_ptr_t; -// b_ptr_t -// out_ptr = output.buffer(), -// r_ptr = r_b.buffer(), -// g_ptr = g_b.buffer(), -// b_ptr = b_b.buffer(); - -// unsigned ntrue; -// for (unsigned n = 0; n < output.nelements(); ++n) -// { -// ntrue = 0; -// if (*r_ptr) -// ++ntrue; -// if (*g_ptr) -// ++ntrue; -// if (*b_ptr) -// ++ntrue; - -// *out_ptr++ = ntrue > 1;; - -// ++r_ptr; -// ++g_ptr; -// ++b_ptr; -// } + output = generic::sauvola_ms(gima, w_1, s, K);
return output; } @@ -959,9 +953,9 @@ namespace scribo mln_ch_value(I,bool) sauvola_ms_dispatch(const mln_value(I)&, const Image<I>& input_1, unsigned w_1, - unsigned s, unsigned lambda_min_1) + unsigned s, double K) { - return impl::generic::sauvola_ms(input_1, w_1, s, lambda_min_1); + return impl::generic::sauvola_ms(input_1, w_1, s, K); }
@@ -970,19 +964,19 @@ namespace scribo mln_ch_value(I,bool) sauvola_ms_dispatch(const value::rgb8&, const Image<I>& input_1, unsigned w_1, - unsigned s, unsigned lambda_min_1) + unsigned s, double K) { - return impl::sauvola_ms_rgb8(input_1, w_1, s, lambda_min_1); + return impl::sauvola_ms_rgb8(input_1, w_1, s, K); }
template <typename I> mln_ch_value(I,bool) sauvola_ms_dispatch(const Image<I>& input_1, unsigned w_1, - unsigned s, unsigned lambda_min_1) + unsigned s, double K) { typedef mln_value(I) V; - return sauvola_ms_dispatch(V(), input_1, w_1, s, lambda_min_1); + return sauvola_ms_dispatch(V(), input_1, w_1, s, K); }
@@ -995,20 +989,28 @@ namespace scribo template <typename I> mln_ch_value(I,bool) sauvola_ms(const Image<I>& input_1_, unsigned w_1, - unsigned s, unsigned lambda_min_1) + unsigned s, double K) { trace::entering("scribo::binarization::sauvola_ms");
- mln_precondition(input_1.is_valid()); + mln_precondition(exact(input_1_).is_valid());
mln_ch_value(I,bool) - output = internal::sauvola_ms_dispatch(input_1_, w_1, s, lambda_min_1); + output = internal::sauvola_ms_dispatch(input_1_, w_1, s, K);
trace::exiting("scribo::binarization::sauvola_ms"); return output; }
+ template <typename I> + mln_ch_value(I,bool) + sauvola_ms(const Image<I>& input_1, unsigned w_1, unsigned s) + { + return sauvola_ms(input_1, w_1, s, SCRIBO_DEFAULT_SAUVOLA_K); + } + + # endif // ! MLN_INCLUDE_ONLY
diff --git a/scribo/binarization/sauvola_ms_split.hh b/scribo/binarization/sauvola_ms_split.hh index cba5d94..de8517c 100644 --- a/scribo/binarization/sauvola_ms_split.hh +++ b/scribo/binarization/sauvola_ms_split.hh @@ -61,6 +61,7 @@ namespace scribo \param[in] min_ntrue A site is set to 'True' in the output if it is set to 'True' at least \p min_ntrue components. Possible values: 1, 2, 3. + \param[in] K Sauvola's formula parameter.
\p w_1 and \p lambda_min_1 are expressed according to the image at scale 0, i.e. the original size. @@ -70,16 +71,27 @@ namespace scribo template <typename I> mln_ch_value(I, bool) sauvola_ms_split(const Image<I>& input_1_, unsigned w_1, + unsigned s, unsigned lambda_min_1, unsigned min_ntrue, + double K); + + + /// \overload + /// K is set to 0.34. + template <typename I> + mln_ch_value(I, bool) + sauvola_ms_split(const Image<I>& input_1_, unsigned w_1, unsigned s, unsigned lambda_min_1, unsigned min_ntrue);
+ # ifndef MLN_INCLUDE_ONLY
template <typename I> mln_ch_value(I, bool) sauvola_ms_split(const Image<I>& input_1_, unsigned w_1, - unsigned s, unsigned lambda_min_1, unsigned min_ntrue) + unsigned s, unsigned lambda_min_1, unsigned min_ntrue, + double K) { trace::entering("scribo::binarization::sauvola_ms_split");
@@ -97,9 +109,9 @@ namespace scribo
bin_t r_b, g_b, b_b;
- r_b = impl::generic::sauvola_ms(r_i, w_1, s, lambda_min_1); - g_b = impl::generic::sauvola_ms(g_i, w_1, s, lambda_min_1); - b_b = impl::generic::sauvola_ms(b_i, w_1, s, lambda_min_1); + r_b = impl::generic::sauvola_ms(r_i, w_1, s, lambda_min_1, K); + g_b = impl::generic::sauvola_ms(g_i, w_1, s, lambda_min_1, K); + b_b = impl::generic::sauvola_ms(b_i, w_1, s, lambda_min_1, K);
border::resize(r_b, input_1.border()); border::resize(g_b, input_1.border()); @@ -138,6 +150,15 @@ namespace scribo }
+ template <typename I> + mln_ch_value(I, bool) + sauvola_ms_split(const Image<I>& input_1, unsigned w_1, + unsigned s, unsigned lambda_min_1, unsigned min_ntrue) + { + return sauvola_ms_split(input_1, w_1, s, lambda_min_1, min_ntrue, + SCRIBO_DEFAULT_SAUVOLA_K); + } + # endif // ! MLN_INCLUDE_ONLY
} // end of namespace scribo::binarization diff --git a/scribo/binarization/sauvola_threshold_image.hh b/scribo/binarization/sauvola_threshold_image.hh index b5bc72d..88b3842 100644 --- a/scribo/binarization/sauvola_threshold_image.hh +++ b/scribo/binarization/sauvola_threshold_image.hh @@ -47,10 +47,24 @@
# include <mln/fun/v2v/rgb_to_int_u.hh>
-# include <mln/debug/println.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 + + + namespace scribo {
@@ -73,11 +87,18 @@ namespace scribo template <typename I, typename J> mln_ch_value(I, value::int_u8) sauvola_threshold_image(const Image<I>& input, unsigned window_size, + double K, Image<J>& simple, Image<J>& squared);
+ /// \overload + template <typename I> + mln_ch_value(I, value::int_u8) + sauvola_threshold_image(const Image<I>& input, unsigned window_size, + double K);
/// \overload + /// K is set to 0.34 template <typename I> mln_ch_value(I, value::int_u8) sauvola_threshold_image(const Image<I>& input, unsigned window_size); @@ -113,9 +134,9 @@ namespace scribo inline double sauvola_threshold_formula(const double m_x_y, const double s_x_y, - const double k, const double R) + const double K, const double R) { - return m_x_y * (1.0 + k * ((s_x_y / R) - 1.0)); + return m_x_y * (1.0 + K * ((s_x_y / R) - 1.0)); }
@@ -125,13 +146,9 @@ namespace scribo double sauvola_threshold_formula(double m_x_y, double s_x_y) { - // Badekas et al. said 0.34 was best. - const double k = 0.34; - - // 128 is best for grayscale documents. - const double R = 128; - - return sauvola_threshold_formula(m_x_y, s_x_y, k, R); + return sauvola_threshold_formula(m_x_y, s_x_y, + SCRIBO_DEFAULT_SAUVOLA_K, + SCRIBO_DEFAULT_SAUVOLA_R); }
@@ -155,7 +172,7 @@ namespace scribo compute_sauvola_threshold(const P& p, const J& simple, const J& squared, - int win_width, double k, double R) + int win_width, double K, double R) { mln_precondition(simple.nrows() == squared.nrows()); mln_precondition(simple.ncols() == squared.ncols()); @@ -191,7 +208,7 @@ namespace scribo 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 = sauvola_threshold_formula(m_x_y, s_x_y, k, R); + double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R);
return t_x_y; } @@ -201,7 +218,8 @@ namespace scribo double compute_sauvola_threshold_single_image(const P& p, const J& integral, - int win_width) + int win_width, + double K, double R) { // Window half width. int w_2 = win_width >> 1; @@ -234,7 +252,7 @@ namespace scribo 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 + 0.34 * ((s_x_y / 128) - 1.0)); + double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R);
return t_x_y; } @@ -248,13 +266,9 @@ namespace scribo const J& 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); + return compute_sauvola_threshold(p, simple, squared, win_width, + SCRIBO_DEFAULT_SAUVOLA_K, + SCRIBO_DEFAULT_SAUVOLA_R); }
@@ -285,6 +299,7 @@ namespace scribo inline mln_concrete(I) sauvola_threshold_image(const Image<I>& input_, unsigned window_size, + double K, Image<J>& simple_, Image<J>& squared_) { @@ -313,7 +328,9 @@ namespace scribo for(def::coord col = 0; col < ncols; ++col) output.at_(row, col) = internal::compute_sauvola_threshold(P(row, col), simple, - squared, window_size); + squared, window_size, + K, + SCRIBO_DEFAULT_SAUVOLA_R);
trace::exiting("scribo::binarization::impl::generic::sauvola_threshold"); return output; @@ -327,10 +344,11 @@ namespace scribo inline mln_concrete(I) sauvola_threshold_image_gl(const I& input, unsigned window_size, - Image<J>& simple, - Image<J>& squared) + double K, + Image<J>& simple, + Image<J>& squared) { - return impl::generic::sauvola_threshold_image(input, window_size, + return impl::generic::sauvola_threshold_image(input, window_size, K, simple, squared); }
@@ -339,6 +357,7 @@ namespace scribo 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) { @@ -350,6 +369,7 @@ namespace scribo
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"); @@ -372,10 +392,12 @@ namespace scribo mln_ch_value(I, value::int_u<n>) sauvola_threshold_image_dispatch(const value::int_u<n>&, const I& input, unsigned window_size, + double K, J& simple, J& squared) { - return impl::sauvola_threshold_image_gl(input, window_size, simple, squared); + return impl::sauvola_threshold_image_gl(input, window_size, K, + simple, squared); }
template <typename I, typename J> @@ -383,11 +405,12 @@ namespace scribo 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, - simple, squared); + K, simple, squared); }
template <typename I, typename J> @@ -395,6 +418,7 @@ namespace scribo mln_ch_value(I, value::int_u8) sauvola_threshold_image_dispatch(const mln_value(I)&, const I& input, unsigned window_size, + double K, J& simple, J& squared) { @@ -413,37 +437,21 @@ namespace scribo template <typename I, typename J> mln_ch_value(I, value::int_u8) sauvola_threshold_image(const Image<I>& input, unsigned window_size, - Image<J>& simple, - Image<J>& squared) + double K, + Image<J>& simple, + Image<J>& squared) { trace::entering("scribo::binarization::sauvola_threshold_image");
mln_precondition(mln_site_(I)::dim == 2); mln_precondition(exact(input).is_valid());
- -// { -// J& simple_ = exact(simple); -// J& squared_ = exact(squared); -// mln_piter(J) p(simple_.domain()); -// for_all(p) -// { -// std::cout << simple_(p) << ", "; -// } -// std::cout << std::endl << " ------- " << std::endl; -// for_all(p) -// { -// std::cout << squared_(p) << ", "; -// } -// std::cout << std::endl << " ------- " << std::endl; -// } - - - typedef mln_value(I) value_t; mln_ch_value(I, value::int_u8) - output = internal::sauvola_threshold_image_dispatch(value_t(), exact(input), + output = internal::sauvola_threshold_image_dispatch(value_t(), + exact(input), window_size, + K, exact(simple), exact(squared));
@@ -455,19 +463,25 @@ namespace scribo template <typename I> inline mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input, unsigned window_size) + sauvola_threshold_image(const Image<I>& input, unsigned window_size, + double K) { mln_ch_value(I, double) simple = init_integral_image(input, scribo::internal::identity_), squared = init_integral_image(input, scribo::internal::square_);
-// debug::println(input); -// std::cout << "============" << std::endl; -// // debug::println(simple); -// // std::cout << "============" << std::endl; -// // debug::println(squared); + return sauvola_threshold_image(input, window_size, + K, simple, squared); + } +
- return sauvola_threshold_image(input, window_size, simple, squared); + template <typename I> + inline + mln_ch_value(I, value::int_u8) + sauvola_threshold_image(const Image<I>& input, unsigned window_size) + { + return sauvola_threshold_image(input, window_size, + SCRIBO_DEFAULT_SAUVOLA_K); }
diff --git a/scribo/binarization/sauvola_threshold_image.hh b/scribo/binarization/sauvola_threshold_image_debug.hh similarity index 55% copy from scribo/binarization/sauvola_threshold_image.hh copy to scribo/binarization/sauvola_threshold_image_debug.hh index b5bc72d..18216a6 100644 --- a/scribo/binarization/sauvola_threshold_image.hh +++ b/scribo/binarization/sauvola_threshold_image_debug.hh @@ -24,8 +24,8 @@ // exception does not however invalidate any other reasons why the // executable file might be covered by the GNU General Public License.
-#ifndef SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_HH -# define SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_HH +#ifndef SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_DEBUG_HH +# define SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_DEBUG_HH
/// \file /// @@ -47,9 +47,23 @@
# include <mln/fun/v2v/rgb_to_int_u.hh>
-# include <mln/debug/println.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 { @@ -72,23 +86,16 @@ namespace scribo */ template <typename I, typename J> mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input, unsigned window_size, - Image<J>& simple, - Image<J>& squared); - + 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(const Image<I>& input, unsigned window_size); - - - /// \overload - /// The window size is set to 11. - // - template <typename I> - mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input); + sauvola_threshold_image_debug(const Image<I>& input, unsigned window_size, + double K);
@@ -98,42 +105,8 @@ namespace scribo namespace internal {
- /*! \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 - // - inline - double - sauvola_threshold_formula(double m_x_y, double s_x_y) - { - // Badekas et al. said 0.34 was best. - const double k = 0.34; - - // 128 is best for grayscale documents. - const double R = 128; - - return sauvola_threshold_formula(m_x_y, s_x_y, k, R); - } - + unsigned mean_debug_factor = 1; + unsigned stddev_debug_factor = 10;
/*! \brief Compute a point wise threshold according Sauvola's binarization. @@ -150,12 +123,13 @@ namespace scribo
\return A threshold. */ - template <typename P, typename J> + template <typename P, typename I, typename J> double compute_sauvola_threshold(const P& p, + I& mean, I& stddev, const J& simple, const J& squared, - int win_width, double k, double R) + int win_width, double K, double R) { mln_precondition(simple.nrows() == squared.nrows()); mln_precondition(simple.ncols() == squared.ncols()); @@ -182,6 +156,8 @@ namespace scribo
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) @@ -190,74 +166,15 @@ namespace scribo
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 = sauvola_threshold_formula(m_x_y, s_x_y, k, R); - - return t_x_y; - } - - - template <typename P, typename J> - double - compute_sauvola_threshold_single_image(const P& p, - const J& integral, - int win_width) - { - // 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)); + stddev(p) = s_x_y * stddev_debug_factor;
// Thresholding. - double t_x_y = m_x_y * (1.0 + 0.34 * ((s_x_y / 128) - 1.0)); + double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, K, R);
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) - { - // 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 @@ -284,13 +201,18 @@ namespace scribo template <typename I, typename J> inline mln_concrete(I) - sauvola_threshold_image(const Image<I>& input_, unsigned window_size, - Image<J>& simple_, - Image<J>& squared_) + sauvola_threshold_image_debug(const Image<I>& input_, + unsigned window_size, + double K, + Image<I>& mean_, Image<I>& stddev_, + Image<J>& simple_, + Image<J>& squared_) { - trace::entering("scribo::binarization::impl::generic::sauvola_threshold_image"); + trace::entering("scribo::binarization::impl::generic::sauvola_threshold_image_debug");
const I& input = exact(input_); + I& mean = exact(mean_); + I& stddev = exact(stddev_); J& simple = exact(simple_); J& squared = exact(squared_);
@@ -312,8 +234,11 @@ namespace scribo 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); + = internal::compute_sauvola_threshold(P(row, col), + mean, stddev, + simple, squared, + window_size, K, + SCRIBO_DEFAULT_SAUVOLA_R);
trace::exiting("scribo::binarization::impl::generic::sauvola_threshold"); return output; @@ -326,33 +251,43 @@ namespace scribo template <typename I, typename J> inline mln_concrete(I) - sauvola_threshold_image_gl(const I& input, unsigned window_size, - Image<J>& simple, - Image<J>& squared) + sauvola_threshold_image_debug_gl(const Image<I>& input, + unsigned window_size, + double K, + Image<I>& mean, Image<I>& stddev, + Image<J>& simple, + Image<J>& squared) { - return impl::generic::sauvola_threshold_image(input, window_size, - simple, squared); + return impl::generic::sauvola_threshold_image_debug(input, window_size, + K, + mean, stddev, + simple, squared); }
template <typename I, typename J> inline mln_ch_value(I, value::int_u8) - sauvola_threshold_image_rgb8(const I& input, unsigned window_size, - Image<J>& simple, - Image<J>& squared) + sauvola_threshold_image_debug_rgb8(const Image<I>& input, + unsigned window_size, + double K, + Image<I>& mean, Image<I>& stddev, + Image<J>& simple, + Image<J>& squared) { - trace::entering("scribo::binarization::impl::sauvola_threshold_image_rgb8"); + 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(gima, window_size, - simple, squared); + output = impl::generic::sauvola_threshold_image_debug(gima, window_size, + K, + mean, stddev, + simple, squared);
- trace::exiting("scribo::binarization::impl::sauvola_threshold_image_rgb8"); + trace::exiting("scribo::binarization::impl::sauvola_threshold_image_debug_rgb8"); return output; }
@@ -370,33 +305,43 @@ namespace scribo template <unsigned n, typename I, typename J> inline mln_ch_value(I, value::int_u<n>) - sauvola_threshold_image_dispatch(const value::int_u<n>&, const I& input, - unsigned window_size, - J& simple, - J& squared) + sauvola_threshold_image_debug_dispatch(const value::int_u<n>&, + const I& input, + unsigned window_size, + double K, + I& mean, I& stddev, + J& simple, + J& squared) { - return impl::sauvola_threshold_image_gl(input, window_size, simple, squared); + return impl::sauvola_threshold_image_debug_gl(input, window_size, K, + mean, stddev, + 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, - J& simple, - J& squared) + sauvola_threshold_image_debug_dispatch(const value::rgb8&, const I& input, + unsigned window_size, + double K, + I& mean, I& stddev, + J& simple, + J& squared) { - return impl::sauvola_threshold_image_rgb8(input, window_size, - simple, squared); + return impl::sauvola_threshold_image_debug_rgb8(input, window_size, + K, mean, stddev, + simple, squared); }
template <typename I, typename J> inline mln_ch_value(I, value::int_u8) - sauvola_threshold_image_dispatch(const mln_value(I)&, const I& input, - unsigned window_size, - J& simple, - J& squared) + sauvola_threshold_image_debug_dispatch(const mln_value(I)&, const I& input, + I& mean, I& stddev, + unsigned window_size, + double K, + J& simple, + J& squared) { // No dispatch for this kind of value type. mlc_abort(I)::check(); @@ -412,40 +357,27 @@ namespace scribo
template <typename I, typename J> mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input, unsigned window_size, - Image<J>& simple, - Image<J>& squared) + sauvola_threshold_image_debug(const Image<I>& input, unsigned window_size, + double K, + Image<I>& mean, Image<I>& stddev, + Image<J>& simple, + Image<J>& squared) { - trace::entering("scribo::binarization::sauvola_threshold_image"); + trace::entering("scribo::binarization::sauvola_threshold_image_debug");
mln_precondition(mln_site_(I)::dim == 2); mln_precondition(exact(input).is_valid());
- -// { -// J& simple_ = exact(simple); -// J& squared_ = exact(squared); -// mln_piter(J) p(simple_.domain()); -// for_all(p) -// { -// std::cout << simple_(p) << ", "; -// } -// std::cout << std::endl << " ------- " << std::endl; -// for_all(p) -// { -// std::cout << squared_(p) << ", "; -// } -// std::cout << std::endl << " ------- " << std::endl; -// } - - - typedef mln_value(I) value_t; mln_ch_value(I, value::int_u8) - output = internal::sauvola_threshold_image_dispatch(value_t(), exact(input), - window_size, - exact(simple), - exact(squared)); + output = internal::sauvola_threshold_image_debug_dispatch(value_t(), + exact(input), + window_size, + K, + exact(mean), + exact(stddev), + exact(simple), + exact(squared));
trace::exiting("scribo::text::ppm2pbm"); return output; @@ -455,28 +387,17 @@ namespace scribo template <typename I> inline mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input, unsigned window_size) + sauvola_threshold_image_debug(const Image<I>& input, unsigned window_size, + double K, + Image<I>& mean, Image<I>& stddev) { mln_ch_value(I, double) simple = init_integral_image(input, scribo::internal::identity_), squared = init_integral_image(input, scribo::internal::square_);
-// debug::println(input); -// std::cout << "============" << std::endl; -// // debug::println(simple); -// // std::cout << "============" << std::endl; -// // debug::println(squared); - - return sauvola_threshold_image(input, window_size, simple, squared); - } - - - template <typename I> - inline - mln_ch_value(I, value::int_u8) - sauvola_threshold_image(const Image<I>& input) - { - return sauvola_threshold_image(input, 11); + return sauvola_threshold_image_debug(input, window_size, K, + mean, stddev, + simple, squared); }
@@ -487,4 +408,4 @@ namespace scribo } // end of namespace scribo
-#endif // ! SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_HH +#endif // ! SCRIBO_BINARIZATION_SAUVOLA_THRESHOLD_IMAGE_DEBUG_HH diff --git a/scribo/canvas/integral_browsing.hh b/scribo/canvas/integral_browsing.hh index 45ff38d..4e55109 100644 --- a/scribo/canvas/integral_browsing.hh +++ b/scribo/canvas/integral_browsing.hh @@ -127,19 +127,6 @@ namespace scribo
unsigned s_2 = s * s;
- // Make sure the window fits in the image domain. - if (w >= static_cast<const unsigned>(ncols)) - { - w = ncols - 1; - trace::warning("integral_browsing - Adjusting window width since it was larger than image width."); - } - if (h >= static_cast<const unsigned>(nrows)) - { - h = nrows - 1; - trace::warning("integral_browsing - Adjusting window height since it was larger than image height."); - } - - // ------------------------------- // T (top) // ------------------------------- diff --git a/scribo/debug/usage.hh b/scribo/debug/usage.hh index 6b6c9b7..2c6fa48 100644 --- a/scribo/debug/usage.hh +++ b/scribo/debug/usage.hh @@ -26,6 +26,7 @@ #ifndef SCRIBO_DEBUG_USAGE_HH # define SCRIBO_DEBUG_USAGE_HH
+#include <libgen.h> #include <iostream>
namespace scribo @@ -45,7 +46,7 @@ namespace scribo /// \return Return 1. // int usage(char* argv[], const char *desc, const char* args, - const char*args_desc[][2], const char *out_desc); + const char*args_desc[][2]);
# ifndef MLN_INCLUDE_ONLY @@ -53,21 +54,21 @@ namespace scribo inline int usage(char* argv[], const char *desc, const char* args, - const char*args_desc[][2], const char *out_desc = 0) + const char*args_desc[][2]) { - std::cout << "Usage: " << argv[0] << " " << args + std::cout << "Usage: " << basename(argv[0]) << " " << args << std::endl << std::endl; std::cout << "-----------" << std::endl; std::cout << desc << std::endl - << std::endl; + << std::endl;
for (unsigned i = 0; args_desc[i][0] != 0; ++i) std::cout << " " << args_desc[i][0] << ": " << args_desc[i][1] << std::endl;
- if (out_desc) - std::cout << std::endl << "Output: " << out_desc << std::endl; +// if (out_desc) +// std::cout << std::endl << "Output: " << out_desc << std::endl;
std::cout << "-----------" << std::endl; std::cout << "EPITA/LRDE - Scribo 2009" << std::endl; diff --git a/scribo/src/binarization/ppm_fg_sauvola_ms.cc b/scribo/src/binarization/fg_sauvola_ms.cc similarity index 87% copy from scribo/src/binarization/ppm_fg_sauvola_ms.cc copy to scribo/src/binarization/fg_sauvola_ms.cc index 5f45470..9c606d6 100644 --- a/scribo/src/binarization/ppm_fg_sauvola_ms.cc +++ b/scribo/src/binarization/fg_sauvola_ms.cc @@ -26,7 +26,7 @@
#include <mln/core/image/image2d.hh> #include <mln/value/rgb8.hh> -#include <mln/io/ppm/load.hh> +#include <mln/io/magick/load.hh> #include <mln/io/pbm/save.hh>
#include <scribo/binarization/sauvola_ms.hh> @@ -53,7 +53,8 @@ bool check_args(int argc, char * argv[])
const char *args_desc[][2] = { - { "input.ppm", "A color image." }, + { "input.*", "An image." }, + { "output.pbm", "A binary image." }, { "lambda", "Lambda used to split bg/fg." }, { "w", "Window size at scale 1. (Common value: 101)" }, { "s", "First subsampling ratio (Common value: 3)." }, @@ -71,9 +72,9 @@ int main(int argc, char *argv[])
if (!check_args(argc, argv)) return scribo::debug::usage(argv, - "Multi-Scale Binarization of a color image based on Sauvola's algorithm. Performs a binarization on each component of the color image and merges the results.", - "input.ppm w s area_threshold output.pbm", - args_desc, "A binary image."); + "Multi-Scale Binarization based on Sauvola's algorithm. Performs a binarization on each component of the color image and merges the results.", + "input.* output.pbm w s area_threshold", + args_desc);
trace::entering("main");
@@ -90,13 +91,13 @@ int main(int argc, char *argv[])
image2dvalue::rgb8 input_1; - io::ppm::load(input_1, argv[1]); + io::magick::load(input_1, argv[1]);
image2dvalue::rgb8 fg = scribo::preprocessing::split_bg_fg(input_1, lambda, 32).first();
image2d<bool> - output = scribo::binarization::sauvola_ms(fg, w_1, s, lambda_min_1); + output = scribo::binarization::sauvola_ms(fg, w_1, s, lambda_min_1, SCRIBO_DEFAULT_SAUVOLA_K);
io::pbm::save(output, argv[6]); } diff --git a/scribo/src/binarization/pgm_global_threshold_auto.cc b/scribo/src/binarization/pgm_global_threshold_auto.cc index 7f1dacf..568eba2 100644 --- a/scribo/src/binarization/pgm_global_threshold_auto.cc +++ b/scribo/src/binarization/pgm_global_threshold_auto.cc @@ -33,6 +33,7 @@ const char *args_desc[][2] = { { "input.pgm", "A gray level image." }, + { "output.pbm", "A binary image." }, {0, 0} };
@@ -46,7 +47,7 @@ int main(int argc, char *argv[]) return scribo::debug::usage(argv, "Binarization of a gray-level image using an automatic global threshold.", "input.pgm output.pbm", - args_desc, "A binary image."); + args_desc);
trace::entering("main");
diff --git a/scribo/src/binarization/pgm_sauvola.cc b/scribo/src/binarization/pgm_sauvola.cc index 843c355..c6ba643 100644 --- a/scribo/src/binarization/pgm_sauvola.cc +++ b/scribo/src/binarization/pgm_sauvola.cc @@ -33,7 +33,9 @@ const char *args_desc[][2] = { { "input.pgm", "A gray level image." }, - { "w", "Window size." }, + { "output.pbm", "A binary image." }, + { "w", "Window size (default 51)." }, + { "k", "Sauvola's formulae parameter (default 0.34)." }, {0, 0} };
@@ -43,23 +45,35 @@ int main(int argc, char *argv[]) using namespace mln; using value::int_u8;
- if (argc != 4) + if (argc != 5 && argc != 4 && argc != 3) return scribo::debug::usage(argv, "Binarization of a gray level image based on Sauvola's algorithm.", - "input.pgm w output.pbm", - args_desc, "A binary image."); + "input.pgm output.pbm <w> <k>", + args_desc);
trace::entering("main");
- unsigned w = atoi(argv[2]); + unsigned w; + if (argc == 4) + w = atoi(argv[3]); + else + w = 51; + + double k; + if (argc == 5) + k = atof(argv[4]); + else + k = 0.34f; + + std::cout << "Using w=" << w << " and k=" << k << std::endl;
image2d<int_u8> input; io::pgm::load(input, argv[1]);
- image2d<bool> out = scribo::binarization::sauvola(input, w); + image2d<bool> out = scribo::binarization::sauvola(input, w, k);
- io::pbm::save(out, argv[3]); + io::pbm::save(out, argv[2]);
trace::exiting("main"); diff --git a/scribo/src/binarization/pgm_sauvola_ms.cc b/scribo/src/binarization/pgm_sauvola_ms.cc index d446c3e..fefdd6a 100644 --- a/scribo/src/binarization/pgm_sauvola_ms.cc +++ b/scribo/src/binarization/pgm_sauvola_ms.cc @@ -34,16 +34,19 @@
bool check_args(int argc, char * argv[]) { - if (argc < 5 || argc > 6) + if (argc < 3 || argc > 6) return false;
- int s = atoi(argv[3]); - - if (s < 1 || s > 3) + if (argc >= 5) { - std::cout << "s must be set to 2 or 3." - << std::endl; - return false; + int s = atoi(argv[4]); + + if (s < 1 || s > 3) + { + std::cout << "s must be set to 2 or 3." + << std::endl; + return false; + } }
return true; @@ -53,9 +56,10 @@ bool check_args(int argc, char * argv[]) const char *args_desc[][2] = { { "input.pgm", "A graylevel image." }, - { "w", "Window size at scale 1. (Common value: 101)" }, - { "s", "First subsampling ratio (Common value: 3)." }, - { "min_area", "Minimum object area at scale 1 (Common value: 67)" }, + { "out.pbm", "A binary image." }, + { "w", "Window size at scale 1. (default: 101)" }, + { "s", "First subsampling ratio (default: 3)." }, + { "k", "Sauvola's formuale parameter (default: 0.34)" }, {0, 0} };
@@ -70,28 +74,43 @@ int main(int argc, char *argv[]) if (!check_args(argc, argv)) return scribo::debug::usage(argv, "Multi-Scale Binarization of a color image based on Sauvola's algorithm.", - "input.pgm w s area_threshold output.pbm", - args_desc, "A binary image."); + "input.pgm output.pbm <w> <s> <k>", + args_desc);
trace::entering("main");
// Window size - unsigned w_1 = atoi(argv[2]); // Scale 1 + unsigned w_1; + if (argc >= 4) + w_1 = atoi(argv[3]); // Scale 1 + else + w_1 = 101u;
// First subsampling scale. - unsigned s = atoi(argv[3]); + unsigned s; + if (argc >= 5) + s = atoi(argv[4]); + else + s = 3u;
// Lambda value - unsigned lambda_min_1 = atoi(argv[4]); + unsigned lambda_min_1 = 67; // FIXME: should be adapted to the + // window size.
+ double k; + if (argc >= 6) + k = atof(argv[5]); + else + k = 0.34f;
image2dvalue::int_u8 input_1; io::pgm::load(input_1, argv[1]);
image2d<bool> - output = scribo::binarization::sauvola_ms(input_1, w_1, s, lambda_min_1); + output = scribo::binarization::sauvola_ms(input_1, w_1, s, + lambda_min_1, k);
- io::pbm::save(output, argv[5]); + io::pbm::save(output, argv[2]); }
diff --git a/scribo/src/binarization/ppm_fg_sauvola_ms.cc b/scribo/src/binarization/ppm_fg_sauvola_ms.cc index 5f45470..65e8621 100644 --- a/scribo/src/binarization/ppm_fg_sauvola_ms.cc +++ b/scribo/src/binarization/ppm_fg_sauvola_ms.cc @@ -35,16 +35,19 @@
bool check_args(int argc, char * argv[]) { - if (argc != 7) + if (argc < 3 || argc > 7) return false;
- int s = atoi(argv[4]); - - if (s < 2 || s > 3) + if (argc >= 6) { - std::cout << "s must be set to 2 or 3." - << std::endl; - return false; + int s = atoi(argv[5]); + + if (s < 2 || s > 3) + { + std::cout << "s must be set to 2 or 3." + << std::endl; + return false; + } }
return true; @@ -54,10 +57,11 @@ bool check_args(int argc, char * argv[]) const char *args_desc[][2] = { { "input.ppm", "A color image." }, + { "output.pbm", "A binary image." }, { "lambda", "Lambda used to split bg/fg." }, - { "w", "Window size at scale 1. (Common value: 101)" }, - { "s", "First subsampling ratio (Common value: 3)." }, - { "min_area", "Minimum object area at scale 1 (Common value: 67)" }, + { "w", "Window size at scale 1. (default: 101)" }, + { "s", "First subsampling ratio. (default: 3)" }, + { "k", "Sauvola's formula parameter. (default: 0.34)" }, {0, 0} };
@@ -72,33 +76,49 @@ int main(int argc, char *argv[]) if (!check_args(argc, argv)) return scribo::debug::usage(argv, "Multi-Scale Binarization of a color image based on Sauvola's algorithm. Performs a binarization on each component of the color image and merges the results.", - "input.ppm w s area_threshold output.pbm", - args_desc, "A binary image."); + "input.ppm output.pbm lambda <w> <s> <k>", + args_desc);
trace::entering("main");
- unsigned lambda = atoi(argv[2]); + unsigned lambda = atoi(argv[3]);
// Window size - unsigned w_1 = atoi(argv[3]); // Scale 1 + unsigned w_1; + if (argc >= 5) + w_1 = atoi(argv[4]); // Scale 1 + else + w_1 = 101u;
// First subsampling scale. - unsigned s = atoi(argv[4]); + unsigned s; + if (argc >= 6) + s = atoi(argv[5]); + else + s = 3u;
// Lambda value - unsigned lambda_min_1 = atoi(argv[5]); + unsigned lambda_min_1 = 67; // FIXME: should be adapted to the + // window size. + + double k; + if (argc >= 7) + k = atof(argv[6]); + else + k = 0.34f; +
image2dvalue::rgb8 input_1; io::ppm::load(input_1, argv[1]);
image2dvalue::rgb8 - fg = scribo::preprocessing::split_bg_fg(input_1, lambda, 32).first(); + fg = scribo::preprocessing::split_bg_fg(input_1, lambda, 32).second();
image2d<bool> - output = scribo::binarization::sauvola_ms(fg, w_1, s, lambda_min_1); + output = scribo::binarization::sauvola_ms(fg, w_1, s, lambda_min_1, k);
- io::pbm::save(output, argv[6]); + io::pbm::save(output, argv[2]); }
diff --git a/scribo/src/binarization/ppm_sauvola.cc b/scribo/src/binarization/ppm_sauvola.cc index c3ce28a..0b798ae 100644 --- a/scribo/src/binarization/ppm_sauvola.cc +++ b/scribo/src/binarization/ppm_sauvola.cc @@ -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. // @@ -25,7 +26,6 @@
#include <mln/io/ppm/load.hh> #include <mln/io/pbm/save.hh> -#include <mln/value/rgb8.hh>
#include <scribo/binarization/sauvola.hh> #include <scribo/debug/usage.hh> @@ -33,7 +33,9 @@ const char *args_desc[][2] = { { "input.ppm", "A color image." }, - { "wsize", "Window size (Common value: 51)." }, + { "output.pbm", "A binary image." }, + { "w", "Window size (default 51)." }, + { "k", "Sauvola's formulae parameter (default 0.34)." }, {0, 0} };
@@ -41,20 +43,36 @@ const char *args_desc[][2] = int main(int argc, char *argv[]) { using namespace mln; - using value::rgb8;
- if (argc != 4) + if (argc != 5 && argc != 4 && argc != 3) return scribo::debug::usage(argv, - "Binarization of a color image based on Sauvola's algorithm. First convert the color image to an intensity image and then run Sauvola.", - "input.ppm wsize output.pbm", - args_desc, "A binary image."); + "Binarization of a gray level image based on Sauvola's algorithm.", + "input.ppm output.pbm <w> <k>", + args_desc);
trace::entering("main");
- image2d<rgb8> input; + unsigned w; + if (argc == 4) + w = atoi(argv[3]); + else + w = 51; + + double k; + if (argc == 5) + k = atof(argv[4]); + else + k = 0.34f; + + std::cout << "Using w=" << w << " and k=" << k << std::endl; + + image2dvalue::rgb8 input; io::ppm::load(input, argv[1]);
- io::pbm::save(scribo::binarization::sauvola(input, atoi(argv[2])), argv[3]); + image2d<bool> out = scribo::binarization::sauvola(input, w, k); + + + io::pbm::save(out, argv[2]);
trace::exiting("main"); diff --git a/scribo/src/binarization/ppm_sauvola_ms.cc b/scribo/src/binarization/ppm_sauvola_ms.cc index d8c1c9c..f2cbb6f 100644 --- a/scribo/src/binarization/ppm_sauvola_ms.cc +++ b/scribo/src/binarization/ppm_sauvola_ms.cc @@ -25,7 +25,7 @@ // executable file might be covered by the GNU General Public License.
#include <mln/core/image/image2d.hh> -#include <mln/value/rgb8.hh> +#include <mln/value/int_u8.hh> #include <mln/io/ppm/load.hh> #include <mln/io/pbm/save.hh>
@@ -34,16 +34,19 @@
bool check_args(int argc, char * argv[]) { - if (argc < 5 || argc > 6) + if (argc < 3 || argc > 6) return false;
- int s = atoi(argv[3]); - - if (s < 2 || s > 3) + if (argc >= 5) { - std::cout << "s must be set to 2 or 3." - << std::endl; - return false; + int s = atoi(argv[4]); + + if (s < 1 || s > 3) + { + std::cout << "s must be set to 2 or 3." + << std::endl; + return false; + } }
return true; @@ -53,9 +56,10 @@ bool check_args(int argc, char * argv[]) const char *args_desc[][2] = { { "input.ppm", "A color image." }, - { "w", "Window size at scale 1. (Common value: 101)" }, - { "s", "First subsampling ratio (Common value: 3)." }, - { "min_area", "Minimum object area at scale 1 (Common value: 67)" }, + { "out.pbm", "A binary image." }, + { "w", "Window size at scale 1. (default: 101)" }, + { "s", "First subsampling ratio (default: 3)." }, + { "k", "Sauvola's formuale parameter (default: 0.34)" }, {0, 0} };
@@ -69,29 +73,44 @@ int main(int argc, char *argv[])
if (!check_args(argc, argv)) return scribo::debug::usage(argv, - "Multi-Scale Binarization of a color image based on Sauvola's algorithm. Performs a binarization on each component of the color image and merges the results.", - "input.ppm w s area_threshold output.pbm", - args_desc, "A binary image."); + "Multi-Scale Binarization of a color image based on Sauvola's algorithm.", + "input.ppm output.pbm <w> <s> <k>", + args_desc);
trace::entering("main");
// Window size - unsigned w_1 = atoi(argv[2]); // Scale 1 + unsigned w_1; + if (argc >= 4) + w_1 = atoi(argv[3]); // Scale 1 + else + w_1 = 101u;
// First subsampling scale. - unsigned s = atoi(argv[3]); + unsigned s; + if (argc >= 5) + s = atoi(argv[4]); + else + s = 3u;
// Lambda value - unsigned lambda_min_1 = atoi(argv[4]); + unsigned lambda_min_1 = 67; // FIXME: should be adapted to the + // window size.
+ double k; + if (argc >= 6) + k = atof(argv[5]); + else + k = 0.34f;
image2dvalue::rgb8 input_1; io::ppm::load(input_1, argv[1]);
image2d<bool> - output = scribo::binarization::sauvola_ms(input_1, w_1, s, lambda_min_1); + output = scribo::binarization::sauvola_ms(input_1, w_1, s, + lambda_min_1, k);
- io::pbm::save(output, argv[5]); + io::pbm::save(output, argv[2]); }
diff --git a/scribo/src/binarization/ppm_sauvola_ms_split.cc b/scribo/src/binarization/ppm_sauvola_ms_split.cc index 3f721db..b1f10ea 100644 --- a/scribo/src/binarization/ppm_sauvola_ms_split.cc +++ b/scribo/src/binarization/ppm_sauvola_ms_split.cc @@ -34,16 +34,19 @@
bool check_args(int argc, char * argv[]) { - if (argc != 7) + if (argc < 3 || argc > 7) return false;
- int s = atoi(argv[3]); - - if (s < 1 || s > 3) + if (argc >= 5) { - std::cout << "s must be set to 2 or 3." - << std::endl; - return false; + int s = atoi(argv[4]); + + if (s < 1 || s > 3) + { + std::cout << "s must be set to 2 or 3." + << std::endl; + return false; + } }
return true; @@ -53,10 +56,11 @@ bool check_args(int argc, char * argv[]) const char *args_desc[][2] = { { "input.ppm", "A color image." }, - { "w", "Window size at scale 1. (Common value: 101)" }, - { "s", "First subsampling ratio (Common value: 3)." }, - { "min_area", "Minimum object area at scale 1 (Common value: 67)" }, - { "min_ntrue", "The number of components in which a site must be set to 'True' in order to be set to 'True' in the output (Possible values: 1, 2, 3). (Common value: 2)" }, + { "output.pbm", "A binary image." }, + { "w", "Window size at scale 1. (default: 101)" }, + { "s", "First subsampling ratio (default: 3)." }, + { "min_ntrue", "The number of components in which a site must be set to 'True' in order to be set to 'True' in the output (Possible values: 1, 2, 3). (default: 2)" }, + { "K", "Sauvola's formula parameter (default: 0.34)." }, {0, 0} };
@@ -71,28 +75,53 @@ int main(int argc, char *argv[]) if (!check_args(argc, argv)) return scribo::debug::usage(argv, "Multi-Scale Binarization of a color image based on Sauvola's algorithm. Performs a binarization on each component of the color image and merges the results.", - "input.ppm w s area_threshold output.pbm", - args_desc, "A binary image."); + "input.ppm output.pbm <w> <s> <min_ntrue> <K>", + args_desc);
trace::entering("main");
// Window size - unsigned w_1 = atoi(argv[2]); // Scale 1 + unsigned w_1; + if (argc >= 4) + w_1 = atoi(argv[3]); // Scale 1 + else + w_1 = 101u;
// First subsampling scale. - unsigned s = atoi(argv[3]); + unsigned s; + if (argc >= 5) + s = atoi(argv[4]); + else + s = 3u; + + // min_ntrue + unsigned min_ntrue; + if (argc >= 6) + min_ntrue = atoi(argv[5]); + else + min_ntrue = 2;
// Lambda value - unsigned lambda_min_1 = atoi(argv[4]); + unsigned lambda_min_1 = 67; // FIXME: should be adapted to the + // window size. + + double k; + if (argc >= 7) + k = atof(argv[6]); + else + k = 0.34f; +
image2dvalue::rgb8 input_1; io::ppm::load(input_1, argv[1]);
+ std::cout << "Using w=" << w_1 << " - s=" << s << " - min_ntrue=" << min_ntrue << " - k=" << k << std::endl; + image2d<bool> - output = scribo::binarization::sauvola_ms_split(input_1, w_1, s, lambda_min_1, atoi(argv[5])); + output = scribo::binarization::sauvola_ms_split(input_1, w_1, s, lambda_min_1, min_ntrue, k);
- io::pbm::save(output, argv[6]); + io::pbm::save(output, argv[2]); }
diff --git a/scribo/src/binarization/pgm_sauvola.cc b/scribo/src/binarization/sauvola.cc similarity index 68% copy from scribo/src/binarization/pgm_sauvola.cc copy to scribo/src/binarization/sauvola.cc index 843c355..fb07b0d 100644 --- a/scribo/src/binarization/pgm_sauvola.cc +++ b/scribo/src/binarization/sauvola.cc @@ -24,7 +24,7 @@ // exception does not however invalidate any other reasons why the // executable file might be covered by the GNU General Public License.
-#include <mln/io/pgm/load.hh> +#include <mln/io/magick/load.hh> #include <mln/io/pbm/save.hh>
#include <scribo/binarization/sauvola.hh> @@ -32,8 +32,10 @@
const char *args_desc[][2] = { - { "input.pgm", "A gray level image." }, - { "w", "Window size." }, + { "input.*", "An image." }, + { "output.pbm", "A binary image." }, + { "w", "Window size (default 51)." }, + { "k", "Sauvola's formulae parameter (default 0.34)." }, {0, 0} };
@@ -41,25 +43,36 @@ const char *args_desc[][2] = int main(int argc, char *argv[]) { using namespace mln; - using value::int_u8;
- if (argc != 4) + if (argc != 5 && argc != 4 && argc != 3) return scribo::debug::usage(argv, - "Binarization of a gray level image based on Sauvola's algorithm.", - "input.pgm w output.pbm", - args_desc, "A binary image."); + "Binarization based on Sauvola's algorithm.", + "input.* output.pbm <w> <k>", + args_desc);
trace::entering("main");
- unsigned w = atoi(argv[2]); + unsigned w; + if (argc >= 4) + w = atoi(argv[3]); + else + w = 51;
- image2d<int_u8> input; - io::pgm::load(input, argv[1]); + double k; + if (argc >= 5) + k = atof(argv[4]); + else + k = 0.34f;
- image2d<bool> out = scribo::binarization::sauvola(input, w); + std::cout << "Using w=" << w << " and k=" << k << std::endl;
+ image2dvalue::rgb8 input; + io::magick::load(input, argv[1]);
- io::pbm::save(out, argv[3]); + image2d<bool> out = scribo::binarization::sauvola(input, w, k); + + + io::pbm::save(out, argv[2]);
trace::exiting("main"); diff --git a/scribo/src/binarization/sauvola_debug.cc b/scribo/src/binarization/sauvola_debug.cc new file mode 100644 index 0000000..8bbc19c --- /dev/null +++ b/scribo/src/binarization/sauvola_debug.cc @@ -0,0 +1,105 @@ +// 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. + +#include <mln/io/magick/load.hh> +#include <mln/io/pbm/save.hh> +#include <mln/io/pgm/save.hh> + +#include <scribo/binarization/local_threshold.hh> +#include <scribo/binarization/sauvola_threshold_image_debug.hh> +#include <scribo/debug/usage.hh> + +const char *args_desc[][2] = +{ + { "input.*", "An image." }, + { "output.pbm", "A binary image." }, + { "mean.pgm", "The local mean image." }, + { "stddev.pgm", "The local standard deviation image." }, + { "mean_factor", "Mean value factor (default 1)." }, + { "stddev_factor", "Standard deviation value factor (default 10)." }, + { "w", "Window size (default 51)." }, + { "k", "Sauvola's formulae parameter (default 0.34)." }, + {0, 0} +}; + + +int main(int argc, char *argv[]) +{ + using namespace mln; + using namespace scribo::binarization; + + if (argc < 5 || argc >= 9) + return scribo::debug::usage(argv, + "Binarization based on Sauvola's algorithm.", + "input.* output.pbm mean.pgm stddev.pgm <mean_factor> <stddev_factor> <w> <k>", + args_desc); + + trace::entering("main"); + + unsigned w; + if (argc >= 8) + w = atoi(argv[7]); + else + w = 51; + + double k; + if (argc >= 9) + k = atof(argv[8]); + else + k = 0.34f; + + std::cout << "Using w=" << w << " and k=" << k << std::endl; + + if (argc >= 6) + scribo::binarization::internal::mean_debug_factor = atoi(argv[5]); + if (argc >= 7) + scribo::binarization::internal::stddev_debug_factor = atoi(argv[6]); + + image2dvalue::rgb8 input; + io::magick::load(input, argv[1]); + + + image2dvalue::int_u8 mean, stddev; + initialize(mean, input); + initialize(stddev, input); + + image2dvalue::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)); + + + io::pbm::save(out, argv[2]); + io::pgm::save(mean, argv[3]); + io::pgm::save(stddev, argv[4]); + + trace::exiting("main"); +} diff --git a/scribo/src/binarization/ppm_sauvola_ms.cc b/scribo/src/binarization/sauvola_ms.cc similarity index 61% copy from scribo/src/binarization/ppm_sauvola_ms.cc copy to scribo/src/binarization/sauvola_ms.cc index d8c1c9c..3983793 100644 --- a/scribo/src/binarization/ppm_sauvola_ms.cc +++ b/scribo/src/binarization/sauvola_ms.cc @@ -25,8 +25,8 @@ // executable file might be covered by the GNU General Public License.
#include <mln/core/image/image2d.hh> -#include <mln/value/rgb8.hh> -#include <mln/io/ppm/load.hh> +#include <mln/value/int_u8.hh> +#include <mln/io/magick/load.hh> #include <mln/io/pbm/save.hh>
#include <scribo/binarization/sauvola_ms.hh> @@ -34,16 +34,19 @@
bool check_args(int argc, char * argv[]) { - if (argc < 5 || argc > 6) + if (argc < 3 || argc > 7) return false;
- int s = atoi(argv[3]); - - if (s < 2 || s > 3) + if (argc >= 5) { - std::cout << "s must be set to 2 or 3." - << std::endl; - return false; + int s = atoi(argv[4]); + + if (s < 1 || s > 3) + { + std::cout << "s must be set to 2 or 3." + << std::endl; + return false; + } }
return true; @@ -52,10 +55,12 @@ bool check_args(int argc, char * argv[])
const char *args_desc[][2] = { - { "input.ppm", "A color image." }, - { "w", "Window size at scale 1. (Common value: 101)" }, - { "s", "First subsampling ratio (Common value: 3)." }, - { "min_area", "Minimum object area at scale 1 (Common value: 67)" }, + { "input.*", "An image." }, + { "out.pbm", "A binary image." }, + { "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." }, {0, 0} };
@@ -69,29 +74,42 @@ int main(int argc, char *argv[])
if (!check_args(argc, argv)) return scribo::debug::usage(argv, - "Multi-Scale Binarization of a color image based on Sauvola's algorithm. Performs a binarization on each component of the color image and merges the results.", - "input.ppm w s area_threshold output.pbm", - args_desc, "A binary image."); + "Multi-Scale Binarization based on Sauvola's algorithm.", + "input.* output.pbm <w> <s> <k> <scale.pgm>", + args_desc);
trace::entering("main");
// Window size - unsigned w_1 = atoi(argv[2]); // Scale 1 + unsigned w_1; + if (argc >= 4) + w_1 = atoi(argv[3]); // Scale 1 + else + w_1 = 101u;
// First subsampling scale. - unsigned s = atoi(argv[3]); + unsigned s; + if (argc >= 5) + s = atoi(argv[4]); + else + s = 3u;
- // Lambda value - unsigned lambda_min_1 = atoi(argv[4]); + double k; + if (argc >= 6) + k = atof(argv[5]); + else + k = 0.34f;
+ if (argc >= 7) + scribo::binarization::internal::scale_image_output = argv[6];
image2dvalue::rgb8 input_1; - io::ppm::load(input_1, argv[1]); + io::magick::load(input_1, argv[1]);
image2d<bool> - output = scribo::binarization::sauvola_ms(input_1, w_1, s, lambda_min_1); + output = scribo::binarization::sauvola_ms(input_1, w_1, s, k);
- io::pbm::save(output, argv[5]); + io::pbm::save(output, argv[2]); }
diff --git a/scribo/src/binarization/ppm_sauvola_ms_split.cc b/scribo/src/binarization/sauvola_ms_split.cc similarity index 64% copy from scribo/src/binarization/ppm_sauvola_ms_split.cc copy to scribo/src/binarization/sauvola_ms_split.cc index 3f721db..af8b604 100644 --- a/scribo/src/binarization/ppm_sauvola_ms_split.cc +++ b/scribo/src/binarization/sauvola_ms_split.cc @@ -26,7 +26,7 @@
#include <mln/core/image/image2d.hh> #include <mln/value/rgb8.hh> -#include <mln/io/ppm/load.hh> +#include <mln/io/magick/load.hh> #include <mln/io/pbm/save.hh>
#include <scribo/binarization/sauvola_ms_split.hh> @@ -34,16 +34,19 @@
bool check_args(int argc, char * argv[]) { - if (argc != 7) + if (argc < 3 || argc > 7) return false;
- int s = atoi(argv[3]); - - if (s < 1 || s > 3) + if (argc >= 5) { - std::cout << "s must be set to 2 or 3." - << std::endl; - return false; + int s = atoi(argv[4]); + + if (s < 1 || s > 3) + { + std::cout << "s must be set to 2 or 3." + << std::endl; + return false; + } }
return true; @@ -52,11 +55,12 @@ bool check_args(int argc, char * argv[])
const char *args_desc[][2] = { - { "input.ppm", "A color image." }, - { "w", "Window size at scale 1. (Common value: 101)" }, - { "s", "First subsampling ratio (Common value: 3)." }, - { "min_area", "Minimum object area at scale 1 (Common value: 67)" }, - { "min_ntrue", "The number of components in which a site must be set to 'True' in order to be set to 'True' in the output (Possible values: 1, 2, 3). (Common value: 2)" }, + { "input.*", "An image." }, + { "output.pbm", "A binary image." }, + { "w", "Window size at scale 1. (default: 101)" }, + { "s", "First subsampling ratio (default: 3)." }, + { "min_ntrue", "The number of components in which a site must be set to 'True' in order to be set to 'True' in the output (Possible values: 1, 2, 3). (default: 2)" }, + { "K", "Sauvola's formula parameter (default: 0.34)." }, {0, 0} };
@@ -71,28 +75,53 @@ int main(int argc, char *argv[]) if (!check_args(argc, argv)) return scribo::debug::usage(argv, "Multi-Scale Binarization of a color image based on Sauvola's algorithm. Performs a binarization on each component of the color image and merges the results.", - "input.ppm w s area_threshold output.pbm", - args_desc, "A binary image."); + "input.* output.pbm <w> <s> <min_ntrue> <K>", + args_desc);
trace::entering("main");
// Window size - unsigned w_1 = atoi(argv[2]); // Scale 1 + unsigned w_1; + if (argc >= 4) + w_1 = atoi(argv[3]); // Scale 1 + else + w_1 = 101u;
// First subsampling scale. - unsigned s = atoi(argv[3]); + unsigned s; + if (argc >= 5) + s = atoi(argv[4]); + else + s = 3u; + + // min_ntrue + unsigned min_ntrue; + if (argc >= 6) + min_ntrue = atoi(argv[5]); + else + min_ntrue = 2;
// Lambda value - unsigned lambda_min_1 = atoi(argv[4]); + unsigned lambda_min_1 = 67; // FIXME: should be adapted to the + // window size. + + double k; + if (argc >= 7) + k = atof(argv[6]); + else + k = 0.34f; +
image2dvalue::rgb8 input_1; - io::ppm::load(input_1, argv[1]); + io::magick::load(input_1, argv[1]); + + std::cout << "Using w=" << w_1 << " - s=" << s << " - min_ntrue=" << min_ntrue << " - k=" << k << std::endl;
image2d<bool> - output = scribo::binarization::sauvola_ms_split(input_1, w_1, s, lambda_min_1, atoi(argv[5])); + output = scribo::binarization::sauvola_ms_split(input_1, w_1, s, lambda_min_1, min_ntrue, k);
- io::pbm::save(output, argv[6]); + io::pbm::save(output, argv[2]); }
diff --git a/scribo/src/preprocessing/to_pgm.cc b/scribo/src/preprocessing/to_pgm.cc new file mode 100644 index 0000000..974e03f --- /dev/null +++ b/scribo/src/preprocessing/to_pgm.cc @@ -0,0 +1,46 @@ +#include <mln/core/image/image2d.hh> +#include <mln/value/int_u8.hh> +#include <mln/value/rgb8.hh> +#include <mln/io/magick/load.hh> +#include <mln/io/pgm/save.hh> + +#include <scribo/debug/usage.hh> + + +const char *args_desc[][2] = +{ + { "input.*", "A color image." }, + { "output.pgm", "A graylevel image." }, + {0, 0} +}; + + + +int main(int argc, char *argv[]) +{ + using namespace mln; + + if (argc != 3) + return scribo::debug::usage(argv, + "Convert a color image using the minimum RGB component value as intensity.", + "input.* output.pgm", + args_desc); + + + typedef image2dvalue::rgb8 I; + I ima; + io::magick::load(ima, argv[1]); + + image2dvalue::int_u8 out; + initialize(out, ima); + + value::rgb8 v; + mln_piter_(I) p(ima.domain()); + for_all(p) + { + v = ima(p); + out(p) = std::min(v.red(), std::min(v.green(), v.blue())); + } + + io::pgm::save(out, argv[2]); +}