我已经声明了一个函数,它将用于使用任意3x3内核计算图像的卷积。我还创建了一个脚本,它将提示用户同时选择一个图像以及进入他们选择的卷积内核。但是,我不知道如何处理各种内核产生的负像素值。如何在我的脚本中实现一个处理这些负值的条件?
这是我的功能:
function y = convul(x,m,H,W)
y=zeros(H,W);
for i=2:(H-1)
for j=2:(W-1)
Z1=(x(i-1,j-1))*(m(1,1));
Z2=(x(i-1,j))*(m(1,2));
Z3=(x(i-1,j+1))*(m(1,3));
Z4=(x(i,j-1))*(m(2,1));
Z5=(x(i,j))*(m(2,2));
Z6=(x(i,j+1))*(m(2,3));
Z7=(x(i+1,j-1))*(m(3,1));
Z8=(x(i+1,j))*(m(3,2));
Z9=(x(i+1,j+1))*(m(3,3));
y(i,j)=Z1+Z2+Z3+Z4+Z5+Z6+Z7+Z8+Z9;
end
end
这是我编写的脚本,提示用户输入图像并选择他们选择的内核:
[file,path]=uigetfile('*.bmp');
x = imread(fullfile(path,file));
x_info=imfinfo(fullfile(path,file));
W=x_info.Width;
H=x_info.Height;
L=x_info.NumColormapEntries;
prompt='Enter a convulation kernel m: ';
m=input(prompt)/9;
y=convul(x,m,H,W);
imshow(y,[0,(L-1)]);
我试图使用卷积的绝对值,以及尝试在输出图像中定位负片,但没有任何效果。
这是原始图片:
这是我使用内核时得到的图像[-1 -1 -1; -1 9 -1; -1 -1 -1]:
我不知道我做错了什么。
MATLAB在处理不同数据类型之间的操作方面非常独特。如果x
是uint8
(因为它可能在这种情况下),并且m
是double
(因为它可能在这种情况下),那么这个操作:
Z1=(x(i-1,j-1))*(m(1,1));
返回uint8
值,而不是double
。 MATLAB中的算术总是采用非双参数的类型。 (除非其中一个是double
,否则你不能在两种不同类型之间进行算术运算。)
MATLAB使用饱和度进行整数运算。这意味着uint8(5) * -1
给出0而不是-5,因为uint8
不能代表负值。
所以你所有的Z1
..Z9
都是uint8
值,负结果已经设置为0.现在你再加上所有这些,饱和度,导致最多255的值。这个值被分配给输出(一个双) 。所以看起来你正在正确地进行计算并输出一个双数组,但你仍然以奇怪的方式将结果钳制起来。
正确的实现会将x
的每个值转换为double
,然后乘以潜在的负数。例如:
for i = 2:H-1
for j = 2:W-1
s = 0;
s = s + double(x(i-1,j-1))*m(1,1);
s = s + double(x(i-1,j))*m(1,2);
s = s + double(x(i-1,j+1))*m(1,3);
s = s + double(x(i,j-1))*m(2,1);
s = s + double(x(i,j))*m(2,2);
s = s + double(x(i,j+1))*m(2,3);
s = s + double(x(i+1,j-1))*m(3,1);
s = s + double(x(i+1,j))*m(3,2);
s = s + double(x(i+1,j+1))*m(3,3);
y(i,j) = s;
end
end
(请注意,我删除了你使用9个不同的变量,我认为这更干净,而且我还删除了很多不必要的括号!)
更简单的实现方式是:
for i = 2:H-1
for j = 2:W-1
s = double(x(i-1:i+1,j-1:j+1)) .* m;
y(i,j) = sum(s(:));
end
end