C# 4.0 如何在频域中实现卷积?

C# 4.0 如何在频域中实现卷积?,c#-4.0,image-processing,fft,C# 4.0,Image Processing,Fft,假设我们有一个位图图像,表示为2D整数数组, int[,]image2D其FFT为复数[,]fftImage2D 假设我们有一个表示为2D整数数组的内核, int[,]kernel2D其FFT为复数[,]fftKernel2D 我们知道,image2D和kernel2D的卷积(在空间域中)是 int Rows = image2D.GetLength(0); int Cols = image2D.GetLength(1); for(int i=0 ; i<Rows ; i++) {

假设我们有一个位图图像,表示为2D整数数组,
int[,]image2D其FFT为
复数[,]fftImage2D

假设我们有一个表示为2D整数数组的内核,
int[,]kernel2D
其FFT为
复数[,]fftKernel2D

我们知道,
image2D
kernel2D
的卷积(在空间域中)是

int Rows = image2D.GetLength(0);
int Cols = image2D.GetLength(1);

for(int i=0 ; i<Rows ; i++)
{
    for(int j=0 ; j<Cols ; j++)
    {
        //sweep the kernel2D across image2D
        //...........................
    }
}
int Rows=image2D.GetLength(0);
int Cols=image2D.GetLength(1);

对于(int i=0;i要在频域中使用乘法执行线性卷积,必须首先确保两个复杂的二维数组具有相同的维数。这可以通过填充两个空域数组(
image2D
kernel2D
)来实现请注意,为了执行线性卷积而不是循环卷积,您必须将空间域数组填充到比两个数组维度之和(沿每个维度)小至少一个的位置

所以这个过程看起来像:

  • 计算填充行数:
    image2D.GetLength(0)+kernel2D.GetLength(0)-1
  • 计算填充的列数:
    image2D.GetLength(1)+kernel2D.GetLength(1)-1
  • image2D
    填充到此新大小,重复边界元素
  • kernel2D
    填充到这个新大小,填充零
  • 计算填充的
    image2D
    kernel2D
  • 执行填充的
    fftImage2D
    fftKernel2D
    的乘法,这两个值现在大小相同
  • 计算逆FFT
  • 可选地将结果截断为原始的
    image2D
    大小(仅当您有兴趣获得通过
    kernel2D
    过滤的图像时才需要此选项,而不需要完全卷积的边缘效果)
对于示例实现,未来的读者可能会看到我在中指出的更改。

您必须使用

下面是一段用于处理两个1D数组的java代码,其编码如下:[R1,C1,R2,C2,…,Rn,Cn]:

public void Multiply(double[] object1, double[] object2, double[] result)
{
double img_r, img_i, mask_r, mask_i ;

for (int pos=0 ; pos < result.length ; pos+=2)
    {
    img_r = object1[pos] ;
    img_i = object1[pos+1] ;

    mask_r = object2[pos] ;
    mask_i = object2[pos+1] ;

    result[pos]   = img_r*mask_r - img_i*mask_i;
    result[pos+1] = img_r*mask_i + img_i*mask_r ;
    }
}
public void Multiply(double[]object1,double[]object2,double[]result)
{
双img_r,img_i,mask_r,mask_i;
对于(int pos=0;pos
如果我取两者中较大的一个(image2D与kernel2D),会怎么样作为焊盘大小?我是否应该将内核保持在填充图像的中心或四个角中的任何一个?以及,我如何截断image2D?如果仅将两者中的较大者作为焊盘大小,则会产生一些来自循环卷积的伪影。只有当大小至少达到上述值时,伪影才会变为零。频域中的内核位置应位于4个角(假设零频率位于中心,这是常见的),除非您还对图像进行FFT移位/ifftshift(即,您需要将两个图像保持在相同的零频率位置).spatial domain中的内核位置可以是任意位置,只要您在截断结果图像时考虑相应的移位。如果您将其放在spatial domain中的4个角,则应得到零移位,因此截断结果图像只需取第一个
GetLength(0)
&
GetLength(1)
像素。