00001 /*!@file Envision/env_c_math_ops.c Fixed-point integer math versions of some of our floating-point image functions */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Envision/env_c_math_ops.c $ 00035 // $Id: env_c_math_ops.c 11331 2009-06-23 17:57:49Z itti $ 00036 // 00037 00038 #ifndef ENVISION_ENV_C_MATH_OPS_C_DEFINED 00039 #define ENVISION_ENV_C_MATH_OPS_C_DEFINED 00040 00041 #include "Envision/env_c_math_ops.h" 00042 00043 #include "Envision/env_log.h" 00044 #include "Envision/env_types.h" 00045 00046 // ###################################################################### 00047 void env_c_lowpass_5_x_dec_x_fewbits_optim(const intg32* src, 00048 const env_size_t w, 00049 const env_size_t h, 00050 intg32* dst, 00051 const env_size_t w2) 00052 { 00053 ENV_ASSERT(w2 == w/2); 00054 00055 if (w == 2 || w == 3) ////////////////////////////////////////////////// 00056 for (env_size_t j = 0; j < h; ++j) 00057 { 00058 // leftmost point [ (6^) 4 ] / 10 00059 *dst++ = (src[0] * 3 + src[1] * 2) / 5; 00060 src += w; // src back to same position as dst 00061 } 00062 else ////////////////////////////// general case for width() >= 4 00063 // *** unfolded version (all particular cases treated) for 00064 // max speed. 00065 // notations: in () is the position of dest ptr, and ^ is src ptr 00066 // ########## horizontal pass 00067 for (env_size_t j = 0; j < h; ++j) 00068 { 00069 const intg32* src2 = src; 00070 // leftmost point [ (8^) 4 ] / 12 00071 *dst++ = (src2[0] * 2 + src2[1]) / 3; 00072 00073 // skip second point 00074 00075 // rest of the line except last 2 points [ .^ 4 (8) 4 ] / 16 00076 for (env_size_t i = 0; i < w-3; i += 2) 00077 { 00078 *dst++ = (src2[1] + src2[3] + src2[2] * 2) >> 2; 00079 src2 += 2; 00080 } 00081 00082 src += w; 00083 } 00084 } 00085 00086 // ###################################################################### 00087 void env_c_lowpass_5_y_dec_y_fewbits_optim(const intg32* src, 00088 const env_size_t w, 00089 const env_size_t h, 00090 intg32* dst, 00091 const env_size_t h2) 00092 { 00093 ENV_ASSERT(h2 == h/2); 00094 00095 // ########## vertical pass (even though we scan horiz for speedup) 00096 const env_size_t w2 = w + w, w3 = w2 + w; // speedup 00097 00098 if (h == 2 || h == 3) ////////////////////////////////////////////////// 00099 { 00100 // topmost points ( [ (6^) 4 ] / 10 )^T 00101 for (env_size_t i = 0; i < w; ++i) 00102 { 00103 *dst++ = (src[0] * 3 + src[w] * 2) / 5; 00104 src++; 00105 } 00106 src -= w; // go back to top-left 00107 } 00108 else ///////////////////////////////// general case for height >= 4 00109 { 00110 // topmost points ( [ (8^) 4 ] / 12 )^T 00111 for (env_size_t k = 0; k < w; ++k) 00112 { 00113 *dst++ = (src[ 0] * 2 + src[ w]) / 3; 00114 src++; 00115 } 00116 src -= w; // go back to top-left 00117 00118 // second point skipped 00119 00120 // rest of the column except last 2 points ( [ .^ 4 (8) 4 ] / 16 )T 00121 for (env_size_t i = 0; i < h-3; i += 2) 00122 { 00123 for (env_size_t k = 0; k < w; ++k) 00124 { 00125 *dst++ = (src[ w] + src[w3] + src[w2] * 2) >> 2; 00126 src++; 00127 } 00128 src += w; 00129 } 00130 } 00131 } 00132 00133 // ###################################################################### 00134 void env_c_lowpass_9_x_fewbits_optim(const intg32* src, 00135 const env_size_t w, 00136 const env_size_t h, 00137 intg32* dst) 00138 { 00139 ENV_ASSERT(w >= 9); 00140 00141 // boundary conditions: truncated filter 00142 for (env_size_t j = 0; j < h; ++j) 00143 { 00144 // leftmost points 00145 *dst++ = // [ (72^) 56 28 8 ] 00146 (src[0] * 72 + 00147 src[1] * 56 + 00148 src[2] * 28 + 00149 src[3] * 8 00150 ) / 164; 00151 *dst++ = // [ 56^ (72) 56 28 8 ] 00152 ((src[0] + src[2]) * 56 + 00153 src[1] * 72 + 00154 src[3] * 28 + 00155 src[4] * 8 00156 ) / 220; 00157 *dst++ = // [ 28^ 56 (72) 56 28 8 ] 00158 ((src[0] + src[4]) * 28 + 00159 (src[1] + src[3]) * 56 + 00160 src[2] * 72 + 00161 src[5] * 8 00162 ) / 248; 00163 00164 // far from the borders 00165 for (env_size_t i = 0; i < w - 6; ++i) 00166 { 00167 *dst++ = // [ 8^ 28 56 (72) 56 28 8 ] 00168 ((src[0] + src[6]) * 8 + 00169 (src[1] + src[5]) * 28 + 00170 (src[2] + src[4]) * 56 + 00171 src[3] * 72 00172 ) >> 8; 00173 ++src; 00174 } 00175 00176 // rightmost points 00177 *dst++ = // [ 8^ 28 56 (72) 56 28 ] 00178 (src[0] * 8 + 00179 (src[1] + src[5]) * 28 + 00180 (src[2] + src[4]) * 56 + 00181 src[3] * 72 00182 ) / 248; 00183 ++src; 00184 *dst++ = // [ 8^ 28 56 (72) 56 ] 00185 (src[0] * 8 + 00186 src[1] * 28 + 00187 (src[2] + src[4]) * 56 + 00188 src[3] * 72 00189 ) / 220; 00190 ++src; 00191 *dst++ = // [ 8^ 28 56 (72) ] 00192 (src[0] * 8 + 00193 src[1] * 28 + 00194 src[2] * 56 + 00195 src[3] * 72 00196 ) / 164; 00197 src += 4; // src back to same as dst (start of next line) 00198 } 00199 } 00200 00201 // ###################################################################### 00202 void env_c_lowpass_9_y_fewbits_optim(const intg32* src, 00203 const env_size_t w, 00204 const env_size_t h, 00205 intg32* dst) 00206 { 00207 ENV_ASSERT(h >= 9); 00208 00209 // index computation speedup: 00210 const env_size_t w2 = w + w, w3 = w2 + w, w4 = w3 + w, w5 = w4 + w, w6 = w5 + w; 00211 00212 // *** vertical pass *** 00213 for (env_size_t i = 0; i < w; ++i) 00214 { 00215 *dst++ = 00216 (src[ 0] * 72 + 00217 src[ w] * 56 + 00218 src[w2] * 28 + 00219 src[w3] * 8 00220 ) / 164; 00221 ++src; 00222 } 00223 src -= w; // back to top-left 00224 for (env_size_t i = 0; i < w; ++i) 00225 { 00226 *dst++ = 00227 ((src[ 0] + src[w2]) * 56 + 00228 src[ w] * 72 + 00229 src[w3] * 28 + 00230 src[w4] * 8 00231 ) / 220; 00232 ++src; 00233 } 00234 src -= w; // back to top-left 00235 for (env_size_t i = 0; i < w; ++i) 00236 { 00237 *dst++ = 00238 ((src[ 0] + src[w4]) * 28 + 00239 (src[ w] + src[w3]) * 56 + 00240 src[w2] * 72 + 00241 src[w5] * 8 00242 ) / 248; 00243 ++src; 00244 } 00245 src -= w; // back to top-left 00246 00247 for (env_size_t j = 0; j < h - 6; j ++) 00248 for (env_size_t i = 0; i < w; ++i) 00249 { 00250 *dst++ = 00251 ((src[ 0] + src[w6]) * 8 + 00252 (src[ w] + src[w5]) * 28 + 00253 (src[w2] + src[w4]) * 56 + 00254 src[w3] * 72 00255 ) >> 8; 00256 ++src; 00257 } 00258 00259 for (env_size_t i = 0; i < w; ++i) 00260 { 00261 *dst++ = 00262 (src[ 0] * 8 + 00263 (src[ w] + src[w5]) * 28 + 00264 (src[w2] + src[w4]) * 56 + 00265 src[w3] * 72 00266 ) / 248; 00267 ++src; 00268 } 00269 for (env_size_t i = 0; i < w; ++i) 00270 { 00271 *dst++ = 00272 (src[ 0] * 8 + 00273 src[ w] * 28 + 00274 (src[w2] + src[w4]) * 56 + 00275 src[w3] * 72 00276 ) / 220; 00277 ++src; 00278 } 00279 for (env_size_t i = 0; i < w; ++i) 00280 { 00281 *dst++ = 00282 (src[ 0] * 8 + 00283 src[ w] * 28 + 00284 src[w2] * 56 + 00285 src[w3] * 72 00286 ) / 164; 00287 ++src; 00288 } 00289 } 00290 00291 // ###################################################################### 00292 void env_c_get_min_max(const intg32* src, const env_size_t sz, 00293 intg32* xmini, intg32* xmaxi) 00294 { 00295 ENV_ASSERT(sz > 0); 00296 *xmini = *xmaxi = src[0]; 00297 for (env_size_t i = 0; i < sz; ++i) 00298 { 00299 if (src[i] < *xmini) *xmini = src[i]; 00300 else if (src[i] > *xmaxi) *xmaxi = src[i]; 00301 } 00302 } 00303 00304 // ###################################################################### 00305 void env_c_inplace_rectify(intg32* dst, const env_size_t sz) 00306 { 00307 for (env_size_t i = 0; i < sz; ++i) 00308 if (dst[i] < 0) dst[i] = 0; 00309 } 00310 00311 // ###################################################################### 00312 void env_c_inplace_normalize(intg32* const dst, const env_size_t sz, 00313 const intg32 nmin, const intg32 nmax, 00314 intg32* const actualmin_p, 00315 intg32* const actualmax_p, 00316 const intg32 rangeThresh) 00317 { 00318 ENV_ASSERT(sz > 0); 00319 ENV_ASSERT(nmax >= nmin); 00320 00321 intg32 mi, ma; 00322 env_c_get_min_max(dst, sz, &mi, &ma); 00323 const intg32 old_scale = ma - mi; 00324 if (old_scale == 0 || old_scale < rangeThresh) // input image is uniform 00325 { for (env_size_t i = 0; i < sz; ++i) dst[i] = 0; return; } 00326 const intg32 new_scale = nmax - nmin; 00327 00328 if (new_scale == 0) // output range is uniform 00329 { for (env_size_t i = 0; i < sz; ++i) dst[i] = nmin; return; } 00330 00331 00332 intg32 actualmin, actualmax; 00333 00334 if (old_scale == new_scale) 00335 { 00336 const intg32 add = nmin - mi; 00337 if (add != 0) 00338 for (env_size_t i = 0; i < sz; ++i) 00339 dst[i] += add; 00340 00341 actualmin = nmin; 00342 actualmax = nmax; 00343 } 00344 #if defined(ENV_INTG64_TYPE) 00345 else 00346 { 00347 for (env_size_t i = 0; i < sz; ++i) 00348 dst[i] = nmin + ((((intg64)(dst[i] - mi)) * new_scale) 00349 / old_scale); 00350 00351 actualmin = nmin; 00352 actualmax = nmin + ((((intg64)(old_scale)) * new_scale) 00353 / old_scale); 00354 } 00355 #else 00356 else if (old_scale > new_scale) 00357 { 00358 // we want to do new = (old*new_scale)/oscale; 00359 // however, the old*new_scale part might overflow if 00360 // old or new_scale is too large, so let's reduce both 00361 // new_scale and oscale until new_scale*old won't 00362 // overflow 00363 00364 const intg32 nscale_max = INTG32_MAX / old_scale; 00365 00366 intg32 new_scale_reduced = new_scale; 00367 intg32 old_scale_reduced = old_scale; 00368 00369 while (new_scale_reduced > nscale_max) 00370 { 00371 new_scale_reduced /= 2; 00372 old_scale_reduced /= 2; 00373 } 00374 00375 ENV_ASSERT(new_scale_reduced >= 1); 00376 ENV_ASSERT(old_scale_reduced >= 1); 00377 00378 for (env_size_t i = 0; i < sz; ++i) 00379 dst[i] = nmin 00380 + (((dst[i] - mi) * new_scale_reduced) 00381 / (old_scale_reduced+1)); 00382 00383 actualmin = nmin; 00384 actualmax = nmin + ((old_scale * new_scale_reduced) 00385 / (old_scale_reduced+1)); 00386 } 00387 else // (old_scale < new_scale) 00388 { 00389 const intg32 mul = new_scale / old_scale; 00390 for (env_size_t i = 0; i < sz; ++i) 00391 dst[i] = nmin + ((dst[i] - mi) * mul); 00392 00393 actualmin = nmin; 00394 actualmax = nmin + (old_scale * mul); 00395 } 00396 #endif // !defined(ENV_INTG64_TYPE) 00397 00398 // Don't assign to the pointers until the very end, in case 00399 // the user passes pointers to nmin,nmax as the 00400 // actualmin/actualmax pointers 00401 if (actualmin_p) 00402 *actualmin_p = actualmin; 00403 if (actualmax_p) 00404 *actualmax_p = actualmax; 00405 00406 } 00407 00408 // ###################################################################### 00409 void env_c_luminance_from_byte(const struct env_rgb_pixel* const src, 00410 const env_size_t sz, 00411 const env_size_t nbits, 00412 intg32* const dst) 00413 { 00414 if (nbits > 8) 00415 for (env_size_t i = 0; i < sz; ++i) 00416 dst[i] = ((src[i].p[0] + src[i].p[1] + src[i].p[2]) / 3) << (nbits - 8); 00417 else if (nbits < 8) 00418 for (env_size_t i = 0; i < sz; ++i) 00419 dst[i] = ((src[i].p[0] + src[i].p[1] + src[i].p[2]) / 3) >> (8 - nbits); 00420 else // nbits == 8 00421 for (env_size_t i = 0; i < sz; ++i) 00422 dst[i] = (src[i].p[0] + src[i].p[1] + src[i].p[2]) / 3; 00423 } 00424 00425 // ###################################################################### 00426 void env_c_image_div_scalar(const intg32* const a, 00427 const env_size_t sz, 00428 intg32 val, 00429 intg32* const dst) 00430 { 00431 for (env_size_t i = 0; i < sz; ++i) 00432 dst[i] = a[i] / val; 00433 } 00434 00435 // ###################################################################### 00436 void env_c_image_div_scalar_accum(const intg32* const a, 00437 const env_size_t sz, 00438 intg32 val, 00439 intg32* const dst) 00440 { 00441 for (env_size_t i = 0; i < sz; ++i) 00442 dst[i] += a[i] / val; 00443 } 00444 00445 // ###################################################################### 00446 void env_c_image_minus_image(const intg32* const a, 00447 const intg32* const b, 00448 const env_size_t sz, 00449 intg32* const dst) 00450 { 00451 for (env_size_t i = 0; i < sz; ++i) 00452 dst[i] = a[i] - b[i]; 00453 } 00454 00455 // ###################################################################### 00456 /* So things look consistent in everyone's emacs... */ 00457 /* Local Variables: */ 00458 /* indent-tabs-mode: nil */ 00459 /* c-file-style: "linux" */ 00460 /* End: */ 00461 00462 #endif // ENVISION_ENV_C_MATH_OPS_C_DEFINED