【发布时间】:2019-02-03 19:35:25
【问题描述】:
Here 我们有 Gabor 滤波器的空间域实现。但是,我需要在频域中实现一个 Gabor 滤波器for performance reasons.
我找到了Frequency Domain equation of Gabor Filter:
我实际上怀疑这个公式的正确性和/或适用性。
源代码
所以,我实现了以下内容:
public partial class GaborFfftForm : Form
{
private double Gabor(double u, double v, double f0, double theta, double a, double b)
{
double rad = Math.PI / 180 * theta;
double uDash = u * Math.Cos(rad) + v * Math.Sin(rad);
double vDash = (-1) * u * Math.Sin(rad) + v * Math.Cos(rad);
return Math.Exp((-1) * Math.PI * Math.PI * ((uDash - f0) / (a * a)) + (vDash / (b * b)));
}
public Array2d<Complex> GaborKernelFft(int sizeX, int sizeY, double f0, double theta, double a, double b)
{
int halfX = sizeX / 2;
int halfY = sizeY / 2;
Array2d<Complex> kernel = new Array2d<Complex>(sizeX, sizeY);
for (int u = -halfX; u < halfX; u++)
{
for (int v = -halfY; v < halfY; v++)
{
double g = Gabor(u, v, f0, theta, a, b);
kernel[u + halfX, v + halfY] = new Complex(g, 0);
}
}
return kernel;
}
public GaborFfftForm()
{
InitializeComponent();
Bitmap image = DataConverter2d.ReadGray(StandardImage.LenaGray);
Array2d<double> dImage = DataConverter2d.ToDouble(image);
int newWidth = Tools.ToNextPowerOfTwo(dImage.Width) * 2;
int newHeight = Tools.ToNextPowerOfTwo(dImage.Height) * 2;
double u0 = 0.2;
double v0 = 0.2;
double alpha = 10;//1.5;
double beta = alpha;
Array2d<Complex> kernel2d = GaborKernelFft(newWidth, newHeight, u0, v0, alpha, beta);
dImage.PadTo(newWidth, newHeight);
Array2d<Complex> cImage = DataConverter2d.ToComplex(dImage);
Array2d<Complex> fImage = FourierTransform.ForwardFft(cImage);
// FFT convolution .................................................
Array2d<Complex> fOutput = new Array2d<Complex>(newWidth, newHeight);
for (int x = 0; x < newWidth; x++)
{
for (int y = 0; y < newHeight; y++)
{
fOutput[x, y] = fImage[x, y] * kernel2d[x, y];
}
}
Array2d<Complex> cOutput = FourierTransform.InverseFft(fOutput);
Array2d<double> dOutput = Rescale2d.Rescale(DataConverter2d.ToDouble(cOutput));
//dOutput.CropBy((newWidth-image.Width)/2, (newHeight - image.Height)/2);
Bitmap output = DataConverter2d.ToBitmap(dOutput, image.PixelFormat);
Array2d<Complex> cKernel = FourierTransform.InverseFft(kernel2d);
cKernel = FourierTransform.RemoveFFTShift(cKernel);
Array2d<double> dKernel = DataConverter2d.ToDouble(cKernel);
Array2d<double> dRescaledKernel = Rescale2d.Rescale(dKernel);
Bitmap kernel = DataConverter2d.ToBitmap(dRescaledKernel, image.PixelFormat);
pictureBox1.Image = image;
pictureBox2.Image = kernel;
pictureBox3.Image = output;
}
}
此时只关注算法步骤。
我在频域中生成了一个 Gabor 核。由于内核已经在频域中,因此我没有对其应用 FFT,而图像是 FFT-ed。然后,我将内核和图像相乘以实现 FFT-Convolution。然后像往常一样对它们进行逆 FFT 并转换回位图。
输出
- 内核看起来没问题。但是,过滤器输出看起来不是很有希望(或者,是吗?)。
- 方向 (theta) 对内核没有任何影响。
- 计算/公式在值变化时经常出现被零除异常。
我该如何解决这些问题?
哦,还有,
- 参数α、β代表什么?
- f0的适当值应该是多少?
更新:
我根据@Cris Luoengo的回答修改了我的代码。
private double Gabor(double u, double v, double u0, double v0, double a, double b)
{
double p = (-2) * Math.PI * Math.PI;
double q = (u-u0)/(a*a);
double r = (v - v0) / (b * b);
return Math.Exp(p * (q + r));
}
public Array2d<Complex> GaborKernelFft(int sizeX, int sizeY, double u0, double v0, double a, double b)
{
double xx = sizeX;
double yy = sizeY;
double halfX = (xx - 1) / xx;
double halfY = (yy - 1) / yy;
Array2d<Complex> kernel = new Array2d<Complex>(sizeX, sizeY);
for (double u = 0; u <= halfX; u += 0.1)
{
for (double v = 0; v <= halfY; v += 0.1)
{
double g = Gabor(u, v, u0, v0, a, b);
int x = (int)(u * 10);
int y = (int)(v * 10);
kernel[x,y] = new Complex(g, 0);
}
}
return kernel;
}
在哪里,
double u0 = 0.2;
double v0 = 0.2;
double alpha = 10;//1.5;
double beta = alpha;
我不确定这是否是一个好的输出。
【问题讨论】:
-
中间图是您在频域中的 Gabor 滤波器吗?它应该看起来像一个移位的高斯(即远离原点,即左上角的像素)。在空间域中,它将具有复数值。过滤后的结果也是如此。你显示震级了吗?
-
另外,出于性能原因,您应该在空间域中实现递归算法:researchgate.net/publication/3318442_Recursive_Gabor_filtering——这比 FFT 快得多。
-
@CrisLuengo,
Is the middle plot your Gabor filter in the frequency domain?--- 是。Did you display the magnitude?--- 是。 -
以
f0= sizeX/4左右开头。这应该会给你一个介于 0 和奈奎斯特频率之间的高斯中间值。 Alpha 和 beta 是高斯的 sigmas,它们越小,您对频率的选择性就越高,而在空间上的选择性越低。如果sizeX和sizeY为 256,则您的 10 和 15 相当大。没关系,但如果结果仍然不佳,请尝试使用较小的值。 -
Gabor 是一种自适应滤波器,就像高斯、FFT 和许多其他滤波器一样。您将其应用于每个图像行,然后在结果上,在每个图像列上。在这种情况下,separable 意味着您可以将空间域滤波器写为两个 1D 滤波器的外积。
标签: c# image-processing gabor-filter