Commit 542fcf95 authored by Guillaume Lazzara's avatar Guillaume Lazzara
Browse files

Improve stats computation in Sauvola Multi-scale.

	* binarization/internal/first_pass_functor.hh: Use
	sauvola_threshold routine.

	* binarization/sauvola_threshold.hh: Remove debug and fix invalid
	read in integral image.

	* canvas/integral_browsing.hh,
	* subsampling/integral_single_image.hh: Fix stats computation.

	* src/binarization/sauvola_ms.cc: Fix window parameter and make
	debug output optional.
parent 32e461a6
2009-12-11 Guillaume Lazzara <z@lrde.epita.fr>
Improve Sauvola Multi-scale.
* binarization/internal/first_pass_functor.hh: Use
sauvola_threshold routine.
* binarization/sauvola_threshold.hh: Remove debug and fix invalid
read in integral image.
* canvas/integral_browsing.hh,
* subsampling/integral_single_image.hh: Fix stats computation.
* src/binarization/sauvola_ms.cc: Fix window parameter and make
debug output optional.
2009-12-04 Guillaume Lazzara <z@lrde.epita.fr>
Optimize Sauvola's multiscale binarization.
......
......@@ -98,8 +98,16 @@ namespace scribo
// Use an inlined and developed version of sauvola's
// threshold formula.
value::int_u8 t_p = mean * (one_k + k_R * stddev);
// value::int_u8 t_p = sauvola_threshold_formula(mean, stddev);
// value::int_u8 t_p = mean * (one_k + k_R * stddev);
// std::cout << t_p << ", ";
// std::cout << input.element(p) << " - " << t_p << std::endl;
value::int_u8 t_p = sauvola_threshold_formula(mean, stddev);
// std::cout << input.point_at_index(p)
// << " - " << sauvola_threshold_formula(mean, stddev);
msk.element(p) = input.element(p) < t_p;
t_sub.element(p) = t_p;
......@@ -128,6 +136,8 @@ namespace scribo
void finalize()
{
mln_assertion(! pxl.is_valid());
// std::cout << std::endl << " ------- " << std::endl;
}
};
......
......@@ -46,6 +46,9 @@
# include <scribo/core/init_integral_image.hh>
#include <mln/io/pgm/save.hh>
namespace scribo
{
......@@ -168,8 +171,8 @@ namespace scribo
// Window half width.
int w_2 = win_width >> 1;
int row_min = std::max(0, p.row() - w_2);
int col_min = std::max(0, p.col() - w_2);
int row_min = std::max(0, p.row() - w_2 - 1);
int col_min = std::max(0, p.col() - w_2 - 1);
int row_max = std::min(static_cast<int>(simple.nrows()) - 1,
p.row() + w_2);
......@@ -177,12 +180,7 @@ namespace scribo
p.col() + w_2);
// std::cout << "sauvola threshold : "
// << simple.domain() << " - "
// << row_max << " - "
// << col_max << std::endl;
double wh = (row_max - row_min + 1) * (col_max - col_min + 1);
double wh = (row_max - row_min) * (col_max - col_min);
// Mean.
double m_x_y_tmp = (simple.at_(row_max, col_max)
......@@ -200,9 +198,38 @@ namespace scribo
double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh - 1.f));
// if (p == point2d(3,3))// || p == point2d(4,4) || p == point2d(1,1))
// {
// // std::cout << "p" << p << " - A(" << row_min << ", " << col_min
// // << ") = " << simple.at_(row_min, col_min)
// << " - B(" << row_min << ", " << col_max
// << ") = " << simple.at_(row_min, col_max)
// << " - C(" << row_max << ", " << col_min
// << ") = " << simple.at_(row_max, col_min)
// << " - D(" << row_max << ", " << col_max
// << ") = " << simple.at_(row_max, col_max)
// << " - n = " << wh
// << std::endl;
// << std::endl;
// }
// Thresholding.
double t_x_y = sauvola_threshold_formula(m_x_y, s_x_y, k, R);
// std::cout << p
// << " - m = " << m_x_y
// << " - s = " << s_x_y
// << " - t = " << t_x_y
// << " - sum = " << m_x_y_tmp
// << " - sum_2 = " << s_x_y_tmp
// << std::endl;
return t_x_y;
}
......@@ -219,19 +246,12 @@ namespace scribo
int row_min = std::max(0, p.row() - w_2);
int col_min = std::max(0, p.col() - w_2);
//FIXME: offset (-4) should be replaced by the number of
//padding pixels.
int row_max = std::min(static_cast<int>(integral.nrows()) - 1,
p.row() + w_2);
int col_max = std::min(static_cast<int>(integral.ncols()) - 1,
p.col() + w_2);
// std::cout << "sauvola threshold : "
// << simple.domain() << " - "
// << row_max << " - "
// << col_max << std::endl;
double wh = (row_max - row_min + 1) * (col_max - col_min + 1);
// Mean.
......@@ -251,7 +271,7 @@ namespace scribo
double s_x_y = std::sqrt((s_x_y_tmp - (m_x_y_tmp * m_x_y_tmp) / wh) / (wh - 1.f));
// Thresholding.
double t_x_y = m_x_y * (1.0 + 0.14 * ((s_x_y / 128) - 1.0));
double t_x_y = m_x_y * (1.0 + 0.34 * ((s_x_y / 128) - 1.0));
return t_x_y;
}
......@@ -438,6 +458,25 @@ namespace scribo
mln_precondition(mln_site_(I)::dim == 2);
mln_precondition(exact(input).is_valid());
// {
// J& simple_ = exact(simple);
// J& squared_ = exact(squared);
// mln_piter(J) p(simple_.domain());
// for_all(p)
// {
// std::cout << simple_(p) << ", ";
// }
// std::cout << std::endl << " ------- " << std::endl;
// for_all(p)
// {
// std::cout << squared_(p) << ", ";
// }
// std::cout << std::endl << " ------- " << std::endl;
// }
typedef mln_value(I) value_t;
mln_ch_value(I, value::int_u8)
output = internal::sauvola_threshold_dispatch(value_t(), exact(input),
......@@ -445,6 +484,8 @@ namespace scribo
exact(simple),
exact(squared));
// std::cout << std::endl << " ------- " << std::endl;
io::pgm::save(output, "ref_2_t.pgm");
trace::exiting("scribo::text::ppm2pbm");
return output;
}
......
......@@ -58,9 +58,13 @@ namespace scribo
double& mean, double& stddev)
{
mean = sum / n;
stddev = std::sqrt(sum_2 / n - mean * mean);
// stddev = std::sqrt(sum_2 / n - mean * mean);
// std::cout << "(" << mean << " - " << stddev << " - " << n << "),";
// unbias version:
// stddev = std::sqrt((sum_2 - n * mean * mean) / (n - 1));
stddev = std::sqrt((sum_2 - sum * sum / n) / (n - 1));
}
} // end of namespace scribo::canvas::internal
......@@ -72,6 +76,7 @@ namespace scribo
void integral_browsing(const image2d<util::couple<double, double> >& ima,
unsigned step,
unsigned w, unsigned h,
unsigned s,
F& functor)
{
typedef util::couple<double, double> V;
......@@ -112,6 +117,8 @@ namespace scribo
double mean, stddev;
unsigned s_2 = s * s;
// -------------------------------
// T (top)
......@@ -146,7 +153,7 @@ namespace scribo
// D
internal::compute_stats(d_ima->first(),
d_ima->second(),
size_tl,
size_tl * s_2,
mean, stddev);
functor.exec(mean, stddev);
d_ima += step;
......@@ -166,7 +173,7 @@ namespace scribo
// D - C
internal::compute_stats(d_ima->first() - c_ima->first(),
d_ima->second() - c_ima->second(),
size_tc,
size_tc * s_2,
mean, stddev);
functor.exec(mean, stddev);
c_ima += step;
......@@ -188,7 +195,7 @@ namespace scribo
// D* - C
internal::compute_stats(d_sum - c_ima->first(),
d_sum_2 - c_ima->second(),
size_tr,
size_tr * s_2,
mean, stddev);
functor.exec(mean, stddev);
c_ima += step;
......@@ -239,7 +246,7 @@ namespace scribo
// D - B
internal::compute_stats(d_ima->first() - b_ima->first(),
d_ima->second() - b_ima->second(),
size_ml,
size_ml * s_2,
mean, stddev);
functor.exec(mean, stddev);
b_ima += step;
......@@ -258,11 +265,40 @@ namespace scribo
for (; col <= max_col_mid; col += step)
{
// D + A - B - C
// if (row == 3 && col == 3)
// std::cout << "p(" << row << "," << col << ") - "
// << "A" << ima.point_at_index(a_ima - ima.buffer())
// << "=" << a_ima->first() << " - "
// << "B" << ima.point_at_index(b_ima - ima.buffer())
// << "=" << b_ima->first() << " - "
// << "C" << ima.point_at_index(c_ima - ima.buffer())
// << "=" << c_ima->first() << " - "
// << "D" << ima.point_at_index(d_ima - ima.buffer())
// << "=" << d_ima->first() << " - "
// << "n =" << size_mc << " - "
// << "n*s_2 =" << size_mc * s_2
// << std::endl;
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,
size_mc * s_2,
mean, stddev);
functor.exec(mean, stddev);
// std::cout << " - " << mean
// << " - " << stddev
// << " - " << (d_ima->first() - b_ima->first()) + (a_ima->first() - c_ima->first())
// << " - " << (d_ima->second() - b_ima->second()) + (a_ima->second() - c_ima->second())
// << std::endl;
a_ima += step;
b_ima += step;
c_ima += step;
......@@ -283,7 +319,7 @@ namespace scribo
// 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,
size_mr * s_2,
mean, stddev);
functor.exec(mean, stddev);
a_ima += step;
......@@ -332,7 +368,7 @@ namespace scribo
// D* - B
internal::compute_stats(d_ima->first() - b_ima->first(),
d_ima->second() - b_ima->second(),
size_bl,
size_bl * s_2,
mean, stddev);
functor.exec(mean, stddev);
b_ima += step;
......@@ -354,7 +390,7 @@ 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,
size_bc * s_2,
mean, stddev);
// std::cout << (d_ima->second() - b_ima->second()) + (a_ima->second() - c_ima->second()) << std::endl;
......@@ -385,7 +421,7 @@ namespace scribo
// 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,
size_br * s_2,
mean, stddev);
functor.exec(mean, stddev);
a_ima += step;
......
This diff is collapsed.
......@@ -107,7 +107,6 @@ namespace scribo
const I& input = exact(input_);
J& integral_sum_sum_2 = exact(integral_sum_sum_2_);
const unsigned area = scale * scale;
mln_precondition(input.is_valid());
mln_precondition(input.domain().pmin() == literal::origin);
......@@ -142,19 +141,22 @@ namespace scribo
const V* ptr3 = & input.at_(row + 2, 0);
for (unsigned col = 0; col < ncols; col += scale)
{
S sum;
sum = *ptr1 + *(ptr1 + 1) + *(ptr1 + 2);
sum += *ptr2 + *(ptr2 + 1) + *(ptr2 + 2);
sum += *ptr3 + *(ptr3 + 1) + *(ptr3 + 2);
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;
S val = sum / area;
*p_sub++ = val;
h_sum += val;
h_sum_2 += val * val;
*p_sub++ = local_sum / 9;
h_sum += local_sum;
h_sum_2 += local_sum_2;
// exception
p_integ->first() = h_sum;
......@@ -172,24 +174,27 @@ namespace scribo
for (row += scale; row < nrows; row += scale)
{
S h_sum = 0, h_sum_2 = 0;
const V* ptr1 = & input.at_(row, 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)
{
S sum;
sum = *ptr1 + *(ptr1 + 1) + *(ptr1 + 2);
sum += *ptr2 + *(ptr2 + 1) + *(ptr2 + 2);
sum += *ptr3 + *(ptr3 + 1) + *(ptr3 + 2);
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;
S val = sum / area;
*p_sub++ = val;
h_sum += val;
h_sum_2 += val * val;
*p_sub++ = local_sum / 9;
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();
......@@ -220,7 +225,6 @@ namespace scribo
const I& input = exact(input_);
J& integral_sum_sum_2 = exact(integral_sum_sum_2_);
const unsigned area = scale * scale;
typedef mln_value(I) V;
typedef mln_sum(V) S;
......@@ -257,6 +261,7 @@ namespace scribo
const V* ptr2 = & input.at_(row + 1, 0);
for (unsigned col = 0; col < ncols; col += scale)
{
/*
S sum;
sum = *ptr1 + *(ptr1 + 1);
sum += *ptr2 + *(ptr2 + 1);
......@@ -268,6 +273,22 @@ namespace scribo
h_sum += val;
h_sum_2 += val * val;
*/
// NEW:
V v11 = *ptr1, v12 = *(ptr1 + 1),
v21 = *ptr2, v22 = *(ptr2 + 1);
ptr1 += 2;
ptr2 += 2;
S local_sum = v11 + v12 + v21 + v22,
local_sum_2 = v11*v11 + v12*v12 + v21*v21 + v22*v22;
*p_sub++ = local_sum / 4;
h_sum += local_sum;
h_sum_2 += local_sum_2;
// end of NEW.
// exception
p_integ->first() = h_sum;
......@@ -289,6 +310,29 @@ namespace scribo
const V* ptr2 = & input.at_(row + 1, 0);
for (unsigned col = 0; col < ncols; col += scale)
{
// NEW:
V v11 = *ptr1, v12 = *(ptr1 + 1),
v21 = *ptr2, v22 = *(ptr2 + 1);
ptr1 += 2;
ptr2 += 2;
S local_sum = v11 + v12 + v21 + v22,
local_sum_2 = v11*v11 + v12*v12 + v21*v21 + v22*v22;
*p_sub++ = local_sum / 4;
h_sum += local_sum;
h_sum_2 += local_sum_2;
// end of NEW.
/*
// To get the strict equivalent to the integral image
// computed at working scale (scale (2)), we need the code
// below. In addition, the integral_browsing shall call
// the threshold formula with (..size..) and NOT with
// (..size * s_2..).
S sum;
sum = *ptr1 + *(ptr1 + 1);
sum += *ptr2 + *(ptr2 + 1);
......@@ -297,10 +341,22 @@ namespace scribo
S val = sum / area;
*p_sub++ = val;
h_sum += val;
h_sum_2 += val * val;
*/
// Never write something like this:
// *p_sub++ = sum / area;
// h_sum += sum;
// h_sum_2 += sum * sum;
// because the product 'sum * sum' is not
// equivalent to the sum of the value^2. E.g.
// we have (v1 + v2 + v3 + v4)^2 + etc. instead
// of having the correct sum_2 being v1^2 + v2^2 etc.
p_integ->first() = h_sum + (p_integ + up)->first();
p_integ->second() = h_sum_2 + (p_integ + up)->second();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment