JeVoisBase  1.3
JeVois Smart Embedded Machine Vision Toolkit Base Modules
Share this page:
env_c_math_ops.c
Go to the documentation of this file.
1 /*!@file Envision/env_c_math_ops.c Fixed-point integer math versions of some of our floating-point image functions */
2 
3 // //////////////////////////////////////////////////////////////////// //
4 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 //
5 // by the University of Southern California (USC) and the iLab at USC. //
6 // See http://iLab.usc.edu for information about this project. //
7 // //////////////////////////////////////////////////////////////////// //
8 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
9 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
10 // in Visual Environments, and Applications'' by Christof Koch and //
11 // Laurent Itti, California Institute of Technology, 2001 (patent //
12 // pending; application number 09/912,225 filed July 23, 2001; see //
13 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). //
14 // //////////////////////////////////////////////////////////////////// //
15 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. //
16 // //
17 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can //
18 // redistribute it and/or modify it under the terms of the GNU General //
19 // Public License as published by the Free Software Foundation; either //
20 // version 2 of the License, or (at your option) any later version. //
21 // //
22 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope //
23 // that it will be useful, but WITHOUT ANY WARRANTY; without even the //
24 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
25 // PURPOSE. See the GNU General Public License for more details. //
26 // //
27 // You should have received a copy of the GNU General Public License //
28 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write //
29 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, //
30 // Boston, MA 02111-1307 USA. //
31 // //////////////////////////////////////////////////////////////////// //
32 //
33 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu>
34 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Envision/env_c_math_ops.c $
35 // $Id: env_c_math_ops.c 11331 2009-06-23 17:57:49Z itti $
36 //
37 
39 
42 
43 // ######################################################################
45  intg32* dst, const env_size_t w2)
46 {
47  ENV_ASSERT(w2 == w/2);
48 
49  if (w == 2 || w == 3) //////////////////////////////////////////////////
50  for (env_size_t j = 0; j < h; ++j)
51  {
52  // leftmost point [ (6^) 4 ] / 10
53  *dst++ = (src[0] * 3 + src[1] * 2) / 5;
54  src += w; // src back to same position as dst
55  }
56  else ////////////////////////////// general case for width() >= 4
57  // *** unfolded version (all particular cases treated) for
58  // max speed.
59  // notations: in () is the position of dest ptr, and ^ is src ptr
60  // ########## horizontal pass
61  for (env_size_t j = 0; j < h; ++j)
62  {
63  const intg32* src2 = src;
64  // leftmost point [ (8^) 4 ] / 12
65  *dst++ = (src2[0] * 2 + src2[1]) / 3;
66 
67  // skip second point
68 
69  // rest of the line except last 2 points [ .^ 4 (8) 4 ] / 16
70  for (env_size_t i = 0; i < w-3; i += 2)
71  {
72  *dst++ = (src2[1] + src2[3] + src2[2] * 2) >> 2;
73  src2 += 2;
74  }
75 
76  src += w;
77  }
78 }
79 
80 // ######################################################################
82  intg32* dst, const env_size_t h2)
83 {
84  ENV_ASSERT(h2 == h/2);
85 
86  // ########## vertical pass (even though we scan horiz for speedup)
87  const env_size_t w2 = w + w, w3 = w2 + w; // speedup
88 
89  if (h == 2 || h == 3) //////////////////////////////////////////////////
90  {
91  // topmost points ( [ (6^) 4 ] / 10 )^T
92  for (env_size_t i = 0; i < w; ++i)
93  {
94  *dst++ = (src[0] * 3 + src[w] * 2) / 5;
95  src++;
96  }
97  src -= w; // go back to top-left
98  }
99  else ///////////////////////////////// general case for height >= 4
100  {
101  // topmost points ( [ (8^) 4 ] / 12 )^T
102  for (env_size_t k = 0; k < w; ++k)
103  {
104  *dst++ = (src[ 0] * 2 + src[ w]) / 3;
105  src++;
106  }
107  src -= w; // go back to top-left
108 
109  // second point skipped
110 
111  // rest of the column except last 2 points ( [ .^ 4 (8) 4 ] / 16 )T
112  for (env_size_t i = 0; i < h-3; i += 2)
113  {
114  for (env_size_t k = 0; k < w; ++k)
115  {
116  *dst++ = (src[ w] + src[w3] + src[w2] * 2) >> 2;
117  src++;
118  }
119  src += w;
120  }
121  }
122 }
123 
124 // ######################################################################
125 void env_c_lowpass_9_x_fewbits_optim(const intg32* src, const env_size_t w, const env_size_t h, intg32* dst)
126 {
127  ENV_ASSERT(w >= 9);
128 
129  // boundary conditions: truncated filter
130  for (env_size_t j = 0; j < h; ++j)
131  {
132  // leftmost points
133  *dst++ = // [ (72^) 56 28 8 ]
134  (src[0] * 72 +
135  src[1] * 56 +
136  src[2] * 28 +
137  src[3] * 8
138  ) / 164;
139  *dst++ = // [ 56^ (72) 56 28 8 ]
140  ((src[0] + src[2]) * 56 +
141  src[1] * 72 +
142  src[3] * 28 +
143  src[4] * 8
144  ) / 220;
145  *dst++ = // [ 28^ 56 (72) 56 28 8 ]
146  ((src[0] + src[4]) * 28 +
147  (src[1] + src[3]) * 56 +
148  src[2] * 72 +
149  src[5] * 8
150  ) / 248;
151 
152  // far from the borders
153  for (env_size_t i = 0; i < w - 6; ++i)
154  {
155  *dst++ = // [ 8^ 28 56 (72) 56 28 8 ]
156  ((src[0] + src[6]) * 8 +
157  (src[1] + src[5]) * 28 +
158  (src[2] + src[4]) * 56 +
159  src[3] * 72
160  ) >> 8;
161  ++src;
162  }
163 
164  // rightmost points
165  *dst++ = // [ 8^ 28 56 (72) 56 28 ]
166  (src[0] * 8 +
167  (src[1] + src[5]) * 28 +
168  (src[2] + src[4]) * 56 +
169  src[3] * 72
170  ) / 248;
171  ++src;
172  *dst++ = // [ 8^ 28 56 (72) 56 ]
173  (src[0] * 8 +
174  src[1] * 28 +
175  (src[2] + src[4]) * 56 +
176  src[3] * 72
177  ) / 220;
178  ++src;
179  *dst++ = // [ 8^ 28 56 (72) ]
180  (src[0] * 8 +
181  src[1] * 28 +
182  src[2] * 56 +
183  src[3] * 72
184  ) / 164;
185  src += 4; // src back to same as dst (start of next line)
186  }
187 }
188 
189 // ######################################################################
190 void env_c_lowpass_9_y_fewbits_optim(const intg32* src, const env_size_t w, const env_size_t h, intg32* dst)
191 {
192  ENV_ASSERT(h >= 9);
193 
194  // index computation speedup:
195  const env_size_t w2 = w + w, w3 = w2 + w, w4 = w3 + w, w5 = w4 + w, w6 = w5 + w;
196 
197  // *** vertical pass ***
198  for (env_size_t i = 0; i < w; ++i)
199  {
200  *dst++ =
201  (src[ 0] * 72 +
202  src[ w] * 56 +
203  src[w2] * 28 +
204  src[w3] * 8
205  ) / 164;
206  ++src;
207  }
208  src -= w; // back to top-left
209  for (env_size_t i = 0; i < w; ++i)
210  {
211  *dst++ =
212  ((src[ 0] + src[w2]) * 56 +
213  src[ w] * 72 +
214  src[w3] * 28 +
215  src[w4] * 8
216  ) / 220;
217  ++src;
218  }
219  src -= w; // back to top-left
220  for (env_size_t i = 0; i < w; ++i)
221  {
222  *dst++ =
223  ((src[ 0] + src[w4]) * 28 +
224  (src[ w] + src[w3]) * 56 +
225  src[w2] * 72 +
226  src[w5] * 8
227  ) / 248;
228  ++src;
229  }
230  src -= w; // back to top-left
231 
232  for (env_size_t j = 0; j < h - 6; j ++)
233  for (env_size_t i = 0; i < w; ++i)
234  {
235  *dst++ =
236  ((src[ 0] + src[w6]) * 8 +
237  (src[ w] + src[w5]) * 28 +
238  (src[w2] + src[w4]) * 56 +
239  src[w3] * 72
240  ) >> 8;
241  ++src;
242  }
243 
244  for (env_size_t i = 0; i < w; ++i)
245  {
246  *dst++ =
247  (src[ 0] * 8 +
248  (src[ w] + src[w5]) * 28 +
249  (src[w2] + src[w4]) * 56 +
250  src[w3] * 72
251  ) / 248;
252  ++src;
253  }
254  for (env_size_t i = 0; i < w; ++i)
255  {
256  *dst++ =
257  (src[ 0] * 8 +
258  src[ w] * 28 +
259  (src[w2] + src[w4]) * 56 +
260  src[w3] * 72
261  ) / 220;
262  ++src;
263  }
264  for (env_size_t i = 0; i < w; ++i)
265  {
266  *dst++ =
267  (src[ 0] * 8 +
268  src[ w] * 28 +
269  src[w2] * 56 +
270  src[w3] * 72
271  ) / 164;
272  ++src;
273  }
274 }
275 
276 // ######################################################################
277 void env_c_get_min_max(const intg32* src, const env_size_t sz, intg32* xmini, intg32* xmaxi)
278 {
279  ENV_ASSERT(sz > 0);
280  *xmini = *xmaxi = src[0];
281  for (env_size_t i = 0; i < sz; ++i)
282  {
283  if (src[i] < *xmini) *xmini = src[i];
284  else if (src[i] > *xmaxi) *xmaxi = src[i];
285  }
286 }
287 
288 // ######################################################################
290 {
291  for (env_size_t i = 0; i < sz; ++i) if (dst[i] < 0) dst[i] = 0;
292 }
293 
294 // ######################################################################
295 void env_c_inplace_normalize(intg32* const dst, const env_size_t sz, const intg32 nmin, const intg32 nmax,
296  intg32* const actualmin_p, intg32* const actualmax_p, const intg32 rangeThresh)
297 {
298  ENV_ASSERT(sz > 0);
299  ENV_ASSERT(nmax >= nmin);
300 
301  intg32 mi, ma;
302  env_c_get_min_max(dst, sz, &mi, &ma);
303  const intg32 old_scale = ma - mi;
304  if (old_scale == 0 || old_scale < rangeThresh) // input image is uniform
305  { for (env_size_t i = 0; i < sz; ++i) dst[i] = 0; return; }
306  const intg32 new_scale = nmax - nmin;
307 
308  if (new_scale == 0) // output range is uniform
309  { for (env_size_t i = 0; i < sz; ++i) dst[i] = nmin; return; }
310 
311 
312  intg32 actualmin, actualmax;
313 
314  if (old_scale == new_scale)
315  {
316  const intg32 add = nmin - mi;
317  if (add != 0) for (env_size_t i = 0; i < sz; ++i) dst[i] += add;
318 
319  actualmin = nmin;
320  actualmax = nmax;
321  }
322 #if defined(ENV_INTG64_TYPE)
323  else
324  {
325  for (env_size_t i = 0; i < sz; ++i)
326  dst[i] = nmin + ((((intg64)(dst[i] - mi)) * new_scale) / old_scale);
327 
328  actualmin = nmin;
329  actualmax = nmin + ((((intg64)(old_scale)) * new_scale) / old_scale);
330  }
331 #else
332  else if (old_scale > new_scale)
333  {
334  // we want to do new = (old*new_scale)/oscale; however, the old*new_scale part might overflow if old or new_scale is
335  // too large, so let's reduce both new_scale and oscale until new_scale*old won't overflow
336 
337  const intg32 nscale_max = INTG32_MAX / old_scale;
338 
339  intg32 new_scale_reduced = new_scale;
340  intg32 old_scale_reduced = old_scale;
341 
342  while (new_scale_reduced > nscale_max)
343  {
344  new_scale_reduced /= 2;
345  old_scale_reduced /= 2;
346  }
347 
348  ENV_ASSERT(new_scale_reduced >= 1);
349  ENV_ASSERT(old_scale_reduced >= 1);
350 
351  for (env_size_t i = 0; i < sz; ++i)
352  dst[i] = nmin + (((dst[i] - mi) * new_scale_reduced) / (old_scale_reduced+1));
353 
354  actualmin = nmin;
355  actualmax = nmin + ((old_scale * new_scale_reduced) / (old_scale_reduced+1));
356  }
357  else // (old_scale < new_scale)
358  {
359  const intg32 mul = new_scale / old_scale;
360  for (env_size_t i = 0; i < sz; ++i) dst[i] = nmin + ((dst[i] - mi) * mul);
361 
362  actualmin = nmin;
363  actualmax = nmin + (old_scale * mul);
364  }
365 #endif // !defined(ENV_INTG64_TYPE)
366 
367  // Don't assign to the pointers until the very end, in case
368  // the user passes pointers to nmin,nmax as the
369  // actualmin/actualmax pointers
370  if (actualmin_p) *actualmin_p = actualmin;
371  if (actualmax_p) *actualmax_p = actualmax;
372 }
373 
374 // ######################################################################
375 void env_c_luminance_from_byte(const struct env_rgb_pixel* const src, const env_size_t sz,
376  const env_size_t nbits, intg32* const dst)
377 {
378  if (nbits > 8)
379  for (env_size_t i = 0; i < sz; ++i)
380  dst[i] = ((src[i].p[0] + src[i].p[1] + src[i].p[2]) / 3) << (nbits - 8);
381  else if (nbits < 8)
382  for (env_size_t i = 0; i < sz; ++i)
383  dst[i] = ((src[i].p[0] + src[i].p[1] + src[i].p[2]) / 3) >> (8 - nbits);
384  else // nbits == 8
385  for (env_size_t i = 0; i < sz; ++i)
386  dst[i] = (src[i].p[0] + src[i].p[1] + src[i].p[2]) / 3;
387 }
388 
389 // ######################################################################
390 void env_c_image_div_scalar(const intg32* const a, const env_size_t sz, intg32 val, intg32* const dst)
391 {
392  for (env_size_t i = 0; i < sz; ++i) dst[i] = a[i] / val;
393 }
394 
395 // ######################################################################
396 void env_c_image_div_scalar_accum(const intg32* const a, const env_size_t sz, intg32 val, intg32* const dst)
397 {
398  for (env_size_t i = 0; i < sz; ++i) dst[i] += a[i] / val;
399 }
400 
401 // ######################################################################
402 void env_c_image_minus_image(const intg32* const a, const intg32* const b, const env_size_t sz, intg32* const dst)
403 {
404  for (env_size_t i = 0; i < sz; ++i) dst[i] = a[i] - b[i];
405 }
#define INTG32_MAX
Definition: env_types.h:54
void env_c_luminance_from_byte(const struct env_rgb_pixel *const src, const env_size_t sz, const env_size_t nbits, intg32 *const dst)
get the luminance with nbits of precision of the input image
void env_c_lowpass_9_y_fewbits_optim(const intg32 *src, const env_size_t w, const env_size_t h, intg32 *dst)
Like env_c_lowpass_9_y_fewbits() but uses optimized filter coefficients.
void env_c_get_min_max(const intg32 *src, const env_size_t sz, intg32 *xmini, intg32 *xmaxi)
Get min and max values.
void env_c_inplace_normalize(intg32 *const dst, const env_size_t sz, const intg32 nmin, const intg32 nmax, intg32 *const actualmin_p, intg32 *const actualmax_p, const intg32 rangeThresh)
void env_c_image_div_scalar_accum(const intg32 *const a, const env_size_t sz, intg32 val, intg32 *const dst)
result += a / val
void env_c_inplace_rectify(intg32 *dst, const env_size_t sz)
Saturate values < 0.
void env_c_lowpass_5_x_dec_x_fewbits_optim(const intg32 *src, const env_size_t w, const env_size_t h, intg32 *dst, const env_size_t w2)
void env_c_image_minus_image(const intg32 *const a, const intg32 *const b, const env_size_t sz, intg32 *const dst)
result = a - b
unsigned long env_size_t
Definition: env_types.h:71
RGB pixel class.
Definition: env_types.h:74
ENV_INTG32_TYPE intg32
32-bit signed integer
Definition: env_types.h:52
void env_c_lowpass_9_x_fewbits_optim(const intg32 *src, const env_size_t w, const env_size_t h, intg32 *dst)
Like env_c_lowpass_9_x_fewbits() but uses optimized filter coefficients.
void env_c_lowpass_5_y_dec_y_fewbits_optim(const intg32 *src, const env_size_t w, const env_size_t h, intg32 *dst, const env_size_t h2)
void env_c_image_div_scalar(const intg32 *const a, const env_size_t sz, intg32 val, intg32 *const dst)
result = a / val
#define ENV_ASSERT(expr)
Definition: env_log.h:63