空间域中的图像卷积

时间:2018-07-10 10:32:42

标签: c# image-processing convolution

我正在尝试使用空间域中的线性卷积来复制this link的结果。

首先将图像转换为2d double数组,然后进行卷积。映像和内核大小相同。在卷积之前填充图像,并在卷积之后相应地裁剪图像。

enter image description here

与基于FFT的卷积相比,输出很奇怪且不正确

如何解决此问题?

请注意,我从Matlab获得了与我的C#FFT输出匹配的以下图像输出:

enter image description here

Update-1::按照@ Ben Voigt 的评论,我更改了Rescale()函数,将255.0替换为{ {1}},从而大大提高了输出。但是,输出仍然与FFT输出不匹配(这是正确的输出)。
enter image description here

Update-2 :在@ Cris Luengo 的评论之后,我通过缝合填充了图像,然后进行了空间卷积。结果如下:
enter image description here

因此,输出比上一个更差。但是,这与linked answer的第二个输出有相似之处,这意味着圆形卷积不是解决方案。

Update-3 :我使用了@ Cris Luengo 的答案提出的1功能。结果是Sum()的改进版本:
enter image description here

但是,它与FFT版本仍然不是100%相似。

Update-4 :在@ Cris Luengo 的评论之后,我减去了两个结果以得出区别:
enter image description hereenter image description here

 1.空间负频域
 2.频率减去空间域

看起来,差异很大,这意味着空间卷积没有正确完成。

源代码:

(如果需要更多源代码,请通知我。)

**Update-1**

2 个答案:

答案 0 :(得分:5)

您的当前输出看起来更像是自相关函数,而不是Lena和她自己的卷积。我认为问题可能出在您的Sum函数中。

如果您查看convolution sum的定义,则会看到内核(或映像,无关紧要)已被镜像:

sum_m( f[n-m] g[m] )

对于一个功能,m带有加号,而另一个功能带有减号。

您需要修改Sum函数以按正确的顺序读取mask1图像:

static double Sum(double[,] paddedImage1, double[,] mask1, int startX, int startY)
{
    double sum = 0;

    int maskWidth = mask1.GetLength(0);
    int maskHeight = mask1.GetLength(1);

    for (int y = startY; y < (startY + maskHeight); y++)
    {
        for (int x = startX; x < (startX + maskWidth); x++)
        {
            double img = paddedImage1[x, y];
            double msk = mask1[maskWidth - x + startX - 1, maskHeight - y + startY - 1];
            sum = sum + (img * msk);
        }
    }

    return sum;
}

另一种选择是将mask1的镜像版本传递给该函数。

答案 1 :(得分:3)

我从this link找到了解决方案。主要线索是引入offsetfactor

  • factor 是内核中所有值的总和。
  • 偏移量是一个任意值,用于进一步固定输出。

@ 克里斯·伦戈的回答也提出了一个有效的观点。

给定链接中提供了以下源代码:

    private void SafeImageConvolution(Bitmap image, ConvMatrix fmat) 
    { 
        //Avoid division by 0 
        if (fmat.Factor == 0) 
            return; 

        Bitmap srcImage = (Bitmap)image.Clone(); 

        int x, y, filterx, filtery; 
        int s = fmat.Size / 2; 
        int r, g, b; 
        Color tempPix; 

        for (y = s; y < srcImage.Height - s; y++) 
        { 
            for (x = s; x < srcImage.Width - s; x++) 
            { 
                r = g = b = 0; 

                // Convolution 
                for (filtery = 0; filtery < fmat.Size; filtery++) 
                { 
                    for (filterx = 0; filterx < fmat.Size; filterx++) 
                    { 
                        tempPix = srcImage.GetPixel(x + filterx - s, y + filtery - s); 

                        r += fmat.Matrix[filtery, filterx] * tempPix.R; 
                        g += fmat.Matrix[filtery, filterx] * tempPix.G; 
                        b += fmat.Matrix[filtery, filterx] * tempPix.B; 
                    } 
                } 

                r = Math.Min(Math.Max((r / fmat.Factor) + fmat.Offset, 0), 255); 
                g = Math.Min(Math.Max((g / fmat.Factor) + fmat.Offset, 0), 255); 
                b = Math.Min(Math.Max((b / fmat.Factor) + fmat.Offset, 0), 255); 

                image.SetPixel(x, y, Color.FromArgb(r, g, b)); 
            } 
        } 
    }