使用大半径/标准偏差高斯模糊图像时的奇怪行为

时间:2016-09-06 08:53:05

标签: algorithm matlab image-processing convolution gaussianblur

请参阅编辑

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

我找到了interesting implementation,有人已经问过how to code that kind of algorithm。所以这不是生意。

此外,我使用以下公式计算给定半径的标准偏差,如GIMP

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

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

My result

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

Matlab´s / GIMP´s result

显然,算法计算的输出图像不同(或至少相似)。 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));

结果: The implemented algorithm

GIMP的结果: GIMP

在完全回答问题并帮助其他人提出相同问题方面,我认为要求差异的根源可能是有用的。

谢谢!

2 个答案:

答案 0 :(得分:1)

h负责出现的水平和垂直条纹。虽然您已经使用角度对称定义了h,如下图所示,但它的边界打破了这种对称性:

h

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

truncated 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.

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

enter image description here

gaussianBlurSepTest(半径= 35)之后:

enter image description here

修改后的功能:

enter image description here

注意:输出稍微变暗。如果这是一个问题,您可以重新规范化stdDeviation或加宽网格网格。

答案 1 :(得分:0)

我认为罪魁祸首是conv2指令,因为您的图片类型为uint8uint16,当您过滤图片时,应使用float或{ {1}}类型。 您的滤波器大小非常高,系数窗口在像素上的应用结果超过8位或16位整数范围(255或65535)。我建议您在应用过滤器之前尝试将图片转换为double,并在应用过滤器后将其转换回double,如下所示:

uint8
祝你好运。