$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
kim.hh
1 // Copyright (C) 2012, 2013 EPITA Research and Development Laboratory
2 // (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 #ifndef SCRIBO_BINARIZATION_KIM_HH
28 # define SCRIBO_BINARIZATION_KIM_HH
29 
33 
34 #include <cmath>
35 #include <map>
36 #include <scribo/binarization/sauvola.hh>
37 #include <scribo/util/integral_sum_sum2_functor.hh>
38 #include <scribo/text/extract_lines.hh>
39 
40 namespace scribo
41 {
42 
43  namespace binarization
44  {
45 
46  using namespace mln;
47 
59  template <typename I>
60  mln_ch_value(I, bool)
61  kim(const Image<I>& input, unsigned window_size, double k);
62 
68  template <typename I>
69  mln_ch_value(I, bool)
70  kim(const Image<I>& input, unsigned window_size);
71 
72 
73 # ifndef MLN_INCLUDE_ONLY
74 
75  namespace internal
76  {
77 
78  double
79  compute_thres(const mln::image2d<mln::util::couple<double,double> >& integral_sum_sum_2,
80  int row, int col, unsigned win_size,
82  {
83  point2d
84  tl(row - win_size - 1,
85  col - win_size - 1),
86  br(row + win_size,
87  col + win_size);
88 
89  box2d b(tl, br);
90  b.crop_wrt(integral_sum_sum_2.domain());
91 
92  point2d tr = b.pmax();
93  tr.row() = b.pmin().row();
94  point2d bl = b.pmin();
95  bl.row() = b.pmax().row();
96 
97  unsigned card_min = b.nsites() - b.height() - b.width() + 1;
98 
100  D = integral_sum_sum_2(b.pmax()),
101  B = integral_sum_sum_2(tr),
102  C = integral_sum_sum_2(bl),
103  A = integral_sum_sum_2(b.pmin());
104 
105  double sum = D.first() - B.first() - C.first() + A.first();
106  double sum_2 = D.second() - B.second() - C.second() + A.second();
107  double mean = sum / card_min;
108 
109  double num = (sum_2 - sum * sum / card_min);
110  double stddev;
111  if (num > 0)
112  stddev = std::sqrt(num / (card_min - 1));
113  else
114  stddev = 0;
115 
116  return formula(mean, stddev);
117  }
118 
119  } // end of namespace scribo::binarization::internal
120 
121 
122  template <typename I>
123  mln_ch_value(I, bool)
124  kim(const Image<I>& input_, unsigned window_size, double k)
125  {
126  mln_trace("scribo::binarization::kim");
127 
128  const I& input = exact(input_);
129 
130  mln_precondition(input.is_valid());
131 
132  // 1st simple binarization
134  output = scribo::binarization::sauvola(input, window_size, k);
135 
136  // Compute integral image
139  integral_sum_sum_2 = scribo::util::init_integral_image(input, 1, f_sum_sum2);
140 
141  // Find text lines
142  line_set<image2d<scribo::def::lbl_type> >
143  lines = scribo::text::extract_lines(output, c8());
144 
145  typedef scribo::def::lbl_type V;
146  typedef image2d<V> L;
147  mln::util::array<unsigned> thickness(lines.nelements() + 1, 0);
148  const component_set<L>& comp_set = lines.components();
149  const L& lbl = comp_set.labeled_image();
150 
151  // Compute run-lengths histogram in order to compute character
152  // thickness for each line.
153  for_all_lines(i, lines)
154  {
155  if (!lines(i).is_textline())
156  continue;
157 
158  std::map<unsigned, unsigned> histo;
159  int count = 0;
160  for (int l = lines(i).bbox().pmin().row(); l <= lines(i).bbox().pmax().row(); ++l)
161  {
162  const V* end_ptr = &lbl.at_(l, lines(i).bbox().pmax().col() + 1);
163  for (const V* run_ptr = &lbl.at_(l, lines(i).bbox().pmin().col()); run_ptr != end_ptr; ++run_ptr)
164  if (*run_ptr)
165  ++count;
166  else
167  if (count)
168  {
169  if (histo.find(count) != histo.end())
170  histo[count]++;
171  else
172  histo.insert(std::make_pair(count, 1));
173  count = 0;
174  }
175  }
176 
177  unsigned max = 0;
178  unsigned thick = 0;
179  for (std::map<unsigned, unsigned>::const_iterator it = histo.begin(); it != histo.end(); ++it)
180  if (it->second > max)
181  {
182  max = it->second;
183  thick = it->first;
184  }
185 
186  thickness(lines(i).id()) = thick;
187  }
188 
189  // Compute thresholds for each pixel of each line and binarize again!
190  for_all_lines(i, lines)
191  {
192  if (!lines(i).is_textline())
193  continue;
194 
195  double
196  win_min = thickness(lines(i).id()),
197  win_max = lines(i).bbox().height();;
198 
199  mln_assertion(win_min != 0);
200  mln_assertion(win_max != 0);
201 
203 
204  double teta = 0.3; // Good results from 0.1 to 0.3 according
205  // to the paper.
206  for (int row = lines(i).bbox().pmin().row();
207  row <= lines(i).bbox().pmax().row();
208  ++row)
209  {
210  bool* out_ptr = &output.at_(row, lines(i).bbox().pmin().col());
211  const mln_value(I)* in_ptr = &input.at_(row, lines(i).bbox().pmin().col());
212  for (int col = lines(i).bbox().pmin().col();
213  col <= lines(i).bbox().pmax().col();
214  ++col)
215  {
216  // Min case
217  double T_min = compute_thres(integral_sum_sum_2, row, col, win_min, formula);
218 
219  // Max case
220  double T_max = compute_thres(integral_sum_sum_2, row, col, win_max, formula);
221 
222  // Final threshold
223  double T = teta * T_max + (1 - teta) * T_min;
224 
225  mln_assertion(T_min <= 255);
226  mln_assertion(T_max <= 255);
227  mln_assertion(T <= 255);
228 
229  *out_ptr++ = *in_ptr++ <= T;
230  }
231  }
232  }
233 
234  return output;
235  }
236 
237 
238  template <typename I>
239  mln_ch_value(I, bool)
240  kim(const Image<I>& input, unsigned window_size)
241  {
242  return kim(input, window_size, SCRIBO_DEFAULT_SAUVOLA_K);
243  }
244 
245 # endif // ! MLN_INCLUDE_ONLY
246 
247  } // end of namespace scribo::binarization
248 
249 } // end of namespace scribo
250 
251 #endif // ! SCRIBO_BINARIZATION_KIM_HH