//*************************************************************************** #include <stdio.h> #include <stdlib.h> #include <math.h> #include "image.h" #include "matrix.h" #include "gabor.h" //*************************************************************************** // The Gabor routine is modified from the following code: // http://vivaldi.ece.ucsb.edu/users/wei/code_gabor/ //*************************************************************************** // The Gabor function generates a Gabor filter with the selected index 's' // and 'n' (scale and orientation, respectively) from a Gabor filter bank. // This filter bank is designed by giving the range of spatial frequency // (Uh and Ul) and the total number of scales and orientations used to // partition the spectrum. // // The returned filter is stored in 'Gr' (real part) and 'Gi' (imaginary part). // // Symbol translation from paper (pg 19, 20 of extended paper): // http://vivaldi.ece.ucsb.edu/users/wei/mypapers/edgeflow.ps.gz // S = scale // k = orientation //*************************************************************************** // The GaborFilteredImg provides the outputs of the Gabor filter bank void GaborFilteredImg(Matrix **OutR, Matrix **OutI, Matrix &img, int side, double Ul, double Uh, int scale, int orientation, int flag) { int border = side; int height = img.nx; int width = img.ny; /* FFT2 */ int xs = (int) pow(2.0, ceil(log2((double)(height+2.0*border)))); int ys = (int) pow(2.0, ceil(log2((double)(width+2.0*border)))); Matrix IMG(xs,ys); int r1, r2, r3, r4; r1 = width+border; r2 = width+2*border; for (int w = 0; w < border; w++) { for (int h = 0; h < border; h++) IMG.p[w][h] = img.p[border-1-w][border-1-h]; for (int h = border; h < r1; h++) IMG.p[w][h] = img.p[border-1-w][h-border]; for (int h = r1; h < r2; h++) IMG.p[w][h] = img.p[border-1-w][2*width-h+border-1]; } r1 = height+border; r2 = width+border; r3 = width+2*border; for (int w = border; w < r1; w++) { for (int h = 0; h < border; h++) IMG.p[w][h] = img.p[w-border][border-1-h]; for (int h = border; h < r2; h++) IMG.p[w][h] = img.p[w-border][h-border]; for (int h = r2; h < r3; h++) IMG.p[w][h] = img.p[w-border][2*width-h+border-1]; } r1 = height+border; r2 = height+2*border; r3 = width+border; r4 = width+2*border; for (int w = r1; w < r2; w++) { for (int h = 0; h < border; h++) IMG.p[w][h] = img.p[2*height-w+border-1][border-1-h]; for (int h = border; h < r3; h++) IMG.p[w][h] = img.p[2*height-w+border-1][h-border]; for (int h = r3; h < r4; h++) IMG.p[w][h] = img.p[2*height-w+border-1][2*width-h+border-1]; } Matrix F_real(xs,ys), F_imag(xs,ys), IMG_imag(xs,ys); MatrixFFT2D(&F_real, &F_imag, &IMG, &IMG_imag); // ----------- compute the Gabor filtered output ------------- Matrix Gr(2*side+1, 2*side+1), Gi(2*side+1, 2*side+1); Matrix Tmp_1(xs,ys), Tmp_2(xs,ys); Matrix F_1(xs,ys), F_2(xs,ys); Matrix G_real(xs,ys), G_imag(xs,ys); cout << " GaborFilteredImg (S=" << scale << ",N=" << orientation << "): Processing Image 0/" << scale*orientation; for (int s = 0; s < scale; s++) { for (int n = 0; n < orientation; n++) { cout << "\r GaborFilteredImg (S=" << scale << ",N=" << orientation << "): Processing Image " << s*orientation+n+1 << "/" << scale*orientation; cout.flush(); Gabor(&Gr, &Gi, s+1, n+1, Ul, Uh, scale, orientation, flag); MatCopy(&F_1, &Gr, 0, 0, 0, 0, 2*side, 2*side); MatCopy(&F_2, &Gi, 0, 0, 0, 0, 2*side, 2*side); MatrixFFT2D(&G_real, &G_imag, &F_1, &F_2); // ^ stands for pixel by pixel multiplication Tmp_1 = G_real ^ F_real; Tmp_2 = G_imag ^ F_imag; IMG = Tmp_1 - Tmp_2; // ^ stands for pixel by pixel multiplication Tmp_1 = G_real ^ F_imag; Tmp_2 = G_imag ^ F_real; IMG_imag = Tmp_1 + Tmp_2; MatrixIFFT2D(&Tmp_1, &Tmp_2, &IMG, &IMG_imag); MatCopy(&OutR[s][n], &Tmp_1, 0, 0, 2*border, 2*border, height+2*border-1, width+2*border-1); MatCopy(&OutI[s][n], &Tmp_2, 0, 0, 2*border, 2*border, height+2*border-1, width+2*border-1); } } cout << "...done!" << endl; cout.flush(); } //*************************************************************************** void Gabor(Matrix *Gr, Matrix *Gi, int s, int n, double Ul, double Uh, int scale, int orientation, int flag) { double base = Uh/Ul; double a = pow(base, 1.0/(double)(scale-1)); double u0 = Uh/pow(a, (double) (scale-s)); double Uvar = (a-1.0)*u0/((a+1.0)*sqrt(2.0*log(2.0))); double z = -2.0*log(2.0)*(Uvar*Uvar)/u0; double Vvar = tan(Pi/(2*orientation))*(u0+z)/sqrt(2.0*log(2.0)-z*z/(Uvar*Uvar)); double Xvar = 1.0/(2.0*Pi*Uvar); double Yvar = 1.0/(2.0*Pi*Vvar); double t1 = cos(Pi/orientation*(n-1.0)); double t2 = sin(Pi/orientation*(n-1.0)); int side = (Gr->nx-1)/2; for (int x = 0; x < 2*side+1; x++) { for (int y = 0; y < 2*side+1; y++) { double X = (double) ( (x-side)*t1 + (y-side)*t2); double Y = (double) (-(x-side)*t2 + (y-side)*t1); double G = 1.0/(2.0*Pi*Xvar*Yvar)*pow(a, (double) (scale-s)) *exp(-0.5*((X*X)/(Xvar*Xvar)+(Y*Y)/(Yvar*Yvar))); Gr->p[x][y] = G*cos(2.0*Pi*u0*X); Gi->p[x][y] = G*sin(2.0*Pi*u0*X); } } /* if flag = 1, then remove the DC from the filter */ if (flag == 1) { double m = 0.0; for (int x = 0; x < 2*side+1; x++) for (int y = 0; y < 2*side+1; y++) m += Gr->p[x][y]; m /= pow((double) (2.0*side+1), 2.0); for (int x = 0; x < 2*side+1; x++) for (int y = 0; y < 2*side+1; y++) Gr->p[x][y] -= m; } } //***************************************************************************