$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
integral_single_image.hh
1 // Copyright (C) 2009, 2010, 2011 EPITA Research and Development
2 // 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 #ifndef SCRIBO_SUBSAMPLING_INTEGRAL_HH
28 # define SCRIBO_SUBSAMPLING_INTEGRAL_HH
29 
33 
34 #include <mln/core/concept/image.hh>
35 #include <mln/core/concept/box.hh>
36 #include <mln/make/box2d.hh>
37 #include <mln/metal/equal.hh>
38 #include <mln/extension/fill.hh>
39 #include <mln/debug/println.hh>
40 #include <mln/debug/println_with_border.hh>
41 
42 
43 
44 namespace scribo
45 {
46 
47  namespace subsampling
48  {
49  using namespace mln;
50 
51 
64  template <typename I, typename J>
65  mln_concrete(I)
66  integral(const Image<I>& input_, unsigned scale,
67  Image<J>& integral_sum_sum_2,
68  const mln_domain(I)& output_domain, unsigned border_thickness);
69 
81  template <typename I, typename J>
82  inline
83  mln_concrete(I)
84  integral(const Image<I>& input_, unsigned scale,
85  Image<J>& integral_sum_sum_2);
86 
87 # ifndef MLN_INCLUDE_ONLY
88 
89 
90  // Implementation.
91 
92  namespace impl
93  {
94 
95  template <typename I, typename J>
96  inline
97  mln_concrete(I)
98  integral_3(const Image<I>& input_,
99  Image<J>& integral_sum_sum_2_,
100  const mln_domain(I)& output_domain,
101  unsigned border_thickness)
102  {
103  mln_trace("subsampling::impl::integral_3");
104 
105  const unsigned scale = 3;
106 
107  const I& input = exact(input_);
108  J& integral_sum_sum_2 = exact(integral_sum_sum_2_);
109 
110  mln_precondition(input.is_valid());
111  mln_precondition(input.domain().pmin() == literal::origin);
112  mln_precondition(scale > 1);
113 
114  typedef mln_value(I) V;
115  typedef mln_sum(V) S;
116  typedef mln_value(J) V2;
117  typedef mln_site(I) P;
118 
119  mln_concrete(I) sub(output_domain, border_thickness);
120  V* p_sub = sub.buffer();
121 
122  integral_sum_sum_2.init_(output_domain, border_thickness);
123  V2* p_integ = integral_sum_sum_2.buffer();
124 
125  const int up = sub.delta_offset(dpoint2d(-1, 0));
126 
127  const unsigned nrows = 3 * output_domain.nrows();
128  const unsigned ncols = 3 * output_domain.ncols();
129 
130  unsigned row = 0;
131 
132  unsigned b_offset = sub.delta_offset(dpoint2d(border_thickness,
133  border_thickness));
134  p_sub += b_offset;
135  p_integ += b_offset;
136  {
137  S h_sum = 0, h_sum_2 = 0;
138  const V* ptr1 = & input.at_(row, 0);
139  const V* ptr2 = & input.at_(row + 1, 0);
140  const V* ptr3 = & input.at_(row + 2, 0);
141  for (unsigned col = 0; col < ncols; col += scale)
142  {
143  V v11 = *ptr1, v12 = *(ptr1 + 1), v13 = *(ptr1 + 2),
144  v21 = *ptr2, v22 = *(ptr2 + 1), v23 = *(ptr2 + 2),
145  v31 = *ptr3, v32 = *(ptr3 + 1), v33 = *(ptr3 + 2);
146  ptr1 += 3;
147  ptr2 += 3;
148  ptr3 += 3;
149  S local_sum = v11 + v12 + v13
150  + v21 + v22 + v23
151  + v31 + v32 + v33,
152  local_sum_2 = v11*v11 + v12*v12 + v13*v13
153  + v21*v21 + v22*v22 + v23*v23
154  + v31*v31 + v32*v32 + v33*v33;
155 
156  mln::convert::from_to(local_sum / 9, *p_sub++);
157  h_sum += local_sum;
158  h_sum_2 += local_sum_2;
159 
160  // exception
161  p_integ->first() = h_sum;
162  p_integ->second() = h_sum_2;
163 
164  p_integ += 1;
165  }
166  }
167 
168  unsigned b_next = 2 * border_thickness;
169 
170  p_sub += b_next;
171  p_integ += b_next;
172 
173  for (row += scale; row < nrows; row += scale)
174  {
175  S h_sum = 0, h_sum_2 = 0;
176  const V* ptr1 = & input.at_(row, 0);
177  const V* ptr2 = & input.at_(row + 1, 0);
178  const V* ptr3 = & input.at_(row + 2, 0);
179  for (unsigned col = 0; col < ncols; col += scale)
180  {
181  V v11 = *ptr1, v12 = *(ptr1 + 1), v13 = *(ptr1 + 2),
182  v21 = *ptr2, v22 = *(ptr2 + 1), v23 = *(ptr2 + 2),
183  v31 = *ptr3, v32 = *(ptr3 + 1), v33 = *(ptr3 + 2);
184  ptr1 += 3;
185  ptr2 += 3;
186  ptr3 += 3;
187  S local_sum = v11 + v12 + v13
188  + v21 + v22 + v23
189  + v31 + v32 + v33,
190  local_sum_2 = v11*v11 + v12*v12 + v13*v13
191  + v21*v21 + v22*v22 + v23*v23
192  + v31*v31 + v32*v32 + v33*v33;
193 
194  mln::convert::from_to(local_sum / 9, *p_sub++);
195  h_sum += local_sum;
196  h_sum_2 += local_sum_2;
197 
198  p_integ->first() = h_sum + (p_integ + up)->first();
199  p_integ->second() = h_sum_2 + (p_integ + up)->second();
200 
201  p_integ += 1;
202  }
203 
204  p_sub += b_next;
205  p_integ += b_next;
206  }
207 
208  return sub;
209  }
210 
211 
212  template <typename I, typename J>
213  inline
214  mln_concrete(I)
215  integral_2(const Image<I>& input_,
216  Image<J>& integral_sum_sum_2_,
217  const mln_domain(I)& output_domain,
218  unsigned border_thickness)
219  {
220  mln_trace("subsampling::impl::integral_2");
221 
222  const unsigned scale = 2;
223 
224  const I& input = exact(input_);
225  J& integral_sum_sum_2 = exact(integral_sum_sum_2_);
226 
227  typedef mln_value(I) V;
228  typedef mln_sum(V) S;
229  typedef mln_site(I) P;
230  typedef mln_value(J) V2;
231 
232  mlc_bool(P::dim == 2)::check();
233  mln_precondition(input.is_valid());
234  mln_precondition(input.domain().pmin() == literal::origin);
235  mln_precondition(scale > 1);
236 
237  mln_concrete(I) sub(output_domain, border_thickness);
238  V* p_sub = sub.buffer();
239 
240  integral_sum_sum_2.init_(output_domain, border_thickness);
241  V2* p_integ = integral_sum_sum_2.buffer();
242 
243  const int up = sub.delta_offset(dpoint2d(-1, 0));
244 
245  const unsigned nrows = 2 * output_domain.nrows();
246  const unsigned ncols = 2 * output_domain.ncols();
247 
248  extension::fill(sub, 0);
249 
250  unsigned b_offset = sub.delta_offset(dpoint2d(border_thickness,
251  border_thickness));
252  p_sub += b_offset;
253  p_integ += b_offset;
254 
255  unsigned row = 0;
256  {
257  S h_sum = 0, h_sum_2 = 0;
258  const V* ptr1 = & input.at_(row, 0);
259  const V* ptr2 = & input.at_(row + 1, 0);
260  for (unsigned col = 0; col < ncols; col += scale)
261  {
262 /*
263  S sum;
264  sum = *ptr1 + *(ptr1 + 1);
265  sum += *ptr2 + *(ptr2 + 1);
266  ptr1 += 2;
267  ptr2 += 2;
268 
269  S val = sum / area;
270  *p_sub++ = val;
271 
272  h_sum += val;
273  h_sum_2 += val * val;
274 */
275 
276  // NEW:
277 
278  V v11 = *ptr1, v12 = *(ptr1 + 1),
279  v21 = *ptr2, v22 = *(ptr2 + 1);
280  ptr1 += 2;
281  ptr2 += 2;
282  S local_sum = v11 + v12 + v21 + v22,
283  local_sum_2 = v11*v11 + v12*v12 + v21*v21 + v22*v22;
284  mln::convert::from_to(local_sum / 4, *p_sub++);
285  h_sum += local_sum;
286  h_sum_2 += local_sum_2;
287 
288  // end of NEW.
289 
290 
291  // exception
292  p_integ->first() = h_sum;
293  p_integ->second() = h_sum_2;
294 
295  p_integ += 1;
296  }
297  }
298 
299  unsigned b_next = 2 * border_thickness;
300 
301  p_sub += b_next;
302  p_integ += b_next;
303 
304  for (row += scale; row < nrows; row += scale)
305  {
306  S h_sum = 0, h_sum_2 = 0;
307  const V* ptr1 = & input.at_(row, 0);
308  const V* ptr2 = & input.at_(row + 1, 0);
309  for (unsigned col = 0; col < ncols; col += scale)
310  {
311  // NEW:
312 
313  V v11 = *ptr1, v12 = *(ptr1 + 1),
314  v21 = *ptr2, v22 = *(ptr2 + 1);
315  ptr1 += 2;
316  ptr2 += 2;
317  S local_sum = v11 + v12 + v21 + v22,
318  local_sum_2 = v11*v11 + v12*v12 + v21*v21 + v22*v22;
319  mln::convert::from_to(local_sum / 4, *p_sub++);
320  h_sum += local_sum;
321  h_sum_2 += local_sum_2;
322 
323  // end of NEW.
324 
325 
326  /*
327 
328  // To get the strict equivalent to the integral image
329  // computed at working scale (scale (2)), we need the code
330  // below. In addition, the integral_browsing shall call
331  // the threshold formula with (..size..) and NOT with
332  // (..size * s_2..).
333 
334  S sum;
335  sum = *ptr1 + *(ptr1 + 1);
336  sum += *ptr2 + *(ptr2 + 1);
337  ptr1 += 2;
338  ptr2 += 2;
339 
340  S val = sum / area;
341  *p_sub++ = val;
342  h_sum += val;
343  h_sum_2 += val * val;
344 
345  */
346 
347 
348  // Never write something like this:
349  // *p_sub++ = sum / area;
350  // h_sum += sum;
351  // h_sum_2 += sum * sum;
352  // because the product 'sum * sum' is not
353  // equivalent to the sum of the value^2. E.g.
354  // we have (v1 + v2 + v3 + v4)^2 + etc. instead
355  // of having the correct sum_2 being v1^2 + v2^2 etc.
356 
357 
358  p_integ->first() = h_sum + (p_integ + up)->first();
359  p_integ->second() = h_sum_2 + (p_integ + up)->second();
360 
361  p_integ += 1;
362  }
363 
364  p_sub += b_next;
365  p_integ += b_next;
366  }
367 
368  return sub;
369  }
370 
371 
372  template <typename I, typename J>
373  inline
374  mln_concrete(I)
375  integral(const Image<I>& input, unsigned scale,
376  Image<J>& integral_sum_sum_2,
377  const mln_domain(I)& output_domain, unsigned border_thickness)
378  {
379  // mln_precondition(input.nrows() % scale == 0);
380  // mln_precondition(input.ncols() % scale == 0);
381  if (scale == 3)
382  return integral_3(input, integral_sum_sum_2,
383  output_domain, border_thickness);
384  else if (scale == 2)
385  return integral_2(input, integral_sum_sum_2,
386  output_domain, border_thickness);
387  else
388  std::cerr << "NYI!" << std::endl;
389 
390  typedef mln_concrete(I) output_t;
391  return output_t();
392  }
393 
394 
395  } // end of namespace mln::subsampling::impl
396 
397 
398 
399 
400  // Facades.
401 
402  template <typename I, typename J>
403  inline
404  mln_concrete(I)
405  integral(const Image<I>& input_, unsigned scale,
406  Image<J>& integral_sum_sum_2,
407  const mln_domain(I)& output_domain, unsigned border_thickness)
408  {
409  mln_trace("subsampling::integral");
410 
411  const I& input = exact(input_);
412 
413  mln_precondition(input.is_valid());
414  mln_precondition(input.domain().pmin() == literal::origin);
415  mln_precondition(scale > 1);
416 
417  mln_concrete(I)
418  output = impl::integral(input, scale, integral_sum_sum_2,
419  output_domain, border_thickness);
420 
421  return output;
422  }
423 
424  template <typename I, typename J>
425  inline
426  mln_concrete(I)
427  integral(const Image<I>& input_, unsigned scale,
428  Image<J>& integral_sum_sum_2)
429  {
430  mln_trace("subsampling::integral");
431 
432  const I& input = exact(input_);
433 
434  mln_precondition(input.is_valid());
435  mln_precondition(input.domain().pmin() == literal::origin);
436  mln_precondition(scale > 1);
437 
439  b = mln::make::box2d((input.nrows() + scale - 1) / scale,
440  (input.ncols() + scale - 1) / scale);
441  mln_concrete(I) output;
442  output = integral(input_, scale, integral_sum_sum_2,
443  b, mln::border::thickness);
444 
445  return output;
446  }
447 
448 # endif // ! MLN_INCLUDE_ONLY
449 
450  } // end of namespace scribo::subsampling
451 
452 } // end of namespace scribo
453 
454 
455 #endif // ! SCRIBO_SUBSAMPLING_INTEGRAL_HH