gpt4 book ai didi

c# - 空间域图像卷积

转载 作者:可可西里 更新时间:2023-11-01 08:10:50 26 4
gpt4 key购买 nike

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

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

enter image description here

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

我该如何解决这个问题?

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

enter image description here

.

Update-1:根据@Ben Voigt 的评论,我更改了 Rescale() 函数以替换 255.01,因此输出得到了显着改善。但是,输出仍然与 FFT 输出不匹配(这是正确的输出)。
enter image description here

.

Update-2:根据@Cris Luengo的评论,我通过拼接填充图像,然后进行空间卷积。结果如下:
enter image description here

所以,输出比上一个差。但是,这与 linked answer 的第二个输出有相似之处。这意味着循环卷积不是解决方案。

.

Update-3:我使用了@Cris Luengo 的回答中提出的Sum() 函数。结果是 **Update-1** 的改进版本:
enter image description here

但是,它仍然不是 100% 类似于 FFT 版本。

.

Update-4:根据@Cris Luengo 的评论,我减去两个结果以查看差异:
enter image description here , enter image description here

<支持> 1.空间负频域
2.频率减空间域

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

.

源代码:

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

    public static double[,] LinearConvolutionSpatial(double[,] image, double[,] mask)
{
int maskWidth = mask.GetLength(0);
int maskHeight = mask.GetLength(1);

double[,] paddedImage = ImagePadder.Pad(image, maskWidth);

double[,] conv = Convolution.ConvolutionSpatial(paddedImage, mask);

int cropSize = (maskWidth/2);

double[,] cropped = ImageCropper.Crop(conv, cropSize);

return conv;
}
static double[,] ConvolutionSpatial(double[,] paddedImage1, double[,] mask1)
{
int imageWidth = paddedImage1.GetLength(0);
int imageHeight = paddedImage1.GetLength(1);

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

int convWidth = imageWidth - ((maskWidth / 2) * 2);
int convHeight = imageHeight - ((maskHeight / 2) * 2);

double[,] convolve = new double[convWidth, convHeight];

for (int y = 0; y < convHeight; y++)
{
for (int x = 0; x < convWidth; x++)
{
int startX = x;
int startY = y;

convolve[x, y] = Sum(paddedImage1, mask1, startX, startY);
}
}

Rescale(convolve);

return convolve;
}

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[x - startX, y - startY];
sum = sum + (img * msk);
}
}

return sum;
}

static void Rescale(double[,] convolve)
{
int imageWidth = convolve.GetLength(0);
int imageHeight = convolve.GetLength(1);

double maxAmp = 0.0;

for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
maxAmp = Math.Max(maxAmp, convolve[i, j]);
}
}

double scale = 1.0 / maxAmp;

for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
double d = convolve[i, j] * scale;
convolve[i, j] = d;
}
}
}

public static Bitmap ConvolveInFrequencyDomain(Bitmap image1, Bitmap kernel1)
{
Bitmap outcome = null;

Bitmap image = (Bitmap)image1.Clone();
Bitmap kernel = (Bitmap)kernel1.Clone();

//linear convolution: sum.
//circular convolution: max
uint paddedWidth = Tools.ToNextPow2((uint)(image.Width + kernel.Width));
uint paddedHeight = Tools.ToNextPow2((uint)(image.Height + kernel.Height));

Bitmap paddedImage = ImagePadder.Pad(image, (int)paddedWidth, (int)paddedHeight);
Bitmap paddedKernel = ImagePadder.Pad(kernel, (int)paddedWidth, (int)paddedHeight);

Complex[,] cpxImage = ImageDataConverter.ToComplex(paddedImage);
Complex[,] cpxKernel = ImageDataConverter.ToComplex(paddedKernel);

// call the complex function
Complex[,] convolve = Convolve(cpxImage, cpxKernel);

outcome = ImageDataConverter.ToBitmap(convolve);

outcome = ImageCropper.Crop(outcome, (kernel.Width/2)+1);

return outcome;
}

最佳答案

您当前的输出看起来更像是自相关函数,而不是 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 的镜像版本传递给此函数。

关于c# - 空间域图像卷积,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51262986/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com