env_c_math_ops.c

Go to the documentation of this file.
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
Generated on Sun May 8 08:40:38 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3