JeVoisBase  1.21
JeVois Smart Embedded Machine Vision Toolkit Base Modules
Share this page:
Loading...
Searching...
No Matches
env_c_math_ops.c
Go to the documentation of this file.
1/*!@file 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// ######################################################################
125void 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// ######################################################################
190void 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// ######################################################################
277void 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// ######################################################################
295void 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// ######################################################################
375void 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// ######################################################################
390void 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// ######################################################################
396void 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// ######################################################################
402void 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}
int h
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_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_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_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_inplace_rectify(intg32 *dst, const env_size_t sz)
Saturate values < 0.
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_accum(const intg32 *const a, const env_size_t sz, intg32 val, intg32 *const dst)
result += a / val
void env_c_image_div_scalar(const intg32 *const a, const env_size_t sz, intg32 val, intg32 *const dst)
result = a / val
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_minus_image(const intg32 *const a, const intg32 *const b, const env_size_t sz, intg32 *const dst)
result = a - b
#define ENV_ASSERT(expr)
Definition env_log.h:63
ENV_INTG32_TYPE intg32
32-bit signed integer
Definition env_types.h:52
#define INTG32_MAX
Definition env_types.h:54
unsigned long env_size_t
Definition env_types.h:71
RGB pixel class.
Definition env_types.h:75