【问题标题】:How can I implement convolution in frequency domain?如何在频域中实现卷积?
【发布时间】:2016-10-13 06:11:02
【问题描述】:

假设,我们有一个表示为二维整数数组的位图图像, int [,] image2D;,其 FFT 为 Complex[,] fftImage2D;

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

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

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
        //...........................
    }
}

以下链接都是关于空间域卷积的:

http://www.codeproject.com/Articles/2008/Image-Processing-for-Dummies-with-C-and-GDI-Part http://www.gutgames.com/post/Matrix-Convolution-Filters-in-C.aspx https://softwarebydefault.com/2013/05/01/image-convolution-filters/

频域卷积是fftImage2DfftKernel2D之间的乘积。

我该如何做这个乘法?

如何将两个不同维度的Complex [,] 类型的二维数组相乘?

【问题讨论】:

    标签: c#-4.0 image-processing fft


    【解决方案1】:

    要通过在频域中使用乘法来执行线性卷积,您必须首先确保两个复杂的二维数组具有相同的维度。这可以通过将两个空间域数组(image2Dkernel2D)填充到相同的大小来实现。请注意,您已经必须将空间域数组填充到至少比两个数组维度(沿每个维度)的总和小 1 以执行线性卷积而不是循环卷积。

    所以过程如下:

    • 计算填充的行数:image2D.GetLength(0)+kernel2D.GetLength(0)-1
    • 计算填充的列数:image2D.GetLength(1)+kernel2D.GetLength(1)-1
    • image2D 填充到这个新大小,重复边框元素
    • kernel2D 填充到这个新大小,填充零
    • 计算填充 image2Dkernel2D 的 FFT
    • 将填充后的 fftImage2DfftKernel2D 现在大小相同
    • 计算逆 FFT
    • 可以选择将结果截断为原始image2D 大小(仅当您有兴趣获得由kernel2D 过滤的图像而没有完全卷积带来的边缘效应时才需要这样做)。

    对于示例实现,未来的读者可能会查看this other question from @anonymous 以及我在my answer 中指出的更改。

    【讨论】:

    • 如果我取两者中较大的一个(image2D vs kernel2D)作为焊盘尺寸?我应该将内核保持在填充图像的中心还是四个角中的任何一个?而且,我怎样才能截断 image2D?
    • 如果你只取两者中较大的一个作为焊盘尺寸,你最终会得到一些来自圆形卷积的伪影。只有当尺寸至少达到上述值时,工件才会变为零。频域中的内核位置应位于 4 个角(假设零频率位于中心,这很常见),除非您还对图像进行 fftshift/ifftshift (即,您需要保持两个图像具有相同的零频率位置)。
    • 空间域中的内核位置可以在任何地方,只要您在截断结果图像时考虑相应的偏移。如果你把它放在空间域的 4 个角落,你应该得到一个零偏移,所以截断结果图像只会取第一个 GetLength(0)GetLength(1) 像素。
    【解决方案2】:

    您必须使用multiplication of two complex numbers

    这里有一段 java 代码,用于处理两个 1D 数组,编码如下:[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 ;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-09
      • 1970-01-01
      • 2016-08-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多