【问题标题】:Laplacian filter returning very black image拉普拉斯滤波器返回非常黑的图像
【发布时间】:2021-11-18 23:16:31
【问题描述】:

我正在尝试使用blockproc 将本地拉普拉斯滤波器应用于图像,但我得到的结果比教科书中的结果要暗得多。我看过其他一些关于同样问题的帖子,但我不确定我到底没有掌握什么。

我的代码:

img1 = im2double(imread('Fig0352(a)(blurry_moon).tif'));
kernel = [0 1 0; 1 -4 1; 0 1 0];

%generate laplacian image
fun = @(block_struct)laplacian_kernel(block_struct.data, kernel);
img2 = blockproc(img1, [3 3], fun, 'PadPartialBlocks', true, 'TrimBorder', true);
img3 = img2(:, 1:end-2);%crop extra two columns added by last passthrough of blockproc
img4 = imsubtract(img1,img3);%get enhanced image

%display
figure;
subplot(2,2,1);
imshow(img1)
subplot(2,2,2);
imshow(img3);
subplot(2,2,3);
imshow(img4);


function f = laplacian_kernel(img, kernal)
%want to pad this 3x3 chunk of the image so we don't exceed the bounds of
%the array when doing laplacian
img1 = padarray(img, [1 1]);
out = zeros(size(img1));
for i = 2 : (length(img1)-1)
   for j = 2 : (length(img1)-1)
       neighborhood = img1(i-1: i+1, j-1: j+1);%get neighborhood
       out(i,j)= sum(neighborhood .* kernal, 'all'); 
   end
end
f = out(2:length(img1)-1, 2:length(img1)-1);%remove padding
end

我得到的图像是

拉普拉斯是右上角的图像,比书中显示的要暗得多。

书中的图片看起来更像这样:

我知道它仍然很暗(而且图片很小,抱歉),但它的细节比我使用自定义代码生成的要多得多。我的拉普拉斯人做错了什么?我已经尝试多次重写代码,但总是得到或多或少相同的结果。

如果我使用nlfilter,我的结果与书中的结果一致。但是,它需要更多时间,我不喜欢使用它。当我用 blockproc 将块拼凑在一起时,我显然很困惑,但我无法概念化我哪里出错了。这是我使用 nlfilter 时的结果:

img1 = im2double(imread('Fig0352(a)(blurry_moon).tif'));

kernel = [0 1 0; 1 -4 1; 0 1 0];
k2 = [1 1 1; 1 -8 1; 1 1 1];

fun = @(x)laplacian_kernel(x, kernel);
img2 = nlfilter(img1, 'indexed', [3 3], fun);

img3 = imsubtract(img1, img2);

figure;
subplot(1,3,1);
imshow(img1);
title('original image');
subplot(1,3,2);
imshow(img2);
title('laplacian using nlfilter');
subplot(1,3,3);
imshow(img3);
title('enhanced image');

function f = laplacian_kernel(img, kernal)
f = sum(img.*kernal, 'all');
end

有输出:

显然,nlfilter 的结果要好得多。我只是不确定 blockproc 哪里出了问题。

【问题讨论】:

  • 我猜你应该标准化输出以适应 0 和 1(或 0 和 255,或任何你需要的)。此外,我会使用 2D 卷积将内核应用于您的图像,例如 conv2(img,kernel,'same')
  • @obchardon 感谢您的建议。但是,标准化图像会使它看起来更好,但它仍然不能解决我的增强问题。我要比较的书图像(对于拉普拉斯)没有标准化。出于某种原因,当我使用 nlfilter 时,我的答案与这本书相匹配,但它需要的时间太长了,我不喜欢使用它。将积木拼凑在一起时,我显然遗漏了一些东西,但我不确定它是什么。

标签: matlab image-processing


【解决方案1】:

拉普拉斯算子的典型输出非常暗,大约一半的像素为负值。要正确显示它,而不是 imshow(img3),请使用 imshow(img3,[])。这将缩放图像,使其最小值为黑色,最大值为白色。大多数像素现在将是中灰色,正像素更接近白色,负像素更接近黑色。

但您在代码中遇到了更大的问题:通过使用零填充处理每个 3x3 块,该块中只有一个像素具有正确的值,其他 8 个像素对一些填充进行采样。您想在blockproc 中使用BorderSize 选项而不是零填充:

img2 = blockproc(img1, [3 3],  @(s)conv2(s.data, kernel, 'same'), ...
                 'PadPartialBlocks', false, ...
                 'BorderSize', [1,1], 'TrimBorder', true);
img3 = img1 - img2;

我们现在使用conv2,因为这就是我们所需要的,无需重新发明轮子。但是,如果您确实想使用自己的代码进行过滤,请考虑交换两个循环,因为这样更有效,并使用 size(img,1)size(img,2) 而不是 length(img)

请注意,不填充部分块应该使您后续的图像修剪变得不必要。

使用比 3x3 更大的块会提高效率。


要模拟 conv2blockproc,请使用 1x1 块和 1 像素边框(在图像中提供 3x3 窗口),并使用带有内核的点积作为块处理函数:

img2 = blockproc(img1, [1 1],  @(s)sum(s.data(:).*kernel(:)), ...
                 'BorderSize', [1,1], 'TrimBorder', false);
img3 = img1 - img2;

这显然一点也不快,手动编写一个卷积作为双循环导致代码的速度大约是使用 blockproc 的 5 倍。

【讨论】:

  • 我试图避免 conv2,但感谢您的回复。我一定会看看 BorderSize,看看它会把我带到哪里。
  • @Ben 您可以通过在 1x1 块中处理来模拟 conv2blockproc。添加的填充将为您的函数提供图像的 3x3 区域,使用 3x3 内核的点积将为您提供正确的结果。
  • @Ben 查看编辑。
猜你喜欢
  • 2011-04-28
  • 2015-05-25
  • 2019-02-02
  • 1970-01-01
  • 2011-02-02
  • 2020-07-05
  • 2021-02-26
  • 2012-12-03
相关资源
最近更新 更多