# GABOR

Gabor变换的本质实际上还是对二维图像求卷积。因此二维卷积运算的效率就直接决定了Gabor变换的效率。在这里我先说说二维卷积运算以及如何通过二维傅立叶变换提高卷积运算效率。在下一步分内容中我们将此应用到Gabor变换上，抽取笔迹纹理的特征。

1、离散二维叠加和卷积

2、快速傅立叶变换卷积

using System;
using Exocortex.DSP;
class MainEntry
{
static void Main()
{
fftConv2 c = new fftConv2();
c.DoFFTConv2();
}
}
public class fftConv2
{
double[,] kernel = {{-1, 1},
{0, 1}};
double[,] data = {{10,5,20,20,20},
{10,5,20,20,20},
{10,5,20,20,20},
{10,5,20,20,20},
{10,5,20,20,20}};
Complex[] Kernel = new Complex[8*8];
Complex[] Data = new Complex[8*8];
Complex[] Result = new Complex[8*8];
private void Init()
{
for(int y=0; y<2; y++)
for(int x=0; x<2; x++)
Kernel[y*8+x].Re = kernel[y,x];
for(int y=0; y<5; y++)
for(int x=0; x<5; x++)
Data[y*8+x].Re = data[y,x];
}
public void DoFFTConv2()
{
Init();
Fourier.FFT2(Data, 8, 8, FourierDirection.Forward);
Fourier.FFT2(Kernel, 8, 8, FourierDirection.Forward);
for(int i=0; i<8*8; i++)
Result[i] = Data[i] * Kernel[i] / (8*8);
Fourier.FFT2(Result, 8, 8, FourierDirection.Backward);
for(int y=0; y<6; y++)
{
for(int x=0; x<6; x++)
Console.Write("{0,8:F2}", Result[y*8+x].Re);
Console.WriteLine();
}
}
}

using System;
using Exocortex.DSP;
class MainEntry
{
static void Main()
{
CenterfftConv2 s = new CenterfftConv2();
s.CommonMethod();
s.DoFFTConv2();
}
}
public class CenterfftConv2
{
double[,] kernel = {{0, 1, 0},
{1, 2, 0},
{0, 0, 3}};
double[,] data = new double[12,12];
Complex[] Kernel = new Complex[16*16];
Complex[] Data = new Complex[16*16];
Complex[] Result = new Complex[16*16];
public CenterfftConv2()
{
Random r = new Random();
for(int y=0; y<12; y++)
for(int x=0; x<12; x++)
data[y,x] = r.NextDouble();
for(int y=0; y<3; y++)
for(int x=0; x<3; x++)
Kernel[y*16+x].Re = kernel[y,x];
for(int y=1; y<13; y++)
for(int x=1; x<13; x++)
Data[y*16+x].Re = data[y-1,x-1];
}
public void DoFFTConv2()
{
Console.WriteLine(" ========= By FFT2Conv2 Method =========");
Fourier.FFT2(Data, 16, 16, FourierDirection.Forward);
Fourier.FFT2(Kernel, 16, 16, FourierDirection.Forward);
for(int i=0; i<16*16; i++)
Result[i] = Data[i] * Kernel[i] / (16*16);
Fourier.FFT2(Result, 16, 16, FourierDirection.Backward);
for(int y=2; y<14; y++)
{
for(int x=2; x<14; x++)
Console.Write("{0,5:F2}", Result[y*16+x].GetModulus());
Console.WriteLine();
}
}
public void CommonMethod()
{
double real = 0;
Console.WriteLine(" ========== Direct Transform ===========");
for(int y=0; y < 12; y++)
{
for(int x=0; x < 12; x++)
{
for(int y1=0; y1 < 3; y1++)
for(int x1=0; x1 < 3; x1++)
{
// (kernel.Length-1)/2 = 1
if(((y - 1 + y1)>=0) &&
((y - 1 + y1)<12) &&
((x - 1 + x1)>=0) &&
((x - 1 + x1)<12))
{
real += data[y - 1 + y1, x - 1 + x1] * kernel[2 - x1, 2 - y1];
}
}
Console.Write("{0,5:F2}", real);
real=0;
}
Console.WriteLine();
}
Console.WriteLine("n");
}
}

Gabor变换属于加窗傅立叶变换，Gabor函数可以在频域不同尺度、不同方向上提取相关的特征。另外Gabor函数与人眼的生物作用相仿，所以经常用作纹理识别上，并取得了较好的效果。二维Gabor函数可以表示为：

v的取值决定了Gabor滤波的波长，u的取值表示Gabor核函数的方向，K表示总的方向数。参数决定了高斯窗口的大小，这里取。程序中取4个频率（v=0, 1, ..., 3），8个方向（即K=8，u＝0, 1, ... ,7），共32个Gabor核函数。不同频率不同方向的Gabor函数可通过下图表示：

Gabor函数是复值函数，因此在运算过程中要分别计算其实部和虚部。代码如下：

private void CalculateKernel(int Orientation, int Frequency)
{
double real, img;
for(int x = -(GaborWidth-1)/2; x<(GaborWidth-1)/2+1; x++)
for(int y = -(GaborHeight-1)/2; y<(GaborHeight-1)/2+1; y++)
{
real = KernelRealPart(x, y, Orientation, Frequency);
img = KernelImgPart(x, y, Orientation, Frequency);
KernelFFT2[(x+(GaborWidth-1)/2) + 256 * (y+(GaborHeight-1)/2)].Re = real;
KernelFFT2[(x+(GaborWidth-1)/2) + 256 * (y+(GaborHeight-1)/2)].Im = img;
}
}
private double KernelRealPart(int x, int y, int Orientation, int Frequency)
{
double U, V;
double Sigma, Kv, Qu;
double tmp1, tmp2;
U = Orientation;
V = Frequency;
Sigma = 2 * Math.PI * Math.PI;
Kv = Math.PI * Math.Exp((-(V+2)/2)*Math.Log(2, Math.E));
Qu = U * Math.PI / 8;
tmp1 = Math.Exp(-(Kv * Kv * ( x*x + y*y)/(2 * Sigma)));
tmp2 = Math.Cos(Kv * Math.Cos(Qu) * x + Kv * Math.Sin(Qu) * y) - Math.Exp(-(Sigma/2));
return tmp1 * tmp2 * Kv * Kv / Sigma;
}
private double KernelImgPart(int x, int y, int Orientation, int Frequency)
{
double U, V;
double Sigma, Kv, Qu;
double tmp1, tmp2;
U = Orientation;
V = Frequency;
Sigma = 2 * Math.PI * Math.PI;
Kv = Math.PI * Math.Exp((-(V+2)/2)*Math.Log(2, Math.E));
Qu = U * Math.PI / 8;
tmp1 = Math.Exp(-(Kv * Kv * ( x*x + y*y)/(2 * Sigma)));
tmp2 = Math.Sin(Kv * Math.Cos(Qu) * x + Kv * Math.Sin(Qu) * y) - Math.Exp(-(Sigma/2));
return tmp1 * tmp2 * Kv * Kv / Sigma;
}

[@more@]

• 博文量
17
• 访问量
33772