这里我们有Gabor过滤器的Spatial域实现。但是,出于性能原因,我需要在频域中实现Gabor滤波器。
我实际上对这个公式的正确性和/或适用性存有疑问。
源代码
所以,我已经实现了以下内容:
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 Complex[,] GaborKernelFft(int sizeX, int sizeY, double f0, double theta, double a, double b)
{
int halfX = sizeX / 2;
int halfY = sizeY / 2;
Complex[,] kernel = new 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 f0 = (newWidth+newHeight)/8;
double theta = 45;
double alpha = 3.7;
double beta = 1.3;
Complex[,] kernel2d = GaborKernelFft(newWidth, newHeight, f0, theta, 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 = ImageRescaler.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(new Array2d<Complex>(kernel2d));
cKernel = FourierTransform.RemoveFFTShift(cKernel);
Array2d<double> dKernel = ImageRescaler.Rescale(DataConverter2d.ToDouble(cKernel));
Bitmap kernel = DataConverter2d.ToBitmap(dKernel, image.PixelFormat);
pictureBox1.Image = image;
pictureBox2.Image = kernel;
pictureBox3.Image = output;
}
}
现在只关注算法步骤。
我在频域中生成了一个Gabor内核。因为内核已经在频域中,所以我没有对它应用FFT,而图像是FFT编辑的。然后,我将内核与图像相乘以实现FFT-Convolution。然后它们被反FFT并像往常一样转换回位图。
产量
我该如何解决这些问题?
哦,而且,
发布于 2018-08-30 16:07:04
您找到的Gabor滤波器的等式中似乎存在拼写错误。Gabor滤波器是频域中的平移高斯滤波器。因此,它需要具有u²
和v²
在指数中。
链接中的等式(2)似乎更明智,但仍然错过了2:
exp( -2(πσ)² (u-f₀)² )
这是1D情况,这是我们想要在θ方向使用的滤波器。我们现在在垂直方向上乘以v
非移位高斯。我设置α
并β
成为两个sigmas的反转:
exp( -2(π/α)² (u-f₀)² ) exp( -2(π/β)² v² ) = exp( -2π²((u-f₀)/α)² + -2π²(v/β)² )
您应该使用上面的公式u
并v
在θ上旋转,就像您已经做的那样。
此外,u
并v
应运行从-0.5到0.5之间,而不是-sizeX/2
到sizeX/2
。这就是假设您的FFT在图像中间设置原点,这并不常见。通常,FFT算法将原点设置在图像的一角。所以你应该拥有你的u
,v
从0开始运行(sizeX-1)/sizeX
。
使用上面的校正实现,你应该设置f₀
在0和0.5之间(尝试0.2开始),α
并且β
应该足够小,使得高斯不会达到0频率(你希望滤波器在那里为0) )
在频域中,您的滤镜看起来像是远离原点的旋转高斯。
在空间域中,滤镜的幅度应该再次像高斯一样。虚构组件应如下所示(图片链接到我发现的维基百科页面):
(即,它在θ方向上是反对称的(奇数)),可能有更多的波瓣取决于α
,β
和f₀
。真实组件应该相似但对称(偶数),中间最大。请注意,在IFFT之后,您可能需要将原点从左上角移动到图像的中间(Google“fftshift”)。
https://stackoverflow.com/questions/-100008834
复制相似问题