28 #ifndef SCRIBO_BINARIZATION_SAUVOLA_MS_HH
29 # define SCRIBO_BINARIZATION_SAUVOLA_MS_HH
39 # include <mln/core/alias/neighb2d.hh>
40 # include <mln/data/fill.hh>
41 # include <mln/data/compare.hh>
43 # include <mln/subsampling/antialiased.hh>
45 # include <mln/transform/influence_zone_geodesic.hh>
47 # include <mln/data/split.hh>
49 # include <mln/value/int_u8.hh>
50 # include <mln/border/mirror.hh>
51 # include <mln/border/adjust.hh>
52 # include <mln/border/resize.hh>
54 # include <mln/core/box_runend_piter.hh>
56 # include <mln/util/couple.hh>
58 # include <mln/extension/adjust.hh>
60 # include <scribo/subsampling/integral_single_image.hh>
62 # include <scribo/core/macros.hh>
64 # include <scribo/binarization/internal/sauvola_ms_functor.hh>
66 # include <scribo/canvas/integral_browsing.hh>
68 # include <scribo/util/init_integral_image.hh>
69 # include <scribo/util/integral_sub_sum_sum2_functor.hh>
70 # include <scribo/util/compute_sub_domains.hh>
72 # include <scribo/debug/logger.hh>
73 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
74 # include <scribo/binarization/internal/local_threshold_debug.hh>
75 # include <mln/io/pgm/save.hh>
76 # include <mln/io/dump/save.hh>
77 # include <mln/debug/filename.hh>
78 # include <mln/labeling/compute.hh>
79 # include <mln/accu/math/count.hh>
80 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
127 template <
typename I>
131 image2d<mln::util::couple<
double,
double> >& integral_sum_sum_2);
139 template <typename I>
150 template <typename I>
157 template <typename I>
160 double k2,
double k3,
double k4);
165 template <typename I>
171 # ifndef MLN_INCLUDE_ONLY
182 template <
typename V>
183 V my_find_root(
image2d<V>& parent,
const V& x)
187 return parent.
element(x) = my_find_root(parent,
195 unsigned lambda_min,
unsigned lambda_max,
197 unsigned q,
unsigned i,
unsigned w,
204 unsigned ratio =
unsigned(std::pow(
float(q),
float(i - 2u)));
213 f(sub, SCRIBO_DEFAULT_SAUVOLA_R, e_2, i, q);
214 scribo::canvas::integral_browsing(integral_sum_sum_2,
216 w_local_w, w_local_h,
225 mln_box_runend_piter_(I) sp(sub.domain());
226 unsigned ncols = sp.run_length();
229 unsigned p = &sub(sp) - sub.
buffer();
233 P tmp = site * ratio;
236 if (tmp.row() + ratio >=
nrows)
237 ptr.resize(nrows - tmp.row());
241 for (
unsigned j = 1; j < ptr.size(); ++j)
248 for (
unsigned j = 0; j <
ncols; ++j)
250 if (f.msk.element(p))
252 mln_site_(I) sq = site * ratio;
254 if (f.parent.element(p) == p)
257 f.msk.element(p) = f.card.element(p) > lambda_min
258 && f.card.element(p) < lambda_max;
259 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
260 f.full_msk.element(p) =
true;
263 unsigned area = f.card.element(p) * ratio * s;
264 if (area_histo[i - 2].
find(area) != area_histo[i - 2].end())
265 ++area_histo[i - 2][
area];
267 area_histo[i - 2][
area] = 1;
269 for (
unsigned l = 0; l < ratio; ++l)
270 for (
unsigned k = 0; k < ratio; ++k)
271 debug_scale_proba(
point3d(i - 2, sq.row() + l, sq.col() + k)) = f.card.element(p);
272 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
274 if (f.msk.element(p) && e_2(sq) == 0u)
276 for (
unsigned l = 0; l < ptr.size(); ++l)
277 std::memset(ptr(l), i, ratio *
sizeof(mln_value_(I)));
284 f.msk.element(p) = f.msk.element(f.parent.element(p));
285 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
286 f.full_msk.element(p) = f.full_msk.element(f.parent.element(p));
288 point2d sqp = f.parent.point_at_offset(f.parent.element(p)) * ratio;
289 unsigned v = debug_scale_proba(
point3d(i - 2, sqp.
row(), sqp.
col()));
291 for (
unsigned l = 0; l < ratio; ++l)
292 for (
unsigned k = 0; k < ratio; ++k)
293 debug_scale_proba(
point3d(i - 2, sq.row() + l, sq.col() + k)) = v;
294 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
296 if (f.msk.element(p) && e_2(sq) == 0u)
298 for (
unsigned l = 0; l < ptr.size(); ++l)
299 std::memset(ptr(l), i, ratio *
sizeof(mln_value_(I)));
305 for (
unsigned l = 0; l < ptr.size(); ++l)
316 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
317 if (internal::threshold_image_output)
320 if (internal::full_threshold_image_output)
323 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
330 template <
typename I,
typename J,
typename K>
332 multi_scale_binarization(const I& in, const J& e2,
333 const mln::util::array<K>& t_ima,
339 typedef const mln_value(K)* ptr_type;
344 ptr_t[2] = & t_ima[2].at_(0, 0);
345 ptr_t[3] = & t_ima[3].at_(0, 0);
346 ptr_t[4] = & t_ima[4].at_(0, 0);
349 const mln_value(J)* ptr_e2 = & e2.at_(0, 0);
350 const mln_value(I)* ptr__in = & in.at_(0, 0);
351 bool* ptr__out = & out.at_(0, 0);
358 int more_offset = - ((4 * s) - in.ncols() % (4 * s));
360 if (more_offset == - (static_cast<
int>(4*s)))
364 nrows4 = t_ima[4].nrows(),
365 ncols4 = t_ima[4].ncols(),
367 delta1 = in.delta_offset(
dpoint2d(+1, -(s - 1))),
368 delta1b = in.delta_offset(dpoint2d(+1, -(s + s - 1))),
369 delta1c = in.delta_offset(dpoint2d(-(s + s - 1), +1)),
370 delta1d = in.delta_offset(dpoint2d(+1, -(s * 4 - 1))),
371 delta1e = in.delta_offset(dpoint2d(-(s * 4 - 1), +1)),
372 delta1f = in.delta_offset(dpoint2d(-(s - 1), +1)),
374 delta2 = t_ima[2].delta_offset(dpoint2d(+1, -1)),
375 delta2b = t_ima[2].delta_offset(dpoint2d(+1, -3)),
376 delta2c = t_ima[2].delta_offset(dpoint2d(-3, +1)),
378 delta3 = t_ima[3].delta_offset(dpoint2d(+1, -1)),
380 eor1 = in.delta_offset(dpoint2d(+4 * s, - in.ncols())) + more_offset,
381 eor2 = t_ima[2].delta_offset(dpoint2d(+4,- t_ima[2].ncols())),
382 eor3 = t_ima[3].delta_offset(dpoint2d(+2,- t_ima[3].ncols())),
383 eor4 = t_ima[4].delta_offset(dpoint2d(+1,- t_ima[4].ncols()));
386 for (
int row4 = 0; row4 < nrows4; ++row4)
388 for (
int col4 = 0; col4 < ncols4; ++col4)
392 threshold = *ptr_t[*ptr_e2];
394 for (
unsigned i = 1; i < s; ++i)
396 for (
unsigned j = 1; j < s; ++j)
399 ++ptr__out; ++ptr__in;
403 ptr__out += delta1; ptr__in += delta1;
406 for (
unsigned j = 1; j < s; ++j)
409 ++ptr__out; ++ptr__in;
412 ptr__out += delta1f; ptr__in += delta1f;
415 ++ptr_t[2]; ++ptr_e2;
416 threshold = *ptr_t[*ptr_e2];
418 for (
unsigned i = 1; i < s; ++i)
420 for (
unsigned j = 1; j < s; ++j)
423 ++ptr__out; ++ptr__in;
427 ptr__out += delta1; ptr__in += delta1;
430 for (
unsigned j = 1; j < s; ++j)
433 ++ptr__out; ++ptr__in;
436 ptr__out += delta1b; ptr__in += delta1b;
439 ptr_t[2] += delta2; ptr_e2 += delta2;
440 threshold = *ptr_t[*ptr_e2];
442 for (
unsigned i = 1; i < s; ++i)
444 for (
unsigned j = 1; j < s; ++j)
447 ++ptr__out; ++ptr__in;
451 ptr__out += delta1; ptr__in += delta1;
454 for (
unsigned j = 1; j < s; ++j)
457 ++ptr__out; ++ptr__in;
460 ptr__out += delta1f; ptr__in += delta1f;
464 ++ptr_t[2]; ++ptr_e2;
465 threshold = *ptr_t[*ptr_e2];
467 for (
unsigned i = 1; i < s; ++i)
469 for (
unsigned j = 1; j < s; ++j)
472 ++ptr__out; ++ptr__in;
476 ptr__out += delta1; ptr__in += delta1;
479 for (
unsigned j = 1; j < s; ++j)
482 ++ptr__out; ++ptr__in;
485 ptr__out += delta1c; ptr__in += delta1c;
488 ptr_t[2] -= delta2; ptr_e2 -= delta2;
494 threshold = *ptr_t[*ptr_e2];
496 for (
unsigned i = 1; i < s; ++i)
498 for (
unsigned j = 1; j < s; ++j)
501 ++ptr__out; ++ptr__in;
505 ptr__out += delta1; ptr__in += delta1;
508 for (
unsigned j = 1; j < s; ++j)
511 ++ptr__out; ++ptr__in;
514 ptr__out += delta1f; ptr__in += delta1f;
517 ++ptr_t[2]; ++ptr_e2;
518 threshold = *ptr_t[*ptr_e2];
520 for (
unsigned i = 1; i < s; ++i)
522 for (
unsigned j = 1; j < s; ++j)
525 ++ptr__out; ++ptr__in;
529 ptr__out += delta1; ptr__in += delta1;
532 for (
unsigned j = 1; j < s; ++j)
535 ++ptr__out; ++ptr__in;
538 ptr__out += delta1b; ptr__in += delta1b;
541 ptr_t[2] += delta2; ptr_e2 += delta2;
542 threshold = *ptr_t[*ptr_e2];
544 for (
unsigned i = 1; i < s; ++i)
546 for (
unsigned j = 1; j < s; ++j)
549 ++ptr__out; ++ptr__in;
553 ptr__out += delta1; ptr__in += delta1;
556 for (
unsigned j = 1; j < s; ++j)
559 ++ptr__out; ++ptr__in;
562 ptr__out += delta1f; ptr__in += delta1f;
565 ++ptr_t[2]; ++ptr_e2;
566 threshold = *ptr_t[*ptr_e2];
568 for (
unsigned i = 1; i < s; ++i)
570 for (
unsigned j = 1; j < s; ++j)
573 ++ptr__out; ++ptr__in;
577 ptr__out += delta1; ptr__in += delta1;
580 for (
unsigned j = 1; j < s; ++j)
583 ++ptr__out; ++ptr__in;
586 ptr__out += delta1d; ptr__in += delta1d;
589 ptr_t[2] += delta2b; ptr_e2 += delta2b;
595 threshold = *ptr_t[*ptr_e2];
597 for (
unsigned i = 1; i < s; ++i)
599 for (
unsigned j = 1; j < s; ++j)
602 ++ptr__out; ++ptr__in;
606 ptr__out += delta1; ptr__in += delta1;
609 for (
unsigned j = 1; j < s; ++j)
612 ++ptr__out; ++ptr__in;
615 ptr__out += delta1f; ptr__in += delta1f;
618 ++ptr_t[2]; ++ptr_e2;
619 threshold = *ptr_t[*ptr_e2];
621 for (
unsigned i = 1; i < s; ++i)
623 for (
unsigned j = 1; j < s; ++j)
626 ++ptr__out; ++ptr__in;
630 ptr__out += delta1; ptr__in += delta1;
633 for (
unsigned j = 1; j < s; ++j)
636 ++ptr__out; ++ptr__in;
639 ptr__out += delta1b; ptr__in += delta1b;
642 ptr_t[2] += delta2; ptr_e2 += delta2;
643 threshold = *ptr_t[*ptr_e2];
645 for (
unsigned i = 1; i < s; ++i)
647 for (
unsigned j = 1; j < s; ++j)
650 ++ptr__out; ++ptr__in;
654 ptr__out += delta1; ptr__in += delta1;
657 for (
unsigned j = 1; j < s; ++j)
660 ++ptr__out; ++ptr__in;
663 ptr__out += delta1f; ptr__in += delta1f;
666 ++ptr_t[2]; ++ptr_e2;
667 threshold = *ptr_t[*ptr_e2];
669 for (
unsigned i = 1; i < s; ++i)
671 for (
unsigned j = 1; j < s; ++j)
674 ++ptr__out; ++ptr__in;
678 ptr__out += delta1; ptr__in += delta1;
681 for (
unsigned j = 1; j < s; ++j)
684 ++ptr__out; ++ptr__in;
687 ptr__out += delta1c; ptr__in += delta1c;
690 ptr_t[2] -= delta2; ptr_e2 -= delta2;
696 threshold = *ptr_t[*ptr_e2];
698 for (
unsigned i = 1; i < s; ++i)
700 for (
unsigned j = 1; j < s; ++j)
703 ++ptr__out; ++ptr__in;
707 ptr__out += delta1; ptr__in += delta1;
710 for (
unsigned j = 1; j < s; ++j)
713 ++ptr__out; ++ptr__in;
716 ptr__out += delta1f; ptr__in += delta1f;
719 ++ptr_t[2]; ++ptr_e2;
720 threshold = *ptr_t[*ptr_e2];
722 for (
unsigned i = 1; i < s; ++i)
724 for (
unsigned j = 1; j < s; ++j)
727 ++ptr__out; ++ptr__in;
731 ptr__out += delta1; ptr__in += delta1;
734 for (
unsigned j = 1; j < s; ++j)
737 ++ptr__out; ++ptr__in;
740 ptr__out += delta1b; ptr__in += delta1b;
743 ptr_t[2] += delta2; ptr_e2 += delta2;
744 threshold = *ptr_t[*ptr_e2];
746 for (
unsigned i = 1; i < s; ++i)
748 for (
unsigned j = 1; j < s; ++j)
751 ++ptr__out; ++ptr__in;
755 ptr__out += delta1; ptr__in += delta1;
758 for (
unsigned j = 1; j < s; ++j)
761 ++ptr__out; ++ptr__in;
764 ptr__out += delta1f; ptr__in += delta1f;
767 ++ptr_t[2]; ++ptr_e2;
768 threshold = *ptr_t[*ptr_e2];
770 for (
unsigned i = 1; i < s; ++i)
772 for (
unsigned j = 1; j < s; ++j)
775 ++ptr__out; ++ptr__in;
779 ptr__out += delta1; ptr__in += delta1;
782 for (
unsigned j = 1; j < s; ++j)
785 ++ptr__out; ++ptr__in;
788 ptr__out += delta1e; ptr__in += delta1e;
793 ptr_t[2] += delta2c; ptr_e2 += delta2c;
794 ptr_t[3] = ptr_t[3] - delta3;
799 ptr__out += eor1; ptr__in += eor1;
800 ptr_t[2] += eor2; ptr_e2 += eor2;
820 template <
typename I>
824 image2d<mln::util::couple<
double,
double> >& integral_sum_sum_2)
826 mln_trace(
"scribo::binarization::sauvola_ms");
828 const I& input_1 =
exact(input_1_);
829 typedef mln_value(I) V;
831 mlc_is_a(mln_value(I),
value::Scalar)::check();
832 mln_precondition(input_1.is_valid());
837 unsigned nb_subscale = 3;
840 unsigned w_work = w_1 * s;
851 mln::util::array<I> t_ima;
856 for (
unsigned i = 0; i < nb_subscale + 2; ++i)
870 sub_domains = scribo::util::compute_sub_domains(input_1,
886 fi(s, sub_domains[2].first(), sub_domains[2].second());
888 integral_sum_sum_2 = scribo::util::init_integral_image(input_1, s, fi,
889 sub_domains[2].first(),
890 sub_domains[2].second());
901 for (
unsigned i = 3; i <= nb_subscale + 1; ++i)
903 sub_domains[i].first(),
904 sub_domains[i].second()));
915 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
917 integral_sum_sum_2.nrows(),
918 integral_sum_sum_2.ncols(),
919 integral_sum_sum_2.border());
920 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
928 max_s2 = (w_1 * w_1) / (s * s) * 0.7,
934 int i = sub_ima.
size() - 1;
935 t_ima[i] = internal::compute_t_n_and_e_2(sub_ima[i], e_2,
936 (max_s2 * q_2) / (q_2) * min_coef,
945 for (
int i = sub_ima.
size() - 2; i > 2; --i)
947 t_ima[i] = internal::compute_t_n_and_e_2(sub_ima[i], e_2,
948 max_s2 / (q_2) * min_coef,
958 t_ima[2] = internal::compute_t_n_and_e_2(sub_ima[2], e_2,
970 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
971 if (internal::scale_image_output)
974 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
987 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
988 internal::debug_e_2 = e_2;
989 if (internal::scale_iz_image_output)
998 << count[2] / (
float)npixels * 100
1000 << count[3] / (
float)npixels * 100
1002 << count[4] / (
float)npixels * 100 <<
")"
1005 if (internal::scale_proba_output)
1008 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
1016 output = internal::multi_scale_binarization(input_1, e_2, t_ima, s);
1031 template <
typename I>
1034 image2d<mln::util::couple<
double,
double> >& integral_sum_sum_2)
1036 mln_trace(
"scribo::binarization::sauvola_ms");
1038 mln_precondition(
exact(input_1_).is_valid());
1039 mln_precondition(s > 1);
1042 mlc_is_not_a(mln_value(I), value::Vectorial)::check();
1043 mlc_is_not(mln_value(I),
bool)::check();
1046 output = impl::generic::
sauvola_ms(exact(input_1_), w_1, s,
1047 integral_sum_sum_2);
1052 template <typename I>
1053 mln_ch_value(I,
bool)
1056 mln_trace(
"scribo::binarization::sauvola_ms");
1058 mln_precondition(
exact(input_1_).is_valid());
1059 mln_precondition(s > 1);
1062 mlc_is_not_a(mln_value(I), value::Vectorial)::check();
1063 mlc_is_not(mln_value(I),
bool)::check();
1066 integral_t integral_sum_sum_2;
1069 output =
sauvola_ms(input_1_, w_1, s, integral_sum_sum_2);
1075 template <typename I>
1076 mln_ch_value(I,
bool)
1083 template <
typename I>
1086 double k2,
double k3,
double k4)
1088 binarization::internal::k2 = k2;
1089 binarization::internal::k3 = k3;
1090 binarization::internal::k4 = k4;
1096 template <
typename I>
1101 binarization::internal::k2 = all_k;
1102 binarization::internal::k3 = all_k;
1103 binarization::internal::k4 = all_k;
1109 # endif // ! MLN_INCLUDE_ONLY
1117 #endif // SCRIBO_BINARIZATION_SAUVOLA_MS_HH