2

见编辑

为了详细了解它,我尝试在MATLAB中自己实现高斯模糊算法,而不是使用内置算法。

我发现了一个有趣的实现,有人已经问过如何编写这种算法。所以这不是生意。

此外,我使用以下公式来计算给定半径的标准偏差,就像GIMP一样:

stdDeviation = sqrt(-(radius^2) / (2*log10(1 / 255)));

我的算法适用于小半径值(例如 3、5、7),没有任何问题(至少你看不到差异)。如果我尝试模糊半径为 21 的图像,输出如下:

我的结果

与 GIMP 的 / MATLAB 的imgaussfilt(A,sigma)输出相比:

Matlab 的 / GIMP 的结果

显然,算法计算的输出图像不同(或至少相似)。除此之外,GIMP / MATLAB 还能imgaussfilt(A,sigma)做什么?

图像的边界可以忽略。我知道这个问题。但我不明白输出图像中“奇怪的像素条纹”的来源。

为了完整起见,这里是源代码:

function y = gaussianBlurSepTest(inputImage)
% radius in pixel; RADIUS MUST BE ODD! 
radius = 21;
% approximate value for standard deviation
stdDeviation = sqrt(-(radius^2) / (2*log10(1 / 255)));

ind = -floor(radius/2):floor(radius/2);
[X, Y] = meshgrid(ind, ind);
h = exp(-(X.^2 + Y.^2) / (2*stdDeviation*stdDeviation));
h = h / sum(h(:));

redChannel = inputImage(:,:,1);
greenChannel = inputImage(:,:,2);
blueChannel = inputImage(:,:,3);

redBlurred = conv2(redChannel, h);
greenBlurred = conv2(greenChannel, h);
blueBlurred = conv2(blueChannel, h);

y = cat(3, uint8(redBlurred), uint8(greenBlurred), uint8(blueBlurred));

编辑:

为了完整起见并帮助他人:我应用了erfan的修改。现在的结果好多了,但是仍然可以看到与 gimp 的计算有明显差异。GIMP 的结果看起来“更平滑”。

实现的算法:

function y = gaussianBlurSepTest(inputImage)
radius = 21;
stdDeviation = sqrt(-(radius^2) / (2*log10(1 / 255)));
ind = -floor(radius/2):floor(radius/2);
[X, Y] = meshgrid(ind, ind);
[~, R] = cart2pol(X, Y);  % Here R is defined
h = exp(-R.^2 / (2*stdDeviation*stdDeviation));
h = h / sum(h(:));
h(R > radius/2) = 0;
h = h / sum(h(:));
redChannel = inputImage(:,:,1);
greenChannel = inputImage(:,:,2);
blueChannel = inputImage(:,:,3);
redBlurred = conv2(redChannel, h);
greenBlurred = conv2(greenChannel, h);
blueBlurred = conv2(blueChannel, h);
y = cat(3, uint8(redBlurred), uint8(greenBlurred), uint8(blueBlurred));

结果: 实现的算法

GIMP的结果: GIMP

在完全回答这个问题并帮助其他人解决同样的问题方面,我认为询问差异的根源可能是有用的。

谢谢!

4

2 回答 2

1

h负责出现横竖条纹。尽管您已经定义h了角对称,如下图所示,但它的边界打破了这种对称性:

H

为了使事情正确,您可以截断h正确的半径:

截断的 h

我将修改应用于您的函数,现在它应该会给出更好的结果:

function y = gaussianBlurSepTest(inputImage, radius)
stdDeviation = sqrt(-(radius^2) / (2*log10(1 / 255)));
ind = -floor(radius/2):floor(radius/2);
[X, Y] = meshgrid(ind, ind);
[~, R] = cart2pol(X, Y);  % Here R is defined
h = exp(-R.^2 / (2*stdDeviation*stdDeviation));
h = h / sum(h(:));
h(R > radius/2) = 0;  % And here h is truncated. The rest is the same.

这是我的测试。我的形象:

在此处输入图像描述

在您的gaussianBlurSepTest(半径 = 35)之后:

在此处输入图像描述

修改后的功能:

在此处输入图像描述

注意:输出变暗一点。如果这是一个问题,您可以重新规范化stdDeviation或扩大您的网格。

于 2016-09-06T23:17:41.520 回答
0

我认为罪魁祸首是conv2指令,这是因为您的图像类型是uint8or uint16,当您过滤图像时,您应该使用floatdouble输入。您的过滤器尺寸太大,以至于在像素上应用系数窗口的结果超过了 8 位或 16 位整数范围(255 或 65535)。我建议尝试将您的图像投射到double应用滤镜之前和应用滤镜之后将其投射回uint8如下:

   Output=gaussianBlurSepTest(double(inputImage));
   Output=uint8(Output);

祝你好运。

于 2016-09-06T16:54:27.123 回答