$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
sauvola_ms.hh
1 // Copyright (C) 2009, 2010, 2011, 2012, 2013 EPITA Research and
2 // Development Laboratory (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 
28 #ifndef SCRIBO_BINARIZATION_SAUVOLA_MS_HH
29 # define SCRIBO_BINARIZATION_SAUVOLA_MS_HH
30 
37 
38 
39 # include <mln/core/alias/neighb2d.hh>
40 # include <mln/data/fill.hh>
41 # include <mln/data/compare.hh>
42 
43 # include <mln/subsampling/antialiased.hh>
44 
45 # include <mln/transform/influence_zone_geodesic.hh>
46 
47 # include <mln/data/split.hh>
48 
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>
53 
54 # include <mln/core/box_runend_piter.hh>
55 
56 # include <mln/util/couple.hh>
57 
58 # include <mln/extension/adjust.hh>
59 
60 # include <scribo/subsampling/integral_single_image.hh>
61 
62 # include <scribo/core/macros.hh>
63 
64 # include <scribo/binarization/internal/sauvola_ms_functor.hh>
65 
66 # include <scribo/canvas/integral_browsing.hh>
67 
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>
71 
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
81 
82 
83 namespace scribo
84 {
85 
86  namespace binarization
87  {
88 
89  using namespace mln;
90  using value::int_u8;
91 
92 
127  template <typename I>
128  mln_ch_value(I,bool)
129  sauvola_ms(const Image<I>& input_1, unsigned w_1,
130  unsigned s,
131  image2d<mln::util::couple<double,double> >& integral_sum_sum_2);
132 
138  //
139  template <typename I>
140  mln_ch_value(I,bool)
141  sauvola_ms(const Image<I>& input_1, unsigned w_1, unsigned s);
142 
149  //
150  template <typename I>
151  mln_ch_value(I,bool)
152  sauvola_ms(const Image<I>& input_1, unsigned w_1);
153 
156  //
157  template <typename I>
158  mln_ch_value(I,bool)
159  sauvola_ms(const Image<I>& input_1, unsigned w_1, unsigned s,
160  double k2, double k3, double k4);
161 
164  //
165  template <typename I>
166  mln_ch_value(I,bool)
167  sauvola_ms(const Image<I>& input_1, unsigned w_1, unsigned s,
168  double all_k);
169 
170 
171 # ifndef MLN_INCLUDE_ONLY
172 
173 
174  // Routines
175 
176  namespace internal
177  {
178 
179  using namespace mln;
180 
181 
182  template <typename V>
183  V my_find_root(image2d<V>& parent, const V& x)
184  {
185  if (parent.element(x) == x)
186  return x;
187  return parent.element(x) = my_find_root(parent,
188  parent.element(x));
189  }
190 
191 
192  inline
194  compute_t_n_and_e_2(const image2d<int_u8>& sub, image2d<int_u8>& e_2,
195  unsigned lambda_min, unsigned lambda_max,
196  unsigned s,
197  unsigned q, unsigned i, unsigned w,
198  const image2d<mln::util::couple<double,double> >& integral_sum_sum_2)
199  {
200  typedef image2d<int_u8> I;
201  typedef point2d P;
202 
203  // Cast to float is needed on MacOS X.
204  unsigned ratio = unsigned(std::pow(float(q), float(i - 2u))); // Ratio in comparison to e_2
205 
206  unsigned
207  w_local = w * ratio,
208  w_local_h = w_local,
209  w_local_w = w_local;
210 
211  // 1st pass
213  f(sub, SCRIBO_DEFAULT_SAUVOLA_R, e_2, i, q);
214  scribo::canvas::integral_browsing(integral_sum_sum_2,
215  ratio,
216  w_local_w, w_local_h,
217  s,
218  f);
219 
220  // 2nd pass
221  {
223  unsigned nrows = geom::nrows(e_2);
224 
225  mln_box_runend_piter_(I) sp(sub.domain()); // Backward.
226  unsigned ncols = sp.run_length();
227  for_all(sp)
228  {
229  unsigned p = &sub(sp) - sub.buffer(); // Offset
230  P site = sp;
231 
232  {
233  P tmp = site * ratio;
234 
235  // FIXME: to be removed!
236  if (tmp.row() + ratio >= nrows)
237  ptr.resize(nrows - tmp.row());
238 
239  ptr(0) = &e_2(tmp);
240  // FIXME: pointers could just be updated with an offset.
241  for (unsigned j = 1; j < ptr.size(); ++j)
242  {
243  tmp[0] += 1;
244  ptr(j) = & e_2(tmp);
245  }
246  }
247 
248  for (unsigned j = 0; j < ncols; ++j)
249  {
250  if (f.msk.element(p))
251  {
252  mln_site_(I) sq = site * ratio;
253 
254  if (f.parent.element(p) == p)
255  {
256  // test over the component cardinality
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;
261 
262 
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];
266  else
267  area_histo[i - 2][area] = 1;
268 
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
273 
274  if (f.msk.element(p) && e_2(sq) == 0u)
275  {
276  for (unsigned l = 0; l < ptr.size(); ++l)
277  std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
278  }
279 
280  }
281  else
282  {
283  // Propagation
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));
287 
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()));
290 
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
295 
296  if (f.msk.element(p) && e_2(sq) == 0u)
297  {
298  for (unsigned l = 0; l < ptr.size(); ++l)
299  std::memset(ptr(l), i, ratio * sizeof(mln_value_(I)));
300  }
301 
302  }
303  }
304 
305  for (unsigned l = 0; l < ptr.size(); ++l)
306  ptr(l) -= ratio;
307 
308  --site[1];
309  --p;
310  }
311 
312  }
313  } // end of 2nd pass
314 
315 
316 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
317  if (internal::threshold_image_output)
318  io::pbm::save(f.msk,
319  mln::debug::filename(internal::threshold_image_output));
320  if (internal::full_threshold_image_output)
321  io::pbm::save(f.full_msk,
322  mln::debug::filename(internal::full_threshold_image_output));
323 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
324 
325  return f.t_sub;
326  }
327 
328 
329 
330  template <typename I, typename J, typename K>
331  mln_ch_value(I, bool)
332  multi_scale_binarization(const I& in, const J& e2,
333  const mln::util::array<K>& t_ima,
334  unsigned s)
335  {
336  mln_ch_value(I,bool) out;
337  initialize(out, in);
338 
339  typedef const mln_value(K)* ptr_type;
340 
341  // Warning: if there are pixels with value different from 2, 3
342  // or 4 in e2, it will crash because of that array...
343  ptr_type ptr_t[5];
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);
347 
348 
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);
352 
353 
354  // Since we iterate from a smaller image in the largest ones and
355  // image at scale 1 does not always have a size which can be
356  // divided by (4*s), some sites in the border may not be processed
357  // and we must skip them.
358  int more_offset = - ((4 * s) - in.ncols() % (4 * s));
359 
360  if (more_offset == - (static_cast<int>(4*s)))
361  more_offset = 0; // No offset needed.
362 
363  const int
364  nrows4 = t_ima[4].nrows(),
365  ncols4 = t_ima[4].ncols(),
366 
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)),
373 
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)),
377 
378  delta3 = t_ima[3].delta_offset(dpoint2d(+1, -1)),
379 
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()));
384 
385  mln_value(J) threshold;
386  for (int row4 = 0; row4 < nrows4; ++row4)
387  {
388  for (int col4 = 0; col4 < ncols4; ++col4)
389  {
390  // top left 1
391  {
392  threshold = *ptr_t[*ptr_e2];
393  {
394  for (unsigned i = 1; i < s; ++i)
395  {
396  for (unsigned j = 1; j < s; ++j)
397  {
398  *ptr__out = *ptr__in <= threshold;
399  ++ptr__out; ++ptr__in;
400  }
401 
402  *ptr__out = *ptr__in <= threshold;
403  ptr__out += delta1; ptr__in += delta1;
404  }
405 
406  for (unsigned j = 1; j < s; ++j)
407  {
408  *ptr__out = *ptr__in <= threshold;
409  ++ptr__out; ++ptr__in;
410  }
411  *ptr__out = *ptr__in <= threshold;
412  ptr__out += delta1f; ptr__in += delta1f;
413  }
414 
415  ++ptr_t[2]; ++ptr_e2;
416  threshold = *ptr_t[*ptr_e2];
417  {
418  for (unsigned i = 1; i < s; ++i)
419  {
420  for (unsigned j = 1; j < s; ++j)
421  {
422  *ptr__out = *ptr__in <= threshold;
423  ++ptr__out; ++ptr__in;
424  }
425 
426  *ptr__out = *ptr__in <= threshold;
427  ptr__out += delta1; ptr__in += delta1;
428  }
429 
430  for (unsigned j = 1; j < s; ++j)
431  {
432  *ptr__out = *ptr__in <= threshold;
433  ++ptr__out; ++ptr__in;
434  }
435  *ptr__out = *ptr__in <= threshold;
436  ptr__out += delta1b; ptr__in += delta1b;
437  }
438 
439  ptr_t[2] += delta2; ptr_e2 += delta2;
440  threshold = *ptr_t[*ptr_e2];
441  {
442  for (unsigned i = 1; i < s; ++i)
443  {
444  for (unsigned j = 1; j < s; ++j)
445  {
446  *ptr__out = *ptr__in <= threshold;
447  ++ptr__out; ++ptr__in;
448  }
449 
450  *ptr__out = *ptr__in <= threshold;
451  ptr__out += delta1; ptr__in += delta1;
452  }
453 
454  for (unsigned j = 1; j < s; ++j)
455  {
456  *ptr__out = *ptr__in <= threshold;
457  ++ptr__out; ++ptr__in;
458  }
459  *ptr__out = *ptr__in <= threshold;
460  ptr__out += delta1f; ptr__in += delta1f;
461 
462  }
463 
464  ++ptr_t[2]; ++ptr_e2;
465  threshold = *ptr_t[*ptr_e2];
466  {
467  for (unsigned i = 1; i < s; ++i)
468  {
469  for (unsigned j = 1; j < s; ++j)
470  {
471  *ptr__out = *ptr__in <= threshold;
472  ++ptr__out; ++ptr__in;
473  }
474 
475  *ptr__out = *ptr__in <= threshold;
476  ptr__out += delta1; ptr__in += delta1;
477  }
478 
479  for (unsigned j = 1; j < s; ++j)
480  {
481  *ptr__out = *ptr__in <= threshold;
482  ++ptr__out; ++ptr__in;
483  }
484  *ptr__out = *ptr__in <= threshold;
485  ptr__out += delta1c; ptr__in += delta1c;
486  }
487 
488  ptr_t[2] -= delta2; ptr_e2 -= delta2;
489  }
490 
491  // top right 1
492  ptr_t[3] += 1;
493  {
494  threshold = *ptr_t[*ptr_e2];
495  {
496  for (unsigned i = 1; i < s; ++i)
497  {
498  for (unsigned j = 1; j < s; ++j)
499  {
500  *ptr__out = *ptr__in <= threshold;
501  ++ptr__out; ++ptr__in;
502  }
503 
504  *ptr__out = *ptr__in <= threshold;
505  ptr__out += delta1; ptr__in += delta1;
506  }
507 
508  for (unsigned j = 1; j < s; ++j)
509  {
510  *ptr__out = *ptr__in <= threshold;
511  ++ptr__out; ++ptr__in;
512  }
513  *ptr__out = *ptr__in <= threshold;
514  ptr__out += delta1f; ptr__in += delta1f;
515  }
516 
517  ++ptr_t[2]; ++ptr_e2;
518  threshold = *ptr_t[*ptr_e2];
519  {
520  for (unsigned i = 1; i < s; ++i)
521  {
522  for (unsigned j = 1; j < s; ++j)
523  {
524  *ptr__out = *ptr__in <= threshold;
525  ++ptr__out; ++ptr__in;
526  }
527 
528  *ptr__out = *ptr__in <= threshold;
529  ptr__out += delta1; ptr__in += delta1;
530  }
531 
532  for (unsigned j = 1; j < s; ++j)
533  {
534  *ptr__out = *ptr__in <= threshold;
535  ++ptr__out; ++ptr__in;
536  }
537  *ptr__out = *ptr__in <= threshold;
538  ptr__out += delta1b; ptr__in += delta1b;
539  }
540 
541  ptr_t[2] += delta2; ptr_e2 += delta2;
542  threshold = *ptr_t[*ptr_e2];
543  {
544  for (unsigned i = 1; i < s; ++i)
545  {
546  for (unsigned j = 1; j < s; ++j)
547  {
548  *ptr__out = *ptr__in <= threshold;
549  ++ptr__out; ++ptr__in;
550  }
551 
552  *ptr__out = *ptr__in <= threshold;
553  ptr__out += delta1; ptr__in += delta1;
554  }
555 
556  for (unsigned j = 1; j < s; ++j)
557  {
558  *ptr__out = *ptr__in <= threshold;
559  ++ptr__out; ++ptr__in;
560  }
561  *ptr__out = *ptr__in <= threshold;
562  ptr__out += delta1f; ptr__in += delta1f;
563  }
564 
565  ++ptr_t[2]; ++ptr_e2;
566  threshold = *ptr_t[*ptr_e2];
567  {
568  for (unsigned i = 1; i < s; ++i)
569  {
570  for (unsigned j = 1; j < s; ++j)
571  {
572  *ptr__out = *ptr__in <= threshold;
573  ++ptr__out; ++ptr__in;
574  }
575 
576  *ptr__out = *ptr__in <= threshold;
577  ptr__out += delta1; ptr__in += delta1;
578  }
579 
580  for (unsigned j = 1; j < s; ++j)
581  {
582  *ptr__out = *ptr__in <= threshold;
583  ++ptr__out; ++ptr__in;
584  }
585  *ptr__out = *ptr__in <= threshold;
586  ptr__out += delta1d; ptr__in += delta1d;
587  }
588 
589  ptr_t[2] += delta2b; ptr_e2 += delta2b;
590  }
591 
592  // bot left 1
593  ptr_t[3] += delta3;
594  {
595  threshold = *ptr_t[*ptr_e2];
596  {
597  for (unsigned i = 1; i < s; ++i)
598  {
599  for (unsigned j = 1; j < s; ++j)
600  {
601  *ptr__out = *ptr__in <= threshold;
602  ++ptr__out; ++ptr__in;
603  }
604 
605  *ptr__out = *ptr__in <= threshold;
606  ptr__out += delta1; ptr__in += delta1;
607  }
608 
609  for (unsigned j = 1; j < s; ++j)
610  {
611  *ptr__out = *ptr__in <= threshold;
612  ++ptr__out; ++ptr__in;
613  }
614  *ptr__out = *ptr__in <= threshold;
615  ptr__out += delta1f; ptr__in += delta1f;
616  }
617 
618  ++ptr_t[2]; ++ptr_e2;
619  threshold = *ptr_t[*ptr_e2];
620  {
621  for (unsigned i = 1; i < s; ++i)
622  {
623  for (unsigned j = 1; j < s; ++j)
624  {
625  *ptr__out = *ptr__in <= threshold;
626  ++ptr__out; ++ptr__in;
627  }
628 
629  *ptr__out = *ptr__in <= threshold;
630  ptr__out += delta1; ptr__in += delta1;
631  }
632 
633  for (unsigned j = 1; j < s; ++j)
634  {
635  *ptr__out = *ptr__in <= threshold;
636  ++ptr__out; ++ptr__in;
637  }
638  *ptr__out = *ptr__in <= threshold;
639  ptr__out += delta1b; ptr__in += delta1b;
640  }
641 
642  ptr_t[2] += delta2; ptr_e2 += delta2;
643  threshold = *ptr_t[*ptr_e2];
644  {
645  for (unsigned i = 1; i < s; ++i)
646  {
647  for (unsigned j = 1; j < s; ++j)
648  {
649  *ptr__out = *ptr__in <= threshold;
650  ++ptr__out; ++ptr__in;
651  }
652 
653  *ptr__out = *ptr__in <= threshold;
654  ptr__out += delta1; ptr__in += delta1;
655  }
656 
657  for (unsigned j = 1; j < s; ++j)
658  {
659  *ptr__out = *ptr__in <= threshold;
660  ++ptr__out; ++ptr__in;
661  }
662  *ptr__out = *ptr__in <= threshold;
663  ptr__out += delta1f; ptr__in += delta1f;
664  }
665 
666  ++ptr_t[2]; ++ptr_e2;
667  threshold = *ptr_t[*ptr_e2];
668  {
669  for (unsigned i = 1; i < s; ++i)
670  {
671  for (unsigned j = 1; j < s; ++j)
672  {
673  *ptr__out = *ptr__in <= threshold;
674  ++ptr__out; ++ptr__in;
675  }
676 
677  *ptr__out = *ptr__in <= threshold;
678  ptr__out += delta1; ptr__in += delta1;
679  }
680 
681  for (unsigned j = 1; j < s; ++j)
682  {
683  *ptr__out = *ptr__in <= threshold;
684  ++ptr__out; ++ptr__in;
685  }
686  *ptr__out = *ptr__in <= threshold;
687  ptr__out += delta1c; ptr__in += delta1c;
688  }
689 
690  ptr_t[2] -= delta2; ptr_e2 -= delta2;
691  }
692 
693  // bot right 1
694  ptr_t[3] += 1;
695  {
696  threshold = *ptr_t[*ptr_e2];
697  {
698  for (unsigned i = 1; i < s; ++i)
699  {
700  for (unsigned j = 1; j < s; ++j)
701  {
702  *ptr__out = *ptr__in <= threshold;
703  ++ptr__out; ++ptr__in;
704  }
705 
706  *ptr__out = *ptr__in <= threshold;
707  ptr__out += delta1; ptr__in += delta1;
708  }
709 
710  for (unsigned j = 1; j < s; ++j)
711  {
712  *ptr__out = *ptr__in <= threshold;
713  ++ptr__out; ++ptr__in;
714  }
715  *ptr__out = *ptr__in <= threshold;
716  ptr__out += delta1f; ptr__in += delta1f;
717  }
718 
719  ++ptr_t[2]; ++ptr_e2;
720  threshold = *ptr_t[*ptr_e2];
721  {
722  for (unsigned i = 1; i < s; ++i)
723  {
724  for (unsigned j = 1; j < s; ++j)
725  {
726  *ptr__out = *ptr__in <= threshold;
727  ++ptr__out; ++ptr__in;
728  }
729 
730  *ptr__out = *ptr__in <= threshold;
731  ptr__out += delta1; ptr__in += delta1;
732  }
733 
734  for (unsigned j = 1; j < s; ++j)
735  {
736  *ptr__out = *ptr__in <= threshold;
737  ++ptr__out; ++ptr__in;
738  }
739  *ptr__out = *ptr__in <= threshold;
740  ptr__out += delta1b; ptr__in += delta1b;
741  }
742 
743  ptr_t[2] += delta2; ptr_e2 += delta2;
744  threshold = *ptr_t[*ptr_e2];
745  {
746  for (unsigned i = 1; i < s; ++i)
747  {
748  for (unsigned j = 1; j < s; ++j)
749  {
750  *ptr__out = *ptr__in <= threshold;
751  ++ptr__out; ++ptr__in;
752  }
753 
754  *ptr__out = *ptr__in <= threshold;
755  ptr__out += delta1; ptr__in += delta1;
756  }
757 
758  for (unsigned j = 1; j < s; ++j)
759  {
760  *ptr__out = *ptr__in <= threshold;
761  ++ptr__out; ++ptr__in;
762  }
763  *ptr__out = *ptr__in <= threshold;
764  ptr__out += delta1f; ptr__in += delta1f;
765  }
766 
767  ++ptr_t[2]; ++ptr_e2;
768  threshold = *ptr_t[*ptr_e2];
769  {
770  for (unsigned i = 1; i < s; ++i)
771  {
772  for (unsigned j = 1; j < s; ++j)
773  {
774  *ptr__out = *ptr__in <= threshold;
775  ++ptr__out; ++ptr__in;
776  }
777 
778  *ptr__out = *ptr__in <= threshold;
779  ptr__out += delta1; ptr__in += delta1;
780  }
781 
782  for (unsigned j = 1; j < s; ++j)
783  {
784  *ptr__out = *ptr__in <= threshold;
785  ++ptr__out; ++ptr__in;
786  }
787  *ptr__out = *ptr__in <= threshold;
788  ptr__out += delta1e; ptr__in += delta1e;
789  }
790  }
791 
792  // bot right -> next top left
793  ptr_t[2] += delta2c; ptr_e2 += delta2c;
794  ptr_t[3] = ptr_t[3] - delta3;
795  ptr_t[4] += 1;
796  }
797 
798  // eof -> next bof
799  ptr__out += eor1; ptr__in += eor1;
800  ptr_t[2] += eor2; ptr_e2 += eor2;
801  ptr_t[3] += eor3;
802  ptr_t[4] += eor4;
803  }
804 
805  return out;
806  }
807 
808  } // end of namespace scribo::binarization::internal
809 
810 
811 
812  // Implementation
813 
814  namespace impl
815  {
816 
817  namespace generic
818  {
819 
820  template <typename I>
821  mln_ch_value(I,bool)
822  sauvola_ms(const Image<I>& input_1_, unsigned w_1,
823  unsigned s,
824  image2d<mln::util::couple<double,double> >& integral_sum_sum_2)
825  {
826  mln_trace("scribo::binarization::sauvola_ms");
827 
828  const I& input_1 = exact(input_1_);
829  typedef mln_value(I) V;
830 
831  mlc_is_a(mln_value(I), value::Scalar)::check();
832  mln_precondition(input_1.is_valid());
833 
834  dpoint2d none(0, 0);
835 
836  // Number of subscales.
837  unsigned nb_subscale = 3;
838 
839  // Window size.
840  unsigned w_work = w_1 * s; // Scale 2
841 
842 
843  // Subscale step.
844  unsigned q = 2;
845 
846 
847  /*==========================
848  == Step 1 - Subsampling ==
849  ========================*/
850 
851  mln::util::array<I> t_ima;
852 
853  // Make sure t_ima indexes start from 2.
854  {
855  I dummy(1,1);
856  for (unsigned i = 0; i < nb_subscale + 2; ++i)
857  t_ima.append(dummy);
858  }
859 
860  mln::util::array<I> sub_ima;
861 
862  // Make sure sub_ima indexes start from 2.
863  {
864  I dummy(1,1);
865  sub_ima.append(dummy);
866  sub_ima.append(dummy);
867  }
868 
870  sub_domains = scribo::util::compute_sub_domains(input_1,
871  nb_subscale, s);
872 
873  border::adjust(input_1, sub_domains(1).second());
874  border::mirror(input_1);
875 
876 
877  // Resize input and compute integral images.
878  typedef image2d<mln::util::couple<double,double> > integral_t;
879 // integral_t integral_sum_sum_2;
880 
882 
883  // Subsampling from scale 1 to 2.
884  {
886  fi(s, sub_domains[2].first(), sub_domains[2].second());
887 
888  integral_sum_sum_2 = scribo::util::init_integral_image(input_1, s, fi,
889  sub_domains[2].first(),
890  sub_domains[2].second());
891  sub_ima.append(fi.sub);
892  }
893 
894  scribo::debug::logger().stop_time_logging("1. subsampling and integral -");
896 
897  // Subsampling to scale 3 and 4.
898  //
899  // FIXME: we may use the integral image to compute
900  // subsampled images -> faster and more precise.
901  for (unsigned i = 3; i <= nb_subscale + 1; ++i)
902  sub_ima.append(mln::subsampling::antialiased(sub_ima[i - 1], q,
903  sub_domains[i].first(),
904  sub_domains[i].second()));
905 
906  scribo::debug::logger().stop_time_logging("2. More subsampling -");
908 
909  // Compute threshold images.
910  image2d<int_u8> e_2;
911  initialize(e_2, sub_ima[2]);
912  data::fill(e_2, 0u);
913 
914 
915 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
916  internal::debug_scale_proba = image3d<double>(3,
917  integral_sum_sum_2.nrows(),
918  integral_sum_sum_2.ncols(),
919  integral_sum_sum_2.border());
920 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
921 
922  /*=============================================
923  == Step 2 - Object selection at each scale ==
924  ===========================================*/
925 
926  float
927  min_coef = 0.8,
928  max_s2 = (w_1 * w_1) / (s * s) * 0.7,
929  q_2 = q * q;
930 
931 
932  // Highest scale -> no maximum component size.
933  {
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,
937  mln_max(unsigned),
938  s,
939  q, i, w_work,
940  integral_sum_sum_2);
941  }
942 
943  // Other scales -> maximum and minimum component size.
944  {
945  for (int i = sub_ima.size() - 2; i > 2; --i)
946  {
947  t_ima[i] = internal::compute_t_n_and_e_2(sub_ima[i], e_2,
948  max_s2 / (q_2) * min_coef,
949  max_s2 * q_2,
950  s,
951  q, i, w_work,
952  integral_sum_sum_2);
953  }
954  }
955 
956  // Lowest scale -> no minimum component size.
957  {
958  t_ima[2] = internal::compute_t_n_and_e_2(sub_ima[2], e_2,
959  // FIXME: was '0'. '2' is to avoid too much noise with k=0.2.
960  2,
961  max_s2,
962  s, 1, 2, w_work,
963  integral_sum_sum_2);
964  }
965 
966  scribo::debug::logger().stop_time_logging("3. Multi-scale processing -");
968 
969 
970 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
971  if (internal::scale_image_output)
972  io::pgm::save(e_2,
973  mln::debug::filename(internal::scale_image_output));
974 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
975 
976  /*==============================
977  == Step 3 - Results Merging ==
978  ============================*/
979 
980  // Propagate scale values.
982 
983  scribo::debug::logger().stop_time_logging("4. Influence Zone on Scale image -");
985 
986 
987 # ifdef SCRIBO_LOCAL_THRESHOLD_DEBUG
988  internal::debug_e_2 = e_2;
989  if (internal::scale_iz_image_output)
990  io::pgm::save(e_2,
991  mln::debug::filename(internal::scale_iz_image_output));
992 
993  // Computing scale ratios.
995  count = labeling::compute(accu::meta::math::count(), e_2, 4);
996  unsigned npixels = e_2.domain().nsites();
997  scribo::debug::logger() << "Scale ratios: 2 ("
998  << count[2] / (float)npixels * 100
999  << ") - 3 ("
1000  << count[3] / (float)npixels * 100
1001  << ") - 4 ("
1002  << count[4] / (float)npixels * 100 << ")"
1003  << std::endl;
1004 
1005  if (internal::scale_proba_output)
1006  io::dump::save(internal::debug_scale_proba,
1007  mln::debug::filename(internal::scale_proba_output));
1008 # endif // ! SCRIBO_LOCAL_THRESHOLD_DEBUG
1009 
1010  /*=================================
1011  == Step 4 - Final Binarization ==
1012  ===============================*/
1013 
1014  // Binarize
1016  output = internal::multi_scale_binarization(input_1, e_2, t_ima, s);
1017 
1018  scribo::debug::logger().stop_time_logging("5. Final binarization -");
1019 
1020  return output;
1021  }
1022 
1023  } // end of namespace scribo::binarization::impl::generic
1024 
1025 
1026  } // end of namespace scribo::binarization::impl
1027 
1028 
1029  // Facade
1030 
1031  template <typename I>
1032  mln_ch_value(I,bool)
1033  sauvola_ms(const Image<I>& input_1_, unsigned w_1, unsigned s,
1034  image2d<mln::util::couple<double,double> >& integral_sum_sum_2)
1035  {
1036  mln_trace("scribo::binarization::sauvola_ms");
1037 
1038  mln_precondition(exact(input_1_).is_valid());
1039  mln_precondition(s > 1);
1040 
1041  // Gray level images ONLY.
1042  mlc_is_not_a(mln_value(I), value::Vectorial)::check();
1043  mlc_is_not(mln_value(I), bool)::check();
1044 
1045  mln_ch_value(I,bool)
1046  output = impl::generic::sauvola_ms(exact(input_1_), w_1, s,
1047  integral_sum_sum_2);
1048 
1049  return output;
1050  }
1051 
1052  template <typename I>
1053  mln_ch_value(I,bool)
1054  sauvola_ms(const Image<I>& input_1_, unsigned w_1, unsigned s)
1055  {
1056  mln_trace("scribo::binarization::sauvola_ms");
1057 
1058  mln_precondition(exact(input_1_).is_valid());
1059  mln_precondition(s > 1);
1060 
1061  // Gray level images ONLY.
1062  mlc_is_not_a(mln_value(I), value::Vectorial)::check();
1063  mlc_is_not(mln_value(I), bool)::check();
1064 
1065  typedef image2d<mln::util::couple<double,double> > integral_t;
1066  integral_t integral_sum_sum_2;
1067 
1068  mln_ch_value(I,bool)
1069  output = sauvola_ms(input_1_, w_1, s, integral_sum_sum_2);
1070 
1071  return output;
1072  }
1073 
1074 
1075  template <typename I>
1076  mln_ch_value(I,bool)
1077  sauvola_ms(const Image<I>& input_1, unsigned w_1)
1078  {
1079  return sauvola_ms(input_1, w_1, 3);
1080  }
1081 
1082 
1083  template <typename I>
1084  mln_ch_value(I,bool)
1085  sauvola_ms(const Image<I>& input_1, unsigned w_1, unsigned s,
1086  double k2, double k3, double k4)
1087  {
1088  binarization::internal::k2 = k2;
1089  binarization::internal::k3 = k3;
1090  binarization::internal::k4 = k4;
1091 
1092  return sauvola_ms(input_1, w_1, s);
1093  }
1094 
1095 
1096  template <typename I>
1097  mln_ch_value(I,bool)
1098  sauvola_ms(const Image<I>& input_1, unsigned w_1, unsigned s,
1099  double all_k)
1100  {
1101  binarization::internal::k2 = all_k;
1102  binarization::internal::k3 = all_k;
1103  binarization::internal::k4 = all_k;
1104 
1105  return sauvola_ms(input_1, w_1, s);
1106  }
1107 
1108 
1109 # endif // ! MLN_INCLUDE_ONLY
1110 
1111 
1112  } // end of namespace scribo::binarization
1113 
1114 } // end of namespace scribo
1115 
1116 
1117 #endif // SCRIBO_BINARIZATION_SAUVOLA_MS_HH