00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #ifndef NEURO_GISTESTIMATORFFT_C_DEFINED
00042 #define NEURO_GISTESTIMATORFFT_C_DEFINED
00043
00044 #include "Neuro/GistEstimatorFFT.H"
00045
00046 #include "Neuro/gistParams.H"
00047 #include "Channels/IntensityChannel.H"
00048 #include "Image/Kernels.H"
00049 #include "Image/CutPaste.H"
00050 #include "Image/MathOps.H"
00051 #include "Image/DrawOps.H"
00052 #include "Raster/Raster.H"
00053
00054 #include "Simulation/SimEventQueue.H"
00055 #include "Neuro/NeuroSimEvents.H"
00056 #include "Simulation/SimEvents.H"
00057
00058 #define NUM_G_LEV 5 // number of gabor levels
00059 #define NUM_G_DIR 8 // number of gabor orientations
00060
00061 #define WIN_NUM 4 // 4: 4 by 4 windows
00062
00063
00064 GistEstimatorFFT::GistEstimatorFFT(OptionManager& mgr,
00065 const std::string& descrName,
00066 const std::string& tagName)
00067 :
00068 GistEstimatorAdapter(mgr, descrName, tagName),
00069 SIMCALLBACK_INIT(SimEventRetinaImage)
00070 {
00071 gaborMaskImg = NULL;
00072
00073
00074 itsGistVector.resize
00075 (1, WIN_NUM * WIN_NUM * NUM_G_LEV * NUM_G_DIR, NO_INIT);
00076 }
00077
00078
00079 GistEstimatorFFT::~GistEstimatorFFT()
00080 { }
00081
00082
00083 Image<double> GistEstimatorFFT::getGist()
00084 {
00085 return itsGistVector;
00086 }
00087
00088
00089 void GistEstimatorFFT::
00090 onSimEventRetinaImage(SimEventQueue& q, rutz::shared_ptr<SimEventRetinaImage>& e)
00091 {
00092 Image<float> img = normalize(e->frame().grayFloat());
00093 computeGistFeatureVector(img);
00094 LINFO("Gist features are computed");
00095
00096
00097 rutz::shared_ptr<SimEventGistOutput>
00098 ew(new SimEventGistOutput(this, itsGistVector));
00099 q.post(ew);
00100 }
00101
00102
00103 void GistEstimatorFFT::computeGistFeatureVector(Image<float> img)
00104 {
00105
00106
00107 int w = img.getWidth()/WIN_NUM, h = img.getHeight()/WIN_NUM;
00108 Image<float> wImg(w,h, ZEROS);
00109
00110 itsFftImage.resize(img.getDims());
00111
00112
00113 if((gaborMaskImg == NULL) ||
00114 (w != gaborMaskImg[0][0].getWidth() ) ||
00115 (h != gaborMaskImg[0][0].getHeight()))
00116 {
00117
00118
00119
00120 LDEBUG("w: %d, h: %d",w,h);
00121 setupFFTW(w,h);
00122 }
00123
00124
00125
00126 Image<float> cImg(img.getWidth(), img.getHeight(), ZEROS);
00127 Image<float> dImg = img;
00128 float mn, mx; getMinMax(dImg,mn,mx);
00129 drawGrid(dImg, img.getWidth()/4,img.getHeight()/4,1,1, mx);
00130
00131 Image<double>::iterator aptr = itsGistVector.beginw();
00132 for(uint ii = 0; ii < WIN_NUM; ii++)
00133 for(uint jj = 0; jj < WIN_NUM; jj++)
00134 {
00135 Point2D<int> p((ii*img.getWidth())/WIN_NUM,
00136 (jj*img.getHeight())/WIN_NUM);
00137 Rectangle r(p, Dims(w,h));
00138 wImg = crop(img, r);
00139
00140
00141
00142 fftCompute(wImg, itsOutFftwBuffer);
00143
00144
00145 for(int i = 0; i < NUM_G_LEV; i++)
00146 for(int j = 0; j < NUM_G_DIR; j++)
00147 {
00148
00149 double sum = 0.0;
00150 for(int k = 0; k < h; k++)
00151 for(int l = 0; l < w/2+1; l++)
00152 {
00153 sum += log(1.0 + gaborMask[i][j][k][l]) *
00154 log(1.0 + itsOutFftwBuffer[k][l]);
00155 }
00156 *aptr++ = sum/(h*w/2+1);
00157 }
00158
00159
00160 Image<float> temp = getFftImage(itsOutFftwBuffer, w, h);
00161 LDEBUG("w,h:%d:%d: i,j:%d:%d [%d %d]",
00162 ii*w, jj*h, temp.getWidth(), temp.getHeight(),
00163 itsFftImage.getWidth(), itsFftImage.getHeight());
00164
00165 inplacePaste(itsFftImage, temp, Point2D<int>(ii*w, jj*h));
00166 }
00167 }
00168
00169
00170
00171 void GistEstimatorFFT::setupFFTW(int w, int h)
00172 {
00173 itsFftw = new FFTWWrapper(w,h);
00174 delete [] itsFftwBuffer;
00175 itsFftwBuffer = new double[w*h];
00176 itsFftw->init(itsFftwBuffer);
00177
00178
00179 itsOutFftwBuffer = new double*[h];
00180 for(int i = 0; i < h; i++)
00181 itsOutFftwBuffer[i] = new double[w/2+1];
00182
00183
00184 setupGaborMask(w,h);
00185 }
00186
00187
00188 void GistEstimatorFFT::setupGaborMask(int w, int h)
00189 {
00190 int dim = (w<h)?w:h;
00191 float stdev = double(floor((dim - 3.0)/2.0/sqrt(10.0)));
00192 float period = double(stdev * 2.0);
00193 LDEBUG("w:h: %d:%d; dim -> %d== %f, %f",w,h,dim, stdev, period);
00194 itsStddev = stdev;
00195
00196
00197 gaborMask = new double***[NUM_G_LEV];
00198 for(int i = 0; i < NUM_G_LEV; i++)
00199 gaborMask[i] = new double**[NUM_G_DIR];
00200
00201 gaborMaskImg = new Image<float>*[NUM_G_LEV];
00202 for(int i = 0; i < NUM_G_LEV; i++)
00203 gaborMaskImg[i] = new Image<float>[NUM_G_DIR];
00204
00205
00206 float scale = 1.0;
00207 for(int i = 0; i < NUM_G_LEV; i++)
00208 {
00209 for(int j = 0; j < NUM_G_DIR; j++)
00210 {
00211
00212 gaborMask[i][j] = new double*[h];
00213 for(int k = 0; k < h; k++)
00214 gaborMask[i][j][k] = new double[w/2+1];
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 computeFFTgabor(stdev/scale, period/scale, (j*180.0)/NUM_G_DIR, w, h,
00228 gaborMask[i][j]);
00229
00230 gaborMaskImg[i][j] = getFftImage(gaborMask[i][j], w, h);
00231
00232
00233
00234 }
00235 scale *= 2;
00236 }
00237 }
00238
00239
00240 void GistEstimatorFFT::computeFFTgabor
00241 ( const float stddev, const float period,
00242 const float theta, uint w, uint h, double **gm)
00243 {
00244 float rtDeg = M_PI / 180.0F * theta;
00245 LDEBUG("std: %f, period: %f 1/p:[%f], theta: %f:%f:: cos: %f, sin: %f",
00246 stddev, period, 1.0/period, theta,rtDeg, cos(rtDeg), sin(rtDeg));
00247
00248 double aSq = 1/(2.0*M_PI*stddev*stddev);
00249 double Kf = itsStddev*8.0;
00250 float X = M_PI/aSq/4800.0;
00251 LDEBUG("Kf: %f X: %f, a^2: %f", Kf, X, aSq);
00252
00253
00254
00255
00256 double co = cos(rtDeg); double si = sin(rtDeg);
00257 double u0 = Kf*co/period; double v0 = Kf*si/period;
00258 LDEBUG("1: [u0,v0]:[%f,%f]", u0,v0);
00259 for(uint i = 0; i < w/2+1; i++)
00260 {
00261 for(uint j = 0; j < h/2; j++)
00262 {
00263 float ur = (float(i) - u0)*co + (float(j) - v0)*si;
00264 float vr = -1.0*(float(i) - u0)*si + (float(j) - v0)*co;
00265 gm[j][i] = exp(-X*(ur*ur + vr*vr))/aSq;
00266
00267 }
00268 }
00269
00270 co = cos(rtDeg); si = sin(rtDeg);
00271 u0 = Kf*co/period; v0 = Kf*si/period + float(h);
00272 LDEBUG("2: [u0,v0]:[%f,%f]", u0,v0);
00273 for(uint i = 0; i < w/2+1; i++)
00274 {
00275 for(uint j = h/2; j < h; j++)
00276 {
00277 float ur = (float(i) - u0)*co + (float(j) - v0)*si;
00278 float vr = -1.0*(float(i) - u0)*si + (float(j) - v0)*co;
00279 gm[j][i] = exp(-X*(ur*ur + vr*vr))/aSq;
00280 }
00281 }
00282
00283 co = cos(-rtDeg); si = sin(-rtDeg);
00284 u0 = -Kf*co/period; v0 = Kf*si/period;
00285 LDEBUG("3: [u0,v0]:[%f,%f]", u0,v0);
00286 for(uint i = 0; i < w/2+1; i++)
00287 {
00288 for(uint j = 0; j < h/2; j++)
00289 {
00290 float ur = (float(i) - u0)*co + (float(j) - v0)*si;
00291 float vr = -1.0*(float(i) - u0)*si + (float(j) - v0)*co;
00292 gm[j][i] += exp(-X*(ur*ur + vr*vr))/aSq;
00293 }
00294 }
00295
00296 co = cos(-rtDeg); si = sin(-rtDeg);
00297 u0 = -Kf*co/period; v0 = Kf*si/period + float(h);
00298 LDEBUG("4: [u0,v0]:[%f,%f]", u0,v0);
00299 for(uint i = 0; i < w/2+1; i++)
00300 {
00301 for(uint j = h/2; j < h; j++)
00302 {
00303 float ur = (float(i) - u0)*co + (float(j) - v0)*si;
00304 float vr = -1.0*(float(i) - u0)*si + (float(j) - v0)*co;
00305 gm[j][i] += exp(-X*(ur*ur + vr*vr))/aSq;
00306 }
00307 }
00308 }
00309
00310
00311
00312
00313 void GistEstimatorFFT::fftCompute(Image<float> img, double **fftOut)
00314 {
00315 int w = img.getWidth(), h = img.getHeight();
00316
00317 double *itsFftwInputData = itsFftwBuffer;
00318 for(int j = 0; j < h; j++)
00319 for(int i = 0; i < w; i++)
00320 *itsFftwInputData++ = (double)img.getVal(i,j);
00321
00322 itsFftw->compute(fftOut);
00323 }
00324
00325
00326 Image<float> GistEstimatorFFT::getFftImage(double **res, int w, int h)
00327 {
00328
00329
00330
00331
00332
00333 float gc = 1.5;
00334
00335
00336 Image<float> ftImg(w,h,ZEROS);
00337 for(int i = 0; i < w/2; i++)
00338 for(int j = 0; j < h/2; j++)
00339 ftImg.setVal(i+w/2, h/2-j,
00340 pow(log(1.0 + res[j][i+1]), gc));
00341
00342 for(int i = 0; i < w/2; i++)
00343 for(int j = h/2; j < h; j++)
00344 ftImg.setVal(i+w/2, 3*h/2-1-j,
00345 pow(log(1.0 + res[j][i+1]), gc));
00346
00347 for(int i = 0; i < w/2; i++)
00348 for(int j = 0; j < h; j++)
00349 ftImg.setVal(i, j, ftImg.getVal(w-1-i, h-1-j));
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367 return ftImg;
00368 }
00369
00370
00371
00372 Image<float> GistEstimatorFFT::normalize(Image<float> img)
00373 {
00374 Image<float> tImg = img;
00375 double tMean = float(mean(img));
00376 double tStdev = float(stdev(img));
00377 tImg -= tMean;
00378 tImg /= tStdev;
00379
00380 return tImg;
00381 }
00382
00383
00384 Image<float> GistEstimatorFFT::getFftImage()
00385 {
00386 return itsFftImage;
00387 }
00388
00389
00390
00391
00392
00393
00394
00395 #endif // NEURO_GISTESTIMATORFFT_C_DEFINED