AFP*_*AFP 1 matlab image-processing filter convolution
我想了解 MATLAB 的imfilter函数是如何工作的。
im = imread("cameraman.tif");
% Kernel for sharpening the image
kernel = [
0 -1 0;
-1 5 -1;
0 -1 0];
im2 = zeros(size(im));
for y = 1 : size(im,1) - 3
for x = 1 : size(im,2) - 3
sum = 0;
for ky = 1:3
for kx = 1:3
xx = x + kx - 1;
yy = y + ky - 1;
sum = sum + im(yy,xx)*kernel(ky,kx);
end
end
im2(y,x) = sum;
end
end
% Map im2 to 0 - 255
im2 = im2 - min(im2(:));
im2 = im2 / max(im2(:)) * 255;
im2 = uint8(im2);
subplot(131), imshow(im), title('Original Image')
subplot(132), imshow(imfilter(im,kernel)), title('Matlab imfilter')
subplot(133), imshow(im2), title('My filter')
Run Code Online (Sandbox Code Playgroud)
边界处的差异不是我关心的,但我的结果(右侧的子图)与 MATLAB 生成的结果(中间的子图)明显不同,尽管使用了相同的内核。
我可以知道可能有什么偏差吗?据我所知,内核补丁将按元素应用于图像并对结果求和。有人可以让我知道我缺少什么吗?谢谢。
你的错误在这一行:
sum = sum + im(yy,xx)*kernel(ky,kx);
Run Code Online (Sandbox Code Playgroud)
这并不明显,但 MATLAB 在使用不同数据类型进行算术运算时会做出奇怪的选择。在 MATLAB 中,默认情况下所有数值数组(所有值)都是双精度数。sum初始化时 ( sum = 0) 为 double*,与kernel和一样im2。但是im是一个8位无符号整数数组。im(yy,xx)*kernel(ky,kx)uint8 与 double 的乘法也是如此。这是在一个操作中组合不同数据类型的奇怪情况。
使用整数数组进行算术运算时,另一个操作数必须具有相同类型,除非它是双精度标量(1x1 双精度数组)。在这种情况下,标量值将转换为整数类型,然后应用运算。此外,整数算术是饱和的,这意味着整数范围之外的任何结果都被限制在该范围内(不存在其他语言中的溢出)。
所以im(yy,xx)*kernel(ky,kx)结果是 uint8。接下来,sum + <uint8 result>也是一个 uint8 值,它被分配给sum。现在sum是uint8!
要解决此问题,请执行以下操作
sum = sum + double(im(yy,xx)) * kernel(ky,kx);
Run Code Online (Sandbox Code Playgroud)
* 另请注意,一切都是数组。0是一个 1x1 数组。
未经请求的建议:
您不应该缩放im2图像,您应该直接将其转换为uint8. MATLAB 将为您将值限制在 [0,255] 范围内。缩放会导致对比度损失。
不要用作sum变量名。sum是一个内置函数,您可以使用此变量隐藏它(使其不可用)。sum(im(:))例如,运行代码后,您不能再执行。
内部两个循环很容易矢量化:
tmp = double(im(x + (0:2), y + (0:2))) .* kernel;
im2(y,x) = sum(tmp(:));
Run Code Online (Sandbox Code Playgroud)
或者,在 MATLAB 的最新版本中,
im2(y,x) = sum(double(im(x + (0:2), y + (0:2))) .* kernel, 'all');
Run Code Online (Sandbox Code Playgroud)
(并注意此处对该功能的需求sum!)