Olena-patches
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- 9625 discussions
olena-2.0-72-gbd5b77d backup - fast multiscale binarization + skewness/revert on input image.
by Guillaume Lazzara 22 Jun '12
by Guillaume Lazzara 22 Jun '12
22 Jun '12
---
scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc | 60 +++++
scribo/sandbox/z/sauvola_ms_rv/pgm_local_mean.cc | 29 +++
.../z/sauvola_ms_rv/ppm_influence_zone_geodesic.cc | 24 ++
.../z/{skewness => sauvola_ms_rv}/skewness.cc | 0
.../skewness/integral_browsing_rv.hh} | 135 ++++++------
.../sandbox/z/sauvola_ms_rv/skewness/skewness2.cc | 230 ++++++++++++++++++++
scribo/sandbox/z/skewness/skewness2.cc | 154 -------------
7 files changed, 414 insertions(+), 218 deletions(-)
create mode 100644 scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc
create mode 100644 scribo/sandbox/z/sauvola_ms_rv/pgm_local_mean.cc
create mode 100644 scribo/sandbox/z/sauvola_ms_rv/ppm_influence_zone_geodesic.cc
rename scribo/sandbox/z/{skewness => sauvola_ms_rv}/skewness.cc (100%)
copy scribo/{scribo/canvas/integral_browsing.hh => sandbox/z/sauvola_ms_rv/skewness/integral_browsing_rv.hh} (72%)
create mode 100644 scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc
delete mode 100644 scribo/sandbox/z/skewness/skewness2.cc
diff --git a/scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc b/scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc
new file mode 100644
index 0000000..7474c46
--- /dev/null
+++ b/scribo/sandbox/z/sauvola_ms_rv/pgm_color_diff.cc
@@ -0,0 +1,60 @@
+#include <mln/core/concept/function.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/ppm/save.hh>
+#include <mln/data/transform.hh>
+#include <mln/arith/minus.hh>
+
+namespace mln
+{
+
+ struct color_diff : Function_v2v<color_diff>
+ {
+ typedef value::rgb8 result;
+
+ color_diff(int threshold) : threshold_(threshold) {}
+
+ value::rgb8 operator()(const int& v) const
+ {
+ int v_d2 = std::abs(v / 2);
+
+ if (v >= -threshold_ && v <= threshold_)
+ return value::rgb8(255, 255, 255);
+ else if (v > threshold_)
+ return value::rgb8(v_d2, 128 + v_d2, v_d2);
+ else
+ return value::rgb8(128 + v_d2, v_d2, v_d2);
+ }
+
+
+ int threshold_;
+ };
+
+}
+
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+
+
+ if (argc != 5)
+ {
+ std::cout << "Usage: " << argv[0] << " in.pgm ref.pgm threshold out.ppm" << std::endl;
+ return 1;
+ }
+
+ image2d<value::int_u8> input, ref;
+
+ io::pgm::load(input, argv[1]);
+ io::pgm::load(ref, argv[2]);
+
+ image2d<int> diff = input - ref;
+
+ color_diff f(atoi(argv[3]));
+ image2d<value::rgb8> result = data::transform(diff, f);
+
+ io::ppm::save(result, argv[4]);
+}
diff --git a/scribo/sandbox/z/sauvola_ms_rv/pgm_local_mean.cc b/scribo/sandbox/z/sauvola_ms_rv/pgm_local_mean.cc
new file mode 100644
index 0000000..06c51e9
--- /dev/null
+++ b/scribo/sandbox/z/sauvola_ms_rv/pgm_local_mean.cc
@@ -0,0 +1,29 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/data/compute_in_window.hh>
+#include <mln/accu/stat/mean.hh>
+#include <mln/win/rectangle2d.hh>
+#include <mln/data/convert.hh>
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+
+ if (argc != 4)
+ {
+ std::cout << "Usage: " << argv[0] << " in.pgm win_size out.pgm" << std::endl;
+ return 1;
+ }
+
+ unsigned win_size = atoi(argv[2]);
+ win::rectangle2d win(win_size, win_size);
+ typedef value::int_u8 V;
+ image2d<V> input;
+ io::pgm::load(input, argv[1]);
+
+ image2d<float> mean = data::compute_in_window(accu::stat::mean<V>(), input, win);
+
+ io::pgm::save(data::convert(value::int_u8(), mean), argv[3]);
+}
diff --git a/scribo/sandbox/z/sauvola_ms_rv/ppm_influence_zone_geodesic.cc b/scribo/sandbox/z/sauvola_ms_rv/ppm_influence_zone_geodesic.cc
new file mode 100644
index 0000000..f7b66b7
--- /dev/null
+++ b/scribo/sandbox/z/sauvola_ms_rv/ppm_influence_zone_geodesic.cc
@@ -0,0 +1,24 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/transform/influence_zone_geodesic.hh>
+#include <mln/io/ppm/all.hh>
+
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+
+ if (argc != 3)
+ {
+ std::cout << argv[0] << " input.ppm output.ppm" << std::endl;
+ return 1;
+ }
+
+ image2d<value::rgb8> input;
+ io::ppm::load(input, argv[1]);
+
+ image2d<value::rgb8> iz = transform::influence_zone_geodesic(input, c8());
+
+ io::ppm::save(iz, argv[2]);
+}
diff --git a/scribo/sandbox/z/skewness/skewness.cc b/scribo/sandbox/z/sauvola_ms_rv/skewness.cc
similarity index 100%
rename from scribo/sandbox/z/skewness/skewness.cc
rename to scribo/sandbox/z/sauvola_ms_rv/skewness.cc
diff --git a/scribo/scribo/canvas/integral_browsing.hh b/scribo/sandbox/z/sauvola_ms_rv/skewness/integral_browsing_rv.hh
similarity index 72%
copy from scribo/scribo/canvas/integral_browsing.hh
copy to scribo/sandbox/z/sauvola_ms_rv/skewness/integral_browsing_rv.hh
index 0ec3d83..79d5e34 100644
--- a/scribo/scribo/canvas/integral_browsing.hh
+++ b/scribo/sandbox/z/sauvola_ms_rv/skewness/integral_browsing_rv.hh
@@ -25,8 +25,8 @@
// executable file might be covered by the GNU General Public License.
-#ifndef SCRIBO_CANVAS_INTEGRAL_BROWSING_HH
-# define SCRIBO_CANVAS_INTEGRAL_BROWSING_HH
+#ifndef SCRIBO_CANVAS_INTEGRAL_BROWSING_RV_HH
+# define SCRIBO_CANVAS_INTEGRAL_BROWSING_RV_HH
# include <mln/core/image/image2d.hh>
# include <mln/util/couple.hh>
@@ -40,10 +40,10 @@ namespace scribo
template <typename F>
- void integral_browsing(const image2d<mln::util::couple<double, double> >& ima,
- unsigned step,
- unsigned w, unsigned h,
- F& functor);
+ void integral_browsing_rv(const image2d<mln::util::couple<double, mln::util::couple<double, double> > >& ima,
+ unsigned step,
+ unsigned w, unsigned h,
+ F& functor);
# ifndef MLN_INCLUDE_ONLY
@@ -54,19 +54,15 @@ namespace scribo
inline
void compute_stats(// in
- double sum, double sum_2, unsigned n,
+ double sum, double sum_2, double sum_3, unsigned n,
// out
- double& mean, double& stddev)
+ double& skewness)
{
- mean = sum / n;
-
- // unbias version:
- double num = (sum_2 - sum * sum / n);
- if (num > 0)
- stddev = std::sqrt(num / (n - 1));
- else
- stddev = 0;
+ // Mean
+ double mean = sum / n;
+ // Skewness
+ skewness = (sum_3 - 3. * mean * sum_2) / (double) n + 2. * std::pow(mean, 3);
}
} // end of namespace scribo::canvas::internal
@@ -75,13 +71,13 @@ namespace scribo
template <typename F>
- void integral_browsing(const image2d<mln::util::couple<double, double> >& ima,
- unsigned step,
- unsigned w, unsigned h,
- unsigned s,
- F& functor)
+ void integral_browsing_rv(const image2d<mln::util::couple<double, mln::util::couple<double, double> > >& ima,
+ unsigned w, unsigned h,
+ F& functor)
{
- typedef mln::util::couple<double, double> V;
+ unsigned step = 1;
+
+ typedef mln::util::couple<double, mln::util::couple<double, double> > V;
typedef const V* Ptr;
Ptr a_ima, b_ima, c_ima, d_ima;
@@ -121,9 +117,8 @@ namespace scribo
b_ml_start = 0, d_ml_start = 0, b_mr_start = 0, d_mr_start = 0,
b_bl_start = 0, d_bl_start = 0, b_br_start = 0, d_br = 0;
- double mean, stddev;
+ double skewness;
- unsigned s_2 = s * s;
// -------------------------------
// T (top)
@@ -157,10 +152,11 @@ namespace scribo
{
// D
internal::compute_stats(d_ima->first(),
- d_ima->second(),
- size_tl * s_2,
- mean, stddev);
- functor.exec(mean, stddev);
+ d_ima->second().first(),
+ d_ima->second().second(),
+ size_tl,
+ skewness);
+ functor.exec(skewness);
d_ima += step;
size_tl += delta_size_tl;
}
@@ -177,10 +173,11 @@ namespace scribo
{
// D - C
internal::compute_stats(d_ima->first() - c_ima->first(),
- d_ima->second() - c_ima->second(),
- size_tc * s_2,
- mean, stddev);
- functor.exec(mean, stddev);
+ d_ima->second().first() - c_ima->second().first(),
+ d_ima->second().second() - c_ima->second().second(),
+ size_tc,
+ skewness);
+ functor.exec(skewness);
c_ima += step;
d_ima += step;
}
@@ -192,17 +189,19 @@ namespace scribo
d_ima = d_tr_start;
double
d_sum = d_ima->first(),
- d_sum_2 = d_ima->second();
+ d_sum_2 = d_ima->second().first(),
+ d_sum_3 = d_ima->second().second();
size_tr = size_tr_start;
for (; col < ncols; col += step)
{
// D* - C
internal::compute_stats(d_sum - c_ima->first(),
- d_sum_2 - c_ima->second(),
- size_tr * s_2,
- mean, stddev);
- functor.exec(mean, stddev);
+ d_sum_2 - c_ima->second().first(),
+ d_sum_3 - c_ima->second().second(),
+ size_tr,
+ skewness);
+ functor.exec(skewness);
c_ima += step;
size_tr -= delta_size_tr;
}
@@ -249,10 +248,11 @@ namespace scribo
{
// D - B
internal::compute_stats(d_ima->first() - b_ima->first(),
- d_ima->second() - b_ima->second(),
- size_ml * s_2,
- mean, stddev);
- functor.exec(mean, stddev);
+ d_ima->second().first() - b_ima->second().first(),
+ d_ima->second().second() - b_ima->second().second(),
+ size_ml,
+ skewness);
+ functor.exec(skewness);
b_ima += step;
d_ima += step;
size_ml += h_step;
@@ -271,11 +271,12 @@ namespace scribo
// D + A - B - C
internal::compute_stats((d_ima->first() - b_ima->first()) + (a_ima->first() - c_ima->first()),
- (d_ima->second() - b_ima->second()) + (a_ima->second() - c_ima->second()),
- size_mc * s_2,
- mean, stddev);
+ (d_ima->second().first() - b_ima->second().first()) + (a_ima->second().first() - c_ima->second().first()),
+ (d_ima->second().second() - b_ima->second().second()) + (a_ima->second().second() - c_ima->second().second()),
+ size_mc,
+ skewness);
- functor.exec(mean, stddev);
+ functor.exec(skewness);
a_ima += step;
b_ima += step;
@@ -290,16 +291,18 @@ namespace scribo
d_ima = d_mr_start;
double
d_b_sum = d_ima->first() - b_ima->first(),
- d_b_sum_2 = d_ima->second() - b_ima->second();
+ d_b_sum_2 = d_ima->second().first() - b_ima->second().first(),
+ d_b_sum_3 = d_ima->second().second() - b_ima->second().second();
for (; col < ncols; col += step)
{
// D* + A - B* - C
internal::compute_stats(d_b_sum + (a_ima->first() - c_ima->first()),
- d_b_sum_2 + (a_ima->second() - c_ima->second()),
- size_mr * s_2,
- mean, stddev);
- functor.exec(mean, stddev);
+ d_b_sum_2 + (a_ima->second().first() - c_ima->second().first()),
+ d_b_sum_3 + (a_ima->second().second() - c_ima->second().second()),
+ size_mr,
+ skewness);
+ functor.exec(skewness);
a_ima += step;
c_ima += step;
size_mr -= h_step;
@@ -345,10 +348,11 @@ namespace scribo
{
// D* - B
internal::compute_stats(d_ima->first() - b_ima->first(),
- d_ima->second() - b_ima->second(),
- size_bl * s_2,
- mean, stddev);
- functor.exec(mean, stddev);
+ d_ima->second().first() - b_ima->second().first(),
+ d_ima->second().second() - b_ima->second().second(),
+ size_bl,
+ skewness);
+ functor.exec(skewness);
b_ima += step;
d_ima += step;
size_bl += delta_size_bl;
@@ -367,10 +371,11 @@ namespace scribo
{
// D* + A - B - C*
internal::compute_stats((d_ima->first() - b_ima->first()) + (a_ima->first() - c_ima->first()),
- (d_ima->second() - b_ima->second()) + (a_ima->second() - c_ima->second()),
- size_bc * s_2,
- mean, stddev);
- functor.exec(mean, stddev);
+ (d_ima->second().first() - b_ima->second().first()) + (a_ima->second().first() - c_ima->second().first()),
+ (d_ima->second().second() - b_ima->second().second()) + (a_ima->second().second() - c_ima->second().second()),
+ size_bc,
+ skewness);
+ functor.exec(skewness);
a_ima += step;
b_ima += step;
c_ima += step;
@@ -386,16 +391,18 @@ namespace scribo
d_ima = d_br;
double
d_b_sum = d_ima->first() - b_ima->first(),
- d_b_sum_2 = d_ima->second() - b_ima->second();
+ d_b_sum_2 = d_ima->second().first() - b_ima->second().first(),
+ d_b_sum_3 = d_ima->second().second() - b_ima->second().second();
for (; col < ncols; col += step)
{
// D* + A - B* - C*
internal::compute_stats(d_b_sum + (a_ima->first() - c_ima->first()),
- d_b_sum_2 + (a_ima->second() - c_ima->second()),
- size_br * s_2,
- mean, stddev);
- functor.exec(mean, stddev);
+ d_b_sum_2 + (a_ima->second().first() - c_ima->second().first()),
+ d_b_sum_3 + (a_ima->second().second() - c_ima->second().second()),
+ size_br,
+ skewness);
+ functor.exec(skewness);
a_ima += step;
c_ima += step;
size_br -= delta_size_br;
@@ -417,4 +424,4 @@ namespace scribo
} // end of namespace mln
-#endif // ! SCRIBO_CANVAS_INTEGRAL_BROWSING_HH
+#endif // ! SCRIBO_CANVAS_INTEGRAL_BROWSING_RV_HH
diff --git a/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc b/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc
new file mode 100644
index 0000000..043e0ad
--- /dev/null
+++ b/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc
@@ -0,0 +1,230 @@
+#include <mln/io/pgm/all.hh>
+#include <mln/io/pbm/all.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/core/image/dmorph/sub_image.hh>
+#include <mln/pw/all.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/neighb.hh>
+#include <mln/win/rectangle2d.hh>
+#include <mln/extension/adjust.hh>
+#include <mln/border/mirror.hh>
+#include <mln/extension/duplicate.hh>
+#include <mln/core/alias/window2d.hh>
+
+#include <mln/data/convert.hh>
+#include <mln/data/stretch.hh>
+#include <mln/debug/println.hh>
+#include <mln/data/transform.hh>
+#include <mln/io/dump/save.hh>
+#include <mln/accu/math/sumpow.hh>
+#include <mln/accu/stat/mean.hh>
+#include <mln/data/compute_in_window.hh>
+#include <mln/core/var.hh>
+#include <mln/data/saturate.hh>
+#include <mln/fun/v2b/threshold_le.hh>
+#include <mln/arith/revert.hh>
+#include <mln/util/timer.hh>
+
+mln::image2d<double> skewness;
+
+#include <scribo/binarization/sauvola_ms.hh>
+#include "integral_browsing_rv.hh"
+
+mln::image2d<bool> skewness_pbm;
+std::string prefix;
+
+
+namespace scribo
+{
+ using namespace mln;
+
+ template <typename I, typename J>
+ void
+ integral_rv(const Image<I>& input_,
+ Image<J>& integral_sum_sum_2_sum_3_)
+ {
+ trace::entering("subsampling::impl::integral_2");
+
+ const unsigned scale = 1;
+
+ const I& input = exact(input_);
+ J& integral_sum_sum_2_sum_3 = exact(integral_sum_sum_2_sum_3_);
+
+ typedef mln_value(I) V;
+ typedef mln_sum(V) S;
+ typedef mln_site(I) P;
+ typedef mln_value(J) V2;
+
+ mlc_bool(P::dim == 2)::check();
+ mln_precondition(input.is_valid());
+ mln_precondition(input.domain().pmin() == literal::origin);
+
+ initialize(integral_sum_sum_2_sum_3, input);
+ V2* p_integ = integral_sum_sum_2_sum_3.buffer();
+
+ const int up = integral_sum_sum_2_sum_3.delta_index(dpoint2d(-1, 0));
+
+ const unsigned nrows = input.nrows();
+ const unsigned ncols = input.ncols();
+
+ unsigned border_thickness = input.border();
+ unsigned b_offset = integral_sum_sum_2_sum_3.delta_index(dpoint2d(border_thickness,
+ border_thickness));
+ p_integ += b_offset;
+
+ unsigned row = 0;
+ {
+ S h_sum = 0, h_sum_2 = 0, h_sum_3 = 0;
+ const V* ptr1 = & input.at_(row, 0);
+ for (unsigned col = 0; col < ncols; ++col)
+ {
+ V v11 = *ptr1++;
+ h_sum += v11;
+ h_sum_2 += v11 * v11;
+ h_sum_3 += v11 * v11 * v11;
+
+ // exception
+ p_integ->first() = h_sum;
+ p_integ->second().first() = h_sum_2;
+ p_integ->second().second() = h_sum_3;
+
+ ++p_integ;
+ }
+ }
+
+ unsigned b_next = 2 * border_thickness;
+
+ p_integ += b_next;
+
+ for (row += scale; row < nrows; ++row)
+ {
+ S h_sum = 0, h_sum_2 = 0, h_sum_3 = 0;
+ const V* ptr1 = & input.at_(row, 0);
+ for (unsigned col = 0; col < ncols; ++col)
+ {
+ V v11 = *ptr1++;
+ h_sum += v11;
+ h_sum_2 += v11 * v11;
+ h_sum_3 += v11 * v11 * v11;
+
+ p_integ->first() = h_sum + (p_integ + up)->first();
+ p_integ->second().first() = h_sum_2 + (p_integ + up)->second().first();
+ p_integ->second().second() = h_sum_3 + (p_integ + up)->second().second();
+
+ ++p_integ;
+ }
+
+ p_integ += b_next;
+ }
+
+ trace::exiting("subsampling::impl::integral_2");
+ }
+
+} // end of namespace scribo
+
+
+namespace mln
+{
+
+ template <typename I>
+ struct invert_on_skewness
+ {
+ I input;
+ image2d<double> skewness_;
+ mln_fwd_pixter(I) pxl;
+
+ invert_on_skewness(const I& input_)
+ : input(duplicate(input_)),
+ pxl(input)
+ {
+ pxl.start();
+ initialize(skewness_, input);
+ }
+
+ void exec(double skewness)
+ {
+ skewness_.element(pxl.offset()) = skewness;
+
+ if (skewness > 1000.)
+ pxl.val() = 255 - pxl.val();
+
+ pxl.next(); // next pixel
+ }
+
+ void finalize()
+ {
+ }
+ };
+
+}
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+
+ if (argc != 4)
+ {
+ std::cerr << "Usage: " << argv[0] << " <input.pgm> <prefix> <win_size>" << std::endl;
+ return 1;
+ }
+
+ util::timer tt;
+ tt.start();
+ util::timer t;
+
+ t.start();
+ image2d<value::int_u8> input;
+ io::pgm::load(input, argv[1]);
+
+ prefix = argv[2];
+
+ int win_size = atoi(argv[3]);
+ t.stop();
+ std::cout << "Initialization - " << t << std::endl;
+
+ // invert data if skewness > 0
+ t.restart();
+
+ image2d<util::couple<double, util::couple<double, double> > > integral_sum_sum_2_sum_3;
+ scribo::integral_rv(input, integral_sum_sum_2_sum_3);
+
+ invert_on_skewness<image2d<value::int_u8> > f(input);
+ scribo::canvas::integral_browsing_rv(integral_sum_sum_2_sum_3, win_size, win_size, f);
+
+ t.stop();
+ std::cout << "invert on skewness - " << t << std::endl;
+
+ io::dump::save(f.skewness_, prefix + "skewness.dump");
+
+ t.restart();
+ image2d<bool> bin = scribo::binarization::sauvola_ms(f.input, 101, 2);
+ std::cout << "sauvola_ms - " << t << std::endl;
+
+
+ std::cout << "Total time : " << tt << std::endl;
+ // prefix += "i_";
+
+ // image2d<bool> bin_i = scribo::binarization::sauvola(arith::revert(input), 51);
+
+ // prefix = argv[2];
+
+ io::pbm::save(bin, prefix + "bin.pbm");
+ // io::pbm::save(bin_i, prefix + "bin_i.pbm");
+
+ // image2d<bool> out;
+ // initialize(out, bin);
+ // mln_piter_(image2d<bool>) p(out.domain());
+ // for_all(p)
+ // if (skewness_pbm(p))
+ // out(p) = bin(p);
+ // else
+ // out(p) = bin_i(p);
+
+ // io::pbm::save(out, prefix + "output.pbm");
+
+ // io::dump::save(scribo::binarization::internal::debug_stddev, prefix + "stddev.dump");
+ // io::dump::save(scribo::binarization::internal::debug_mean, prefix + "mean.dump");
+ // io::dump::save(scribo::binarization::internal::debug_threshold, prefix + "threshold.dump");
+
+}
diff --git a/scribo/sandbox/z/skewness/skewness2.cc b/scribo/sandbox/z/skewness/skewness2.cc
deleted file mode 100644
index 642ae3f..0000000
--- a/scribo/sandbox/z/skewness/skewness2.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-#include <mln/io/pgm/all.hh>
-#include <mln/io/pbm/all.hh>
-#include <mln/core/image/dmorph/image_if.hh>
-#include <mln/core/image/dmorph/sub_image.hh>
-#include <mln/pw/all.hh>
-#include <mln/value/int_u8.hh>
-#include <mln/core/image/image2d.hh>
-#include <mln/core/neighb.hh>
-#include <mln/win/rectangle2d.hh>
-#include <mln/extension/adjust.hh>
-#include <mln/border/mirror.hh>
-#include <mln/extension/duplicate.hh>
-#include <mln/core/alias/window2d.hh>
-
-#include <mln/data/convert.hh>
-#include <mln/data/stretch.hh>
-#include <mln/debug/println.hh>
-#include <mln/data/transform.hh>
-#include <mln/io/dump/save.hh>
-#include <mln/accu/math/sumpow.hh>
-#include <mln/accu/stat/mean.hh>
-#include <mln/data/compute_in_window.hh>
-#include <mln/core/var.hh>
-#include <mln/data/saturate.hh>
-#include <mln/fun/v2b/threshold_le.hh>
-#include <mln/arith/revert.hh>
-#include <mln/util/timer.hh>
-
-mln::image2d<double> skewness;
-
-#include <scribo/binarization/sauvola_ms.hh>
-
-mln::image2d<bool> skewness_pbm;
-std::string prefix;
-
-
-int main(int argc, char *argv[])
-{
- using namespace mln;
-
- if (argc != 4)
- {
- std::cerr << "Usage: " << argv[0] << " <input.pgm> <prefix> <win_size>" << std::endl;
- return 1;
- }
-
- util::timer tt;
- tt.start();
- util::timer t;
-
- t.start();
- image2d<value::int_u8> input;
- io::pgm::load(input, argv[1]);
-
- prefix = argv[2];
-
- int win_size = atoi(argv[3]);
- win::rectangle2d wr = win::rectangle2d(win_size,win_size);
- window2d win;
- win.insert(wr);
-
- accu::pair<accu::stat::mean<value::int_u8,double>,
- accu::pair<accu::math::sumpow<2,value::int_u8,double>,
- accu::math::sumpow<3,value::int_u8,double> > > accu;
- t.stop();
- std::cout << "initialization - " << t << std::endl;
-
-
- t.restart();
- mln_VAR(res, data::compute_in_window(accu, input, win));
- t.stop();
- std::cout << "compute in window - " << t << std::endl;
-
- initialize(skewness, res);
- data::fill(skewness, 0);
-
-
- point2d pc = input.domain().pcenter();
- std::cout << pc << " - sum_2 = " << res(pc).second.first << " - sum_3 = " << res(pc).second.second << " - mean = " << res(pc).first << std::endl;
-
- t.restart();
- {
- int n;
- mln_pixter_(image2d<double>) p(skewness);
- for_all(p)
- {
- n = win.size();
- mln_VAR(d, res.element(p.offset()));
- double m = d.first;
- double sum_3 = d.second.second;
- double sum_2 = d.second.first;
- p.val() = (sum_3 - 3. * m * sum_2) / (double) n + 2. * std::pow(m, 3);
- }
- }
- t.stop();
- std::cout << "Compute unskew - " << t << std::endl;
-
-
- // t.restart();
- // skewness_pbm = data::transform(skewness, fun::v2b::threshold_le<double>(0));
- // t.stop();
- // std::cout << "binarize - " << t << std::endl;
-
- // {
- // io::dump::save(skewness, prefix + "skewness.dump");
- // io::pgm::save(data::convert(value::int_u8(), skewness), prefix + "skewness_u8.pgm");
- // io::pgm::save(data::stretch(value::int_u8(), skewness), prefix + "skewness_stretch.pgm");
- // io::pbm::save(skewness_pbm, prefix + "skewness.pbm");
- // }
-
- t.restart();
- {
- border::resize(skewness, input.border());
- mln_pixter_(image2d<value::int_u8>) p(input);
- for_all(p)
- {
- if (skewness.element(p.offset()) > 0)
- p.val() = mln_max(value::int_u8) - p.val();
- }
- }
- t.stop();
- std::cout << "Negate parts of input image - " << t << std::endl;
-
- t.restart();
- image2d<bool> bin = scribo::binarization::sauvola_ms(input, 101, 2);
- std::cout << "sauvola_ms - " << t << std::endl;
-
-
- std::cout << "Total time : " << tt << std::endl;
- // prefix += "i_";
-
- // image2d<bool> bin_i = scribo::binarization::sauvola(arith::revert(input), 51);
-
- // prefix = argv[2];
-
- io::pbm::save(bin, prefix + "bin.pbm");
- // io::pbm::save(bin_i, prefix + "bin_i.pbm");
-
- // image2d<bool> out;
- // initialize(out, bin);
- // mln_piter_(image2d<bool>) p(out.domain());
- // for_all(p)
- // if (skewness_pbm(p))
- // out(p) = bin(p);
- // else
- // out(p) = bin_i(p);
-
- // io::pbm::save(out, prefix + "output.pbm");
-
- // io::dump::save(scribo::binarization::internal::debug_stddev, prefix + "stddev.dump");
- // io::dump::save(scribo::binarization::internal::debug_mean, prefix + "mean.dump");
- // io::dump::save(scribo::binarization::internal::debug_threshold, prefix + "threshold.dump");
-
-}
--
1.7.2.5
1
0
T = (255 - m) * alpha
si (255 - f(p)) < T
-> noir
sinon -> blanc
---
.../sandbox/z/sauvola_ms_rv/skewness/skewness2.cc | 31 +++++++++++++-------
.../internal/compute_local_threshold.hh | 15 ++++++++-
.../binarization/internal/first_pass_functor.hh | 2 +-
.../binarization/internal/sauvola_formula.hh | 22 +++++++++----
scribo/scribo/binarization/local_threshold.hh | 27 +++++++++++------
5 files changed, 67 insertions(+), 30 deletions(-)
diff --git a/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc b/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc
index 043e0ad..9b77a99 100644
--- a/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc
+++ b/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc
@@ -26,9 +26,9 @@
#include <mln/arith/revert.hh>
#include <mln/util/timer.hh>
-mln::image2d<double> skewness;
#include <scribo/binarization/sauvola_ms.hh>
+#include <scribo/binarization/sauvola.hh>
#include "integral_browsing_rv.hh"
mln::image2d<bool> skewness_pbm;
@@ -131,7 +131,8 @@ namespace mln
struct invert_on_skewness
{
I input;
- image2d<double> skewness_;
+ image2d<bool> skewness_;
+ image2d<double> skewness_d_;
mln_fwd_pixter(I) pxl;
invert_on_skewness(const I& input_)
@@ -140,14 +141,16 @@ namespace mln
{
pxl.start();
initialize(skewness_, input);
+ initialize(skewness_d_, input);
}
void exec(double skewness)
{
- skewness_.element(pxl.offset()) = skewness;
+ skewness_d_.element(pxl.offset()) = skewness;
+ skewness_.element(pxl.offset()) = (skewness <= 1000.);
- if (skewness > 1000.)
- pxl.val() = 255 - pxl.val();
+ // if (skewness > 1000.)
+ // pxl.val() = 255 - pxl.val();
pxl.next(); // next pixel
}
@@ -163,9 +166,9 @@ int main(int argc, char *argv[])
{
using namespace mln;
- if (argc != 4)
+ if (argc != 5)
{
- std::cerr << "Usage: " << argv[0] << " <input.pgm> <prefix> <win_size>" << std::endl;
+ std::cerr << "Usage: " << argv[0] << " <input.pgm> <prefix> <skewness_win_size> <sauvola_win_size>" << std::endl;
return 1;
}
@@ -179,7 +182,8 @@ int main(int argc, char *argv[])
prefix = argv[2];
- int win_size = atoi(argv[3]);
+ int skewness_win_size = atoi(argv[3]);
+ int sauvola_win_size = atoi(argv[4]);
t.stop();
std::cout << "Initialization - " << t << std::endl;
@@ -190,16 +194,21 @@ int main(int argc, char *argv[])
scribo::integral_rv(input, integral_sum_sum_2_sum_3);
invert_on_skewness<image2d<value::int_u8> > f(input);
- scribo::canvas::integral_browsing_rv(integral_sum_sum_2_sum_3, win_size, win_size, f);
+ scribo::canvas::integral_browsing_rv(integral_sum_sum_2_sum_3, skewness_win_size, skewness_win_size, f);
+
+ skewness_pbm = f.skewness_;
t.stop();
std::cout << "invert on skewness - " << t << std::endl;
io::dump::save(f.skewness_, prefix + "skewness.dump");
+ io::dump::save(f.skewness_d_, prefix + "skewness_d.dump");
t.restart();
- image2d<bool> bin = scribo::binarization::sauvola_ms(f.input, 101, 2);
- std::cout << "sauvola_ms - " << t << std::endl;
+// image2d<bool> bin = scribo::binarization::sauvola_ms(input, 101, 2);
+// std::cout << "sauvola_ms - " << t << std::endl;
+ image2d<bool> bin = scribo::binarization::sauvola(input, sauvola_win_size);
+ std::cout << "sauvola - " << t << std::endl;
std::cout << "Total time : " << tt << std::endl;
diff --git a/scribo/scribo/binarization/internal/compute_local_threshold.hh b/scribo/scribo/binarization/internal/compute_local_threshold.hh
index 147ef0f..4c25e17 100644
--- a/scribo/scribo/binarization/internal/compute_local_threshold.hh
+++ b/scribo/scribo/binarization/internal/compute_local_threshold.hh
@@ -42,7 +42,8 @@
-// extern mln::image2d<double> skewness;
+extern mln::image2d<double> skewness;
+extern mln::image2d<bool> skewness_pbm;
namespace scribo
{
@@ -117,6 +118,11 @@ namespace scribo
- simple.at_(row_max, col_min)
- simple.at_(row_min, col_max));
+ // if (!skewness_pbm(p))
+ // {
+ // m_x_y_tmp = 255 * wh - m_x_y_tmp;
+ // }
+
double m_x_y = m_x_y_tmp / wh;
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
@@ -130,6 +136,11 @@ namespace scribo
- squared.at_(row_max, col_min)
- squared.at_(row_min, col_max));
+ // if (!skewness_pbm(p))
+ // {
+ // s_x_y_tmp = std::pow(255, 2) * wh - s_x_y_tmp;
+ // }
+
double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh - 1.f));
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
@@ -140,7 +151,7 @@ namespace scribo
// Thresholding.
// skewness_ = skewness(p);
// b = (p == point2d(5,5));
- double t_x_y = formula(m_x_y, s_x_y, K, R);
+ double t_x_y = formula(p, m_x_y, s_x_y, K, R);
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
double alpha = K * (1 - s_x_y / R);
diff --git a/scribo/scribo/binarization/internal/first_pass_functor.hh b/scribo/scribo/binarization/internal/first_pass_functor.hh
index 8da401b..f0ae5a9 100644
--- a/scribo/scribo/binarization/internal/first_pass_functor.hh
+++ b/scribo/scribo/binarization/internal/first_pass_functor.hh
@@ -132,7 +132,7 @@ namespace scribo
unsigned p = pxl.offset();
value::int_u8 t_p;
- mln::convert::from_to(formula_(mean, stddev, K_, R_),
+ mln::convert::from_to(formula_(input.point_at_index(p), mean, stddev, K_, R_),
t_p);
msk.element(p) = input.element(p) < t_p;
diff --git a/scribo/scribo/binarization/internal/sauvola_formula.hh b/scribo/scribo/binarization/internal/sauvola_formula.hh
index adbef13..e010e85 100644
--- a/scribo/scribo/binarization/internal/sauvola_formula.hh
+++ b/scribo/scribo/binarization/internal/sauvola_formula.hh
@@ -46,6 +46,10 @@
# define SCRIBO_DEFAULT_SAUVOLA_R 128
+#include <mln/core/alias/point2d.hh>
+
+extern mln::image2d<bool> skewness_pbm;
+
namespace scribo
{
@@ -55,6 +59,8 @@ namespace scribo
namespace internal
{
+ using namespace mln;
+
struct sauvola_formula
{
@@ -70,13 +76,13 @@ namespace scribo
\return A threshold.
*/
- double operator()(const double m_x_y, const double s_x_y,
+ double operator()(const point2d& p, const double m_x_y, const double s_x_y,
const double K, const double R) const;
/*!
\overload K = 0.34 and R = 128.
*/
- double operator()(const double m_x_y, const double s_x_y) const;
+ double operator()(const point2d& p, const double m_x_y, const double s_x_y) const;
};
@@ -88,7 +94,7 @@ namespace scribo
inline
double
- sauvola_formula::operator()(const double m_x_y, const double s_x_y,
+ sauvola_formula::operator()(const point2d& p, const double m_x_y, const double s_x_y,
const double K, const double R) const
{
// if (b)
@@ -98,15 +104,17 @@ namespace scribo
// if (skewness_ > 0)
// if (new_t != old_t)
// std::cout << skewness_ << " - " << new_t << " vs " << old_t << std::endl;
-
- return m_x_y * (1.0 + K * ((s_x_y / R) - 1.0));
+ if (skewness_pbm(p))
+ return m_x_y * (1.0 + K * ((s_x_y / R) - 1.0));
+ else
+ return (255 - m_x_y) * (1.0 + K * ((s_x_y / R) - 1.0));
}
inline
double
- sauvola_formula::operator()(const double m_x_y, const double s_x_y) const
+ sauvola_formula::operator()(const point2d& p, const double m_x_y, const double s_x_y) const
{
- return (*this)(m_x_y, s_x_y,
+ return (*this)(p, m_x_y, s_x_y,
SCRIBO_DEFAULT_SAUVOLA_K, SCRIBO_DEFAULT_SAUVOLA_R);
}
diff --git a/scribo/scribo/binarization/local_threshold.hh b/scribo/scribo/binarization/local_threshold.hh
index 9d116ed..ab589e2 100644
--- a/scribo/scribo/binarization/local_threshold.hh
+++ b/scribo/scribo/binarization/local_threshold.hh
@@ -34,12 +34,13 @@
///
/// \brief Binarize an image using a threshold image.
+extern mln::image2d<bool> skewness_pbm;
+
namespace scribo
{
using namespace mln;
-
namespace binarization
{
@@ -110,8 +111,10 @@ namespace scribo
mln_piter(I) p(input.domain());
for_all(p)
- output(p) = (input(p) <= threshold(p));
-
+ if (skewness_pbm(p))
+ output(p) = (input(p) <= threshold(p));
+ else
+ output(p) = ((255 - input(p)) <= threshold(p));
trace::exiting("scribo::binarization::impl::generic::local_threshold");
return output;
@@ -132,6 +135,8 @@ namespace scribo
const I& input = exact(input_);
const T& threshold = exact(threshold_);
+ border::resize(::skewness_pbm, input.border());
+
typedef mln_ch_value(I, bool) O;
O output;
initialize(output, input);
@@ -139,8 +144,12 @@ namespace scribo
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();
+ if (skewness_pbm.element(pi.offset()))
+ po.val() = (pi.val() <= pt.val());
+ else
+ po.val() = ((255 - pi.val()) <= pt.val());
trace::exiting("scribo::binarization::impl::generic::local_threshold_fastest");
return output;
@@ -159,7 +168,7 @@ namespace scribo
template <typename I, typename T>
mln_ch_value(I, bool)
- local_threshold_dispatch(trait::image::value_alignment::any,
+ local_threshold_dispatch(trait::image::speed::any,
trait::image::speed::any,
const Image<I>& input, const Image<T>& threshold)
{
@@ -169,7 +178,7 @@ namespace scribo
template <typename I, typename T>
mln_ch_value(I, bool)
- local_threshold_dispatch(trait::image::value_alignment::with_grid,
+ local_threshold_dispatch(trait::image::speed::fastest,
trait::image::speed::fastest,
const Image<I>& input, const Image<T>& threshold)
{
@@ -181,9 +190,9 @@ namespace scribo
local_threshold_dispatch(const Image<I>& input,
const Image<T>& threshold)
{
- return local_threshold_dispatch(mln_trait_image_value_alignment(I)(),
- mln_trait_image_speed(I)(),
- exact(input), exact(threshold));
+ return local_threshold_dispatch(mln_trait_image_speed(I)(),
+ mln_trait_image_speed(T)(),
+ input, threshold);
}
} // end of namespace scribo::binarization::internal
--
1.7.2.5
1
0
---
.../sandbox/z/sauvola_ms_rv/skewness/skewness2.cc | 2 ++
scribo/scribo/binarization/sauvola_threshold.hh | 6 +++++-
2 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc b/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc
index 9b77a99..331575f 100644
--- a/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc
+++ b/scribo/sandbox/z/sauvola_ms_rv/skewness/skewness2.cc
@@ -32,6 +32,7 @@
#include "integral_browsing_rv.hh"
mln::image2d<bool> skewness_pbm;
+mln::image2d<double> skewness_d;
std::string prefix;
@@ -197,6 +198,7 @@ int main(int argc, char *argv[])
scribo::canvas::integral_browsing_rv(integral_sum_sum_2_sum_3, skewness_win_size, skewness_win_size, f);
skewness_pbm = f.skewness_;
+ skewness_d = f.skewness_d_;
t.stop();
std::cout << "invert on skewness - " << t << std::endl;
diff --git a/scribo/scribo/binarization/sauvola_threshold.hh b/scribo/scribo/binarization/sauvola_threshold.hh
index df46e95..7950c13 100644
--- a/scribo/scribo/binarization/sauvola_threshold.hh
+++ b/scribo/scribo/binarization/sauvola_threshold.hh
@@ -44,7 +44,7 @@
# include <scribo/binarization/internal/compute_local_threshold.hh>
# include <scribo/binarization/internal/sauvola_formula.hh>
-
+extern std::string prefix;
namespace scribo
{
@@ -130,6 +130,7 @@ namespace scribo
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
initialize(internal::debug_mean, input);
initialize(internal::debug_stddev, input);
+
initialize(internal::debug_threshold, input);
initialize(internal::debug_alpham, input);
initialize(internal::debug_alphacond, input);
@@ -262,6 +263,9 @@ namespace scribo
simple = init_integral_image(input, scribo::internal::identity_),
squared = init_integral_image(input, scribo::internal::square_);
+ io::dump::save(simple, prefix + "simple.dump");
+ io::dump::save(squared, prefix + "squared.dump");
+
return sauvola_threshold(input, window_size,
K, simple, squared);
}
--
1.7.2.5
1
0
---
scribo/sauvola_fast.cc | 175 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 175 insertions(+), 0 deletions(-)
create mode 100644 scribo/sauvola_fast.cc
diff --git a/scribo/sauvola_fast.cc b/scribo/sauvola_fast.cc
new file mode 100644
index 0000000..8018135
--- /dev/null
+++ b/scribo/sauvola_fast.cc
@@ -0,0 +1,175 @@
+#include <mln/core/image/image2d.hh>
+#include <scribo/canvas/integral_browsing.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/util/couple.hh>
+#include <mln/util/timer.hh>
+#include <scribo/binarization/internal/sauvola_formula.hh>
+
+namespace mln
+{
+
+ template <typename I>
+ struct sauvola_fast_functor
+ {
+
+ const I& input;
+ typedef mln_ch_value(I,bool) bin_t;
+ bin_t bin;
+
+ mln_fwd_pixter(const I) pi;
+ mln_fwd_pixter(bin_t) po;
+
+ double K_;
+ double R_;
+
+ scribo::binarization::internal::sauvola_formula formula_;
+
+ unsigned count_;
+
+ sauvola_fast_functor(const I& input_, mln_ch_value(I,bool)& bin_, double K, double R)
+ : input(input_),
+ bin(bin_),
+ pi(input),
+ po(bin),
+ K_(K),
+ R_(R)
+ {
+ pi.start();
+ po.start();
+ count_ = 0;
+ }
+
+ void exec(double mean, double stddev)
+ {
+ static point2d p(0,0);
+ po.val() = (pi.val() <= formula_(p, mean, stddev, K_, R_));
+
+ pi.next(); // next pixel
+ po.next(); // next pixel
+
+ ++count_;
+ }
+
+ void finalize()
+ {
+ std::cout << input.domain().nsites() << " - " << input.domain().nrows() * input.domain().ncols() << " - " << count_ << std::endl;
+ }
+
+ };
+
+
+
+
+ template <typename I, typename J>
+ void
+ init_integral(const Image<I>& input_,
+ Image<J>& integral_sum_sum_2_)
+ {
+ trace::entering("subsampling::impl::integral_3");
+
+ const I& input = exact(input_);
+ J& integral_sum_sum_2 = exact(integral_sum_sum_2_);
+
+ mln_precondition(input.is_valid());
+ mln_precondition(input.domain().pmin() == literal::origin);
+
+ typedef mln_value(I) V;
+ typedef mln_sum(V) S;
+ typedef mln_value(J) V2;
+ typedef mln_site(I) P;
+
+ initialize(integral_sum_sum_2, input);
+ V2* p_integ = integral_sum_sum_2.buffer();
+
+ const int up = input.delta_index(dpoint2d(-1, 0));
+
+ const unsigned nrows = input.domain().nrows();
+ const unsigned ncols = input.domain().ncols();
+
+ unsigned row = 0;
+
+ unsigned b_offset = input.delta_index(dpoint2d(input.border(),
+ input.border()));
+ p_integ += b_offset;
+ {
+ S h_sum = 0, h_sum_2 = 0;
+ const V* ptr1 = & input.at_(row, 0);
+ for (unsigned col = 0; col < ncols; ++col)
+ {
+ V v = *ptr1++;
+
+ h_sum += v;
+ h_sum_2 += v * v;
+
+ // exception
+ p_integ->first() = h_sum;
+ p_integ->second() = h_sum_2;
+
+ ++p_integ;
+ }
+ }
+
+ unsigned b_next = 2 * input.border();
+
+ p_integ += b_next;
+
+ for (row += 1; row < nrows; ++row)
+ {
+ S h_sum = 0, h_sum_2 = 0;
+ const V* ptr1 = & input.at_(row, 0);
+ for (unsigned col = 0; col < ncols; ++col)
+ {
+ V v = *ptr1++;
+
+ h_sum += v;
+ h_sum_2 += v * v;
+
+ p_integ->first() = h_sum + (p_integ + up)->first();
+ p_integ->second() = h_sum_2 + (p_integ + up)->second();
+
+ ++p_integ;
+ }
+
+ p_integ += b_next;
+ }
+
+ trace::exiting("subsampling::impl::integral_3");
+ }
+
+
+
+ image2d<bool>
+ sauvola_fast(const image2d<value::int_u8>& input, unsigned win)
+ {
+ image2d<util::couple<double,double> > integral;
+ init_integral(input, integral);
+
+ image2d<bool> output;
+ initialize(output, input);
+ sauvola_fast_functor<image2d<value::int_u8> > f(input, output, SCRIBO_DEFAULT_SAUVOLA_K, SCRIBO_DEFAULT_SAUVOLA_R);
+ scribo::canvas::integral_browsing(integral, 1, win, win, 1, f);
+
+ return f.bin;
+ }
+
+}
+
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+
+ image2d<value::int_u8> input;
+ io::pgm::load(input, argv[1]);
+
+ unsigned win = atoi(argv[2]);
+
+ util::timer t;
+ t.start();
+ image2d<bool> output = sauvola_fast(input, win);
+ t.stop();
+ std::cout << t << std::endl;
+
+ io::pbm::save(output, argv[3]);
+}
--
1.7.2.5
1
0
---
scribo/sauvola_fast.cc | 85 +++++++++++++++++++++++++++++++----------------
1 files changed, 56 insertions(+), 29 deletions(-)
diff --git a/scribo/sauvola_fast.cc b/scribo/sauvola_fast.cc
index 8018135..95e49b2 100644
--- a/scribo/sauvola_fast.cc
+++ b/scribo/sauvola_fast.cc
@@ -17,43 +17,63 @@ namespace mln
typedef mln_ch_value(I,bool) bin_t;
bin_t bin;
- mln_fwd_pixter(const I) pi;
- mln_fwd_pixter(bin_t) po;
+ image2d<double> th_;
+
+ const mln_value(I)* pi;
+ bool* po;
double K_;
double R_;
scribo::binarization::internal::sauvola_formula formula_;
- unsigned count_;
+ int step_;
+ unsigned next_line1;
+ unsigned next_line2;
+ unsigned next_line3;
+ unsigned offset1;
+ unsigned offset2;
sauvola_fast_functor(const I& input_, mln_ch_value(I,bool)& bin_, double K, double R)
: input(input_),
bin(bin_),
- pi(input),
- po(bin),
+ pi(&input(input.domain().pmin())),
+ po(&bin(bin.domain().pmin())),
K_(K),
R_(R)
{
- pi.start();
- po.start();
- count_ = 0;
+ step_ = 3;
+ next_line1 = 2 * input.border();
+ next_line2 = input.delta_index(dpoint2d(+1,0)) + next_line1;
+ next_line3 = input.delta_index(dpoint2d(+2,0)) + next_line1;
+
+ offset1 = input.delta_index(dpoint2d(+1,0));
+ offset2 = input.delta_index(dpoint2d(+2,0));
}
void exec(double mean, double stddev)
{
static point2d p(0,0);
- po.val() = (pi.val() <= formula_(p, mean, stddev, K_, R_));
- pi.next(); // next pixel
- po.next(); // next pixel
+ double th = formula_(p, mean, stddev, K_, R_);
+
+ for (int i = 0; i < step_; ++i, ++po, ++pi)
+ {
+ *po = (*pi <= th);
+ *(po + offset1) = (*(pi + offset1) <= th);
+ *(po + offset2) = (*(pi + offset2) <= th);
+ }
+ }
- ++count_;
+ void end_of_row(int)
+ {
+ po += next_line3;
+ pi += next_line3;
}
+
void finalize()
{
- std::cout << input.domain().nsites() << " - " << input.domain().nrows() * input.domain().ncols() << " - " << count_ << std::endl;
}
};
@@ -64,7 +84,7 @@ namespace mln
template <typename I, typename J>
void
init_integral(const Image<I>& input_,
- Image<J>& integral_sum_sum_2_)
+ Image<J>& integral_sum_sum_2_)
{
trace::entering("subsampling::impl::integral_3");
@@ -90,23 +110,23 @@ namespace mln
unsigned row = 0;
unsigned b_offset = input.delta_index(dpoint2d(input.border(),
- input.border()));
+ input.border()));
p_integ += b_offset;
{
S h_sum = 0, h_sum_2 = 0;
const V* ptr1 = & input.at_(row, 0);
for (unsigned col = 0; col < ncols; ++col)
{
- V v = *ptr1++;
+ V v = *ptr1++;
- h_sum += v;
- h_sum_2 += v * v;
+ h_sum += v;
+ h_sum_2 += v * v;
- // exception
- p_integ->first() = h_sum;
- p_integ->second() = h_sum_2;
+ // exception
+ p_integ->first() = h_sum;
+ p_integ->second() = h_sum_2;
- ++p_integ;
+ ++p_integ;
}
}
@@ -120,15 +140,15 @@ namespace mln
const V* ptr1 = & input.at_(row, 0);
for (unsigned col = 0; col < ncols; ++col)
{
- V v = *ptr1++;
+ V v = *ptr1++;
- h_sum += v;
- h_sum_2 += v * v;
+ h_sum += v;
+ h_sum_2 += v * v;
- p_integ->first() = h_sum + (p_integ + up)->first();
- p_integ->second() = h_sum_2 + (p_integ + up)->second();
+ p_integ->first() = h_sum + (p_integ + up)->first();
+ p_integ->second() = h_sum_2 + (p_integ + up)->second();
- ++p_integ;
+ ++p_integ;
}
p_integ += b_next;
@@ -142,13 +162,20 @@ namespace mln
image2d<bool>
sauvola_fast(const image2d<value::int_u8>& input, unsigned win)
{
+ util::timer t;
+ t.start();
image2d<util::couple<double,double> > integral;
init_integral(input, integral);
+ t.stop();
+ std::cout << "image integrale - " << t << std::endl;
+ t.restart();
image2d<bool> output;
initialize(output, input);
sauvola_fast_functor<image2d<value::int_u8> > f(input, output, SCRIBO_DEFAULT_SAUVOLA_K, SCRIBO_DEFAULT_SAUVOLA_R);
- scribo::canvas::integral_browsing(integral, 1, win, win, 1, f);
+ scribo::canvas::integral_browsing(integral, 3, win, win, 1, f);
+ t.stop();
+ std::cout << "Binarization - " << t << std::endl;
return f.bin;
}
--
1.7.2.5
1
0
---
scribo/sauvola_fast.cc | 118 +++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 116 insertions(+), 2 deletions(-)
diff --git a/scribo/sauvola_fast.cc b/scribo/sauvola_fast.cc
index 95e49b2..ed4e6d4 100644
--- a/scribo/sauvola_fast.cc
+++ b/scribo/sauvola_fast.cc
@@ -83,6 +83,117 @@ namespace mln
template <typename I, typename J>
void
+ init_integral_3(const Image<I>& input_,
+ Image<J>& integral_sum_sum_2_)
+ {
+ trace::entering("subsampling::impl::integral_3");
+
+ const unsigned scale = 3;
+
+ const I& input = exact(input_);
+ J& integral_sum_sum_2 = exact(integral_sum_sum_2_);
+
+ box<mln_site(I)>
+ output_domain = mln::make::box2d((input.nrows() + scale - 1) / scale,
+ (input.ncols() + scale - 1) / scale);
+
+ mln_precondition(input.is_valid());
+ mln_precondition(input.domain().pmin() == literal::origin);
+ mln_precondition(scale > 1);
+
+ typedef mln_value(I) V;
+ typedef mln_sum(V) S;
+ typedef mln_value(J) V2;
+ typedef mln_site(I) P;
+
+ integral_sum_sum_2.init_(output_domain, input.border());
+ V2* p_integ = integral_sum_sum_2.buffer();
+
+ const int up = integral_sum_sum_2.delta_index(dpoint2d(-1, 0));
+
+ const unsigned nrows = 3 * integral_sum_sum_2.nrows();
+ const unsigned ncols = 3 * integral_sum_sum_2.ncols();
+
+ unsigned row = 0;
+
+ unsigned b_offset = integral_sum_sum_2.delta_index(dpoint2d(input.border(),
+ input.border()));
+ p_integ += b_offset;
+ {
+ S h_sum = 0, h_sum_2 = 0;
+ const V* ptr1 = & input.at_(row, 0);
+ const V* ptr2 = & input.at_(row + 1, 0);
+ const V* ptr3 = & input.at_(row + 2, 0);
+ for (unsigned col = 0; col < ncols; col += scale)
+ {
+ V v11 = *ptr1, v12 = *(ptr1 + 1), v13 = *(ptr1 + 2),
+ v21 = *ptr2, v22 = *(ptr2 + 1), v23 = *(ptr2 + 2),
+ v31 = *ptr3, v32 = *(ptr3 + 1), v33 = *(ptr3 + 2);
+ ptr1 += 3;
+ ptr2 += 3;
+ ptr3 += 3;
+ S local_sum = v11 + v12 + v13
+ + v21 + v22 + v23
+ + v31 + v32 + v33,
+ local_sum_2 = v11*v11 + v12*v12 + v13*v13
+ + v21*v21 + v22*v22 + v23*v23
+ + v31*v31 + v32*v32 + v33*v33;
+
+ h_sum += local_sum;
+ h_sum_2 += local_sum_2;
+
+ // exception
+ p_integ->first() = h_sum;
+ p_integ->second() = h_sum_2;
+
+ p_integ += 1;
+ }
+ }
+
+ unsigned b_next = 2 * input.border();
+
+ p_integ += b_next;
+
+ for (row += scale; row < nrows; row += scale)
+ {
+ S h_sum = 0, h_sum_2 = 0;
+ const V* ptr1 = & input.at_(row, 0);
+ const V* ptr2 = & input.at_(row + 1, 0);
+ const V* ptr3 = & input.at_(row + 2, 0);
+ for (unsigned col = 0; col < ncols; col += scale)
+ {
+ V v11 = *ptr1, v12 = *(ptr1 + 1), v13 = *(ptr1 + 2),
+ v21 = *ptr2, v22 = *(ptr2 + 1), v23 = *(ptr2 + 2),
+ v31 = *ptr3, v32 = *(ptr3 + 1), v33 = *(ptr3 + 2);
+ ptr1 += 3;
+ ptr2 += 3;
+ ptr3 += 3;
+ S local_sum = v11 + v12 + v13
+ + v21 + v22 + v23
+ + v31 + v32 + v33,
+ local_sum_2 = v11*v11 + v12*v12 + v13*v13
+ + v21*v21 + v22*v22 + v23*v23
+ + v31*v31 + v32*v32 + v33*v33;
+
+ h_sum += local_sum;
+ h_sum_2 += local_sum_2;
+
+ p_integ->first() = h_sum + (p_integ + up)->first();
+ p_integ->second() = h_sum_2 + (p_integ + up)->second();
+
+ p_integ += 1;
+ }
+
+ p_integ += b_next;
+ }
+
+ trace::exiting("subsampling::impl::integral_3");
+ }
+
+
+
+ template <typename I, typename J>
+ void
init_integral(const Image<I>& input_,
Image<J>& integral_sum_sum_2_)
{
@@ -165,7 +276,10 @@ namespace mln
util::timer t;
t.start();
image2d<util::couple<double,double> > integral;
- init_integral(input, integral);
+ init_integral_3(input, integral);
+
+ // image2d<value::int_u8> sub = scribo::subsampling::integral(input, 3, integral);
+
t.stop();
std::cout << "image integrale - " << t << std::endl;
@@ -173,7 +287,7 @@ namespace mln
image2d<bool> output;
initialize(output, input);
sauvola_fast_functor<image2d<value::int_u8> > f(input, output, SCRIBO_DEFAULT_SAUVOLA_K, SCRIBO_DEFAULT_SAUVOLA_R);
- scribo::canvas::integral_browsing(integral, 3, win, win, 1, f);
+ scribo::canvas::integral_browsing(integral, 1, win / 3, win / 3, 3, f);
t.stop();
std::cout << "Binarization - " << t << std::endl;
--
1.7.2.5
1
0
---
scribo/sauvola_fast.cc | 234 ++++++++----------------------------------------
1 files changed, 36 insertions(+), 198 deletions(-)
diff --git a/scribo/sauvola_fast.cc b/scribo/sauvola_fast.cc
index ed4e6d4..7eb41ca 100644
--- a/scribo/sauvola_fast.cc
+++ b/scribo/sauvola_fast.cc
@@ -5,12 +5,14 @@
#include <mln/util/couple.hh>
#include <mln/util/timer.hh>
#include <scribo/binarization/internal/sauvola_formula.hh>
+#include <scribo/util/init_integral_image.hh>
+#include <scribo/util/integral_sum_sum2_functor.hh>
namespace mln
{
template <typename I>
- struct sauvola_fast_functor
+ struct sauvola_functor
{
const I& input;
@@ -28,13 +30,12 @@ namespace mln
scribo::binarization::internal::sauvola_formula formula_;
int step_;
- unsigned next_line1;
unsigned next_line2;
unsigned next_line3;
unsigned offset1;
unsigned offset2;
- sauvola_fast_functor(const I& input_, mln_ch_value(I,bool)& bin_, double K, double R)
+ sauvola_functor(const I& input_, mln_ch_value(I,bool)& bin_, double K, double R)
: input(input_),
bin(bin_),
pi(&input(input.domain().pmin())),
@@ -43,7 +44,7 @@ namespace mln
R_(R)
{
step_ = 3;
- next_line1 = 2 * input.border();
+ unsigned next_line1 = 2 * input.border();
next_line2 = input.delta_index(dpoint2d(+1,0)) + next_line1;
next_line3 = input.delta_index(dpoint2d(+2,0)) + next_line1;
@@ -51,6 +52,7 @@ namespace mln
offset2 = input.delta_index(dpoint2d(+2,0));
}
+ // Run every 4 pixels.
void exec(double mean, double stddev)
{
static point2d p(0,0);
@@ -63,6 +65,20 @@ namespace mln
*(po + offset1) = (*(pi + offset1) <= th);
*(po + offset2) = (*(pi + offset2) <= th);
}
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ // Store local mean
+ unsigned index = pi - input.buffer();
+
+ internal::debug_mean.element(index) = mean * internal::mean_debug_factor;
+ internal::debug_stddev.element(index) = stddev * internal::stddev_debug_factor;
+ internal::debug_threshold.element(index) = t;
+
+ double alpha = K * (1 - stddev / R);
+ internal::debug_alpham.element(index) = alpha * mean * internal::alpham_debug_factor;
+ internal::debug_alphacond.element(index) = (stddev < (alpha * mean / 2.));
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
}
void end_of_row(int)
@@ -80,213 +96,34 @@ namespace mln
-
- template <typename I, typename J>
- void
- init_integral_3(const Image<I>& input_,
- Image<J>& integral_sum_sum_2_)
- {
- trace::entering("subsampling::impl::integral_3");
-
- const unsigned scale = 3;
-
- const I& input = exact(input_);
- J& integral_sum_sum_2 = exact(integral_sum_sum_2_);
-
- box<mln_site(I)>
- output_domain = mln::make::box2d((input.nrows() + scale - 1) / scale,
- (input.ncols() + scale - 1) / scale);
-
- mln_precondition(input.is_valid());
- mln_precondition(input.domain().pmin() == literal::origin);
- mln_precondition(scale > 1);
-
- typedef mln_value(I) V;
- typedef mln_sum(V) S;
- typedef mln_value(J) V2;
- typedef mln_site(I) P;
-
- integral_sum_sum_2.init_(output_domain, input.border());
- V2* p_integ = integral_sum_sum_2.buffer();
-
- const int up = integral_sum_sum_2.delta_index(dpoint2d(-1, 0));
-
- const unsigned nrows = 3 * integral_sum_sum_2.nrows();
- const unsigned ncols = 3 * integral_sum_sum_2.ncols();
-
- unsigned row = 0;
-
- unsigned b_offset = integral_sum_sum_2.delta_index(dpoint2d(input.border(),
- input.border()));
- p_integ += b_offset;
- {
- S h_sum = 0, h_sum_2 = 0;
- const V* ptr1 = & input.at_(row, 0);
- const V* ptr2 = & input.at_(row + 1, 0);
- const V* ptr3 = & input.at_(row + 2, 0);
- for (unsigned col = 0; col < ncols; col += scale)
- {
- V v11 = *ptr1, v12 = *(ptr1 + 1), v13 = *(ptr1 + 2),
- v21 = *ptr2, v22 = *(ptr2 + 1), v23 = *(ptr2 + 2),
- v31 = *ptr3, v32 = *(ptr3 + 1), v33 = *(ptr3 + 2);
- ptr1 += 3;
- ptr2 += 3;
- ptr3 += 3;
- S local_sum = v11 + v12 + v13
- + v21 + v22 + v23
- + v31 + v32 + v33,
- local_sum_2 = v11*v11 + v12*v12 + v13*v13
- + v21*v21 + v22*v22 + v23*v23
- + v31*v31 + v32*v32 + v33*v33;
-
- h_sum += local_sum;
- h_sum_2 += local_sum_2;
-
- // exception
- p_integ->first() = h_sum;
- p_integ->second() = h_sum_2;
-
- p_integ += 1;
- }
- }
-
- unsigned b_next = 2 * input.border();
-
- p_integ += b_next;
-
- for (row += scale; row < nrows; row += scale)
- {
- S h_sum = 0, h_sum_2 = 0;
- const V* ptr1 = & input.at_(row, 0);
- const V* ptr2 = & input.at_(row + 1, 0);
- const V* ptr3 = & input.at_(row + 2, 0);
- for (unsigned col = 0; col < ncols; col += scale)
- {
- V v11 = *ptr1, v12 = *(ptr1 + 1), v13 = *(ptr1 + 2),
- v21 = *ptr2, v22 = *(ptr2 + 1), v23 = *(ptr2 + 2),
- v31 = *ptr3, v32 = *(ptr3 + 1), v33 = *(ptr3 + 2);
- ptr1 += 3;
- ptr2 += 3;
- ptr3 += 3;
- S local_sum = v11 + v12 + v13
- + v21 + v22 + v23
- + v31 + v32 + v33,
- local_sum_2 = v11*v11 + v12*v12 + v13*v13
- + v21*v21 + v22*v22 + v23*v23
- + v31*v31 + v32*v32 + v33*v33;
-
- h_sum += local_sum;
- h_sum_2 += local_sum_2;
-
- p_integ->first() = h_sum + (p_integ + up)->first();
- p_integ->second() = h_sum_2 + (p_integ + up)->second();
-
- p_integ += 1;
- }
-
- p_integ += b_next;
- }
-
- trace::exiting("subsampling::impl::integral_3");
- }
-
-
-
- template <typename I, typename J>
- void
- init_integral(const Image<I>& input_,
- Image<J>& integral_sum_sum_2_)
- {
- trace::entering("subsampling::impl::integral_3");
-
- const I& input = exact(input_);
- J& integral_sum_sum_2 = exact(integral_sum_sum_2_);
-
- mln_precondition(input.is_valid());
- mln_precondition(input.domain().pmin() == literal::origin);
-
- typedef mln_value(I) V;
- typedef mln_sum(V) S;
- typedef mln_value(J) V2;
- typedef mln_site(I) P;
-
- initialize(integral_sum_sum_2, input);
- V2* p_integ = integral_sum_sum_2.buffer();
-
- const int up = input.delta_index(dpoint2d(-1, 0));
-
- const unsigned nrows = input.domain().nrows();
- const unsigned ncols = input.domain().ncols();
-
- unsigned row = 0;
-
- unsigned b_offset = input.delta_index(dpoint2d(input.border(),
- input.border()));
- p_integ += b_offset;
- {
- S h_sum = 0, h_sum_2 = 0;
- const V* ptr1 = & input.at_(row, 0);
- for (unsigned col = 0; col < ncols; ++col)
- {
- V v = *ptr1++;
-
- h_sum += v;
- h_sum_2 += v * v;
-
- // exception
- p_integ->first() = h_sum;
- p_integ->second() = h_sum_2;
-
- ++p_integ;
- }
- }
-
- unsigned b_next = 2 * input.border();
-
- p_integ += b_next;
-
- for (row += 1; row < nrows; ++row)
- {
- S h_sum = 0, h_sum_2 = 0;
- const V* ptr1 = & input.at_(row, 0);
- for (unsigned col = 0; col < ncols; ++col)
- {
- V v = *ptr1++;
-
- h_sum += v;
- h_sum_2 += v * v;
-
- p_integ->first() = h_sum + (p_integ + up)->first();
- p_integ->second() = h_sum_2 + (p_integ + up)->second();
-
- ++p_integ;
- }
-
- p_integ += b_next;
- }
-
- trace::exiting("subsampling::impl::integral_3");
- }
-
-
-
image2d<bool>
sauvola_fast(const image2d<value::int_u8>& input, unsigned win)
{
util::timer t;
t.start();
- image2d<util::couple<double,double> > integral;
- init_integral_3(input, integral);
- // image2d<value::int_u8> sub = scribo::subsampling::integral(input, 3, integral);
+ scribo::util::integral_sum_sum2_functor<value::int_u8, double> fi;
+ image2d<util::couple<double,double> >
+ integral = scribo::util::init_integral_image(input, 3, fi);
t.stop();
std::cout << "image integrale - " << t << std::endl;
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ initialize(internal::debug_mean, input);
+ initialize(internal::debug_stddev, input);
+
+ initialize(internal::debug_threshold, input);
+ initialize(internal::debug_alpham, input);
+ initialize(internal::debug_alphacond, input);
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
t.restart();
image2d<bool> output;
initialize(output, input);
- sauvola_fast_functor<image2d<value::int_u8> > f(input, output, SCRIBO_DEFAULT_SAUVOLA_K, SCRIBO_DEFAULT_SAUVOLA_R);
+ sauvola_functor<image2d<value::int_u8> > f(input, output,
+ SCRIBO_DEFAULT_SAUVOLA_K,
+ SCRIBO_DEFAULT_SAUVOLA_R);
scribo::canvas::integral_browsing(integral, 1, win / 3, win / 3, 3, f);
t.stop();
std::cout << "Binarization - " << t << std::endl;
@@ -314,3 +151,4 @@ int main(int argc, char *argv[])
io::pbm::save(output, argv[3]);
}
+
--
1.7.2.5
1
0
olena-2.0-80-gf853081 Refactoring of local threshold binarization algorithms
by Guillaume Lazzara 22 Jun '12
by Guillaume Lazzara 22 Jun '12
22 Jun '12
---
.../binarization/internal/first_pass_functor.hh | 177 -------------
.../binarization/internal/local_threshold_debug.hh | 13 +-
.../binarization/internal/niblack_formula.hh | 8 +-
.../binarization/internal/niblack_functor.hh | 150 +++++++++++
.../internal/niblack_threshold_functor.hh | 149 +++++++++++
.../scribo/binarization/internal/sauvola_core.hh | 257 +++++++++++++++++++
.../binarization/internal/sauvola_formula.hh | 18 +-
.../binarization/internal/sauvola_functor.hh | 157 ++++++++++++
.../binarization/internal/sauvola_ms_functor.hh | 185 ++++++++++++++
.../internal/sauvola_threshold_functor.hh | 156 ++++++++++++
scribo/scribo/binarization/local_threshold.hh | 18 +-
scribo/scribo/binarization/niblack.hh | 110 +--------
scribo/scribo/binarization/niblack_threshold.hh | 170 +++++--------
scribo/scribo/binarization/sauvola.hh | 100 +-------
scribo/scribo/binarization/sauvola_ms.hh | 107 ++++-----
scribo/scribo/binarization/sauvola_threshold.hh | 162 +++++--------
.../{internal => trash}/compute_local_threshold.hh | 0
scribo/scribo/canvas/integral_browsing.hh | 4 +-
scribo/scribo/util/compute_sub_domains.hh | 110 ++++++++
scribo/scribo/util/init_integral_image.hh | 264 ++++++++++++++++++++
.../scribo/util/integral_sub_sum_sum2_functor.hh | 193 ++++++++++++++
scribo/scribo/util/integral_sum_sum2_functor.hh | 140 +++++++++++
.../binarization/pgm_niblack_threshold_image.cc | 78 ++++++
scribo/src/binarization/sauvola_ms.cc | 11 +-
scribo/src/binarization/sauvola_ms_debug.cc | 5 +
25 files changed, 2073 insertions(+), 669 deletions(-)
delete mode 100644 scribo/scribo/binarization/internal/first_pass_functor.hh
create mode 100644 scribo/scribo/binarization/internal/niblack_functor.hh
create mode 100644 scribo/scribo/binarization/internal/niblack_threshold_functor.hh
create mode 100644 scribo/scribo/binarization/internal/sauvola_core.hh
create mode 100644 scribo/scribo/binarization/internal/sauvola_functor.hh
create mode 100644 scribo/scribo/binarization/internal/sauvola_ms_functor.hh
create mode 100644 scribo/scribo/binarization/internal/sauvola_threshold_functor.hh
rename scribo/scribo/binarization/{internal => trash}/compute_local_threshold.hh (100%)
create mode 100644 scribo/scribo/util/compute_sub_domains.hh
create mode 100644 scribo/scribo/util/init_integral_image.hh
create mode 100644 scribo/scribo/util/integral_sub_sum_sum2_functor.hh
create mode 100644 scribo/scribo/util/integral_sum_sum2_functor.hh
create mode 100644 scribo/src/binarization/pgm_niblack_threshold_image.cc
diff --git a/scribo/scribo/binarization/internal/first_pass_functor.hh b/scribo/scribo/binarization/internal/first_pass_functor.hh
deleted file mode 100644
index f0ae5a9..0000000
--- a/scribo/scribo/binarization/internal/first_pass_functor.hh
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
-// Laboratory (LRDE)
-//
-// This file is part of Olena.
-//
-// Olena is free software: you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation, version 2 of the License.
-//
-// Olena is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Olena. If not, see <http://www.gnu.org/licenses/>.
-//
-// As a special exception, you may use this file as part of a free
-// software project without restriction. Specifically, if other files
-// instantiate templates or use macros or inline functions from this
-// file, or you compile this file and link it with other files to produce
-// an executable, this file does not by itself cause the resulting
-// executable to be covered by the GNU General Public License. This
-// exception does not however invalidate any other reasons why the
-// executable file might be covered by the GNU General Public License.
-
-#ifndef SCRIBO_BINARIZATION_INTERNAL_FIRST_PASS_FUNCTOR_HH
-# define SCRIBO_BINARIZATION_INTERNAL_FIRST_PASS_FUNCTOR_HH
-
-/// \file
-///
-///
-
-# include <mln/core/image/image2d.hh>
-# include <mln/core/alias/neighb2d.hh>
-# include <mln/extension/fill.hh>
-# include <mln/value/int_u8.hh>
-# include <mln/data/fill.hh>
-
-# include <scribo/binarization/internal/sauvola_formula.hh>
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
-# include <scribo/binarization/internal/local_threshold_debug.hh>
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
-
-namespace scribo
-{
-
- namespace binarization
- {
-
- namespace internal
- {
-
- using namespace mln;
-
-
- template <typename I>
- struct first_pass_functor
- {
- const I& input;
- mln_fwd_pixter(const I) pxl;
- double res;
- image2d<unsigned> parent;
- image2d<unsigned> card;
- image2d<bool> msk;
- image2d<value::int_u8> t_sub;
-
- unsigned n_nbhs;
- mln::util::array<int> dp;
-
- double K_;
- double R_;
-
- sauvola_formula formula_;
-
- first_pass_functor(const I& input, double K, double R);
-
- void exec(double mean, double stddev);
- void finalize();
- };
-
-
-# ifndef MLN_INCLUDE_ONLY
-
- inline
- unsigned my_find_root(image2d<unsigned>& parent, unsigned x)
- {
- if (parent.element(x) == x)
- return x;
- return parent.element(x) = my_find_root(parent,
- parent.element(x));
- }
-
-
- template <typename I>
- first_pass_functor<I>::first_pass_functor(const I& input, double K, double R)
- : input(input),
- pxl(input),
- K_(K),
- R_(R)
- {
- res = 0;
- pxl.start();
-
- initialize(t_sub, input);
- initialize(parent, input);
- initialize(msk, input);
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- initialize(debug_mean, input);
- initialize(debug_stddev, input);
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
- mln::extension::fill(msk, false);
-
- initialize(card, input);
- data::fill(card, 1);
-
- dp = negative_offsets_wrt(input, c4());
- n_nbhs = dp.nelements();
- }
-
-
- template <typename I>
- void
- first_pass_functor<I>::exec(double mean, double stddev)
- {
- mln_precondition(pxl.is_valid());
-
- unsigned p = pxl.offset();
-
- value::int_u8 t_p;
- mln::convert::from_to(formula_(input.point_at_index(p), mean, stddev, K_, R_),
- t_p);
-
- msk.element(p) = input.element(p) < t_p;
- t_sub.element(p) = t_p;
- if (! msk.element(p))
- {
- pxl.next();
- return;
- }
- parent.element(p) = p;
- for (unsigned i = 0; i < n_nbhs; ++i)
- {
- unsigned n = p + dp[i];
- if (! msk.element(n))
- continue;
- unsigned r = my_find_root(parent, n);
- if (r != p)
- {
- parent.element(r) = p;
- card.element(p) += card.element(r);
- }
- }
-
- pxl.next(); // next pixel
- }
-
-
- template <typename I>
- void first_pass_functor<I>::finalize()
- {
- mln_assertion(! pxl.is_valid());
- }
-
-#endif // ! MLN_INCLUDE_ONLY
-
- } // end of namespace scribo::binarization::internal
-
- } // end of namespace scribo::binarization
-
-} // end of namespace scribo
-
-#endif // SCRIBO_BINARIZATION_INTERNAL_FIRST_PASS_FUNCTOR_HH
diff --git a/scribo/scribo/binarization/internal/local_threshold_debug.hh b/scribo/scribo/binarization/internal/local_threshold_debug.hh
index a9da06c..f728df3 100644
--- a/scribo/scribo/binarization/internal/local_threshold_debug.hh
+++ b/scribo/scribo/binarization/internal/local_threshold_debug.hh
@@ -52,14 +52,15 @@ namespace scribo
namespace internal
{
- char* stddev_image_output = 0;
- char* mean_image_output = 0;
- char* threshold_image_output = 0;
+ const char* stddev_image_output = 0;
+ const char* mean_image_output = 0;
+ const char* threshold_image_output = 0;
- char* scale_image_output = 0;
+ const char* scale_image_output = 0;
+ const char* scale_iz_image_output = 0;
- char* alpham_image_output = 0;
- char* alphacond_image_output = 0;
+ const char* alpham_image_output = 0;
+ const char* alphacond_image_output = 0;
// Declare debug images.
image2d<double> debug_stddev;
diff --git a/scribo/scribo/binarization/internal/niblack_formula.hh b/scribo/scribo/binarization/internal/niblack_formula.hh
index 54dbc9b..d7d7580 100644
--- a/scribo/scribo/binarization/internal/niblack_formula.hh
+++ b/scribo/scribo/binarization/internal/niblack_formula.hh
@@ -59,13 +59,11 @@ namespace scribo
\param[in] k Control the threshold value in the local
window. The higher, the lower the threshold
form the local mean m(x, y).
- \param[in] R Maximum value of the standard deviation (128
- for grayscale documents). Unused in this formula.
\return A threshold.
*/
double operator()(const double m_x_y, const double s_x_y,
- const double K, const double R) const;
+ const double K) const;
/*!
\overload K = 0.34.
@@ -80,7 +78,7 @@ namespace scribo
inline
double
niblack_formula::operator()(const double m_x_y, const double s_x_y,
- const double K, const double /*R*/) const
+ const double K) const
{
return m_x_y + K * s_x_y;
}
@@ -90,7 +88,7 @@ namespace scribo
niblack_formula::operator()(const double m_x_y, const double s_x_y) const
{
return (*this)(m_x_y, s_x_y,
- SCRIBO_DEFAULT_NIBLACK_K, 128);
+ SCRIBO_DEFAULT_NIBLACK_K);
}
diff --git a/scribo/scribo/binarization/internal/niblack_functor.hh b/scribo/scribo/binarization/internal/niblack_functor.hh
new file mode 100644
index 0000000..83d5bbd
--- /dev/null
+++ b/scribo/scribo/binarization/internal/niblack_functor.hh
@@ -0,0 +1,150 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_INTERNAL_NIBLACK_FUNCTOR_HH
+# define SCRIBO_BINARIZATION_INTERNAL_NIBLACK_FUNCTOR_HH
+
+/// \file
+///
+/// \todo Refactor with sauvola_functor.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/extension/fill.hh>
+
+# include <scribo/binarization/internal/niblack_formula.hh>
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+# include <scribo/binarization/internal/local_threshold_debug.hh>
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ namespace internal
+ {
+
+ using namespace mln;
+
+
+ template <typename I>
+ struct niblack_functor
+ {
+ niblack_functor(const Image<I>& input, double K);
+
+ // Run every 4 pixels.
+ void exec(double mean, double stddev);
+
+ void end_of_row(int);
+
+ void finalize();
+
+
+ const I input;
+ mln_ch_value(I,bool) output;
+
+ const mln_value(I)* pi;
+ bool* po;
+
+ double K_;
+
+ scribo::binarization::internal::niblack_formula formula_;
+
+ int step_;
+ unsigned next_line3;
+ unsigned offset1;
+ unsigned offset2;
+ };
+
+#ifndef MLN_INCLUDE_ONLY
+
+ template <typename I>
+ niblack_functor<I>::niblack_functor(const Image<I>& input_,
+ double K)
+ : input(exact(input_)),
+ pi(&input(input.domain().pmin())),
+ K_(K)
+ {
+ step_ = 3;
+ next_line3 = input.delta_index(dpoint2d(+2,0)) + 2 * input.border() - 1;
+
+ offset1 = input.delta_index(dpoint2d(+1,0));
+ offset2 = input.delta_index(dpoint2d(+2,0));
+
+ initialize(output, input);
+ po = &output(output.domain().pmin());
+ }
+
+ template <typename I>
+ void
+ niblack_functor<I>::exec(double mean, double stddev)
+ {
+ double th = formula_(mean, stddev, K_);
+
+ for (int i = 0; i < step_; ++i, ++po, ++pi)
+ {
+ *po = (*pi <= th);
+ *(po + offset1) = (*(pi + offset1) <= th);
+ *(po + offset2) = (*(pi + offset2) <= th);
+ }
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ // Store local mean
+ unsigned index = pi - input.buffer();
+
+ debug_mean.element(index) = mean * mean_debug_factor;
+ debug_stddev.element(index) = stddev * stddev_debug_factor;
+ debug_threshold.element(index) = th;
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+ }
+
+ template <typename I>
+ void
+ niblack_functor<I>::end_of_row(int)
+ {
+ po += next_line3;
+ pi += next_line3;
+ }
+
+ template <typename I>
+ void
+ niblack_functor<I>::finalize()
+ {
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization::internal
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+#endif // SCRIBO_BINARIZATION_INTERNAL_NIBLACK_FUNCTOR_HH
diff --git a/scribo/scribo/binarization/internal/niblack_threshold_functor.hh b/scribo/scribo/binarization/internal/niblack_threshold_functor.hh
new file mode 100644
index 0000000..b6d6aae
--- /dev/null
+++ b/scribo/scribo/binarization/internal/niblack_threshold_functor.hh
@@ -0,0 +1,149 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_INTERNAL_NIBLACK_THRESHOLD_FUNCTOR_HH
+# define SCRIBO_BINARIZATION_INTERNAL_NIBLACK_THRESHOLD_FUNCTOR_HH
+
+/// \file
+///
+/// \todo Refactor with sauvola_threshold_functor.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/extension/fill.hh>
+
+# include <scribo/binarization/internal/niblack_formula.hh>
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+# include <scribo/binarization/internal/local_threshold_debug.hh>
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ namespace internal
+ {
+
+ using namespace mln;
+
+
+ template <typename I>
+ struct niblack_threshold_functor
+ {
+ niblack_threshold_functor(const I& input,
+ double K);
+
+ // Run every 4 pixels.
+ void exec(double mean, double stddev);
+
+ void end_of_row(int);
+
+ void finalize();
+
+ typedef mln_concrete(I) th_t;
+ th_t output;
+
+ mln_value(I)* po;
+
+ double K_;
+
+ scribo::binarization::internal::niblack_formula formula_;
+
+ int step_;
+ unsigned next_line3;
+ unsigned offset1;
+ unsigned offset2;
+ };
+
+#ifndef MLN_INCLUDE_ONLY
+
+ template <typename I>
+ niblack_threshold_functor<I>::niblack_threshold_functor(const I& input,
+ double K)
+ : K_(K)
+ {
+ step_ = 3;
+ next_line3 = input.delta_index(dpoint2d(+2,0)) + 2 * input.border() - 1;
+
+ offset1 = input.delta_index(dpoint2d(+1,0));
+ offset2 = input.delta_index(dpoint2d(+2,0));
+
+ initialize(output, input);
+ po = &output(output.domain().pmin());
+ }
+
+ template <typename I>
+ void
+ niblack_threshold_functor<I>::exec(double mean, double stddev)
+ {
+ static point2d p(0,0);
+
+ typedef mln_value(I) V;
+ V th = static_cast<V>(formula_(mean, stddev, K_));
+
+ for (int i = 0; i < step_; ++i, ++po)
+ {
+ *po = th;
+ *(po + offset1) = th;
+ *(po + offset2) = th;
+ }
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ // Store local mean
+ unsigned index = po - output.buffer();
+
+ internal::debug_mean.element(index) = mean * internal::mean_debug_factor;
+ internal::debug_stddev.element(index) = stddev * internal::stddev_debug_factor;
+ internal::debug_threshold.element(index) = t;
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+ }
+
+ template <typename I>
+ void
+ niblack_threshold_functor<I>::end_of_row(int)
+ {
+ po += next_line3;
+ }
+
+ template <typename I>
+ void
+ niblack_threshold_functor<I>::finalize()
+ {
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization::internal
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+#endif // SCRIBO_BINARIZATION_INTERNAL_NIBLACK_THRESHOLD_FUNCTOR_HH
diff --git a/scribo/scribo/binarization/internal/sauvola_core.hh b/scribo/scribo/binarization/internal/sauvola_core.hh
new file mode 100644
index 0000000..9e3592f
--- /dev/null
+++ b/scribo/scribo/binarization/internal/sauvola_core.hh
@@ -0,0 +1,257 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_CORE_HH
+# define SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_CORE_HH
+
+/// \file
+///
+///
+
+# include <mln/core/concept/image.hh>
+# include <mln/data/transform.hh>
+# include <mln/value/int_u8.hh>
+
+# include <mln/border/mirror.hh>
+# include <mln/border/adjust.hh>
+
+# include <scribo/canvas/integral_browsing.hh>
+
+# include <scribo/util/init_integral_image.hh>
+# include <scribo/util/integral_sum_sum2_functor.hh>
+# include <scribo/util/compute_sub_domains.hh>
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+# include <scribo/binarization/internal/local_threshold_debug.hh>
+# include <mln/io/pgm/save.hh>
+# include <mln/io/pbm/save.hh>
+# include <mln/data/saturate.hh>
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+# include <mln/util/timer.hh>
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ namespace internal
+ {
+
+ using namespace mln;
+
+
+ /*! \brief Run Sauvola core algorithm. Use functor \p f to
+ compute the threshold and perform computation.
+
+ \input[in] input An image.
+ \input[in] f Functor computing Sauvola's formula.
+ \input[in] window_size The window size.
+
+ */
+ template <typename I, typename F>
+ void
+ sauvola_core(const Image<I>& input, F& f,
+ unsigned window_size);
+
+
+ /// \overload
+ /// The window size is set to 11.
+ //
+ template <typename I, typename F>
+ void
+ sauvola_core(const Image<I>& input, F& f);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ // Implementations.
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+ using namespace mln;
+
+ template <typename I, typename F>
+ void
+ sauvola_core(const Image<I>& input, unsigned window_size)
+ {
+ trace::entering("scribo::binarization::internal::impl::generic::sauvola_core");
+
+ // Not implemented
+ mlc_abort(I)::check();
+
+ trace::exiting("scribo::binarization::internal::impl::generic::sauvola_core");
+ }
+
+ } // end of namespace scribo::binarization::internal::impl::generic
+
+
+ template <typename I, typename F>
+ void
+ sauvola_core_fastest(const Image<I>& input, F& f, unsigned window_size)
+ {
+ trace::entering("scribo::binarization::internal::impl::generic::sauvola_core");
+ mln_precondition(exact(input).is_valid());
+
+ mln::util::timer t;
+ t.start();
+
+ // Make sure the image sizes are a multiple of 3 in each
+ // dimension. (browsing while binarizing relies on that
+ // property).
+ mln::util::array<mln::util::couple<box2d, unsigned> >
+ sub_domains = scribo::util::compute_sub_domains(input, 1, 3);
+
+ border::adjust(input, sub_domains(1).second());
+ border::mirror(input);
+
+ scribo::util::integral_sum_sum2_functor<value::int_u8, double> fi;
+ image2d<mln::util::couple<double,double> >
+ integral = scribo::util::init_integral_image(input, 3, fi,
+ sub_domains[2].first(),
+ sub_domains[2].second());
+
+ t.stop();
+ std::cout << "image integrale - " << t << std::endl;
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ initialize(internal::debug_mean, input);
+ initialize(internal::debug_stddev, input);
+
+ initialize(internal::debug_threshold, input);
+ initialize(internal::debug_alpham, input);
+ initialize(internal::debug_alphacond, input);
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+ t.restart();
+ scribo::canvas::integral_browsing(integral, 1, window_size / 3,
+ window_size / 3, 3, f);
+ t.stop();
+ std::cout << "Binarization - " << t << std::endl;
+
+ trace::exiting("scribo::binarization::internal::impl::generic::sauvola_core");
+ }
+
+
+ } // end of namespace scribo::binarization::internal::impl
+
+
+
+ // Dispatch
+
+ namespace internal
+ {
+
+ template <typename I, typename F>
+ void
+ sauvola_core_dispatch(const mln_value(I)&,
+ const Image<I>& input, F& f,
+ unsigned window_size)
+ {
+ impl::generic::sauvola_core(input, f, window_size);
+ }
+
+ template <typename I, typename F>
+ void
+ sauvola_core_dispatch(mln::trait::image::speed::fastest,
+ const mln_value(I)&,
+ const Image<I>& input, F& f,
+ unsigned window_size)
+ {
+ impl::sauvola_core_fastest(input, f, window_size);
+ }
+
+
+ template <typename I, typename F>
+ void
+ sauvola_core_dispatch(const Image<I>& input, F& f,
+ unsigned window_size)
+ {
+ typedef mln_value(I) V;
+ sauvola_core_dispatch(mln_trait_image_speed(I)(),
+ V(), input, f, window_size);
+ }
+
+ } // end of namespace scribo::binarization::internal::internal
+
+
+
+ // Facades
+
+ template <typename I, typename F>
+ void
+ sauvola_core(const Image<I>& input, F& f, unsigned window_size)
+ {
+ trace::entering("scribo::binarization::internal::sauvola_core");
+
+ mln_precondition(exact(input).is_valid());
+
+ internal::sauvola_core_dispatch(input, f, window_size);
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ if (stddev_image_output)
+ io::pgm::save(data::saturate(value::int_u8(), debug_stddev),
+ stddev_image_output);
+ if (mean_image_output)
+ io::pgm::save(data::saturate(value::int_u8(), debug_mean),
+ mean_image_output);
+ if (threshold_image_output)
+ io::pgm::save(data::saturate(value::int_u8(), debug_threshold),
+ threshold_image_output);
+
+ if (alpham_image_output)
+ io::pgm::save(data::saturate(value::int_u8(), debug_alpham),
+ alpham_image_output);
+ if (alphacond_image_output)
+ io::pbm::save(debug_alphacond, alphacond_image_output);
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+ trace::exiting("scribo::binarization::internal::sauvola_core");
+ }
+
+ template <typename I, typename F>
+ void
+ sauvola_core(const Image<I>& input, F& f)
+ {
+ sauvola_core(input, f, 11);
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization::internal
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+
+#endif // ! SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_CORE_HH
diff --git a/scribo/scribo/binarization/internal/sauvola_formula.hh b/scribo/scribo/binarization/internal/sauvola_formula.hh
index e010e85..a06d6f9 100644
--- a/scribo/scribo/binarization/internal/sauvola_formula.hh
+++ b/scribo/scribo/binarization/internal/sauvola_formula.hh
@@ -48,7 +48,7 @@
#include <mln/core/alias/point2d.hh>
-extern mln::image2d<bool> skewness_pbm;
+// extern mln::image2d<bool> skewness_pbm;
namespace scribo
{
@@ -76,13 +76,13 @@ namespace scribo
\return A threshold.
*/
- double operator()(const point2d& p, const double m_x_y, const double s_x_y,
+ double operator()(const double m_x_y, const double s_x_y,
const double K, const double R) const;
/*!
\overload K = 0.34 and R = 128.
*/
- double operator()(const point2d& p, const double m_x_y, const double s_x_y) const;
+ double operator()(const double m_x_y, const double s_x_y) const;
};
@@ -94,7 +94,7 @@ namespace scribo
inline
double
- sauvola_formula::operator()(const point2d& p, const double m_x_y, const double s_x_y,
+ sauvola_formula::operator()(const double m_x_y, const double s_x_y,
const double K, const double R) const
{
// if (b)
@@ -104,17 +104,17 @@ namespace scribo
// if (skewness_ > 0)
// if (new_t != old_t)
// std::cout << skewness_ << " - " << new_t << " vs " << old_t << std::endl;
- if (skewness_pbm(p))
+ // if (skewness_pbm(p))
return m_x_y * (1.0 + K * ((s_x_y / R) - 1.0));
- else
- return (255 - m_x_y) * (1.0 + K * ((s_x_y / R) - 1.0));
+ // else
+ // return (255 - m_x_y) * (1.0 + K * ((s_x_y / R) - 1.0));
}
inline
double
- sauvola_formula::operator()(const point2d& p, const double m_x_y, const double s_x_y) const
+ sauvola_formula::operator()(const double m_x_y, const double s_x_y) const
{
- return (*this)(p, m_x_y, s_x_y,
+ return (*this)(m_x_y, s_x_y,
SCRIBO_DEFAULT_SAUVOLA_K, SCRIBO_DEFAULT_SAUVOLA_R);
}
diff --git a/scribo/scribo/binarization/internal/sauvola_functor.hh b/scribo/scribo/binarization/internal/sauvola_functor.hh
new file mode 100644
index 0000000..bff8b6f
--- /dev/null
+++ b/scribo/scribo/binarization/internal/sauvola_functor.hh
@@ -0,0 +1,157 @@
+// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_FUNCTOR_HH
+# define SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_FUNCTOR_HH
+
+/// \file
+///
+///
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/extension/fill.hh>
+
+# include <scribo/binarization/internal/sauvola_formula.hh>
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+# include <scribo/binarization/internal/local_threshold_debug.hh>
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ namespace internal
+ {
+
+ using namespace mln;
+
+
+ template <typename I>
+ struct sauvola_functor
+ {
+ sauvola_functor(const Image<I>& input, double K, double R);
+
+ // Run every 4 pixels.
+ void exec(double mean, double stddev);
+
+ void end_of_row(int);
+
+ void finalize();
+
+
+ const I input;
+ mln_ch_value(I,bool) output;
+
+ const mln_value(I)* pi;
+ bool* po;
+
+ double K_;
+ double R_;
+
+ scribo::binarization::internal::sauvola_formula formula_;
+
+ int step_;
+ unsigned next_line3;
+ unsigned offset1;
+ unsigned offset2;
+ };
+
+#ifndef MLN_INCLUDE_ONLY
+
+ template <typename I>
+ sauvola_functor<I>::sauvola_functor(const Image<I>& input_,
+ double K, double R)
+ : input(exact(input_)),
+ pi(&input(input.domain().pmin())),
+ K_(K),
+ R_(R)
+ {
+ step_ = 3;
+ next_line3 = input.delta_index(dpoint2d(+2,0)) + 2 * input.border() - 1;
+
+ offset1 = input.delta_index(dpoint2d(+1,0));
+ offset2 = input.delta_index(dpoint2d(+2,0));
+
+ initialize(output, input);
+ po = &output(output.domain().pmin());
+ }
+
+ template <typename I>
+ void
+ sauvola_functor<I>::exec(double mean, double stddev)
+ {
+ double th = formula_(mean, stddev, K_, R_);
+
+ for (int i = 0; i < step_; ++i, ++po, ++pi)
+ {
+ *po = (*pi <= th);
+ *(po + offset1) = (*(pi + offset1) <= th);
+ *(po + offset2) = (*(pi + offset2) <= th);
+ }
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ // Store local mean
+ unsigned index = pi - input.buffer();
+
+ debug_mean.element(index) = mean * mean_debug_factor;
+ debug_stddev.element(index) = stddev * stddev_debug_factor;
+ debug_threshold.element(index) = th;
+
+ double alpha = K_ * (1 - stddev / R_);
+ debug_alpham.element(index) = alpha * mean * alpham_debug_factor;
+ debug_alphacond.element(index) = (stddev < (alpha * mean / 2.));
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+ }
+
+ template <typename I>
+ void
+ sauvola_functor<I>::end_of_row(int)
+ {
+ po += next_line3;
+ pi += next_line3;
+ }
+
+ template <typename I>
+ void
+ sauvola_functor<I>::finalize()
+ {
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization::internal
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+#endif // SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_FUNCTOR_HH
diff --git a/scribo/scribo/binarization/internal/sauvola_ms_functor.hh b/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
new file mode 100644
index 0000000..9a23aa4
--- /dev/null
+++ b/scribo/scribo/binarization/internal/sauvola_ms_functor.hh
@@ -0,0 +1,185 @@
+// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_MS_FUNCTOR_HH
+# define SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_MS_FUNCTOR_HH
+
+/// \file
+///
+///
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/extension/fill.hh>
+# include <mln/value/int_u8.hh>
+# include <mln/data/fill.hh>
+
+# include <scribo/binarization/internal/sauvola_formula.hh>
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+# include <scribo/binarization/internal/local_threshold_debug.hh>
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ namespace internal
+ {
+
+ using namespace mln;
+
+
+ template <typename I>
+ struct sauvola_ms_functor
+ {
+ const I& input;
+ mln_fwd_pixter(const I) pxl;
+ double res;
+ image2d<unsigned> parent;
+ image2d<unsigned> card;
+ image2d<bool> msk;
+ image2d<value::int_u8> t_sub;
+
+ unsigned n_nbhs;
+ mln::util::array<int> dp;
+
+ double K_;
+ double R_;
+
+ sauvola_formula formula_;
+
+ sauvola_ms_functor(const I& input, double K, double R);
+
+ void exec(double mean, double stddev);
+ void end_of_row(int row);
+ void finalize();
+
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ inline
+ unsigned my_find_root(image2d<unsigned>& parent, unsigned x)
+ {
+ if (parent.element(x) == x)
+ return x;
+ return parent.element(x) = my_find_root(parent,
+ parent.element(x));
+ }
+
+
+ template <typename I>
+ sauvola_ms_functor<I>::sauvola_ms_functor(const I& input, double K, double R)
+ : input(input),
+ pxl(input),
+ K_(K),
+ R_(R)
+ {
+ res = 0;
+ pxl.start();
+
+ initialize(t_sub, input);
+ initialize(parent, input);
+ initialize(msk, input);
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ initialize(debug_mean, input);
+ initialize(debug_stddev, input);
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+ mln::extension::fill(msk, false);
+
+ initialize(card, input);
+ data::fill(card, 1);
+
+ dp = negative_offsets_wrt(input, c4());
+ n_nbhs = dp.nelements();
+ }
+
+
+ template <typename I>
+ void
+ sauvola_ms_functor<I>::exec(double mean, double stddev)
+ {
+ mln_precondition(pxl.is_valid());
+
+ unsigned p = pxl.offset();
+
+ value::int_u8 t_p;
+ mln::convert::from_to(formula_(mean, stddev, K_, R_), t_p);
+
+ msk.element(p) = input.element(p) < t_p;
+ t_sub.element(p) = t_p;
+ if (! msk.element(p))
+ {
+ pxl.next();
+ return;
+ }
+ parent.element(p) = p;
+ for (unsigned i = 0; i < n_nbhs; ++i)
+ {
+ unsigned n = p + dp[i];
+ if (! msk.element(n))
+ continue;
+ unsigned r = my_find_root(parent, n);
+ if (r != p)
+ {
+ parent.element(r) = p;
+ card.element(p) += card.element(r);
+ }
+ }
+
+ pxl.next(); // next pixel
+ }
+
+
+ template <typename I>
+ void
+ sauvola_ms_functor<I>::end_of_row(int row)
+ {
+ (void) row;
+ }
+
+ template <typename I>
+ void sauvola_ms_functor<I>::finalize()
+ {
+ mln_assertion(! pxl.is_valid());
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization::internal
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+#endif // SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_MS_FUNCTOR_HH
diff --git a/scribo/scribo/binarization/internal/sauvola_threshold_functor.hh b/scribo/scribo/binarization/internal/sauvola_threshold_functor.hh
new file mode 100644
index 0000000..d7eaf4a
--- /dev/null
+++ b/scribo/scribo/binarization/internal/sauvola_threshold_functor.hh
@@ -0,0 +1,156 @@
+// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_THRESHOLD_FUNCTOR_HH
+# define SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_THRESHOLD_FUNCTOR_HH
+
+/// \file
+///
+///
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/extension/fill.hh>
+
+# include <scribo/binarization/internal/sauvola_formula.hh>
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+# include <scribo/binarization/internal/local_threshold_debug.hh>
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+
+namespace scribo
+{
+
+ namespace binarization
+ {
+
+ namespace internal
+ {
+
+ using namespace mln;
+
+
+ template <typename I>
+ struct sauvola_threshold_functor
+ {
+ sauvola_threshold_functor(const I& input,
+ double K, double R);
+
+ // Run every 4 pixels.
+ void exec(double mean, double stddev);
+
+ void end_of_row(int);
+
+ void finalize();
+
+ typedef mln_concrete(I) th_t;
+ th_t output;
+
+ mln_value(I)* po;
+
+ double K_;
+ double R_;
+
+ scribo::binarization::internal::sauvola_formula formula_;
+
+ int step_;
+ unsigned next_line3;
+ unsigned offset1;
+ unsigned offset2;
+ };
+
+#ifndef MLN_INCLUDE_ONLY
+
+ template <typename I>
+ sauvola_threshold_functor<I>::sauvola_threshold_functor(const I& input,
+ double K, double R)
+ : K_(K),
+ R_(R)
+ {
+ step_ = 3;
+ next_line3 = input.delta_index(dpoint2d(+2,0)) + 2 * input.border() - 1;
+
+ offset1 = input.delta_index(dpoint2d(+1,0));
+ offset2 = input.delta_index(dpoint2d(+2,0));
+
+ initialize(output, input);
+ po = &output(output.domain().pmin());
+ }
+
+ template <typename I>
+ void
+ sauvola_threshold_functor<I>::exec(double mean, double stddev)
+ {
+ static point2d p(0,0);
+
+ typedef mln_value(I) V;
+ V th = static_cast<V>(formula_(mean, stddev, K_, R_));
+
+ for (int i = 0; i < step_; ++i, ++po)
+ {
+ *po = th;
+ *(po + offset1) = th;
+ *(po + offset2) = th;
+ }
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ // Store local mean
+ unsigned index = po - output.buffer();
+
+ internal::debug_mean.element(index) = mean * internal::mean_debug_factor;
+ internal::debug_stddev.element(index) = stddev * internal::stddev_debug_factor;
+ internal::debug_threshold.element(index) = t;
+
+ double alpha = K * (1 - stddev / R);
+ internal::debug_alpham.element(index) = alpha * mean * internal::alpham_debug_factor;
+ internal::debug_alphacond.element(index) = (stddev < (alpha * mean / 2.));
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+ }
+
+ template <typename I>
+ void
+ sauvola_threshold_functor<I>::end_of_row(int)
+ {
+ po += next_line3;
+ }
+
+ template <typename I>
+ void
+ sauvola_threshold_functor<I>::finalize()
+ {
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::binarization::internal
+
+ } // end of namespace scribo::binarization
+
+} // end of namespace scribo
+
+#endif // SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_THRESHOLD_FUNCTOR_HH
diff --git a/scribo/scribo/binarization/local_threshold.hh b/scribo/scribo/binarization/local_threshold.hh
index ab589e2..e7b0f5d 100644
--- a/scribo/scribo/binarization/local_threshold.hh
+++ b/scribo/scribo/binarization/local_threshold.hh
@@ -1,5 +1,5 @@
-// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory
-// (LRDE)
+// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -34,8 +34,6 @@
///
/// \brief Binarize an image using a threshold image.
-extern mln::image2d<bool> skewness_pbm;
-
namespace scribo
{
@@ -111,10 +109,7 @@ namespace scribo
mln_piter(I) p(input.domain());
for_all(p)
- if (skewness_pbm(p))
- output(p) = (input(p) <= threshold(p));
- else
- output(p) = ((255 - input(p)) <= threshold(p));
+ output(p) = (input(p) <= threshold(p));
trace::exiting("scribo::binarization::impl::generic::local_threshold");
return output;
@@ -135,8 +130,6 @@ namespace scribo
const I& input = exact(input_);
const T& threshold = exact(threshold_);
- border::resize(::skewness_pbm, input.border());
-
typedef mln_ch_value(I, bool) O;
O output;
initialize(output, input);
@@ -146,10 +139,7 @@ namespace scribo
mln_pixter(O) po(output);
for_all_3(pi, pt, po)
- if (skewness_pbm.element(pi.offset()))
- po.val() = (pi.val() <= pt.val());
- else
- po.val() = ((255 - pi.val()) <= pt.val());
+ po.val() = (pi.val() <= pt.val());
trace::exiting("scribo::binarization::impl::generic::local_threshold_fastest");
return output;
diff --git a/scribo/scribo/binarization/niblack.hh b/scribo/scribo/binarization/niblack.hh
index e66e7b4..00e6ab6 100644
--- a/scribo/scribo/binarization/niblack.hh
+++ b/scribo/scribo/binarization/niblack.hh
@@ -1,4 +1,5 @@
-// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -31,18 +32,8 @@
///
# include <mln/core/concept/image.hh>
-# include <mln/data/transform.hh>
-# include <mln/value/int_u8.hh>
-
-# include <scribo/binarization/niblack_threshold.hh>
-# include <scribo/binarization/local_threshold.hh>
-# include <scribo/binarization/internal/local_threshold_debug.hh>
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
-# include <mln/io/pgm/save.hh>
-# include <mln/io/pbm/save.hh>
-# include <mln/data/saturate.hh>
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+# include <scribo/binarization/internal/niblack_functor.hh>
+# include <scribo/binarization/internal/sauvola_core.hh>
namespace scribo
{
@@ -57,7 +48,7 @@ namespace scribo
\input[in] input An image.
\input[in] window_size The window size.
- \input[in] K Niblack's formulae constant.
+ \input[in] K Sauvola's formulae constant.
\return A binary image.
@@ -70,7 +61,8 @@ namespace scribo
/*! \brief Convert an image into a binary image.
- Niblack's formulae constant K is set to 0.34.
+ Sauvola's formulae constant K is set to
+ SCRIBO_DEFAULT_NIBLACK_K.
\input[in] input An image.
\input[in] window_size The window size.
@@ -93,101 +85,21 @@ namespace scribo
# ifndef MLN_INCLUDE_ONLY
-
- // Implementations.
-
- namespace impl
- {
-
- namespace generic
- {
-
- template <typename I>
- mln_ch_value(I, bool)
- niblack(const Image<I>& input, unsigned window_size, double K)
- {
- trace::entering("scribo::binarization::impl::generic::niblack");
- mln_precondition(exact(input).is_valid());
-
- mln_ch_value(I,value::int_u8)
- threshold_image = binarization::niblack_threshold(input, window_size, K);
-
- mln_ch_value(I, bool)
- output = local_threshold(input, threshold_image);
-
- trace::exiting("scribo::binarization::impl::generic::niblack");
- return output;
- }
-
- } // end of namespace scribo::binarization::impl::generic
-
-
- } // end of namespace scribo::binarization::impl
-
-
-
- // Dispatch
-
- namespace internal
- {
-
- template <typename I>
- mln_ch_value(I, bool)
- niblack_dispatch(const mln_value(I)&,
- const Image<I>& input, unsigned window_size,
- double K)
- {
- return impl::generic::niblack(input, window_size, K);
- }
-
-
- template <typename I>
- mln_ch_value(I, bool)
- niblack_dispatch(const Image<I>& input, unsigned window_size,
- double K)
- {
- typedef mln_value(I) V;
- return niblack_dispatch(V(), input, window_size, K);
- }
-
- } // end of namespace scribo::binarization::internal
-
-
-
// Facades
template <typename I>
mln_ch_value(I, bool)
- niblack(const Image<I>& input, unsigned window_size, double K)
+ niblack(const Image<I>& input, unsigned window_size, double K)
{
trace::entering("scribo::binarization::niblack");
mln_precondition(exact(input).is_valid());
- mln_ch_value(I, bool)
- output = internal::niblack_dispatch(input, window_size, K);
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- if (internal::stddev_image_output)
- io::pgm::save(data::saturate(value::int_u8(), internal::debug_stddev),
- internal::stddev_image_output);
- if (internal::mean_image_output)
- io::pgm::save(data::saturate(value::int_u8(), internal::debug_mean),
- internal::mean_image_output);
- if (internal::threshold_image_output)
- io::pgm::save(data::saturate(value::int_u8(), internal::debug_threshold),
- internal::threshold_image_output);
-
- if (internal::alpham_image_output)
- io::pgm::save(data::saturate(value::int_u8(), internal::debug_alpham),
- internal::alpham_image_output);
- if (internal::alphacond_image_output)
- io::pbm::save(internal::debug_alphacond, internal::alphacond_image_output);
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
+ internal::niblack_functor<I> f(input, K);
+ internal::sauvola_core(input, f, window_size);
trace::exiting("scribo::binarization::niblack");
- return output;
+ return f.output;
}
diff --git a/scribo/scribo/binarization/niblack_threshold.hh b/scribo/scribo/binarization/niblack_threshold.hh
index db4a74e..34517cb 100644
--- a/scribo/scribo/binarization/niblack_threshold.hh
+++ b/scribo/scribo/binarization/niblack_threshold.hh
@@ -1,4 +1,5 @@
-// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -31,7 +32,6 @@
/// Compute an image of local threshold using Niblack algorithm.
/// \fixme return type too restrictive!
-/// \fixme Revamp code and merge with sauvola_threshold.hh.
# include <algorithm>
# include <cmath>
@@ -40,9 +40,18 @@
# include <mln/value/int_u.hh>
# include <mln/value/int_u8.hh>
+# include <mln/border/mirror.hh>
+# include <mln/border/adjust.hh>
+
# include <scribo/core/init_integral_image.hh>
-# include <scribo/binarization/internal/compute_local_threshold.hh>
# include <scribo/binarization/internal/niblack_formula.hh>
+# include <scribo/binarization/internal/niblack_threshold_functor.hh>
+
+# include <scribo/util/init_integral_image.hh>
+# include <scribo/util/integral_sum_sum2_functor.hh>
+# include <scribo/util/compute_sub_domains.hh>
+
+# include <scribo/canvas/integral_browsing.hh>
@@ -68,15 +77,7 @@ namespace scribo
template <typename I, typename J>
mln_ch_value(I, value::int_u8)
niblack_threshold(const Image<I>& input, unsigned window_size,
- double K,
- Image<J>& simple,
- Image<J>& squared);
-
- /// \overload
- template <typename I>
- mln_ch_value(I, value::int_u8)
- niblack_threshold(const Image<I>& input, unsigned window_size,
- double K);
+ double K);
/// \overload
/// K is set to 0.34
@@ -106,81 +107,66 @@ namespace scribo
namespace generic
{
- template <typename I, typename J>
+ template <typename I>
inline
mln_concrete(I)
niblack_threshold(const Image<I>& input_, unsigned window_size,
- double K,
- Image<J>& simple_,
- Image<J>& squared_)
+ double K)
{
trace::entering("scribo::binarization::impl::generic::niblack_threshold");
- const I& input = exact(input_);
- J& simple = exact(simple_);
- J& squared = exact(squared_);
-
- mln_assertion(input.is_valid());
- mln_assertion(simple.is_valid());
- mln_assertion(squared.is_valid());
-
- typedef mln_value(I) V;
- typedef mln_site(I) P;
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- initialize(internal::debug_mean, input);
- initialize(internal::debug_stddev, input);
- initialize(internal::debug_threshold, input);
- initialize(internal::debug_alpham, input);
- initialize(internal::debug_alphacond, input);
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
- mln_concrete(I) output;
- initialize(output, input);
-
- const mln::def::coord
- nrows = static_cast<mln::def::coord>(input.nrows()),
- ncols = static_cast<mln::def::coord>(input.ncols());
-
-
- internal::niblack_formula formula;
- for(mln::def::coord row = 0; row < nrows; ++row)
- for(mln::def::coord col = 0; col < ncols; ++col)
- {
- // FIXME: Setting R parameter to 128 should not be
- // hard-coded. Even though it is not used in Niblack's
- // formula, this parameter is used for debug images and
- // should be adapted to the data range values.
- double t = internal::compute_local_threshold(P(row, col), simple,
- squared, window_size,
- K,
- 128,
- formula);
- mln::convert::from_to(t, output.at_(row, col));
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- internal::debug_threshold.at_(row, col) = t;
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
- }
+ // Not implemented
+ mlc_abort(I)::check();
+ typedef mln_concrete(I) output_t;
trace::exiting("scribo::binarization::impl::generic::niblack_threshold");
- return output;
+ return output_t();
}
} // end of namespace scribo::binarization::impl::generic
-
- template <typename I, typename J>
+ template <typename I>
inline
mln_concrete(I)
- niblack_threshold_gl(const I& input, unsigned window_size,
- double K,
- Image<J>& simple,
- Image<J>& squared)
+ niblack_threshold_gl(const Image<I>& input_, unsigned window_size,
+ double K)
{
- return impl::generic::niblack_threshold(input, window_size, K,
- simple, squared);
+ trace::entering("scribo::binarization::impl::niblack_threshold_gl");
+
+ const I& input = exact(input_);
+
+ mln_precondition(exact(input).is_valid());
+
+ // Make sure the image sizes are a multiple of 3 in each
+ // dimension. (browsing while binarizing relies on that
+ // property).
+ mln::util::array<mln::util::couple<box2d, unsigned> >
+ sub_domains = scribo::util::compute_sub_domains(input, 1, 3);
+
+ border::adjust(input, sub_domains(1).second());
+ border::mirror(input);
+
+ typedef mln::util::couple<double,double> V_i;
+ scribo::util::integral_sum_sum2_functor<mln_value(I), double> fi;
+ mln_ch_value(I,V_i)
+ integral = scribo::util::init_integral_image(input, 3, fi);
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ initialize(internal::debug_mean, input);
+ initialize(internal::debug_stddev, input);
+
+ initialize(internal::debug_threshold, input);
+ initialize(internal::debug_alpham, input);
+ initialize(internal::debug_alphacond, input);
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+
+ internal::niblack_threshold_functor<I> f(input, K);
+ scribo::canvas::integral_browsing(integral, 1, window_size / 3,
+ window_size / 3, 3, f);
+
+ trace::exiting("scribo::binarization::impl::niblack_threshold_gl");
+ return f.output;
}
@@ -194,28 +180,23 @@ namespace scribo
namespace internal
{
- template <unsigned n, typename I, typename J>
+ template <unsigned n, typename I>
inline
mln_ch_value(I, value::int_u<n>)
niblack_threshold_dispatch(const value::int_u<n>&, const I& input,
unsigned window_size,
- double K,
- J& simple,
- J& squared)
+ double K)
{
- return impl::niblack_threshold_gl(input, window_size, K,
- simple, squared);
+ return impl::niblack_threshold_gl(input, window_size, K);
}
- template <typename I, typename J>
+ template <typename I>
inline
mln_ch_value(I, value::int_u8)
niblack_threshold_dispatch(const mln_value(I)&, const I& input,
unsigned window_size,
- double K,
- J& simple,
- J& squared)
+ double K)
{
// No dispatch for this kind of value type.
mlc_abort(I)::check();
@@ -229,12 +210,10 @@ namespace scribo
- template <typename I, typename J>
+ template <typename I>
mln_ch_value(I, value::int_u8)
niblack_threshold(const Image<I>& input, unsigned window_size,
- double K,
- Image<J>& simple,
- Image<J>& squared)
+ double K)
{
trace::entering("scribo::binarization::niblack_threshold");
@@ -246,11 +225,9 @@ namespace scribo
output = internal::niblack_threshold_dispatch(value_t(),
exact(input),
window_size,
- K,
- exact(simple),
- exact(squared));
+ K);
- trace::exiting("scribo::text::ppm2pbm");
+ trace::exiting("scribo::binarization::niblack_threshold");
return output;
}
@@ -258,21 +235,6 @@ namespace scribo
template <typename I>
inline
mln_ch_value(I, value::int_u8)
- niblack_threshold(const Image<I>& input, unsigned window_size,
- double K)
- {
- mln_ch_value(I, double)
- simple = init_integral_image(input, scribo::internal::identity_),
- squared = init_integral_image(input, scribo::internal::square_);
-
- return niblack_threshold(input, window_size,
- K, simple, squared);
- }
-
-
- template <typename I>
- inline
- mln_ch_value(I, value::int_u8)
niblack_threshold(const Image<I>& input, unsigned window_size)
{
return niblack_threshold(input, window_size,
diff --git a/scribo/scribo/binarization/sauvola.hh b/scribo/scribo/binarization/sauvola.hh
index fc3e104..ce95526 100644
--- a/scribo/scribo/binarization/sauvola.hh
+++ b/scribo/scribo/binarization/sauvola.hh
@@ -32,18 +32,8 @@
///
# include <mln/core/concept/image.hh>
-# include <mln/data/transform.hh>
-# include <mln/value/int_u8.hh>
-
-# include <scribo/binarization/sauvola_threshold.hh>
-# include <scribo/binarization/local_threshold.hh>
-# include <scribo/binarization/internal/local_threshold_debug.hh>
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
-# include <mln/io/pgm/save.hh>
-# include <mln/io/pbm/save.hh>
-# include <mln/data/saturate.hh>
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+# include <scribo/binarization/internal/sauvola_functor.hh>
+# include <scribo/binarization/internal/sauvola_core.hh>
namespace scribo
{
@@ -94,67 +84,6 @@ namespace scribo
# ifndef MLN_INCLUDE_ONLY
-
- // Implementations.
-
- namespace impl
- {
-
- namespace generic
- {
-
- template <typename I>
- mln_ch_value(I, bool)
- sauvola(const Image<I>& input, unsigned window_size, double K)
- {
- trace::entering("scribo::binarization::impl::generic::sauvola");
- mln_precondition(exact(input).is_valid());
-
- mln_ch_value(I,value::int_u8)
- threshold_image = binarization::sauvola_threshold(input, window_size, K);
-
- mln_ch_value(I, bool)
- output = local_threshold(input, threshold_image);
-
- trace::exiting("scribo::binarization::impl::generic::sauvola");
- return output;
- }
-
- } // end of namespace scribo::binarization::impl::generic
-
-
- } // end of namespace scribo::binarization::impl
-
-
-
- // Dispatch
-
- namespace internal
- {
-
- template <typename I>
- mln_ch_value(I, bool)
- sauvola_dispatch(const mln_value(I)&,
- const Image<I>& input, unsigned window_size,
- double K)
- {
- return impl::generic::sauvola(input, window_size, K);
- }
-
-
- template <typename I>
- mln_ch_value(I, bool)
- sauvola_dispatch(const Image<I>& input, unsigned window_size,
- double K)
- {
- typedef mln_value(I) V;
- return sauvola_dispatch(V(), input, window_size, K);
- }
-
- } // end of namespace scribo::binarization::internal
-
-
-
// Facades
template <typename I>
@@ -165,30 +94,11 @@ namespace scribo
mln_precondition(exact(input).is_valid());
- mln_ch_value(I, bool)
- output = internal::sauvola_dispatch(input, window_size, K);
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- if (internal::stddev_image_output)
- io::pgm::save(data::saturate(value::int_u8(), internal::debug_stddev),
- internal::stddev_image_output);
- if (internal::mean_image_output)
- io::pgm::save(data::saturate(value::int_u8(), internal::debug_mean),
- internal::mean_image_output);
- if (internal::threshold_image_output)
- io::pgm::save(data::saturate(value::int_u8(), internal::debug_threshold),
- internal::threshold_image_output);
-
- if (internal::alpham_image_output)
- io::pgm::save(data::saturate(value::int_u8(), internal::debug_alpham),
- internal::alpham_image_output);
- if (internal::alphacond_image_output)
- io::pbm::save(internal::debug_alphacond, internal::alphacond_image_output);
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
+ internal::sauvola_functor<I> f(input, K, SCRIBO_DEFAULT_SAUVOLA_R);
+ internal::sauvola_core(input, f, window_size);
trace::exiting("scribo::binarization::sauvola");
- return output;
+ return f.output;
}
diff --git a/scribo/scribo/binarization/sauvola_ms.hh b/scribo/scribo/binarization/sauvola_ms.hh
index 36629f9..fe9f1f0 100644
--- a/scribo/scribo/binarization/sauvola_ms.hh
+++ b/scribo/scribo/binarization/sauvola_ms.hh
@@ -38,6 +38,7 @@
# include <mln/core/alias/neighb2d.hh>
# include <mln/data/fill.hh>
+# include <mln/data/compare.hh>
# include <mln/subsampling/antialiased.hh>
@@ -60,17 +61,21 @@
# include <scribo/core/macros.hh>
-# include <scribo/binarization/internal/first_pass_functor.hh>
+# include <scribo/binarization/internal/sauvola_ms_functor.hh>
# include <scribo/canvas/integral_browsing.hh>
+# include <scribo/util/init_integral_image.hh>
+# include <scribo/util/integral_sub_sum_sum2_functor.hh>
+# include <scribo/util/compute_sub_domains.hh>
+
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
# include <scribo/binarization/internal/local_threshold_debug.hh>
# include <mln/io/pgm/save.hh>
# include <scribo/make/debug_filename.hh>
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
+# include <mln/util/timer.hh>
namespace scribo
{
@@ -177,7 +182,7 @@ namespace scribo
// 1st pass
- scribo::binarization::internal::first_pass_functor< image2d<int_u8> >
+ scribo::binarization::internal::sauvola_ms_functor< image2d<int_u8> >
f(sub, K, SCRIBO_DEFAULT_SAUVOLA_R);
scribo::canvas::integral_browsing(integral_sum_sum_2,
ratio,
@@ -259,8 +264,9 @@ namespace scribo
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- io::pbm::save(f.msk,
- scribo::make::debug_filename(internal::threshold_image_output).c_str());
+ if (internal::threshold_image_output)
+ io::pbm::save(f.msk,
+ scribo::make::debug_filename(internal::threshold_image_output).c_str());
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
return f.t_sub;
@@ -746,50 +752,6 @@ namespace scribo
return out;
}
-
-
- inline
- unsigned sub(unsigned nbr, unsigned down_scaling)
- {
- return (nbr + down_scaling - 1) / down_scaling;
- }
-
- // Compute domains of subsampled images and make sure they can be
- // divided by 2.
- template <typename I>
- mln::util::array<mln::util::couple<mln_domain(I), unsigned> >
- compute_sub_domains(const I& ima, unsigned n_scales, unsigned s)
- {
- mln::util::array<mln::util::couple<unsigned, unsigned> > n(n_scales + 2);
-
- n(1) = mln::make::couple(ima.nrows(), ima.ncols());
- n(2) = mln::make::couple(sub(n(1).first(), s),
- sub(n(1).second(), s));
- for (unsigned i = 3; i <= n_scales + 1; ++i)
- n(i) = mln::make::couple(sub(n(i - 1).first(), 2),
- sub(n(i - 1).second(), 2));
-
-
- mln::util::array<mln::util::couple<mln_domain(I), unsigned> > out(n.size());
- out(0) = mln::make::couple(mln::make::box2d(1,1), 1u);
- out(1) = mln::make::couple(mln::make::box2d(ima.nrows(),
- ima.ncols()), 2u);
- out(n_scales + 1) = mln::make::couple(
- mln::make::box2d(n(n_scales + 1).first(),
- n(n_scales + 1).second()), 1u);
-
- for (unsigned i = n_scales; i > 1; --i)
- out(i) = mln::make::couple(
- mln::make::box2d(2 * out(i + 1).first().nrows(),
- 2 * out(i + 1).first().ncols()),
- 2 * out(i + 1).second());
-
- out(1).second() = std::max(out(2).first().ncols() * s - ima.ncols(),
- out(2).first().nrows() * s - ima.nrows());
-
- return out;
- }
-
} // end of namespace scribo::binarization::internal
@@ -851,7 +813,8 @@ namespace scribo
}
mln::util::array<mln::util::couple<box2d, unsigned> >
- sub_domains = internal::compute_sub_domains(input_1, nb_subscale, s);
+ sub_domains = scribo::util::compute_sub_domains(input_1,
+ nb_subscale, s);
border::adjust(input_1, sub_domains(1).second());
border::mirror(input_1);
@@ -861,11 +824,23 @@ namespace scribo
typedef image2d<mln::util::couple<double,double> > integral_t;
integral_t integral_sum_sum_2;
+ mln::util::timer t;
+ t.start();
+
// Subsampling from scale 1 to 2.
- sub_ima.append(scribo::subsampling::integral(input_1, s,
- integral_sum_sum_2,
- sub_domains[2].first(),
- sub_domains[2].second()));
+ {
+ scribo::util::integral_sub_sum_sum2_functor<I, double>
+ fi(s, sub_domains[2].first(), sub_domains[2].second());
+
+ integral_sum_sum_2 = scribo::util::init_integral_image(input_1, s, fi,
+ sub_domains[2].first(),
+ sub_domains[2].second());
+ sub_ima.append(fi.sub);
+ }
+
+ t.stop();
+ std::cout << "1. subsampling and integral - " << t << std::endl;
+ t.restart();
// Subsampling to scale 3 and 4.
//
@@ -876,6 +851,9 @@ namespace scribo
sub_domains[i].first(),
sub_domains[i].second()));
+ t.stop();
+ std::cout << "2. More subsampling - " << t << std::endl;
+ t.restart();
// Compute threshold images.
image2d<int_u8> e_2;
@@ -921,6 +899,10 @@ namespace scribo
K);
}
+ t.stop();
+ std::cout << "3. Multi-scale processing - " << t << std::endl;
+ t.restart();
+
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
if (internal::scale_image_output)
@@ -930,15 +912,24 @@ namespace scribo
// Propagate scale values.
e_2 = transform::influence_zone_geodesic(e_2, c8());
-// # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
-// if (internal::scale_image_output)
-// io::pgm::save(e_2, internal::scale_image_output);
-// # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+ t.stop();
+ std::cout << "4. Influence Zone on Scale image - " << t << std::endl;
+ t.restart();
+
+
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ if (internal::scale_iz_image_output)
+ io::pgm::save(e_2, internal::scale_iz_image_output);
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
// Binarize
image2d<bool>
output = internal::multi_scale_binarization(input_1, e_2, t_ima, s);
+ t.stop();
+ std::cout << "5. Final binarization - " << t << std::endl;
+ t.restart();
+
trace::exiting("scribo::binarization::sauvola_ms");
return output;
}
diff --git a/scribo/scribo/binarization/sauvola_threshold.hh b/scribo/scribo/binarization/sauvola_threshold.hh
index 7950c13..f93edae 100644
--- a/scribo/scribo/binarization/sauvola_threshold.hh
+++ b/scribo/scribo/binarization/sauvola_threshold.hh
@@ -40,11 +40,20 @@
# include <mln/value/int_u.hh>
# include <mln/value/int_u8.hh>
+# include <mln/border/mirror.hh>
+# include <mln/border/adjust.hh>
+
# include <scribo/core/init_integral_image.hh>
-# include <scribo/binarization/internal/compute_local_threshold.hh>
# include <scribo/binarization/internal/sauvola_formula.hh>
+# include <scribo/binarization/internal/sauvola_threshold_functor.hh>
+
+# include <scribo/util/init_integral_image.hh>
+# include <scribo/util/integral_sum_sum2_functor.hh>
+# include <scribo/util/compute_sub_domains.hh>
+
+# include <scribo/canvas/integral_browsing.hh>
+
-extern std::string prefix;
namespace scribo
{
@@ -68,14 +77,6 @@ namespace scribo
template <typename I, typename J>
mln_ch_value(I, value::int_u8)
sauvola_threshold(const Image<I>& input, unsigned window_size,
- double K,
- Image<J>& simple,
- Image<J>& squared);
-
- /// \overload
- template <typename I>
- mln_ch_value(I, value::int_u8)
- sauvola_threshold(const Image<I>& input, unsigned window_size,
double K);
/// \overload
@@ -106,79 +107,67 @@ namespace scribo
namespace generic
{
- template <typename I, typename J>
+ template <typename I>
inline
mln_concrete(I)
sauvola_threshold(const Image<I>& input_, unsigned window_size,
- double K,
- Image<J>& simple_,
- Image<J>& squared_)
+ double K)
{
trace::entering("scribo::binarization::impl::generic::sauvola_threshold");
- const I& input = exact(input_);
- J& simple = exact(simple_);
- J& squared = exact(squared_);
+ // Not implemented
+ mlc_abort(I)::check();
- mln_assertion(input.is_valid());
- mln_assertion(simple.is_valid());
- mln_assertion(squared.is_valid());
+ typedef mln_concrete(I) output_t;
+ trace::exiting("scribo::binarization::impl::generic::sauvola_threshold");
+ return output_t();
+ }
- typedef mln_value(I) V;
- typedef mln_site(I) P;
+ } // end of namespace scribo::binarization::impl::generic
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- initialize(internal::debug_mean, input);
- initialize(internal::debug_stddev, input);
- initialize(internal::debug_threshold, input);
- initialize(internal::debug_alpham, input);
- initialize(internal::debug_alphacond, input);
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+ template <typename I>
+ inline
+ mln_concrete(I)
+ sauvola_threshold_gl(const Image<I>& input_, unsigned window_size,
+ double K)
+ {
+ trace::entering("scribo::binarization::impl::sauvola_threshold_gl");
- // Sauvola Algorithm with I.I.
+ const I& input = exact(input_);
- mln_concrete(I) output;
- initialize(output, input);
+ mln_precondition(exact(input).is_valid());
- const mln::def::coord
- nrows = static_cast<mln::def::coord>(input.nrows()),
- ncols = static_cast<mln::def::coord>(input.ncols());
+ // Make sure the image sizes are a multiple of 3 in each
+ // dimension. (browsing while binarizing relies on that
+ // property).
+ mln::util::array<mln::util::couple<box2d, unsigned> >
+ sub_domains = scribo::util::compute_sub_domains(input, 1, 3);
- internal::sauvola_formula formula;
- for(mln::def::coord row = 0; row < nrows; ++row)
- for(mln::def::coord col = 0; col < ncols; ++col)
- {
- double t = internal::compute_local_threshold(P(row, col), simple,
- squared, window_size,
- K,
- SCRIBO_DEFAULT_SAUVOLA_R,
- formula);
- mln::convert::from_to(t, output.at_(row, col));
+ border::adjust(input, sub_domains(1).second());
+ border::mirror(input);
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- internal::debug_threshold.at_(row, col) = t;
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
- }
+ typedef mln::util::couple<double,double> V_i;
+ scribo::util::integral_sum_sum2_functor<mln_value(I), double> fi;
+ mln_ch_value(I,V_i)
+ integral = scribo::util::init_integral_image(input, 3, fi);
- trace::exiting("scribo::binarization::impl::generic::sauvola_threshold");
- return output;
- }
-
- } // end of namespace scribo::binarization::impl::generic
+# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
+ initialize(internal::debug_mean, input);
+ initialize(internal::debug_stddev, input);
+ initialize(internal::debug_threshold, input);
+ initialize(internal::debug_alpham, input);
+ initialize(internal::debug_alphacond, input);
+# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
+ internal::sauvola_threshold_functor<I> f(input, K,
+ SCRIBO_DEFAULT_SAUVOLA_R);
+ scribo::canvas::integral_browsing(integral, 1, window_size / 3,
+ window_size / 3, 3, f);
- template <typename I, typename J>
- inline
- mln_concrete(I)
- sauvola_threshold_gl(const I& input, unsigned window_size,
- double K,
- Image<J>& simple,
- Image<J>& squared)
- {
- return impl::generic::sauvola_threshold(input, window_size, K,
- simple, squared);
+ trace::exiting("scribo::binarization::impl::sauvola_threshold_gl");
+ return f.output;
}
@@ -192,28 +181,23 @@ namespace scribo
namespace internal
{
- template <unsigned n, typename I, typename J>
+ template <unsigned n, typename I>
inline
mln_ch_value(I, value::int_u<n>)
sauvola_threshold_dispatch(const value::int_u<n>&, const I& input,
unsigned window_size,
- double K,
- J& simple,
- J& squared)
+ double K)
{
- return impl::sauvola_threshold_gl(input, window_size, K,
- simple, squared);
+ return impl::sauvola_threshold_gl(input, window_size, K);
}
- template <typename I, typename J>
+ template <typename I>
inline
mln_ch_value(I, value::int_u8)
sauvola_threshold_dispatch(const mln_value(I)&, const I& input,
unsigned window_size,
- double K,
- J& simple,
- J& squared)
+ double K)
{
// No dispatch for this kind of value type.
mlc_abort(I)::check();
@@ -227,12 +211,10 @@ namespace scribo
- template <typename I, typename J>
+ template <typename I>
mln_ch_value(I, value::int_u8)
sauvola_threshold(const Image<I>& input, unsigned window_size,
- double K,
- Image<J>& simple,
- Image<J>& squared)
+ double K)
{
trace::entering("scribo::binarization::sauvola_threshold");
@@ -244,11 +226,9 @@ namespace scribo
output = internal::sauvola_threshold_dispatch(value_t(),
exact(input),
window_size,
- K,
- exact(simple),
- exact(squared));
+ K);
- trace::exiting("scribo::text::ppm2pbm");
+ trace::exiting("scribo::binarization::sauvola_threshold");
return output;
}
@@ -256,24 +236,6 @@ namespace scribo
template <typename I>
inline
mln_ch_value(I, value::int_u8)
- sauvola_threshold(const Image<I>& input, unsigned window_size,
- double K)
- {
- mln_ch_value(I, double)
- simple = init_integral_image(input, scribo::internal::identity_),
- squared = init_integral_image(input, scribo::internal::square_);
-
- io::dump::save(simple, prefix + "simple.dump");
- io::dump::save(squared, prefix + "squared.dump");
-
- return sauvola_threshold(input, window_size,
- K, simple, squared);
- }
-
-
- template <typename I>
- inline
- mln_ch_value(I, value::int_u8)
sauvola_threshold(const Image<I>& input, unsigned window_size)
{
return sauvola_threshold(input, window_size,
diff --git a/scribo/scribo/binarization/internal/compute_local_threshold.hh b/scribo/scribo/binarization/trash/compute_local_threshold.hh
similarity index 100%
rename from scribo/scribo/binarization/internal/compute_local_threshold.hh
rename to scribo/scribo/binarization/trash/compute_local_threshold.hh
diff --git a/scribo/scribo/canvas/integral_browsing.hh b/scribo/scribo/canvas/integral_browsing.hh
index 0ec3d83..89e0019 100644
--- a/scribo/scribo/canvas/integral_browsing.hh
+++ b/scribo/scribo/canvas/integral_browsing.hh
@@ -210,7 +210,7 @@ namespace scribo
delta_size_tr += step_2;
size_tr_start += delta_start_right;
d_tr_start += offset_down;
-
+ functor.end_of_row(row);
}
@@ -307,6 +307,7 @@ namespace scribo
b_mr_start += offset_down;
d_mr_start += offset_down;
+ functor.end_of_row(row);
}
@@ -404,6 +405,7 @@ namespace scribo
delta_size_br -= step_2;
size_br_start -= delta_start_right;
b_br_start += offset_down;
+ functor.end_of_row(row);
}
functor.finalize();
diff --git a/scribo/scribo/util/compute_sub_domains.hh b/scribo/scribo/util/compute_sub_domains.hh
new file mode 100644
index 0000000..e81a88f
--- /dev/null
+++ b/scribo/scribo/util/compute_sub_domains.hh
@@ -0,0 +1,110 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_UTIL_COMPUTE_SUB_DOMAINS_HH
+# define SCRIBO_UTIL_COMPUTE_SUB_DOMAINS_HH
+
+/// \file
+///
+///
+
+# include <mln/core/image/image2d.hh>
+
+namespace scribo
+{
+
+ namespace util
+ {
+
+ using namespace mln;
+
+ template <typename I>
+ mln::util::array<mln::util::couple<mln_domain(I), unsigned> >
+ compute_sub_domains(const Image<I>& ima, unsigned n_scales, unsigned s);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace internal
+ {
+
+ inline
+ unsigned sub(unsigned nbr, unsigned down_scaling)
+ {
+ return (nbr + down_scaling - 1) / down_scaling;
+ }
+
+ } // end of namespace scribo::util::internal
+
+
+
+ template <typename I>
+ mln::util::array<mln::util::couple<mln_domain(I), unsigned> >
+ compute_sub_domains(const Image<I>& ima_, unsigned n_scales, unsigned s)
+ {
+ trace::entering("scribo::util::compute_sub_domains");
+
+ const I& ima = exact(ima_);
+ mln_precondition(ima.is_valid());
+
+ mln::util::array<mln::util::couple<unsigned, unsigned> > n(n_scales + 2);
+
+ n(1) = mln::make::couple(ima.nrows(), ima.ncols());
+ n(2) = mln::make::couple(internal::sub(n(1).first(), s),
+ internal::sub(n(1).second(), s));
+ for (unsigned i = 3; i <= n_scales + 1; ++i)
+ n(i) = mln::make::couple(internal::sub(n(i - 1).first(), 2),
+ internal::sub(n(i - 1).second(), 2));
+
+
+ mln::util::array<mln::util::couple<mln_domain(I), unsigned> > out(n.size());
+ out(0) = mln::make::couple(mln::make::box2d(1,1), 1u);
+ out(1) = mln::make::couple(mln::make::box2d(ima.nrows(),
+ ima.ncols()), 2u);
+ out(n_scales + 1) = mln::make::couple(
+ mln::make::box2d(n(n_scales + 1).first(),
+ n(n_scales + 1).second()), 1u);
+
+ for (unsigned i = n_scales; i > 1; --i)
+ out(i) = mln::make::couple(
+ mln::make::box2d(2 * out(i + 1).first().nrows(),
+ 2 * out(i + 1).first().ncols()),
+ 2 * out(i + 1).second());
+
+ out(1).second() = std::max(out(2).first().ncols() * s - ima.ncols(),
+ out(2).first().nrows() * s - ima.nrows());
+
+ trace::exiting("scribo::util::compute_sub_domains");
+ return out;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::util
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_UTIL_COMPUTE_SUB_DOMAINS_HH
+
diff --git a/scribo/scribo/util/init_integral_image.hh b/scribo/scribo/util/init_integral_image.hh
new file mode 100644
index 0000000..19d914d
--- /dev/null
+++ b/scribo/scribo/util/init_integral_image.hh
@@ -0,0 +1,264 @@
+// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
+// Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_UTIL_INIT_INTEGRAL_IMAGE_HH
+# define SCRIBO_UTIL_INIT_INTEGRAL_IMAGE_HH
+
+/// \file
+///
+///
+
+# include <mln/core/image/image2d.hh>
+
+namespace scribo
+{
+
+ namespace util
+ {
+
+ using namespace mln;
+
+
+ template <typename I, typename F>
+ mln_ch_value(I, mln_result(F))
+ init_integral_image(const Image<I>& input, unsigned scale, F& func);
+
+ template <typename I, typename F>
+ mln_ch_value(I, mln_result(F))
+ init_integral_image(const Image<I>& input, unsigned scale, F& func,
+ unsigned border);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace impl
+ {
+
+ namespace generic
+ {
+
+ template <typename I, typename F>
+ mln_ch_value(I, mln_result(F))
+ init_integral_image(const Image<I>& input, unsigned scale, F& f,
+ const mln_box(I)& output_domain, unsigned border)
+ {
+ trace::entering("scribo::util::impl::generic::init_integral_image");
+ typedef mln_ch_value(I, mln_result(F)) J;
+
+ // Not implemented
+ mlc_abort(I)::check();
+
+ trace::exiting("scribo::util::impl::generic::init_integral_image");
+ return J();
+ }
+
+ } // end of namespace scribo::util::impl::generic
+
+
+ template <typename I, typename F>
+ mln_ch_value(I, mln_result(F))
+ init_integral_image_fastest(const Image<I>& input_, unsigned scale, F& f,
+ const mln_box(I)& output_domain, unsigned border)
+ {
+ trace::entering("scribo::util::impl::init_integral_image_fastest");
+
+ const I& input = exact(input_);
+ typedef mln_ch_value(I, mln_result(F)) J;
+
+ mln_precondition(input.is_valid());
+ mln_precondition(input.domain().pmin() == literal::origin);
+
+ typedef mln_value(I) V;
+ typedef mln_sum(V) S;
+ typedef mln_value(J) V2;
+ typedef mln_site(I) P;
+
+ J integral_sum_sum_2(output_domain, border);
+ V2* p_integ = integral_sum_sum_2.buffer();
+
+ const int up = integral_sum_sum_2.delta_index(dpoint2d(-1, 0));
+
+ const unsigned nrows = scale * integral_sum_sum_2.nrows();
+ const unsigned ncols = scale * integral_sum_sum_2.ncols();
+
+ unsigned row = 0;
+
+ unsigned b_offset = integral_sum_sum_2.delta_index(dpoint2d(border,
+ border));
+
+ // First row (special case)
+ p_integ += b_offset;
+ {
+ f.begin_of_first_row(); // <---- begin_of_first_row()
+
+ mln::util::array<const V*> ptr(scale);
+ for (unsigned s = 0; s < scale; ++s)
+ ptr[s] = & input.at_(row + s, 0);
+
+ for (unsigned col = 0; col < ncols; col += scale)
+ {
+ f.begin_of_col(); // <---- begin_of_col()
+
+ for (unsigned s = 0; s < scale; ++s)
+ for (unsigned i = 0; i < scale; ++i)
+ f.take(*(ptr[s]++)); // <---- take()
+
+ // exception
+ *p_integ = f.to_result_first_row(); // <---- to_result_first_row()
+
+ f.end_of_col(); // <---- end_of_col()
+ ++p_integ;
+ }
+ f.end_of_row(); // <---- end_of_row()
+ }
+
+ unsigned b_next = 2 * border;
+
+ // Other rows (general case)
+ p_integ += b_next;
+ for (row += scale; row < nrows; row += scale)
+ {
+ f.begin_of_row(); // <---- begin_of_row()
+
+ mln::util::array<const V*> ptr(scale);
+ for (unsigned s = 0; s < scale; ++s)
+ ptr[s] = & input.at_(row + s, 0);
+
+ for (unsigned col = 0; col < ncols; col += scale)
+ {
+ f.begin_of_col(); // <---- begin_of_col()
+
+ for (unsigned s = 0; s < scale; ++s)
+ for (unsigned i = 0; i < scale; ++i)
+ f.take(*(ptr[s]++)); // <---- take()
+
+ *p_integ = f.to_result(*(p_integ + up)); // <---- to_result()
+
+ f.end_of_col(); // <---- end_of_col()
+ ++p_integ;
+ }
+ f.end_of_row(); // <---- end_of_row()
+ p_integ += b_next;
+ }
+
+ trace::exiting("scribo::util::impl::init_integral_fastest_image");
+ return integral_sum_sum_2;
+ }
+
+ } // end of namespace scribo::util::impl
+
+
+ // Dispatch
+
+ namespace internal
+ {
+
+ template <typename I, typename F>
+ mln_ch_value(I,mln_result(F))
+ init_integral_image_dispatch(mln::trait::image::speed::fastest,
+ const Image<I>& input, unsigned scale,
+ F& func, const mln_box(I)& output_domain,
+ unsigned border)
+ {
+ return impl::init_integral_image_fastest(input, scale, func,
+ output_domain, border);
+ }
+
+
+ template <typename I, typename F>
+ mln_ch_value(I,mln_result(F))
+ init_integral_image_dispatch(mln::trait::image::speed::any,
+ const Image<I>& input, unsigned scale,
+ F& func, const mln_box(I)& output_domain,
+ unsigned border)
+ {
+ return impl::generic::init_integral_image(input, scale, func,
+ output_domain, border);
+ }
+
+
+ template <typename I, typename F>
+ mln_ch_value(I,mln_result(F))
+ init_integral_image_dispatch(const Image<I>& input, unsigned scale, F& func,
+ const mln_box(I)& output_domain, unsigned border)
+ {
+ return init_integral_image_dispatch(mln_trait_image_speed(I)(),
+ input, scale, func, output_domain, border);
+ }
+
+ } // end of namespace scribo::util::internal
+
+
+ // Facade
+
+ template <typename I, typename F>
+ mln_ch_value(I,mln_result(F))
+ init_integral_image(const Image<I>& input_, unsigned scale, F& func,
+ const mln_box(I)& output_domain, unsigned border)
+ {
+ trace::entering("scribo::util::init_integral_image");
+
+ const I& input = exact(input_);
+ mln_precondition(input.is_valid());
+ mln_precondition(input.domain().pmin() == literal::origin);
+
+ mln_ch_value(I,mln_result(F))
+ output = internal::init_integral_image_dispatch(input, scale, func,
+ output_domain, border);
+
+ trace::exiting("scribo::util::init_integral_image");
+ return output;
+ }
+
+ template <typename I, typename F>
+ mln_ch_value(I,mln_result(F))
+ init_integral_image(const Image<I>& input_, unsigned scale, F& func)
+ {
+ trace::entering("scribo::util::init_integral_image");
+
+ const I& input = exact(input_);
+ mln_precondition(input.is_valid());
+ mln_precondition(input.domain().pmin() == literal::origin);
+
+ box<mln_site(I)>
+ output_domain = mln::make::box2d((input.nrows() + scale - 1) / scale,
+ (input.ncols() + scale - 1) / scale);
+
+ mln_ch_value(I,mln_result(F))
+ output = init_integral_image(input, scale, func,
+ output_domain, exact(input).border());
+
+ trace::exiting("scribo::util::init_integral_image");
+ return output;
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::util
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_UTIL_INIT_INTEGRAL_IMAGE_HH
diff --git a/scribo/scribo/util/integral_sub_sum_sum2_functor.hh b/scribo/scribo/util/integral_sub_sum_sum2_functor.hh
new file mode 100644
index 0000000..1c312b7
--- /dev/null
+++ b/scribo/scribo/util/integral_sub_sum_sum2_functor.hh
@@ -0,0 +1,193 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_UTIL_INTEGRAL_SUB_SUM_SUM2_FUNCTOR_HH
+# define SCRIBO_UTIL_INTEGRAL_SUB_SUM_SUM2_FUNCTOR_HH
+
+/// \file
+///
+///
+
+# include <mln/util/couple.hh>
+
+namespace scribo
+{
+
+ namespace util
+ {
+
+ template <typename I, typename S = mln_sum(mln_value(I))>
+ class integral_sub_sum_sum2_functor
+ {
+ typedef mln_concrete(I) J;
+ typedef mln_value(I) V;
+
+ public:
+ typedef mln::util::couple<S, S> result;
+
+ integral_sub_sum_sum2_functor(const I& ima, unsigned scale);
+ integral_sub_sum_sum2_functor(unsigned scale,
+ const mln_box(I)& output_domain,
+ unsigned border);
+
+
+ void take(const V& v);
+
+ result to_result_first_row() const;
+ result to_result(const result& up_result) const;
+
+ void begin_of_col();
+ void end_of_col();
+
+ void begin_of_row();
+ void begin_of_first_row();
+ void end_of_row();
+
+ J sub;
+
+ private:
+ void init_(unsigned scale, const mln_box(I)& b, unsigned border);
+
+ S local_sum;
+ S h_sum;
+ S h_sum_2;
+
+ V *p_sub;
+ unsigned b_next;
+ unsigned area;
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename I, typename S>
+ integral_sub_sum_sum2_functor<I,S>::integral_sub_sum_sum2_functor(unsigned scale,
+ const mln_box(I)& output_domain,
+ unsigned border)
+ {
+ init_(scale, output_domain, border);
+ }
+
+ template <typename I, typename S>
+ integral_sub_sum_sum2_functor<I,S>::integral_sub_sum_sum2_functor(const I& ima,
+ unsigned scale)
+ {
+ box<mln_site(I)>
+ b = mln::make::box2d((ima.nrows() + scale - 1) / scale,
+ (ima.ncols() + scale - 1) / scale);
+ init_(scale, b, ima.border());
+ }
+
+ template <typename I, typename S>
+ void
+ integral_sub_sum_sum2_functor<I,S>::init_(unsigned scale, const mln_box(I)& b,
+ unsigned border)
+ {
+ sub = J(b, border);
+
+ area = scale * scale;
+
+ b_next = 2 * border;
+ unsigned b_offset = sub.delta_index(dpoint2d(border, border));
+ p_sub = sub.buffer() + b_offset;
+ }
+
+ template <typename I, typename S>
+ inline
+ void
+ integral_sub_sum_sum2_functor<I,S>::begin_of_first_row()
+ {
+ h_sum = 0;
+ h_sum_2 = 0;
+ }
+
+ template <typename I, typename S>
+ inline
+ void
+ integral_sub_sum_sum2_functor<I,S>::begin_of_row()
+ {
+ h_sum = 0;
+ h_sum_2 = 0;
+ }
+
+ template <typename I, typename S>
+ inline
+ void
+ integral_sub_sum_sum2_functor<I,S>::take(const V& v)
+ {
+ local_sum += v;
+ h_sum_2 += v * v;
+ }
+
+ template <typename I, typename S>
+ inline
+ typename integral_sub_sum_sum2_functor<I,S>::result
+ integral_sub_sum_sum2_functor<I,S>::to_result_first_row() const
+ {
+ return result(h_sum + local_sum, h_sum_2);
+ }
+
+ template <typename I, typename S>
+ inline
+ typename integral_sub_sum_sum2_functor<I,S>::result
+ integral_sub_sum_sum2_functor<I,S>::to_result(const result& up_result) const
+ {
+ return result(h_sum + local_sum + up_result.first(),
+ h_sum_2 + up_result.second());
+ }
+
+ template <typename I, typename S>
+ inline
+ void
+ integral_sub_sum_sum2_functor<I,S>::begin_of_col()
+ {
+ local_sum = 0;
+ }
+
+ template <typename I, typename S>
+ inline
+ void
+ integral_sub_sum_sum2_functor<I,S>::end_of_col()
+ {
+ mln::convert::from_to(local_sum / area, *p_sub++);
+ h_sum += local_sum;
+ }
+
+ template <typename I, typename S>
+ inline
+ void
+ integral_sub_sum_sum2_functor<I,S>::end_of_row()
+ {
+ p_sub += b_next;
+ }
+
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::util
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_UTIL_INTEGRAL_SUB_SUM_SUM2_FUNCTOR_HH
diff --git a/scribo/scribo/util/integral_sum_sum2_functor.hh b/scribo/scribo/util/integral_sum_sum2_functor.hh
new file mode 100644
index 0000000..c166532
--- /dev/null
+++ b/scribo/scribo/util/integral_sum_sum2_functor.hh
@@ -0,0 +1,140 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef SCRIBO_UTIL_INTEGRAL_SUM_SUM2_FUNCTOR_HH
+# define SCRIBO_UTIL_INTEGRAL_SUM_SUM2_FUNCTOR_HH
+
+/// \file
+///
+///
+
+# include <mln/util/couple.hh>
+
+namespace scribo
+{
+
+ namespace util
+ {
+
+ template <typename V, typename S = mln_sum(V)>
+ class integral_sum_sum2_functor
+ {
+ public:
+ typedef mln::util::couple<S, S> result;
+
+ void begin_of_first_row();
+ void begin_of_row();
+ void end_of_row();
+
+ void begin_of_col();
+ void end_of_col();
+
+
+ void take(const V& v);
+
+ result to_result_first_row() const;
+ result to_result(const result& up_result) const;
+
+ private:
+ S h_sum;
+ S h_sum_2;
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_functor<V,S>::begin_of_first_row()
+ {
+ h_sum = 0;
+ h_sum_2 = 0;
+ }
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_functor<V,S>::begin_of_row()
+ {
+ h_sum = 0;
+ h_sum_2 = 0;
+ }
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_functor<V,S>::take(const V& v)
+ {
+ h_sum += v;
+ h_sum_2 += v * v;
+ }
+
+ template <typename V, typename S>
+ inline
+ typename integral_sum_sum2_functor<V,S>::result
+ integral_sum_sum2_functor<V,S>::to_result_first_row() const
+ {
+ return result(h_sum, h_sum_2);
+ }
+
+ template <typename V, typename S>
+ inline
+ typename integral_sum_sum2_functor<V,S>::result
+ integral_sum_sum2_functor<V,S>::to_result(const result& up_result) const
+ {
+ return result(h_sum + up_result.first(),
+ h_sum_2 + up_result.second());
+ }
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_functor<V,S>::begin_of_col()
+ {
+ }
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_functor<V,S>::end_of_col()
+ {
+ }
+
+
+ template <typename V, typename S>
+ inline
+ void
+ integral_sum_sum2_functor<V,S>::end_of_row()
+ {
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace scribo::util
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_UTIL_INTEGRAL_SUM_SUM2_FUNCTOR_HH
diff --git a/scribo/src/binarization/pgm_niblack_threshold_image.cc b/scribo/src/binarization/pgm_niblack_threshold_image.cc
new file mode 100644
index 0000000..4abd862
--- /dev/null
+++ b/scribo/src/binarization/pgm_niblack_threshold_image.cc
@@ -0,0 +1,78 @@
+// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory
+// (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#include <mln/io/pgm/all.hh>
+
+#include <scribo/binarization/niblack_threshold.hh>
+#include <scribo/debug/usage.hh>
+
+const char *args_desc[][2] =
+{
+ { "input.pgm", "A graylevel image." },
+ { "output.pgm", "A threshold image." },
+ { "w", "Window size (default 101)." },
+ { "k", "Niblack's formulae parameter (default -0.2)." },
+ {0, 0}
+};
+
+
+int main(int argc, char *argv[])
+{
+ using namespace mln;
+
+ if (argc != 5 && argc != 4 && argc != 3)
+ return scribo::debug::usage(argv,
+ "Compute a threshold image based on Niblack's algorithm.",
+ "input.pgm output.pgm <w> <k>",
+ args_desc);
+
+ trace::entering("main");
+
+ unsigned w;
+ if (argc >= 4)
+ w = atoi(argv[3]);
+ else
+ w = 101;
+
+ double k;
+ if (argc >= 5)
+ k = atof(argv[4]);
+ else
+ k = -0.2;
+
+ std::cout << "Using w=" << w << " and k=" << k << std::endl;
+
+ image2d<value::int_u8> input;
+ io::pgm::load(input, argv[1]);
+
+ image2d<value::int_u8> out = scribo::binarization::niblack_threshold(input, w, k);
+
+
+ io::pgm::save(out, argv[2]);
+
+
+ trace::exiting("main");
+}
diff --git a/scribo/src/binarization/sauvola_ms.cc b/scribo/src/binarization/sauvola_ms.cc
index d98b83f..77f839d 100644
--- a/scribo/src/binarization/sauvola_ms.cc
+++ b/scribo/src/binarization/sauvola_ms.cc
@@ -32,12 +32,12 @@
#include <mln/io/pbm/save.hh>
#include <mln/data/transform.hh>
#include <mln/fun/v2v/rgb_to_luma.hh>
+#include <mln/util/timer.hh>
#include <scribo/binarization/sauvola_ms.hh>
#include <scribo/debug/option_parser.hh>
#include <scribo/debug/logger.hh>
-
static const scribo::debug::arg_data arg_desc[] =
{
{ "input.*", "An image." },
@@ -115,9 +115,18 @@ int main(int argc, char *argv[])
input_1_gl = data::transform(input_1,
mln::fun::v2v::rgb_to_luma<value::int_u8>());
+ mln::util::timer t;
+ t.start();
+
// Binarize
image2d<bool>
output = scribo::binarization::sauvola_ms(input_1_gl, w_1, s, k);
+ if (verbose)
+ {
+ t.stop();
+ std::cout << "binarized in " << t << "s" << std::endl;
+ }
+
io::pbm::save(output, options.arg("output.pbm"));
}
diff --git a/scribo/src/binarization/sauvola_ms_debug.cc b/scribo/src/binarization/sauvola_ms_debug.cc
index 70c1a9a..839a3f7 100644
--- a/scribo/src/binarization/sauvola_ms_debug.cc
+++ b/scribo/src/binarization/sauvola_ms_debug.cc
@@ -91,6 +91,8 @@ int main(int argc, char *argv[])
"input.* output.pbm <scale.pgm> <w> <s> <k>",
args_desc);
+ Magick::InitializeMagick(0);
+
trace::entering("main");
// Window size
@@ -116,6 +118,9 @@ int main(int argc, char *argv[])
if (argc >= 4)
scribo::binarization::internal::scale_image_output = argv[3];
+ scribo::binarization::internal::scale_image_output = "scale_image.pgm";
+ scribo::binarization::internal::threshold_image_output = "threshold_image.pbm";
+ scribo::binarization::internal::scale_iz_image_output = "scale_iz.pgm";
// Load
image2d<value::rgb8> input_1;
--
1.7.2.5
1
0
---
.../{sauvola_core.hh => local_threshold_core.hh} | 46 +++---
.../internal/niblack_threshold_functor.hh | 7 +-
.../binarization/internal/sauvola_functor.hh | 3 +-
.../internal/sauvola_threshold_functor.hh | 10 +-
scribo/scribo/binarization/niblack.hh | 4 +-
scribo/scribo/binarization/niblack_threshold.hh | 141 +-------------------
scribo/scribo/binarization/sauvola.hh | 4 +-
scribo/scribo/binarization/sauvola_threshold.hh | 142 +-------------------
8 files changed, 50 insertions(+), 307 deletions(-)
rename scribo/scribo/binarization/internal/{sauvola_core.hh => local_threshold_core.hh} (81%)
diff --git a/scribo/scribo/binarization/internal/sauvola_core.hh b/scribo/scribo/binarization/internal/local_threshold_core.hh
similarity index 81%
rename from scribo/scribo/binarization/internal/sauvola_core.hh
rename to scribo/scribo/binarization/internal/local_threshold_core.hh
index 9e3592f..f2c9cb1 100644
--- a/scribo/scribo/binarization/internal/sauvola_core.hh
+++ b/scribo/scribo/binarization/internal/local_threshold_core.hh
@@ -23,8 +23,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_INTERNAL_SAUVOLA_CORE_HH
-# define SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_CORE_HH
+#ifndef SCRIBO_BINARIZATION_INTERNAL_LOCAL_THRESHOLD_CORE_HH
+# define SCRIBO_BINARIZATION_INTERNAL_LOCAL_THRESHOLD_CORE_HH
/// \file
///
@@ -74,7 +74,7 @@ namespace scribo
*/
template <typename I, typename F>
void
- sauvola_core(const Image<I>& input, F& f,
+ local_threshold_core(const Image<I>& input, F& f,
unsigned window_size);
@@ -83,7 +83,7 @@ namespace scribo
//
template <typename I, typename F>
void
- sauvola_core(const Image<I>& input, F& f);
+ local_threshold_core(const Image<I>& input, F& f);
# ifndef MLN_INCLUDE_ONLY
@@ -101,14 +101,14 @@ namespace scribo
template <typename I, typename F>
void
- sauvola_core(const Image<I>& input, unsigned window_size)
+ local_threshold_core(const Image<I>& input, unsigned window_size)
{
- trace::entering("scribo::binarization::internal::impl::generic::sauvola_core");
+ trace::entering("scribo::binarization::internal::impl::generic::local_threshold_core");
// Not implemented
mlc_abort(I)::check();
- trace::exiting("scribo::binarization::internal::impl::generic::sauvola_core");
+ trace::exiting("scribo::binarization::internal::impl::generic::local_threshold_core");
}
} // end of namespace scribo::binarization::internal::impl::generic
@@ -116,9 +116,9 @@ namespace scribo
template <typename I, typename F>
void
- sauvola_core_fastest(const Image<I>& input, F& f, unsigned window_size)
+ local_threshold_core_fastest(const Image<I>& input, F& f, unsigned window_size)
{
- trace::entering("scribo::binarization::internal::impl::generic::sauvola_core");
+ trace::entering("scribo::binarization::internal::impl::generic::local_threshold_core");
mln_precondition(exact(input).is_valid());
mln::util::timer t;
@@ -157,7 +157,7 @@ namespace scribo
t.stop();
std::cout << "Binarization - " << t << std::endl;
- trace::exiting("scribo::binarization::internal::impl::generic::sauvola_core");
+ trace::exiting("scribo::binarization::internal::impl::generic::local_threshold_core");
}
@@ -172,31 +172,31 @@ namespace scribo
template <typename I, typename F>
void
- sauvola_core_dispatch(const mln_value(I)&,
+ local_threshold_core_dispatch(const mln_value(I)&,
const Image<I>& input, F& f,
unsigned window_size)
{
- impl::generic::sauvola_core(input, f, window_size);
+ impl::generic::local_threshold_core(input, f, window_size);
}
template <typename I, typename F>
void
- sauvola_core_dispatch(mln::trait::image::speed::fastest,
+ local_threshold_core_dispatch(mln::trait::image::speed::fastest,
const mln_value(I)&,
const Image<I>& input, F& f,
unsigned window_size)
{
- impl::sauvola_core_fastest(input, f, window_size);
+ impl::local_threshold_core_fastest(input, f, window_size);
}
template <typename I, typename F>
void
- sauvola_core_dispatch(const Image<I>& input, F& f,
+ local_threshold_core_dispatch(const Image<I>& input, F& f,
unsigned window_size)
{
typedef mln_value(I) V;
- sauvola_core_dispatch(mln_trait_image_speed(I)(),
+ local_threshold_core_dispatch(mln_trait_image_speed(I)(),
V(), input, f, window_size);
}
@@ -208,13 +208,13 @@ namespace scribo
template <typename I, typename F>
void
- sauvola_core(const Image<I>& input, F& f, unsigned window_size)
+ local_threshold_core(const Image<I>& input, F& f, unsigned window_size)
{
- trace::entering("scribo::binarization::internal::sauvola_core");
+ trace::entering("scribo::binarization::internal::local_threshold_core");
mln_precondition(exact(input).is_valid());
- internal::sauvola_core_dispatch(input, f, window_size);
+ internal::local_threshold_core_dispatch(input, f, window_size);
# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
if (stddev_image_output)
@@ -234,14 +234,14 @@ namespace scribo
io::pbm::save(debug_alphacond, alphacond_image_output);
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
- trace::exiting("scribo::binarization::internal::sauvola_core");
+ trace::exiting("scribo::binarization::internal::local_threshold_core");
}
template <typename I, typename F>
void
- sauvola_core(const Image<I>& input, F& f)
+ local_threshold_core(const Image<I>& input, F& f)
{
- sauvola_core(input, f, 11);
+ local_threshold_core(input, f, 11);
}
@@ -254,4 +254,4 @@ namespace scribo
} // end of namespace scribo
-#endif // ! SCRIBO_BINARIZATION_INTERNAL_SAUVOLA_CORE_HH
+#endif // ! SCRIBO_BINARIZATION_INTERNAL_LOCAL_THRESHOLD_CORE_HH
diff --git a/scribo/scribo/binarization/internal/niblack_threshold_functor.hh b/scribo/scribo/binarization/internal/niblack_threshold_functor.hh
index b6d6aae..979bb67 100644
--- a/scribo/scribo/binarization/internal/niblack_threshold_functor.hh
+++ b/scribo/scribo/binarization/internal/niblack_threshold_functor.hh
@@ -56,7 +56,7 @@ namespace scribo
template <typename I>
struct niblack_threshold_functor
{
- niblack_threshold_functor(const I& input,
+ niblack_threshold_functor(const Image<I>& input,
double K);
// Run every 4 pixels.
@@ -84,10 +84,13 @@ namespace scribo
#ifndef MLN_INCLUDE_ONLY
template <typename I>
- niblack_threshold_functor<I>::niblack_threshold_functor(const I& input,
+ niblack_threshold_functor<I>::niblack_threshold_functor(const Image<I>& input_,
double K)
: K_(K)
{
+ const I& input = exact(input_);
+ mln_precondition(input.is_valid());
+
step_ = 3;
next_line3 = input.delta_index(dpoint2d(+2,0)) + 2 * input.border() - 1;
diff --git a/scribo/scribo/binarization/internal/sauvola_functor.hh b/scribo/scribo/binarization/internal/sauvola_functor.hh
index bff8b6f..5363215 100644
--- a/scribo/scribo/binarization/internal/sauvola_functor.hh
+++ b/scribo/scribo/binarization/internal/sauvola_functor.hh
@@ -1,5 +1,4 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
-// Laboratory (LRDE)
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
diff --git a/scribo/scribo/binarization/internal/sauvola_threshold_functor.hh b/scribo/scribo/binarization/internal/sauvola_threshold_functor.hh
index d7eaf4a..bb38696 100644
--- a/scribo/scribo/binarization/internal/sauvola_threshold_functor.hh
+++ b/scribo/scribo/binarization/internal/sauvola_threshold_functor.hh
@@ -1,5 +1,4 @@
-// Copyright (C) 2009, 2010, 2011 EPITA Research and Development
-// Laboratory (LRDE)
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -57,7 +56,7 @@ namespace scribo
template <typename I>
struct sauvola_threshold_functor
{
- sauvola_threshold_functor(const I& input,
+ sauvola_threshold_functor(const Image<I>& input,
double K, double R);
// Run every 4 pixels.
@@ -86,11 +85,14 @@ namespace scribo
#ifndef MLN_INCLUDE_ONLY
template <typename I>
- sauvola_threshold_functor<I>::sauvola_threshold_functor(const I& input,
+ sauvola_threshold_functor<I>::sauvola_threshold_functor(const Image<I>& input_,
double K, double R)
: K_(K),
R_(R)
{
+ const I& input = exact(input_);
+ mln_precondition(input.is_valid());
+
step_ = 3;
next_line3 = input.delta_index(dpoint2d(+2,0)) + 2 * input.border() - 1;
diff --git a/scribo/scribo/binarization/niblack.hh b/scribo/scribo/binarization/niblack.hh
index 00e6ab6..7561525 100644
--- a/scribo/scribo/binarization/niblack.hh
+++ b/scribo/scribo/binarization/niblack.hh
@@ -33,7 +33,7 @@
# include <mln/core/concept/image.hh>
# include <scribo/binarization/internal/niblack_functor.hh>
-# include <scribo/binarization/internal/sauvola_core.hh>
+# include <scribo/binarization/internal/local_threshold_core.hh>
namespace scribo
{
@@ -96,7 +96,7 @@ namespace scribo
mln_precondition(exact(input).is_valid());
internal::niblack_functor<I> f(input, K);
- internal::sauvola_core(input, f, window_size);
+ internal::local_threshold_core(input, f, window_size);
trace::exiting("scribo::binarization::niblack");
return f.output;
diff --git a/scribo/scribo/binarization/niblack_threshold.hh b/scribo/scribo/binarization/niblack_threshold.hh
index 34517cb..a6b2dbf 100644
--- a/scribo/scribo/binarization/niblack_threshold.hh
+++ b/scribo/scribo/binarization/niblack_threshold.hh
@@ -36,23 +36,9 @@
# include <algorithm>
# include <cmath>
-# include <mln/core/image/image2d.hh>
-# include <mln/value/int_u.hh>
-# include <mln/value/int_u8.hh>
-
-# include <mln/border/mirror.hh>
-# include <mln/border/adjust.hh>
-
-# include <scribo/core/init_integral_image.hh>
-# include <scribo/binarization/internal/niblack_formula.hh>
+# include <mln/core/concept/image.hh>
# include <scribo/binarization/internal/niblack_threshold_functor.hh>
-
-# include <scribo/util/init_integral_image.hh>
-# include <scribo/util/integral_sum_sum2_functor.hh>
-# include <scribo/util/compute_sub_domains.hh>
-
-# include <scribo/canvas/integral_browsing.hh>
-
+# include <scribo/binarization/internal/local_threshold_core.hh>
namespace scribo
@@ -97,119 +83,6 @@ namespace scribo
# ifndef MLN_INCLUDE_ONLY
-
- // Implementation
-
-
- namespace impl
- {
-
- namespace generic
- {
-
- template <typename I>
- inline
- mln_concrete(I)
- niblack_threshold(const Image<I>& input_, unsigned window_size,
- double K)
- {
- trace::entering("scribo::binarization::impl::generic::niblack_threshold");
-
- // Not implemented
- mlc_abort(I)::check();
-
- typedef mln_concrete(I) output_t;
- trace::exiting("scribo::binarization::impl::generic::niblack_threshold");
- return output_t();
- }
-
- } // end of namespace scribo::binarization::impl::generic
-
-
- template <typename I>
- inline
- mln_concrete(I)
- niblack_threshold_gl(const Image<I>& input_, unsigned window_size,
- double K)
- {
- trace::entering("scribo::binarization::impl::niblack_threshold_gl");
-
- const I& input = exact(input_);
-
- mln_precondition(exact(input).is_valid());
-
- // Make sure the image sizes are a multiple of 3 in each
- // dimension. (browsing while binarizing relies on that
- // property).
- mln::util::array<mln::util::couple<box2d, unsigned> >
- sub_domains = scribo::util::compute_sub_domains(input, 1, 3);
-
- border::adjust(input, sub_domains(1).second());
- border::mirror(input);
-
- typedef mln::util::couple<double,double> V_i;
- scribo::util::integral_sum_sum2_functor<mln_value(I), double> fi;
- mln_ch_value(I,V_i)
- integral = scribo::util::init_integral_image(input, 3, fi);
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- initialize(internal::debug_mean, input);
- initialize(internal::debug_stddev, input);
-
- initialize(internal::debug_threshold, input);
- initialize(internal::debug_alpham, input);
- initialize(internal::debug_alphacond, input);
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
- internal::niblack_threshold_functor<I> f(input, K);
- scribo::canvas::integral_browsing(integral, 1, window_size / 3,
- window_size / 3, 3, f);
-
- trace::exiting("scribo::binarization::impl::niblack_threshold_gl");
- return f.output;
- }
-
-
- } // end of namespace scribo::binarization::impl
-
-
-
-
- // Dispatch
-
- namespace internal
- {
-
- template <unsigned n, typename I>
- inline
- mln_ch_value(I, value::int_u<n>)
- niblack_threshold_dispatch(const value::int_u<n>&, const I& input,
- unsigned window_size,
- double K)
- {
- return impl::niblack_threshold_gl(input, window_size, K);
- }
-
-
- template <typename I>
- inline
- mln_ch_value(I, value::int_u8)
- niblack_threshold_dispatch(const mln_value(I)&, const I& input,
- unsigned window_size,
- double K)
- {
- // 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>
mln_ch_value(I, value::int_u8)
niblack_threshold(const Image<I>& input, unsigned window_size,
@@ -220,15 +93,11 @@ namespace scribo
mln_precondition(mln_site_(I)::dim == 2);
mln_precondition(exact(input).is_valid());
- typedef mln_value(I) value_t;
- mln_ch_value(I, value::int_u8)
- output = internal::niblack_threshold_dispatch(value_t(),
- exact(input),
- window_size,
- K);
+ internal::niblack_threshold_functor<I> f(input, K);
+ internal::local_threshold_core(input, f, window_size);
trace::exiting("scribo::binarization::niblack_threshold");
- return output;
+ return f.output;
}
diff --git a/scribo/scribo/binarization/sauvola.hh b/scribo/scribo/binarization/sauvola.hh
index ce95526..7022680 100644
--- a/scribo/scribo/binarization/sauvola.hh
+++ b/scribo/scribo/binarization/sauvola.hh
@@ -33,7 +33,7 @@
# include <mln/core/concept/image.hh>
# include <scribo/binarization/internal/sauvola_functor.hh>
-# include <scribo/binarization/internal/sauvola_core.hh>
+# include <scribo/binarization/internal/local_threshold_core.hh>
namespace scribo
{
@@ -95,7 +95,7 @@ namespace scribo
mln_precondition(exact(input).is_valid());
internal::sauvola_functor<I> f(input, K, SCRIBO_DEFAULT_SAUVOLA_R);
- internal::sauvola_core(input, f, window_size);
+ internal::local_threshold_core(input, f, window_size);
trace::exiting("scribo::binarization::sauvola");
return f.output;
diff --git a/scribo/scribo/binarization/sauvola_threshold.hh b/scribo/scribo/binarization/sauvola_threshold.hh
index f93edae..564aaa7 100644
--- a/scribo/scribo/binarization/sauvola_threshold.hh
+++ b/scribo/scribo/binarization/sauvola_threshold.hh
@@ -36,23 +36,10 @@
# include <algorithm>
# include <cmath>
-# include <mln/core/image/image2d.hh>
-# include <mln/value/int_u.hh>
-# include <mln/value/int_u8.hh>
-
-# include <mln/border/mirror.hh>
-# include <mln/border/adjust.hh>
-
-# include <scribo/core/init_integral_image.hh>
-# include <scribo/binarization/internal/sauvola_formula.hh>
+# include <mln/core/concept/image.hh>
+# include <scribo/binarization/internal/local_threshold_core.hh>
# include <scribo/binarization/internal/sauvola_threshold_functor.hh>
-# include <scribo/util/init_integral_image.hh>
-# include <scribo/util/integral_sum_sum2_functor.hh>
-# include <scribo/util/compute_sub_domains.hh>
-
-# include <scribo/canvas/integral_browsing.hh>
-
namespace scribo
@@ -98,121 +85,8 @@ namespace scribo
# ifndef MLN_INCLUDE_ONLY
- // Implementation
-
-
- namespace impl
- {
-
- namespace generic
- {
-
- template <typename I>
- inline
- mln_concrete(I)
- sauvola_threshold(const Image<I>& input_, unsigned window_size,
- double K)
- {
- trace::entering("scribo::binarization::impl::generic::sauvola_threshold");
-
- // Not implemented
- mlc_abort(I)::check();
-
- typedef mln_concrete(I) output_t;
- trace::exiting("scribo::binarization::impl::generic::sauvola_threshold");
- return output_t();
- }
-
- } // end of namespace scribo::binarization::impl::generic
-
-
- template <typename I>
- inline
- mln_concrete(I)
- sauvola_threshold_gl(const Image<I>& input_, unsigned window_size,
- double K)
- {
- trace::entering("scribo::binarization::impl::sauvola_threshold_gl");
-
- const I& input = exact(input_);
-
- mln_precondition(exact(input).is_valid());
-
- // Make sure the image sizes are a multiple of 3 in each
- // dimension. (browsing while binarizing relies on that
- // property).
- mln::util::array<mln::util::couple<box2d, unsigned> >
- sub_domains = scribo::util::compute_sub_domains(input, 1, 3);
-
- border::adjust(input, sub_domains(1).second());
- border::mirror(input);
-
- typedef mln::util::couple<double,double> V_i;
- scribo::util::integral_sum_sum2_functor<mln_value(I), double> fi;
- mln_ch_value(I,V_i)
- integral = scribo::util::init_integral_image(input, 3, fi);
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- initialize(internal::debug_mean, input);
- initialize(internal::debug_stddev, input);
-
- initialize(internal::debug_threshold, input);
- initialize(internal::debug_alpham, input);
- initialize(internal::debug_alphacond, input);
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
- internal::sauvola_threshold_functor<I> f(input, K,
- SCRIBO_DEFAULT_SAUVOLA_R);
- scribo::canvas::integral_browsing(integral, 1, window_size / 3,
- window_size / 3, 3, f);
-
- trace::exiting("scribo::binarization::impl::sauvola_threshold_gl");
- return f.output;
- }
-
-
- } // end of namespace scribo::binarization::impl
-
-
-
-
- // Dispatch
-
- namespace internal
- {
-
- template <unsigned n, typename I>
- inline
- mln_ch_value(I, value::int_u<n>)
- sauvola_threshold_dispatch(const value::int_u<n>&, const I& input,
- unsigned window_size,
- double K)
- {
- return impl::sauvola_threshold_gl(input, window_size, K);
- }
-
-
- template <typename I>
- inline
- mln_ch_value(I, value::int_u8)
- sauvola_threshold_dispatch(const mln_value(I)&, const I& input,
- unsigned window_size,
- double K)
- {
- // 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>
- mln_ch_value(I, value::int_u8)
+ mln_concrete(I)
sauvola_threshold(const Image<I>& input, unsigned window_size,
double K)
{
@@ -221,15 +95,11 @@ namespace scribo
mln_precondition(mln_site_(I)::dim == 2);
mln_precondition(exact(input).is_valid());
- typedef mln_value(I) value_t;
- mln_ch_value(I, value::int_u8)
- output = internal::sauvola_threshold_dispatch(value_t(),
- exact(input),
- window_size,
- K);
+ internal::sauvola_threshold_functor<I> f(input, K, SCRIBO_DEFAULT_SAUVOLA_R);
+ internal::local_threshold_core(input, f, window_size);
trace::exiting("scribo::binarization::sauvola_threshold");
- return output;
+ return f.output;
}
--
1.7.2.5
1
0
---
scribo/sauvola_fast.cc | 109 +++----------------
.../binarization/internal/local_threshold_core.hh | 11 ++-
scribo/tests/binarization/niblack.cc | 1 -
scribo/tests/binarization/niblack.ref.pbm | Bin 32884 -> 32884 bytes
scribo/tests/binarization/sauvola.cc | 1 -
scribo/tests/binarization/sauvola.ref.pbm | Bin 32884 -> 32884 bytes
6 files changed, 27 insertions(+), 95 deletions(-)
diff --git a/scribo/sauvola_fast.cc b/scribo/sauvola_fast.cc
index 7eb41ca..f412bbe 100644
--- a/scribo/sauvola_fast.cc
+++ b/scribo/sauvola_fast.cc
@@ -5,96 +5,18 @@
#include <mln/util/couple.hh>
#include <mln/util/timer.hh>
#include <scribo/binarization/internal/sauvola_formula.hh>
+#include <scribo/binarization/internal/sauvola_functor.hh>
#include <scribo/util/init_integral_image.hh>
#include <scribo/util/integral_sum_sum2_functor.hh>
+#include <scribo/util/compute_sub_domains.hh>
-namespace mln
-{
-
- template <typename I>
- struct sauvola_functor
- {
-
- const I& input;
- typedef mln_ch_value(I,bool) bin_t;
- bin_t bin;
-
- image2d<double> th_;
-
- const mln_value(I)* pi;
- bool* po;
-
- double K_;
- double R_;
-
- scribo::binarization::internal::sauvola_formula formula_;
-
- int step_;
- unsigned next_line2;
- unsigned next_line3;
- unsigned offset1;
- unsigned offset2;
-
- sauvola_functor(const I& input_, mln_ch_value(I,bool)& bin_, double K, double R)
- : input(input_),
- bin(bin_),
- pi(&input(input.domain().pmin())),
- po(&bin(bin.domain().pmin())),
- K_(K),
- R_(R)
- {
- step_ = 3;
- unsigned next_line1 = 2 * input.border();
- next_line2 = input.delta_index(dpoint2d(+1,0)) + next_line1;
- next_line3 = input.delta_index(dpoint2d(+2,0)) + next_line1;
-
- offset1 = input.delta_index(dpoint2d(+1,0));
- offset2 = input.delta_index(dpoint2d(+2,0));
- }
-
- // Run every 4 pixels.
- void exec(double mean, double stddev)
- {
- static point2d p(0,0);
-
- double th = formula_(p, mean, stddev, K_, R_);
-
- for (int i = 0; i < step_; ++i, ++po, ++pi)
- {
- *po = (*pi <= th);
- *(po + offset1) = (*(pi + offset1) <= th);
- *(po + offset2) = (*(pi + offset2) <= th);
- }
-
-# ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
- // Store local mean
- unsigned index = pi - input.buffer();
-
- internal::debug_mean.element(index) = mean * internal::mean_debug_factor;
- internal::debug_stddev.element(index) = stddev * internal::stddev_debug_factor;
- internal::debug_threshold.element(index) = t;
-
- double alpha = K * (1 - stddev / R);
- internal::debug_alpham.element(index) = alpha * mean * internal::alpham_debug_factor;
- internal::debug_alphacond.element(index) = (stddev < (alpha * mean / 2.));
-# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
-
- }
-
- void end_of_row(int)
- {
- po += next_line3;
- pi += next_line3;
- }
-
-
- void finalize()
- {
- }
-
- };
+#include <mln/io/dump/save.hh>
+#include <mln/border/mirror.hh>
+#include <mln/border/adjust.hh>
+namespace mln
+{
image2d<bool>
sauvola_fast(const image2d<value::int_u8>& input, unsigned win)
@@ -102,9 +24,16 @@ namespace mln
util::timer t;
t.start();
+ mln::util::array<mln::util::couple<box2d, unsigned> >
+ sub_domains = scribo::util::compute_sub_domains(input, 1, 3);
+
+ border::adjust(input, sub_domains(1).second());
+ border::mirror(input);
+
scribo::util::integral_sum_sum2_functor<value::int_u8, double> fi;
image2d<util::couple<double,double> >
- integral = scribo::util::init_integral_image(input, 3, fi);
+ integral = scribo::util::init_integral_image(input, 3, fi, sub_domains[2].first(),
+ sub_domains[2].second());
t.stop();
std::cout << "image integrale - " << t << std::endl;
@@ -119,11 +48,9 @@ namespace mln
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
t.restart();
- image2d<bool> output;
- initialize(output, input);
- sauvola_functor<image2d<value::int_u8> > f(input, output,
- SCRIBO_DEFAULT_SAUVOLA_K,
- SCRIBO_DEFAULT_SAUVOLA_R);
+ scribo::binarization::internal::sauvola_functor<image2d<value::int_u8> > f(input,
+ SCRIBO_DEFAULT_SAUVOLA_K,
+ SCRIBO_DEFAULT_SAUVOLA_R);
scribo::canvas::integral_browsing(integral, 1, win / 3, win / 3, 3, f);
t.stop();
std::cout << "Binarization - " << t << std::endl;
diff --git a/scribo/scribo/binarization/internal/local_threshold_core.hh b/scribo/scribo/binarization/internal/local_threshold_core.hh
index f2c9cb1..9ea81f9 100644
--- a/scribo/scribo/binarization/internal/local_threshold_core.hh
+++ b/scribo/scribo/binarization/internal/local_threshold_core.hh
@@ -152,8 +152,15 @@ namespace scribo
# endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
t.restart();
- scribo::canvas::integral_browsing(integral, 1, window_size / 3,
- window_size / 3, 3, f);
+
+ window_size /= 3;
+ if (window_size % 2)
+ window_size += 2;
+ else
+ window_size += 1;
+
+ scribo::canvas::integral_browsing(integral, 1, window_size,
+ window_size, 3, f);
t.stop();
std::cout << "Binarization - " << t << std::endl;
diff --git a/scribo/tests/binarization/niblack.cc b/scribo/tests/binarization/niblack.cc
index 99a58e2..0263c1e 100644
--- a/scribo/tests/binarization/niblack.cc
+++ b/scribo/tests/binarization/niblack.cc
@@ -30,7 +30,6 @@
#include <mln/value/int_u8.hh>
#include <mln/io/pgm/load.hh>
#include <mln/io/pbm/load.hh>
-#include <mln/io/pbm/save.hh>
#include <scribo/binarization/niblack.hh>
diff --git a/scribo/tests/binarization/niblack.ref.pbm b/scribo/tests/binarization/niblack.ref.pbm
index 83cf4fb..225b1df 100644
Binary files a/scribo/tests/binarization/niblack.ref.pbm and b/scribo/tests/binarization/niblack.ref.pbm differ
diff --git a/scribo/tests/binarization/sauvola.cc b/scribo/tests/binarization/sauvola.cc
index 33eb59f..99efce5 100644
--- a/scribo/tests/binarization/sauvola.cc
+++ b/scribo/tests/binarization/sauvola.cc
@@ -30,7 +30,6 @@
#include <mln/value/int_u8.hh>
#include <mln/io/pgm/load.hh>
#include <mln/io/pbm/load.hh>
-#include <mln/io/pbm/save.hh>
#include <scribo/binarization/sauvola.hh>
diff --git a/scribo/tests/binarization/sauvola.ref.pbm b/scribo/tests/binarization/sauvola.ref.pbm
index 65d5a72..6eaf2fa 100644
Binary files a/scribo/tests/binarization/sauvola.ref.pbm and b/scribo/tests/binarization/sauvola.ref.pbm differ
--
1.7.2.5
1
0