Transforms.C

Go to the documentation of this file.
00001 /*!@file Image/Transforms.C Transformations on Image
00002  */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/Transforms.C $
00036 // $Id: Transforms.C 14592 2011-03-11 23:19:12Z jshen $
00037 //
00038 
00039 #ifndef IMAGE_TRANSFORMS_C_DEFINED
00040 #define IMAGE_TRANSFORMS_C_DEFINED
00041 
00042 #include "Image/Transforms.H"
00043 
00044 #include "Image/CutPaste.H"
00045 #include "Image/Image.H"
00046 #include "Image/MathOps.H"
00047 #include "Image/Pixels.H"
00048 #include "Image/Rectangle.H"
00049 #include "Util/Assert.H"
00050 #include "Util/log.H"
00051 
00052 #include <algorithm>
00053 #include <cmath>
00054 #include <vector>
00055 #include <cstdio>  // for printf()
00056 
00057 #define SEGOBJ_START 0.9
00058 #define SEGOBJ_STEP  0.05
00059 #define SEGOBJ_MINA  0.005
00060 #define SEGOBJ_EXPL  1.05
00061 
00062 // ######################################################################
00063 template <class T>
00064 Image<byte> segmentObject(const Image<T>& src,
00065                           const Point2D<int>& seed)
00066 {
00067   ASSERT(src.initialized());
00068   Image<T> tmp;
00069   bool explode = false; int prev = 0; double thresh = 1.0;
00070   double step = double(src.getVal(seed.i, seed.j)) * SEGOBJ_STEP;
00071   int minadiff = int(float(src.getSize()) * SEGOBJ_MINA);
00072   double efac = SEGOBJ_EXPL;
00073   int iter;
00074 
00075   while(explode == false && minadiff > 0 && efac > 1)
00076     {
00077       thresh = double(src.getVal(seed.i, seed.j)) * SEGOBJ_START;
00078       iter = 0;
00079       while(explode == false && thresh > 0)
00080         {
00081           int area = flood(src, tmp, seed, (T)thresh, (T)255.0);
00082           LDEBUG("prev=%d area=%d minadiff=%d thresh=%f efac=%f\n",
00083                  prev, area, minadiff, thresh, efac);
00084           if (iter > 2 && area > prev + minadiff &&
00085               area > int(double(prev)*efac))
00086             explode = true;
00087           else
00088             { prev = area; thresh -= step; }
00089           iter ++;
00090         }
00091       minadiff -= minadiff / 4; efac *= 0.95;
00092     }
00093   // write out segmented object: 255 in object, zero otherwise
00094   thresh += step;  // back 1 step before explosion
00095   flood(src, tmp, seed, (T)thresh, (T)255.0);
00096   return Image<byte>(tmp);
00097 }
00098 
00099 // ######################################################################
00100 template <class T>
00101 int segmentLandmark(const Image<T>& src,
00102                     const Point2D<int>& seed, Image<byte>& target,
00103                     double& activity, double& standout,
00104                     float& area_percentage)
00105 {
00106   ASSERT(src.initialized());
00107   Image<T> tmp;
00108 
00109   bool explode = false; int prev = 0;
00110   double thresh = 1.0;
00111   double step = double(src.getVal(seed.i, seed.j)) * SEGOBJ_STEP;
00112   int minadiff = int(float(src.getSize()) * SEGOBJ_MINA);
00113   double efac = SEGOBJ_EXPL;
00114   double valdiff = 0.0, maxvaldiff = 0.0, sumvaldiff = 0.0,
00115     prev_thresh = 0.0, maxthresh = 0.0;
00116   int iter = 0; int flood_count = 0;
00117   bool gradual_descent = false;
00118 
00119   thresh = double(src.getVal(seed.i, seed.j)) * SEGOBJ_START;
00120   prev_thresh = thresh; activity = 0.0;
00121   while(minadiff > 0 && thresh > 0)
00122     {
00123       explode = false;
00124       while(explode == false && thresh > 0)
00125         {
00126           int area = flood(src, tmp, seed, (T)thresh, (T)255.0);
00127 
00128           // NOTE: g++4.3 warns about precedence of && over ||; should
00129           // this expression be (A&&B)||C or A&&(B||C)?
00130           if ((area > prev + minadiff &&
00131                area > int(double(prev)*efac))
00132               || area > 2 * prev)
00133             {
00134               explode = true;
00135               gradual_descent = false;
00136               flood_count++;
00137               valdiff = prev_thresh - thresh;
00138               sumvaldiff += valdiff;
00139 
00140               if(maxvaldiff < valdiff)
00141                 {
00142                   maxthresh = thresh + step;
00143                   maxvaldiff = valdiff;
00144                 }
00145               prev_thresh = thresh;
00146             }
00147           else if(area > prev + minadiff/4) gradual_descent = true;
00148           prev = area; thresh -= step;
00149           iter ++;
00150         }
00151     }
00152   // write out segmented object: 255.0 inside object, zero otherwise
00153   if(maxvaldiff == 0.0)
00154     {
00155       // flooded the first time and then no more floods
00156 
00157       // is this because of gradual descent?
00158       if(gradual_descent == true)
00159         standout = 0.0;
00160       // this is the only component and the rest is empty
00161       else standout = double(src.getVal(seed.i, seed.j)) * SEGOBJ_START;
00162       maxthresh = step; // back one step
00163     }
00164   else standout = maxvaldiff;
00165 
00166   if(maxthresh <= 0) return -1;
00167   // maxthresh is the threshold where valdiff is max
00168 
00169   if(flood_count != 0)
00170     if(maxvaldiff <= sumvaldiff/(double)flood_count)
00171       thresh = step;
00172     else thresh = maxthresh;
00173 
00174   else thresh = step;
00175 
00176   int area = flood(src, tmp, seed, (T)thresh, (T)255.0);
00177   if (area == -1) return -1;
00178   target = (Image<byte>)tmp;
00179 
00180   // find activity (measure of mean activity in this component)
00181   double threshold = thresh; double sum = 0.0;
00182   thresh = double(src.getVal(seed.i, seed.j)) * SEGOBJ_START;
00183   prev = 0; int sum_area = 0;
00184   activity = thresh;
00185 
00186   while(thresh >= threshold)
00187     {
00188       area = flood(src, tmp, seed, (T)thresh, (T)255.0);
00189       if(area > prev)
00190         activity = thresh;
00191 
00192       sum += activity * (area - prev);
00193       sum_area += area - prev;
00194       thresh -= step; prev = area;
00195     }
00196 
00197   if( sum_area != 0)activity = sum/(double)sum_area;
00198   else activity = threshold;
00199 
00200   if(standout > activity)
00201     standout = activity;
00202 
00203   area_percentage = (area  * 100.0f)/ (float)src.getSize();
00204 
00205   return area;
00206 }
00207 
00208 // ######################################################################
00209 template <class T>
00210 Image<byte> contour2D(const Image<T>& src, const byte onval, const byte offval)
00211 {
00212   ASSERT(src.initialized());
00213 
00214   Image<byte> result(src.getDims(), NO_INIT);
00215   typename Image<T>::const_iterator sptr = src.begin();
00216   Image<byte>::iterator dptr = result.beginw();
00217   T z = T(); const int h = src.getHeight(), w = src.getWidth();
00218 
00219   // This is a 4-connected contour algorithm. We are on the contour if we are not zero but at least: either 1) one of
00220   // our 4-neighbors is zero, or 2) we are on an edge of the image. Here we unfold the algo for max speed, i.e., we
00221   // treat the borders of the image explicitly and then the bulk:
00222 
00223   // first row:
00224   for (int i = 0; i < w; ++i) if (*sptr++) *dptr++ = onval; else *dptr++ = offval;
00225 
00226   // done if the image only has 1 row:
00227   if (h == 1) return result;
00228 
00229   // bulk, will only run if image has >2 rows:
00230   for (int j = 1; j < h-1; ++j)
00231     {
00232       // leftmost pixel of current row:
00233       if (*sptr++) *dptr++ = onval; else *dptr++ = offval;
00234 
00235       // done if image has only 1 column:
00236       if (w == 1) continue;
00237 
00238       // bulk of current row, will run only if image has >2 columns:
00239       for (int i = 1; i < w-1; ++i) {
00240         if (*sptr && (sptr[-1] == z || sptr[1] == z || sptr[-w] == z || sptr[w] == z))
00241           *dptr++ = onval; else *dptr++ = offval;
00242         ++sptr;
00243       }
00244 
00245       // rightmost pixel of current row, we know it exists since image has at least 2 columns:
00246       if (*sptr++) *dptr++ = onval; else *dptr++ = offval;
00247     }
00248 
00249   // last row (we know it exists since image has at least 2 rows):
00250   for (int i = 0; i < w; ++i) if (*sptr++) *dptr++ = onval; else *dptr++ = offval;
00251 
00252   return result;
00253 }
00254 
00255 // ######################################################################
00256 template <class T>
00257 Image<T> chamfer34(const Image<T>& src, const T dmax)
00258 {
00259 
00260   ASSERT(src.initialized());
00261   ASSERT(src.getWidth() >= 3 && src.getHeight() >= 3);
00262 
00263   Image<T> result = src;     // init dest array and copy input to it
00264 
00265   const Dims dims = src.getDims();
00266   const int size = src.getSize();
00267   const int w = dims.w();
00268   const T zero = T();
00269 
00270   typename Image<T>::const_iterator sptr = src.begin();
00271   typename Image<T>::iterator dptr = result.beginw();
00272 
00273   // first, set distance to 0 inside object and max distance outside:
00274   for (int i = 0; i < size; i ++)
00275     if (*sptr++) *dptr++ = zero; else *dptr++ = dmax;
00276   dptr = result.beginw();
00277 
00278   const float tmaxf = float(dmax);
00279 
00280   // now let's propagate the distance first forward, and then backwards:
00281   float d1, d2, d3, d4;
00282 
00283   /* first point is untouched ... */
00284   ++ dptr;
00285 
00286   /* first line : y=0 x=1..MAXX-1 */
00287   for (int i = 1; i < w; ++i)
00288     {
00289       d1 = std::min(dptr[-1] + 3.0F, dptr[-1 + w] + 4.0F);
00290       d2 = std::min(float(*dptr), d1);
00291       *dptr++ = clamped_convert<T>(std::min(d2, tmaxf));
00292     }
00293 
00294   /* y=1..MAXY-2, x=0..MAXX-1 */
00295   for (int j = 1; j < dims.h() - 1; ++j)
00296     {
00297       /* x=0 point on each line : x=0 y=1..MAXY-2 */
00298       d1 = std::min(dptr[-w] + 3.0F, float(*dptr));
00299       *dptr++ = clamped_convert<T>(std::min(d1, tmaxf));
00300 
00301       /* here : x=1..MAXX-1 y=1..MAXY-2 */
00302       for (int k = 1; k < w; k++)
00303         {
00304           d1 = std::min(dptr[-w - 1] + 4.0F, dptr[-w] + 3.0F);
00305           d2 = std::min(dptr[-1] + 3.0F, float(*dptr));
00306           d3 = std::min(dptr[-1 + w] + 4.0F, d1);
00307           d4 = std::min(d2, d3);
00308           *dptr++ = clamped_convert<T>(std::min(d4, tmaxf));
00309         }
00310     }
00311 
00312   /* last line : x=0..MAXX-1 y=MAXY-1 */
00313   /* first point */
00314   d1 = std::min(dptr[-w] + 3.0F, float(*dptr));
00315   *dptr++ = clamped_convert<T>(std::min(d1, tmaxf));
00316 
00317   /* x=1..MAXX-1 y=MAXY-1 */
00318   for (int j = 1; j < w; ++j)
00319     {
00320       d1 = std::min(dptr[-w - 1] + 4.0F, dptr[-w] + 3.0F);
00321       d2 = std::min(dptr[-1] + 3.0F, float(*dptr));
00322       d3 = std::min(d1, d2);
00323       *dptr++ = clamped_convert<T>(std::min(d3, tmaxf));
00324     }
00325   --dptr; // back to last point
00326 
00327   /******************* backward */
00328   /* last point is untouched ... */
00329   --dptr;
00330 
00331   /* last line : y=MAXY-1 x=MAXX-2..0 */
00332   for (int j = w-2; j >= 0; --j)
00333     {
00334       d1 = std::min(dptr[1] + 3.0F, dptr[-w + 1] + 4.0F);
00335       d2 = std::min(float(*dptr), d1);
00336       *dptr-- = clamped_convert<T>(std::min(d2, tmaxf));
00337     }
00338 
00339   /* y=MAXY-2..1, x=MAXX-1..0 */
00340   for (int j = dims.h() - 2; j >= 1; --j)
00341     {
00342       /* x=MAXX-1 point on each line : y=MAXY-2..1 */
00343       d1 = std::min(dptr[w] + 3.0F, float(*dptr));
00344       *dptr-- = clamped_convert<T>(std::min(d1, tmaxf));
00345 
00346       /* here : x=MAXX-2..0 y=MAXY-2..1 z=MAXZ-1 */
00347       for (int k = w - 2; k >= 0; k--)
00348         {
00349           d1 = std::min(float(*dptr), dptr[-w + 1] + 4.0F);
00350           d2 = std::min(dptr[1] + 3.0F, dptr[w] + 3.0F);
00351           d3 = std::min(dptr[w + 1] + 4.0F, d1);
00352           d4 = std::min(d2, d3);
00353           *dptr-- = clamped_convert<T>(std::min(d4, tmaxf));
00354         }
00355     }
00356 
00357   /* first line : x=MAXX-1..0 y=0 */
00358   /* last point */
00359   d1 = std::min(dptr[w] + 3.0F, float(*dptr));
00360   *dptr-- = clamped_convert<T>(std::min(d1, tmaxf));
00361 
00362   /* x=MAXX-2..0 y=0 z=MAXZ-1 */
00363   for (int j = w-2; j >= 0; --j)
00364     {
00365       d1 = std::min(dptr[1] + 3.0F, float(*dptr));
00366       d2 = std::min(dptr[w] + 3.0F, dptr[w + 1] + 4.0F);
00367       d3 = std::min(d1, d2);
00368       *dptr-- = clamped_convert<T>(std::min(d3, tmaxf));
00369     }
00370 
00371   return result;
00372 }
00373 
00374 // ######################################################################
00375 template <class T>
00376 Image<T> saliencyChamfer34(const Image<T>& src, const T dmax)
00377 {
00378 
00379   ASSERT(src.initialized());
00380   ASSERT(src.getWidth() >= 3 && src.getHeight() >= 3);
00381 
00382   Image<T> result = src;     // init dest array and copy input to it
00383 
00384   const Dims dims = src.getDims();
00385   const int size = src.getSize();
00386   const int w = dims.w();
00387   const int h = dims.h();
00388   const T zero = T();
00389 
00390   Image<T> magImg = src;
00391 
00392 #define ALGORITHM CHAMFER34
00393 #if ALGORITHM == CHAMFER34
00394   int MASK_SIZE = 5;
00395   const int x_offset[] = { -1,  0,  1, -1,  0 };
00396   const int y_offset[] = { -1, -1, -1,  0,  0 };
00397   const int i_offset[] = {  4,  3,  4,  3,  0 };
00398 #elif ALGORITHM == CHAMFER5711
00399   int MASK_SIZE = 9;
00400   int x_offset[] = { -1,  1, -2, -1,  0,  1,  2, -1,  0 };
00401   int y_offset[] = { -2, -2, -1, -1, -1, -1, -1,  0,  0 };
00402   int i_offset[] = { 11, 11, 11,  7,  5,  7, 11,  5,  0 };
00403 #endif
00404 
00405   typename Image<T>::iterator sptr = magImg.beginw();
00406   typename Image<T>::iterator dptr = result.beginw();
00407 
00408   float K = 1.0F;
00409 
00410   // first, set distance to 0 inside object and max distance outside:
00411   for (int i = 0; i < size; i ++)
00412     if (*sptr++ > 0) *dptr++ = zero; else *dptr++ = dmax;
00413 
00414   double prev_measure = 0, min_measure = 0, measure = 0;
00415   double min_dist,min_mag;
00416   int d[MASK_SIZE],m[MASK_SIZE];
00417 
00418   int max_iter = 10;
00419 
00420   //Reset the pointers
00421   sptr = magImg.beginw();
00422   dptr = result.beginw();
00423 
00424   /* propagate distance etc */
00425   int j = 0;
00426   bool  change = false;
00427   do {
00428     j++;
00429     change = false;
00430 
00431     /* forward pass */
00432     for (int y = 1; y < h-1; y++) {
00433       for (int x = 1; x < w-1; x++) {
00434 
00435          prev_measure = (double) (dptr[x + w*y]+K) /
00436           (double) ((unsigned int)sptr[x + w*y]+K);
00437         for (int i = 0; i < MASK_SIZE; i++) {
00438           int xn = x + x_offset[i]; int yn = y + y_offset[i];
00439           d[i] = (int)(dptr[xn + w*yn] + i_offset[i]);
00440           m[i] = (unsigned int)sptr[xn + yn*w];
00441         }
00442 
00443         min_dist = d[0];
00444         min_mag = m[0];
00445         min_measure = (double) (d[0]+K) / (double) (m[0]+K);
00446         for (int i = 1; i < MASK_SIZE; i++) {
00447           measure = (double) (d[i]+K) / (double) (m[i]+K);
00448           if (measure < min_measure) {
00449             min_measure = measure;
00450             min_dist = d[i];
00451             min_mag = m[i];
00452           }
00453         }
00454         dptr[x + y*w] = (T)min_dist;
00455         sptr[x + y*w] = (T)min_mag; //TODO ?
00456 
00457         if (prev_measure != min_measure)
00458           change = true;
00459       }
00460     }
00461 
00462     /* backward pass */
00463     for (int y = h-2; y >= 1; y--) {
00464       for (int x = w-2; x >= 1; x--) {
00465         prev_measure = (double) (dptr[x + y*w]+K) /
00466           (double) ((unsigned int)sptr[x + y*w]+K);
00467         for (int i = 0; i < MASK_SIZE; i++) {
00468           int xn = x - x_offset[i]; int yn = y - y_offset[i];
00469           d[i] = (int)( dptr[xn + yn*w] + i_offset[i]);
00470           m[i] = (unsigned int)sptr[xn + yn*w];
00471         }
00472 
00473         min_dist = d[0];
00474         min_mag = m[0];
00475         min_measure = (double) (d[0]+K) / (double) (m[0]+K);
00476         for (int i = 1; i < MASK_SIZE; i++) {
00477           measure = (double) (d[i]+K) / (double) (m[i]+K);
00478           if (measure < min_measure) {
00479             min_measure = measure;
00480             min_dist = d[i];
00481             min_mag = m[i];
00482           }
00483         }
00484         dptr[x + y*w] = (T)min_dist;
00485         sptr[x + y*w] = (T)min_mag; //TODO ?
00486 
00487         if (prev_measure != min_measure)
00488           change = true;
00489       }
00490     }
00491   } while (change && j < max_iter);
00492 
00493   /* calculate measure values */
00494   for (int y = 1; y < h-1; y++) {
00495     for (int x = 1; x < w-1; x++) {
00496       dptr[x + y*w] = (T) ((double) (dptr[x +y*w]+K) /
00497         (double) ((unsigned int)sptr[x + y*w]+K));
00498     }
00499   }
00500 
00501   /* rescale */
00502   T max_val = dptr[0];
00503   for (int y = 1; y < h-1; y++)
00504     for (int x = 1; x < w-1; x++)
00505       if (dptr[x + y*w] > max_val)
00506         max_val = dptr[x + y*w];
00507 
00508   for (int y = 1; y < h-1; y++)
00509     for (int x = 1; x < w-1; x++)
00510       dptr[x + y*w] = (unsigned char)(dptr[x + y*w] * 255 / max_val);
00511 
00512   ///* reset borders */
00513   //for (y = 0; y < height; y++)
00514   //  tmp[0][y] = tmp[width-1][y] = 255;
00515   //for (x = 0; x < width; x++)
00516   //  tmp[x][0] = tmp[x][height-1] = 255;
00517 
00518 
00519   return result;
00520 }
00521 
00522 // ######################################################################
00523 template <class T>
00524 Image<typename promote_trait<T, float>::TP>
00525 dct(const Image<T>& src, const int offx, const int offy, const int size)
00526 {
00527   ASSERT(src.initialized());
00528   ASSERT(offx + size <= src.getWidth() && offy + size <= src.getHeight());
00529 
00530   int m = (int)(log((double)size) / log(2.0) + 0.001);
00531   ASSERT((1 << m) == size);  // size must be a power of two
00532   int N = 1 << m;
00533 
00534   float x[512][512], ct[512], s[512][512];
00535   for (int ii = 0; ii < N; ii ++)
00536     for (int jj = 0; jj < N; jj ++)
00537       x[ii][jj] = (float)src.getVal(ii+offx, jj+offy);
00538 
00539   /* Implementation of 2D FCT through the 1D decimation in
00540      frequency (DIF) split radix algorithm from paper:
00541 
00542      1)Skodras A.N., and Christopoulos C.A., Split-radix fast cosine
00543      transform, Int. J. Electronics, Vol. 74, No. 4, pp. 513-522, 1993.
00544 
00545      2)Christopoulos C.A., Skodras A.N. and Cornelis J., Comparative
00546      performance evaluation of algorithms for fast computation of the
00547      two-dimensional DCT, Proceedings of the IEEE Benelux & ProRISC
00548      Workshop on Circuits, Systems and Signal Processing, Papendal,
00549      Arnhem (The Netherlands), March 24, 1994, pp. 75-79.
00550 
00551      3)Christopoulos C.A., and Skodras A.N., On the computation of the fast
00552      cosine transform, Proceedings of the European Conference on Circuit
00553      Theory and Design (ECCTD' 93), Davos, Switzerland, Aug.30 - Sept.3,
00554      1993, pp. 1037-1042.
00555 
00556      First written:     September 1994
00557      Last modified:             January 1996.
00558 
00559      Author:
00560      Charilaos Christopoulos
00561      Ericsson Telecom AB
00562      Compression Lab, HF/ETX/ML
00563      126 24 Stockholm, Sweden
00564 
00565      ch.christopoulos@clab.ericsson.se
00566 
00567      (c) Please notice that you are allowed to use the algorithms for your
00568      research provided that you always give a reference to the corresponding
00569      paper (which is not always written by myself as you will see) and a
00570      reference to the author of the algorithms. You can do any modifications,
00571      (and add your name in the list of authors that did modifications),
00572      improvements, etc in the programs and you can distribute the programs to
00573      other researchers provided that the name of the authors of the first
00574      version will remain in the software.
00575      */
00576   {
00577     int is,id,i0,i1,i2,i3;
00578 
00579     //makecosinetable() /* 1D cosine table for N points */
00580     {
00581       int n2,n4;
00582       double e;
00583       float *p;
00584 
00585       n2 = N << 1; p = ct;
00586 
00587       for (int k = 1; k < m; k++) {
00588         e  = M_PI / n2;
00589         n2 = n2 >> 1;
00590         n4 = n2 >> 2;
00591 
00592         for (int j = 0; j < n4; j++) {
00593           *p++ = cos(((j<<2)+1)*e);
00594           *p++ = sin(((j<<2)+1)*e);
00595           *p++ = cos((((j<<2)+1)<<1)*e);
00596 
00597         }
00598       }
00599       *p = cos(M_PI/4.0);
00600     }
00601 
00602     // rowsinputmapping()
00603     {
00604       int n1,n2,n;
00605 
00606       for(n1=0; n1 <= N; n1++)
00607         for (n2=0; n2<N; n2++ )
00608           s[n1][n2] = x[n1][n2];
00609 
00610       for (int cols=0; cols<N; cols++) {
00611         for(n=0; n < N/2; n++) {
00612           x[cols][n]     = s[cols][2*n];
00613           x[cols][N-n-1] = s[cols][2*n+1];
00614         }
00615       }
00616     }
00617 
00618     for (int rows=0; rows<N; rows++) {
00619       int p=0;
00620       int n2 = N << 1;
00621       for (int k = 1; k < m; k++) {
00622         n2 = n2 >> 1;
00623         const int n4 = n2 >> 2;
00624 
00625         for (int j = 0; j < n4; j++) {
00626           is = j;
00627           id = n2 << 1;
00628 
00629         again1:
00630           for (i0 = is; i0 < N; i0 +=id) {
00631             i1 = i0 + n4;
00632             i2 = i1 + n4;
00633             i3 = i2 + n4;
00634 
00635             float t1 = 2 * (x[rows][i0] - x[rows][i2]) *ct[p] ;
00636             float t2 = (-2) * (x[rows][i1] - x[rows][i3]) * ct[p+1];
00637 
00638             x[rows][i0] = x[rows][i0] + x[rows][i2];
00639             x[rows][i1] = x[rows][i1] + x[rows][i3];
00640             x[rows][i2] = t1 + t2;
00641             x[rows][i3] = 2 * (t1 - t2) * ct[p+2];
00642 
00643             /* if at the m-1 stage, divide by 2 */
00644             if (k==m-1) {
00645               x[rows][i2] = x[rows][i2]/2;
00646               x[rows][i3] = x[rows][i3]/2;
00647             }
00648           }
00649           is = (id << 1) - n2 + j;
00650           id = id << 2;
00651           if ( is < N ) goto again1;
00652           p+=3;
00653         }
00654       }
00655       /* last stage */
00656       is = 0;
00657       id = 4;
00658     l_again1:
00659       for( i0 = is; i0 < N; i0 += id) {
00660         i1 = i0 + 1;
00661         float t1 = x[rows][i0];
00662         x[rows][i0] = t1 + x[rows][i1];
00663         /* divide the upper element by 2 */
00664         if (i0 != 0) x[rows][i0] = x[rows][i0]/2;
00665         x[rows][i1] = (t1 - x[rows][i1]) * ct[p];
00666       }
00667       is = (id << 1) - 2;
00668       id =  id << 2;
00669       if( is < N ) goto l_again1;
00670     }/* end of for rows */
00671 
00672     //rowsbitreversal() /* 2d bit reversal */
00673     {
00674       int v1, v2, v3,i,k;
00675       float xt;
00676 
00677       /* revesre rows */
00678       for (int cols =0; cols<N; cols ++) {
00679         v1 = (m+1)/2;
00680         v2 = 1 << v1;
00681         v3 = N-1-v2;
00682         int j=0;
00683         for(i=1; i<=v3; i++){
00684           k= N>>1;
00685           while(k<=j){
00686             j=j-k;
00687             k=k>>1;
00688           }
00689           j +=k;
00690           if(i<j){
00691             xt=x[cols][j];
00692             x[cols][j]=x[cols][i];
00693             x[cols][i]=xt;
00694           }
00695         }
00696       }
00697     }
00698     //rowspostadditions()
00699     {
00700       int step,loops,ep,i,l;
00701 
00702       for (int rows=0; rows<N; rows++) {
00703         step =N;
00704         loops = 1;
00705         for (int k=1; k<m; k++)  {
00706           step = step>>1;
00707           ep = step>>1;
00708           loops = loops <<1;
00709           for (int j=0; j<(step>>1); j++) {
00710             l=ep;
00711             for (i=1; i<loops;i++)  {
00712               x[rows][l+step] = x[rows][l+step]-x[rows][l];
00713               l =l+step;
00714             }
00715             ep +=1;
00716           }
00717         }
00718       }
00719     }
00720     //  columnsinputmapping() /* 2d input mapping */
00721     {
00722       int n1,n2,n;
00723 
00724       for(n1=0; n1 <= N; n1++)
00725         for (n2=0; n2<N; n2++ )
00726           s[n1][n2] = x[n1][n2];
00727 
00728       for (int rows=0; rows<N; rows++) {
00729         for(n=0; n < N/2; n++) {
00730           x[n][rows]     = s[2*n][rows];
00731           x[N-n-1][rows] = s[2*n+1][rows];
00732         }
00733       }
00734     }
00735 
00736     for (int cols=0; cols<N; cols++) {
00737       int p=0;
00738 
00739       int n2 = N << 1;
00740       for (int k = 1; k < m; k++) {
00741         n2 = n2 >> 1;
00742         const int n4 = n2 >> 2;
00743 
00744         for (int j = 0; j < n4; j++) {
00745           is = j;
00746           id = n2 << 1;
00747         again2:
00748           for (i0 = is; i0 < N; i0 +=id) {
00749             i1 = i0 + n4;
00750             i2 = i1 + n4;
00751             i3 = i2 + n4;
00752 
00753             float t1 = 2 * (x[i0][cols] - x[i2][cols]) *ct[p] ;
00754             float t2 = (-2) * (x[i1][cols]-x[i3][cols])* ct[p+1];
00755 
00756             x[i0][cols] = x[i0][cols] + x[i2][cols];
00757             x[i1][cols] = x[i1][cols] + x[i3][cols];
00758             x[i2][cols] = t1 + t2;
00759             x[i3][cols] = 2 * (t1 - t2) * ct[p+2];
00760 
00761             /* if at the m-1 stage, divide by 2 */
00762             if (k==m-1) {
00763               x[i2][cols] = x[i2][cols]/2;
00764               x[i3][cols] = x[i3][cols]/2;
00765             }
00766           }
00767 
00768           is = (id << 1) - n2 + j;
00769           id = id << 2;
00770           if ( is < N ) goto again2;
00771           p+=3;
00772         }
00773       }
00774 
00775       /* last stage */
00776       is = 0;
00777       id = 4;
00778     l_again2:
00779       for( i0 = is; i0 < N; i0 += id) {
00780         i1 = i0 + 1;
00781 
00782         float t1 = x[i0][cols];
00783         x[i0][cols] = t1 + x[i1][cols];
00784         /* divide the upper element by 2 */
00785         if (i0 != 0) x[i0][cols] = x[i0][cols]/2;
00786         x[i1][cols] = (t1 - x[i1][cols]) * ct[p];
00787       }
00788 
00789       is = (id << 1) - 2;
00790       id =  id << 2;
00791       if( is < N ) goto l_again2;
00792 
00793     }/* end of for cols */
00794 
00795     //  columnsbitreversal()
00796     {
00797       int v1, v2, v3,i,k;
00798       float xt;
00799       /* reverse columns */
00800       for (int rows =0; rows<N; rows ++) {
00801         v1 = (m+1)/2;
00802         v2 = 1 << v1;
00803         v3 = N-1-v2;
00804         int j=0;
00805         for(i=1; i<=v3; i++){
00806           k= N>>1;
00807           while(k<=j){
00808             j=j-k;
00809             k=k>>1;
00810           }
00811           j +=k;
00812           if(i<j){
00813             xt=x[j][rows];
00814             x[j][rows]=x[i][rows];
00815             x[i][rows]=xt;
00816           }
00817         }
00818       }
00819     }
00820 
00821     //columnspostadditions()
00822     {
00823       int step,loops,ep,i,l;
00824 
00825       for (int cols=0; cols<N; cols++) {
00826         step =N;
00827         loops = 1;
00828         for (int k=1; k<m; k++)  {
00829           step = step>>1;
00830           ep = step>>1;
00831           loops = loops <<1;
00832           for (int j=0; j<(step>>1); j++) {
00833             l=ep;
00834             for (i=1; i<loops; i++)  {
00835               x[l+step][cols] = x[l+step][cols] - x[l][cols];
00836               l =l+step;
00837             }
00838             ep +=1;
00839           }
00840         }
00841       }
00842     } /* end of rowspostadditions */
00843 
00844   }  /*    end of SR_FCT    */
00845   typedef typename promote_trait<T, float>::TP TF;
00846   Image<TF> result(N, N, NO_INIT);
00847   for (int ii = 0; ii < N; ii ++)
00848     for (int jj = 0; jj < N; jj ++)
00849       result.setVal(ii, jj, x[ii][jj] * 4.0F);
00850 
00851   return result;
00852 }
00853 
00854 // ######################################################################
00855 template <class T>
00856 float infoFFT(const Image<T>& src, const float eps, const Rectangle& rect)
00857 {
00858   Image<float> tmp = crop(src, rect);
00859   Image<float> tmp2 = infoFFT(tmp, eps);
00860   float mini, maxi;
00861   getMinMax(tmp2, mini, maxi);
00862   return maxi;
00863 }
00864 
00865 // ######################################################################
00866 template <class T>
00867 Image<float> infoFFT(const Image<T>& src, const float eps)
00868 {
00869   Image<float> result(src.getWidth() / 4, src.getHeight() / 4, NO_INIT);
00870   // look at 16x16 patches every 4 pix in x and y
00871 
00872   const Dims dims = src.getDims();
00873 
00874   for (int cx = 0; cx < dims.w(); cx += 4)      // center of patch
00875     for (int cy = 0; cy < dims.h(); cy += 4)
00876       {
00877         int offx = cx - 8, offy = cy - 8;
00878         if (dims.w() > 32 && dims.h() > 32)
00879           {
00880             // kill last column:
00881             if (offx == dims.w() - 16) offx = dims.w();
00882 
00883             // last line;for symmetry of display:
00884             if (offy == dims.h() - 16) offy = dims.h();
00885           }
00886 
00887         if (offx >= 0 &&
00888             offy >= 0 &&
00889             offx+16 <= dims.w() &&
00890             offy+16 <= dims.h())
00891           {
00892             // take 2D fft of a 16x16 patch starting at offx,
00893             // offy, compute abs, and compute nb coeffs > epsn
00894             float data[16][33];
00895             for (int row = 0; row < 16; row ++)
00896               for (int col = 0; col < 16; col ++)
00897                 {
00898                   data[row][col*2+2] = 0.0;
00899                   data[row][col*2+1] = (float) src.getVal(offx+col, offy+row);
00900                 }
00901 
00902             for (int row = 0; row < 16; row ++)
00903               {
00904                 // 1D FFT routine in x
00905                 // takes abs fft of data[row][1..32]
00906                 int j = 1;
00907                 for (int i = 1; i < 32; i += 2)  // bit reversal procedure
00908                   {
00909                     if (j > i)
00910                       { float tmp = data[row][i]; data[row][i] = data[row][j];
00911                       data[row][j] = tmp; tmp = data[row][i+1];
00912                       data[row][i+1] = data[row][j+1]; data[row][j+1] = tmp; }
00913                     int m = 16; while (m >= 2 && j > m) { j -= m; m >>= 1; }
00914                     j += m;
00915                   }
00916                 int mmax = 2;
00917                 while (32 > mmax)
00918                   {
00919                     int istep = mmax << 1; float theta = -2*M_PI/(float)mmax;
00920                     float wtemp = sin(0.5*theta); float wpr = -2.0*wtemp*wtemp;
00921                     float wpi = sin(theta); float wr = 1.0; float wi = 0.0;
00922                     for (int m = 1; m < mmax; m += 2)
00923                       {
00924                         for (int i = m; i <= 32; i += istep)
00925                           {
00926                             j = i + mmax;
00927                             float tempr=wr*data[row][j]-wi*data[row][j+1];
00928                             float tempi = wr*data[row][j+1]+wi*data[row][j];
00929                             data[row][j] = data[row][i]-tempr;
00930                             data[row][j+1] = data[row][i+1]-tempi;
00931                             data[row][i]+=tempr;
00932                             data[row][i+1]+=tempi;
00933                           }
00934                         wr=(wtemp=wr)*wpr-wi*wpi+wr; wi=wi*wpr+wtemp*wpi+wi;
00935                       }
00936                     mmax = istep;
00937                   }
00938               }
00939 
00940             // transpose to do the same thing in y
00941             for (int row = 0; row < 16; row ++)
00942               for (int col = 0; col < row; col ++)
00943                 {
00944                   // transpose real and imaginary parts
00945                   float tt = data[row][col*2+1];
00946                   data[row][col*2+1] = data[col][row*2+1];
00947                   data[col][row*2+1] = tt;
00948                   tt = data[row][col*2+2];
00949                   data[row][col*2+2] = data[col][row*2+2];
00950                   data[col][row*2+2] = tt;
00951                 }
00952 
00953             // redo the same stuff
00954             for (int row = 0; row < 16; row ++)
00955               {
00956                 // 1D FFT routine in x
00957                 // takes abs fft of data[row][1..32]
00958                 int j = 1;
00959                 for (int i = 1; i < 32; i += 2)  // bit reversal procedure
00960                   {
00961                     if (j > i)
00962                       { float tmp = data[row][i]; data[row][i] = data[row][j];
00963                       data[row][j] = tmp; tmp = data[row][i+1];
00964                       data[row][i+1] = data[row][j+1]; data[row][j+1] = tmp; }
00965                     int m = 16; while (m >= 2 && j > m) { j -= m; m >>= 1; }
00966                     j += m;
00967                   }
00968                 int mmax = 2;
00969                 while (32 > mmax)
00970                   {
00971                     int istep = mmax << 1; float theta = -2*M_PI/(float)mmax;
00972                     float wtemp = sin(0.5*theta); float wpr = -2.0*wtemp*wtemp;
00973                     float wpi = sin(theta); float wr = 1.0; float wi = 0.0;
00974                     for (int m = 1; m < mmax; m += 2)
00975                       {
00976                         for (int i = m; i <= 32; i += istep)
00977                           {
00978                             j = i + mmax;
00979                             float tempr=wr*data[row][j]-wi*data[row][j+1];
00980                             float tempi = wr*data[row][j+1]+wi*data[row][j];
00981                             data[row][j] = data[row][i]-tempr;
00982                             data[row][j+1] = data[row][i+1]-tempi;
00983                             data[row][i]+=tempr;
00984                             data[row][i+1]+=tempi;
00985                           }
00986                         wr=(wtemp=wr)*wpr-wi*wpi+wr; wi=wi*wpr+wtemp*wpi+wi;
00987                       }
00988                     mmax = istep;
00989                   }
00990               }
00991 
00992             // WARNING: at this point we have the transpose of the fft
00993 
00994             // count # coeffs > epsn
00995             float nbsup = 0.0;
00996             float epsn = (eps * 256.0 * 127.5)*(eps * 256.0 * 127.5);
00997             // epsn is normalized by patch size and ^2
00998             for (int row = 0; row < 16; row ++)
00999               for (int col = 1; col <= 32; col += 2)
01000                 {
01001                   float val = data[row][col]*data[row][col] +
01002                     data[row][col+1]*data[row][col+1];  // this is |..|^2
01003                   if (val > epsn) nbsup += 1.0;
01004                 }
01005             result.setVal(cx/4, cy/4, nbsup / 256.0);  // ratio>eps, in [0..1]
01006           }
01007         else
01008           result.setVal(cx/4, cy/4, 0.0);
01009       }
01010 
01011   return result;
01012 }
01013 
01014 // ######################################################################
01015 double learningCoeff(const Image<float>& featureMap,
01016                      const Image<byte>& targetDMap,
01017                      const bool softmask,
01018                      const int in_thresh, const int out_thresh)
01019 {
01020   ASSERT(featureMap.initialized()); ASSERT(targetDMap.initialized());
01021   ASSERT(featureMap.isSameSize(targetDMap));
01022 
01023   const bool havein = (in_thresh >= 0 && in_thresh <= 255);
01024   const bool haveou = (out_thresh >= 0 && out_thresh <= 255);
01025 
01026   if (softmask)
01027     {
01028       // remember that in the dmap zero means in the target and 255
01029       // outside. In the soft version, we just take the product of the
01030       // feature map by the mask (or 255-mask) and look for the avg
01031       // resulting value:
01032       float av = mean(featureMap) / float(featureMap.getSize());
01033       float oav = sum(featureMap * targetDMap) / (255.0f * sum(targetDMap));
01034       Image<float> mask = binaryReverse(targetDMap, byte(255));
01035       float iav = sum(featureMap * mask) / (255.0f * sum(mask));
01036 
01037       if (!havein && !haveou)
01038         { LFATAL("At least one threshold must be valid"); return 0.0;}
01039       else if (!havein && haveou)  // bg only: strong is bad
01040         return double((av - oav) / av);
01041       else if (havein && !haveou)  // target only: strong good
01042         return double((iav - av) / av);
01043       else // target+bg: higher inside than outside is good (>0), opposite bad
01044         return double((iav - oav) / av);
01045     }
01046   else
01047     {
01048       // Hard mask approach: examine local maxs in/out of targets and
01049       // compute learning weight convention: in the given distance
01050       // map, distance 0 is inside targets; is considered target
01051       // everything for which map value <= in_thresh; is considered
01052       // non-target everything for which map value >= out_thresh; the
01053       // transition between target and non-target is not used for
01054       // computation
01055 
01056       Image<byte>::const_iterator dmapptr = targetDMap.begin();
01057       Image<float>::const_iterator sptr = featureMap.begin(),
01058         stop = featureMap.end();
01059 
01060       float glob_min = *sptr; float glob_max = *sptr;
01061       float in_max = 0.0f; float out_max = 0.0f;
01062 
01063       while (sptr != stop)
01064         {
01065           const int mapval = *dmapptr++;
01066           const float val = *sptr++;
01067           if (mapval <= in_thresh && val > in_max) in_max = val;
01068           if (mapval >= out_thresh && val > out_max) out_max = val;
01069           if (val < glob_min) glob_min = val;
01070           if (val > glob_max) glob_max = val;
01071         }
01072 
01073       if (!havein && !haveou)
01074         { LFATAL("At least one threshold must be valid"); return 0.0;}
01075       else if (!havein && haveou)  // bg only: strong is bad
01076         return -double(in_max) / (double(glob_max) - double(glob_min));
01077       else if (havein && !haveou)  // target only: strong good
01078         return double(in_max) / (double(glob_max) - double(glob_min));
01079       else // target+bg: higher inside than outside is good (>0), opposite bad
01080         return (double(in_max) - double(out_max)) /
01081           (double(glob_max) - double(glob_min));
01082     }
01083 }
01084 
01085 // ######################################################################
01086 template <class T>
01087 Image<T> scaleBlock(const Image<T>& src, const Dims newDims)
01088 {
01089   int new_w = newDims.w(), new_h = newDims.h();
01090   std::vector<int> col_idx(new_w), row_idx(new_h);
01091   int w = src.getWidth(), h = src.getHeight();
01092 
01093   for (int x = 0; x < new_w; x++)
01094     col_idx[x] = (int)((float)x / (float)new_w * (float)w);
01095   for (int y = 0; y < new_h; y++)
01096     row_idx[y] = (int)((float)y / (float)new_h * (float)h);
01097 
01098   Image<T> result(new_w, new_h, NO_INIT);
01099   typename Image<T>::iterator rptr = result.beginw();
01100   for (int y = 0; y < new_h; y++)
01101     for (int x = 0; x < new_w; x++)
01102       {
01103         *rptr++ = src.getVal(col_idx[x],row_idx[y]);
01104       }
01105   return result;
01106 }
01107 
01108 // ######################################################################
01109 template <class T>
01110 int floodClean(const Image<T>& src, Image<T>& dest, const Point2D<int>& seed,
01111                const T thresh, const T val, int numConn)
01112 {
01113   ASSERT(src.initialized()); ASSERT(src.coordsOk(seed));
01114 
01115   // if dest is not initialized, initilize it to ZEROS
01116   // ATTENTION: the old behavior is initialization to src
01117   // If you want to have this behavior, you have to explicitely
01118   // initialize dest to src BEFORE calling floodClean
01119   if (!dest.initialized()) dest.resize(src.getDims(),true);
01120 
01121   if (src.getVal(seed) < thresh) return -1; // starting point not in object
01122 
01123   // Allocate space for the recursion stack
01124   std::vector<Point2D<int> > stk;
01125   const int STACKSIZE = 256 * 256 + 20;
01126   stk.reserve(STACKSIZE);
01127   stk.push_back(seed);
01128 
01129   // relative directions
01130   std::vector<Point2D<int> > dirs(8);
01131   dirs[0] = Point2D<int>(1,0);   dirs[1] = Point2D<int>(0,1);
01132   dirs[2] = Point2D<int>(0,-1);  dirs[3] = Point2D<int>(-1,0);
01133   dirs[4] = Point2D<int>(1,1);   dirs[5] = Point2D<int>(1,-1);
01134   dirs[6] = Point2D<int>(-1,-1); dirs[7] = Point2D<int>(-1,1);
01135 
01136   // mask for the region already visited
01137   Image<byte> visited(src.getDims(), ZEROS);
01138   int nbpix = 0;
01139 
01140   while (! stk.empty())
01141     {
01142       Point2D<int> index = stk.back(); stk.pop_back();
01143       if (!visited.getVal(index))  // we have not yet visited this point
01144         {
01145           // we know that the current point IS in our object:
01146           dest.setVal(index, val);  // flood output
01147           visited.setVal(index,1);  // don't count this one again
01148           ++nbpix;                  // one more flooded pixel
01149 
01150           for (int i = 0; i < numConn; i++)
01151             {
01152               Point2D<int> idx2 = index + dirs[i];
01153               if ((src.coordsOk(idx2)) &&
01154                   (!visited.getVal(idx2)) &&
01155                   (src.getVal(idx2) >= thresh)
01156                  )
01157                 stk.push_back(idx2);
01158             }
01159         }
01160     }
01161   return nbpix;
01162 }
01163 
01164 // ######################################################################
01165 template <class T>
01166 int floodCleanBB(const Image<T>& src, Image<T>& dest, const Point2D<int>& seed,
01167                  const T thresh, const T val, Rectangle& bbox)
01168 {
01169   ASSERT(src.initialized()); ASSERT(src.coordsOk(seed));
01170 
01171   int ll = src.getWidth(), rr = -1, tt = src.getHeight(), bb = -1;
01172 
01173   // if dest is not initialized, initilize it to ZEROS
01174   // ATTENTION: the old behavior is initialization to src
01175   // If you want to have this behavior, you have to explicitely
01176   // initialize dest to src BEFORE calling floodClean
01177   if (!dest.initialized()) dest.resize(src.getDims(),true);
01178 
01179   if (src.getVal(seed) < thresh) return -1; // starting point not in object
01180 
01181   // Allocate space for the recursion stack
01182   std::vector<Point2D<int> > stk;
01183   const int STACKSIZE = 256 * 256 + 20;
01184   stk.reserve(STACKSIZE);
01185   stk.push_back(seed);
01186 
01187   // relativ directions
01188   std::vector<Point2D<int> > dirs(8);
01189   dirs[0] = Point2D<int>(1,0);   dirs[1] = Point2D<int>(0,1);
01190   dirs[2] = Point2D<int>(1,1);   dirs[3] = Point2D<int>(1,-1);
01191   dirs[4] = Point2D<int>(0,-1);  dirs[5] = Point2D<int>(-1,0);
01192   dirs[6] = Point2D<int>(-1,-1); dirs[7] = Point2D<int>(-1,1);
01193 
01194   // mask for the region already visited
01195   Image<byte> visited(src.getDims(), ZEROS);
01196   int nbpix = 0;
01197 
01198   while (! stk.empty())
01199     {
01200       Point2D<int> index = stk.back(); stk.pop_back();
01201       if (visited.getVal(index) == 0)  // we have not yet visited this point
01202         {
01203           // we know that the current point IS in our object:
01204           dest.setVal(index, val);  // flood output
01205           visited.setVal(index,1);  // don't count this one again
01206           ++nbpix;                  // one more flooded pixel
01207 
01208           // set the bbox values if necessary
01209           if (index.i < ll) ll = index.i;
01210           if (index.i > rr) rr = index.i;
01211           if (index.j < tt) tt = index.j;
01212           if (index.j > bb) bb = index.j;
01213 
01214           for (int i = 0; i < 8; i++)
01215             {
01216               Point2D<int> idx2 = index + dirs[i];
01217               if ((src.coordsOk(idx2)) &&
01218                   (src.getVal(idx2) >= thresh) &&
01219                   (visited.getVal(idx2) == 0))
01220                 stk.push_back(idx2);
01221             }
01222         }
01223     }
01224   if (nbpix > 0) bbox = Rectangle::tlbrI(tt,ll,bb,rr);
01225   return nbpix;
01226 }
01227 
01228 // ######################################################################
01229 template <class T>
01230 Image<float> distDegrade(const Image<T>& src, const Point2D<int>& foa, const float area)
01231 {
01232   float s2 = area / 100.0;
01233   float dist2,dx,dy;
01234   const T zero = T();
01235   Image<float> result(src.getDims(),ZEROS);
01236   typename Image<float>::iterator rptr = result.beginw();
01237   typename Image<T>::const_iterator sptr = src.begin();
01238 
01239   for (int y = 0; y < src.getHeight(); y++)
01240     for (int x = 0; x < src.getWidth(); x++)
01241       {
01242         if (*sptr > zero)
01243           {
01244             dx = x - foa.i;
01245             dy = y - foa.j;
01246             dist2 = dx * dx + dy * dy;
01247             if (dist2 == 0.0)
01248               *rptr = 1.0;
01249             else
01250               *rptr = 1.0 - exp( - s2 / dist2);
01251           }
01252         sptr++; rptr++;
01253       }
01254   return result;
01255 }
01256 
01257 // ######################################################################
01258 template <class T>
01259 Image<byte> segmentObjectClean(const Image<T>& src,
01260                                const Point2D<int>& seed, int numConn)
01261 {
01262   float start = 0.5, pstep = 0.05, mina = 0.05, expl = 1.05;
01263   float stop = 0.1;
01264   ASSERT(src.initialized());
01265   Image<T> tmp;
01266   bool explode = false; int prev = 0; double thresh = 1.0, minThresh = 0.0;
01267   double step = double(src.getVal(seed.i, seed.j)) * pstep;
01268   int minadiff = int(float(src.getSize()) * mina);
01269   double efac = expl;
01270   int iter = 0;
01271 
01272   // while still not explode and growth factor still above 1.0
01273   while(!explode && minadiff > 0 && efac > 1.0)
01274     {
01275       // update current threshold and minimum threshold
01276       thresh = double(src.getVal(seed.i, seed.j)) * start;
01277       minThresh = double(src.getVal(seed.i, seed.j)) * stop;
01278       iter = 0;
01279 
01280       // while still not explode and threshold still above minimum
01281       while(!explode && thresh > minThresh)
01282         {
01283           tmp.freeMem();
01284           int area = floodClean(src, tmp, seed, (T)thresh, (T)255.0, numConn);
01285           LDEBUG("%d->%d[%d] t=%.3f efac=%.3f",
01286                  prev, area, minadiff, thresh, efac);
01287 
01288           // make sure at least 1 iteration occur
01289           // make sure that the increase in area
01290           // does not go beyond "expl"
01291           if (iter > 1 && area > prev + minadiff &&
01292               area > int(double(prev)*efac))
01293               explode = true;
01294           else
01295             { prev = area; thresh -= step; }
01296           iter ++;
01297         }
01298 
01299       minadiff -= minadiff / 4; efac *= 0.95;
01300     }
01301 
01302   // write out segmented object: 255 in object, zero otherwise
01303   thresh += step;  // back 1 step before explosion
01304   tmp.freeMem();
01305   floodClean(src, tmp, seed, (T)thresh, (T)255.0, numConn);
01306 
01307   return Image<byte>(tmp);
01308 }
01309 
01310 // ######################################################################
01311 template <class T>
01312 Image<T> highThresh(const Image<T>& src, const T thresh, const T val)
01313 {
01314   ASSERT(src.initialized());
01315   Image<T> res(src);
01316   typename Image<T>::iterator aptr = res.beginw(), stop = res.endw();
01317 
01318   while (aptr != stop)
01319     {
01320       if (*aptr >= thresh) *aptr = val;
01321       ++aptr;
01322     }
01323   return res;
01324 }
01325 
01326 // ######################################################################
01327 template <class T_or_RGB>
01328 Image<T_or_RGB> replaceVals(const Image<T_or_RGB>& src,
01329                             const T_or_RGB from,
01330                             const T_or_RGB to,
01331                             const T_or_RGB other)
01332 {
01333   Image<T_or_RGB> result(src.getDims(), NO_INIT);
01334   typename Image<T_or_RGB>::const_iterator sptr = src.begin();
01335   typename Image<T_or_RGB>::iterator rptr = result.beginw();
01336   while (rptr != result.endw())
01337     *rptr++ = (*sptr++ == from) ? to : other;
01338   return result;
01339 }
01340 
01341 // ######################################################################
01342 template <class T_or_RGB>
01343 Image<T_or_RGB> replaceVals(const Image<T_or_RGB>& src,
01344                             const T_or_RGB from,
01345                             const T_or_RGB to)
01346 {
01347   if (from == to) return src;
01348   Image<T_or_RGB> result(src.getDims(), NO_INIT);
01349   typename Image<T_or_RGB>::const_iterator sptr = src.begin();
01350   typename Image<T_or_RGB>::iterator rptr;
01351   for (rptr = result.beginw(); rptr != result.endw(); ++rptr, ++sptr)
01352     *rptr = (*sptr == from) ? to : *sptr;
01353   return result;
01354 }
01355 
01356 // ######################################################################
01357 template <class T_or_RGB>
01358 Image<T_or_RGB> composite(const Image<T_or_RGB>& fg,
01359                           const Image<T_or_RGB>& bg,
01360                           const T_or_RGB transparent)
01361 {
01362   ASSERT(fg.isSameSize(bg));
01363 
01364   Image<T_or_RGB> result(fg.getDims(), NO_INIT);
01365   typename Image<T_or_RGB>::const_iterator
01366     fgptr = fg.begin(), bgptr = bg.begin(), stop = fg.end();
01367   typename Image<T_or_RGB>::iterator rptr = result.beginw();
01368 
01369   while(fgptr != stop)
01370     {
01371       if (*fgptr == transparent) *rptr++ = *bgptr;
01372       else *rptr++ = *fgptr;
01373 
01374       ++fgptr; ++bgptr;
01375     }
01376 
01377   return result;
01378 }
01379 
01380 // ######################################################################
01381 template <class T_or_RGB>
01382 Image<T_or_RGB> createMask(const Image<T_or_RGB>& fg,
01383                            const Image<bool> mask,
01384                            const T_or_RGB transparent = T_or_RGB())
01385 {
01386   ASSERT(fg.isSameSize(mask));
01387   Image<T_or_RGB> result(fg.getDims(), NO_INIT);
01388   typename Image<T_or_RGB>::const_iterator
01389     fgptr = fg.begin(), stop = fg.end();
01390   typename Image<bool>::const_iterator
01391     maskptr = mask.begin();
01392   typename Image<T_or_RGB>::iterator rptr = result.beginw();
01393 
01394   while(fgptr != stop)
01395     {
01396       if (*maskptr) *rptr++ = *fgptr; //non-zero
01397       else *rptr++ = transparent;
01398 
01399       ++fgptr; ++maskptr;
01400     }
01401 
01402   return result;
01403     
01404 }
01405 
01406 // ######################################################################
01407 template <class T_or_RGB>
01408 Image<T_or_RGB> mosaic(const Image<T_or_RGB>& fg,
01409                        const Image<T_or_RGB>* bg,
01410                        const T_or_RGB* transvalues,
01411                        const uint Nimages)
01412 {
01413   uint i;
01414   for(i = 0; i < Nimages; i++)
01415     ASSERT(fg.isSameSize(bg[i]));
01416 
01417   Image<T_or_RGB> result(fg.getDims(), NO_INIT);
01418   typename Image<T_or_RGB>::const_iterator
01419     fgptr = fg.begin(), stop = fg.end();
01420 
01421   typename Image<T_or_RGB>::const_iterator bgptr[Nimages];
01422   for(i = 0; i < Nimages; i++)
01423     bgptr[i] = bg[i].begin();
01424 
01425   typename Image<T_or_RGB>::iterator rptr = result.beginw();
01426 
01427   while(fgptr != stop)
01428     {
01429       i = 0;
01430       while(*fgptr != transvalues[i] && i < Nimages) i++;
01431       if (i < Nimages) 
01432         *rptr++ = *bgptr[i];
01433       else 
01434         *rptr++ = *fgptr;
01435 
01436       ++fgptr; 
01437       for(i = 0; i < Nimages; i++)
01438         bgptr[i]++;
01439     }
01440 
01441   return result;
01442 }
01443 
01444 // ######################################################################
01445 template <class T_or_RGB>
01446 Image<T_or_RGB> alphaBlend(const Image<T_or_RGB>& fg,
01447                            const Image<T_or_RGB>& bg,
01448                            const double alpha,
01449                            const T_or_RGB transparent)
01450 {
01451   ASSERT(fg.isSameSize(bg));
01452   ASSERT(alpha>=0 && alpha<=1);
01453 
01454   Image<T_or_RGB> result(fg.getDims(), NO_INIT);
01455   typename Image<T_or_RGB>::const_iterator
01456     fgptr = fg.begin(), bgptr = bg.begin(), stop = fg.end();
01457   typename Image<T_or_RGB>::iterator rptr = result.beginw();
01458 
01459   while(fgptr != stop)
01460     {
01461       if (*fgptr == transparent) *rptr++ = *bgptr;
01462       else *rptr++ = T_or_RGB((*fgptr) * (1-alpha) + T_or_RGB(*bgptr) * alpha);
01463 
01464       ++fgptr; ++bgptr;
01465     }
01466 
01467   return result;
01468 }
01469 
01470 // ######################################################################
01471 template <class T>
01472 Image<byte> makeBinary(const Image<T>& src, const T& threshold,
01473                        const byte lowVal, const byte highVal)
01474 {
01475   Image<byte> result(src.getDims(), NO_INIT);
01476   typename Image<T>::const_iterator sptr = src.begin();
01477   Image<byte>::iterator rptr = result.beginw(), stop = result.endw();
01478   while (rptr != stop)
01479     *rptr++ = (*sptr++ <= threshold) ? lowVal : highVal;
01480   return result;
01481 }
01482 
01483 // ######################################################################
01484 template <class T>
01485 Image<byte> makeBinary2(const Image<T>& src,
01486     const T& lowThresh, const T& highThresh,
01487     const byte lowVal, const byte highVal)
01488 {
01489   Image<byte> result(src.getDims(), NO_INIT);
01490   typename Image<T>::const_iterator sptr = src.begin();
01491   Image<byte>::iterator rptr = result.beginw(), stop = result.endw();
01492   while (rptr != stop)
01493   {
01494     *rptr++ = (*sptr >= lowThresh && *sptr <= highThresh) ? highVal : lowVal;
01495     sptr++;
01496   }
01497   return result;
01498 }
01499 
01500 // ######################################################################
01501 template <class T_or_RGB>
01502 void pasteImage(Image<T_or_RGB>& background,
01503                 const Image<T_or_RGB>& foreground,
01504                 const T_or_RGB& transparent,
01505                 const Point2D<int> location,
01506                 float opacity)
01507 {
01508   float op2 = 1.0F - opacity;
01509   int bw = background.getWidth();
01510   int bh = background.getHeight();
01511   int fw = foreground.getWidth();
01512   int fh = foreground.getHeight();
01513 
01514   Point2D<int> bStart = location;
01515   Point2D<int> fStart(0,0);
01516   Point2D<int> bEnd(location.i + fw, location.j + fh);
01517   Point2D<int> fEnd(fw,fh);
01518 
01519   if (bStart.i < 0) { fStart.i -= bStart.i; bStart.i = 0; }
01520   if (bStart.j < 0) { fStart.j -= bStart.j; bStart.j = 0; }
01521   if (bEnd.i > bw) { fEnd.i -= (bEnd.i - bw); bEnd.i = bw; }
01522   if (bEnd.j > bh) { fEnd.j -= (bEnd.j - bh); bEnd.j = bh; }
01523 
01524   // initialize the iterators
01525   typename Image<T_or_RGB>::iterator bPtr1, bPtr2;
01526   typename Image<T_or_RGB>::const_iterator fPtr1, fPtr2;
01527   bPtr1 = background.beginw() + bStart.j * bw + bStart.i;
01528   fPtr1 = foreground.begin()  + fStart.j * fw + fStart.i;
01529 
01530   // loop over the image patch and paste it in
01531   for (int y = bStart.j; y < bEnd.j; ++y)
01532     {
01533       bPtr2 = bPtr1; fPtr2 = fPtr1;
01534       for (int x = bStart.i; x < bEnd.i; ++x)
01535         {
01536           if (*fPtr2 != transparent)
01537             *bPtr2 = T_or_RGB(*bPtr2 * op2 + *fPtr2 * opacity);
01538           ++bPtr2; ++fPtr2;
01539         }
01540       bPtr1 += bw; fPtr1 += fw;
01541     }
01542 }
01543 
01544 // ######################################################################
01545 template <class T>
01546 void inplacePasteGabor(Image<T>& dst,
01547                        const Image<T>& gabor,
01548                        const Point2D<int>& pos, const T background)
01549 {
01550   int w = dst.getWidth(), h = dst.getHeight();
01551   int iw = gabor.getWidth(), ih = gabor.getHeight();
01552   ASSERT(pos.i + iw <= w && pos.j + ih <= h);
01553   T dist, idist;
01554 
01555   typename Image<T>::const_iterator sptr = gabor.begin();
01556   typename Image<T>::iterator dptr = dst.beginw() + pos.i + pos.j * w;
01557   for (int j = 0; j < ih; j ++)
01558     {
01559       for (int i = 0; i < iw; i ++)
01560         {
01561           dist = T(*dptr - background);
01562           if (dist < 0.0F) dist = T(dist * -1);
01563           if (*sptr < 0.0F) idist = T(*sptr * -1);
01564           else idist = *sptr;
01565           //take the value furthest from grey (background)
01566           if (dist < idist)
01567             {
01568               *dptr = T(*sptr+background);
01569             }
01570           dptr++;
01571           sptr++;
01572         }
01573       dptr += w - iw;
01574     }
01575 }
01576 
01577 // ######################################################################
01578 template <class T>
01579 int flood(const Image<T>& src,
01580           Image<T>& dest, const Point2D<int>& seed,
01581           const T thresh, const T val)
01582 {
01583   ASSERT(src.initialized());
01584   ASSERT(src.coordsOk(seed));
01585 
01586   // clear destination image if necessary
01587   if (!dest.initialized()) dest.resize(src.getDims(), true);
01588 
01589   if (src.getVal(seed) < thresh) return -1; // starting point not in object
01590 
01591   const T zero = T();
01592 
01593   const int size = src.getSize();
01594   const int w = src.getWidth();
01595 
01596   // Allocate space for the recursion stack
01597   std::vector<int> stk;
01598 
01599   const int STACKSIZE = 256 * 256 + 20;
01600   stk.reserve(STACKSIZE);
01601 
01602   stk.push_back(seed.i + w * seed.j);
01603 
01604   Image<T> input = src;  // copy input because we will modify it
01605   typename Image<T>::iterator const inptr = input.beginw();
01606 
01607   int nbpix = 0;
01608 
01609   while (! stk.empty())
01610     {
01611       int index = stk.back(); stk.pop_back();
01612       if (inptr[index] != zero)  // we have not already visited this point
01613         {
01614           // we know that the current point IS in our object:
01615           dest.setVal(index, val);  // flood output
01616           inptr[index] = zero;      // clear this point in input
01617           ++nbpix;                 // one more flooded pixel
01618 
01619           // explore recursively the 8-connected neighbors:
01620           if ((index+1 < size) && (inptr[index+1] >= thresh))
01621             stk.push_back( index+1 );
01622 
01623           if ((index+w < size) && (inptr[index+w] >= thresh))
01624             stk.push_back( index+w );
01625 
01626           if ((index+w+1 < size) && (inptr[index+w+1] >= thresh))
01627             stk.push_back( index+w+1 );
01628 
01629           if ((index+w-1 < size) && (inptr[index+w-1] >= thresh))
01630             stk.push_back( index+w-1 );
01631 
01632           if ((index-1 >= 0) && (inptr[index-1] >= thresh))
01633             stk.push_back( index-1 );
01634 
01635           if ((index-w >= 0) && (inptr[index-w] >= thresh))
01636             stk.push_back( index-w );
01637 
01638           if ((index-w-1 >= 0) && (inptr[index-w-1] >= thresh))
01639             stk.push_back( index-w-1 );
01640 
01641           if ((index-w+1 >= 0) && (inptr[index-w+1] >= thresh))
01642             stk.push_back( index-w+1 );
01643         }
01644     }
01645   return nbpix;
01646 }
01647 
01648 // ######################################################################
01649 template <class T>
01650 int countParticles(const Image<T>& src, const T thresh)
01651 {
01652   Point2D<int> p;
01653   int nbpart = 0;
01654   Image<T> tmp = src;
01655   T fill = thresh;
01656   const T zero = T();
01657   if (fill >= zero + (T)1.0) fill -= (T)1.0;  // fill with val below thresh
01658   else LFATAL("Cannot count particles with such low threshold");
01659 
01660   for (p.i = 0; p.i < src.getWidth(); ++p.i)
01661     for (p.j = 0; p.j < src.getHeight(); ++p.j)
01662       if (tmp.getVal(p) >= thresh)  // found one particle
01663         {
01664           ++nbpart;
01665           Image<T> tmp2 = tmp;
01666           flood(tmp2, tmp, p, thresh, fill);  // discard it
01667         }
01668   return nbpart;
01669 }
01670 
01671 // ######################################################################
01672 template <class T>
01673 void inplaceAddBGnoise(Image<T>& src, const float range)
01674 {
01675 // background noise level: as coeff of map full dynamic range:
01676 #define BGNOISELEVEL 0.00001
01677 
01678   inplaceAddBGnoise2(src, range * BGNOISELEVEL);
01679 }
01680 
01681 // ######################################################################
01682 template <class T>
01683 void inplaceAddBGnoise2(Image<T>& src, const float range)
01684 {
01685   ASSERT(src.initialized());
01686   const int w = src.getWidth(), h = src.getHeight();
01687 
01688   // do not put noise very close to image borders:
01689   int siz = std::min(w, h) / 10;
01690 
01691   typename Image<T>::iterator sptr = src.beginw() + siz + siz * w;
01692 
01693   for (int j = siz; j < h - siz; ++j)
01694     {
01695       for (int i = siz; i < w - siz; ++i)
01696         *sptr++ += clamped_convert<T>(range * randomDouble());
01697       sptr += siz + siz;
01698     }
01699 }
01700 
01701 // Include the explicit instantiations
01702 #include "inst/Image/Transforms.I"
01703 
01704 // ######################################################################
01705 /* So things look consistent in everyone's emacs... */
01706 /* Local Variables: */
01707 /* indent-tabs-mode: nil */
01708 /* End: */
01709 
01710 #endif // !IMAGE_TRANSFORMS_C_DEFINED
Generated on Sun May 8 08:40:57 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3