问题复制MATLAB

发布于 2025-01-31 03:56:40 字数 1088 浏览 3 评论 0原文

我正在尝试了解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')

边界的差异不是我的关注,而是我的结果(右侧的子图)与MATLAB产生的(中间子图)显然不同,尽管使用了相同的内核。

我可以知道会有什么偏差?据我所知,内核贴片将应用于图像元素,并在结果上概括。有人可以让我知道我想念什么吗?谢谢。

I am trying to understand how MATLAB's imfilter function works.

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')

Differences at the boundaries are not my concern but my result (the subplot at the right) is clearly different than what MATLAB produces (the middle subplot) although the same kernel was used.

enter image description here

May I know what could be the deviation? As far as I know, kernel patch will be applied to the image element-wise and be summed over the result. Could someone let me know what I am missing? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

累赘 2025-02-07 03:56:40

您的错误是在这一行中:

sum = sum + im(yy,xx)*kernel(ky,kx);

这并不明显,但是Matlab在使用不同的数据类型进行算术时会做出一个奇怪的选择。在MATLAB中,默认情况下,所有数字阵列(所有值)都是双重的。 sum是double*初始化时(sum = 0),内核im2也是如此。但是im是一个8位未签名的整数数组。因此,im(YY,xx)*内核(KY,KX)对UINT8进行倍增8。这是将不同数据类型组合在操作中的奇怪情况。

当使用整数数组进行算术时,另一个操作数必须具有相同的类型,除非它是双标量表(1x1双阵列)。在这种情况下,标量值将转换为整数类型,然后应用操作。同样,整数算术饱和,这意味着整数范围之外的任何结果都夹在范围内(没有其他语言中的溢出)。

因此,im(YY,XX)*内核(KY,KX)导致UINT8。接下来,sum +< uint8结果>也是UINT8值,该值分配给sum。现在sum是UINT8!

要解决此问题,请

sum = sum + double(im(yy,xx)) * kernel(ky,kx);

*请注意,所有内容都是一个数组。 0是一个1x1数组。


未经请求的建议:

  1. 您不应缩放im2图像,您应该将其直接投放到uint8。 MATLAB将为您限制[0,255]范围的值。缩放会导致对比的丢失。

  2. 不要使用sum作为变量名称。 sum是一个内置功能,您可以使用此变量来遮盖它(使其不可用)。运行代码后,您不能再做sum(im(:))

  3. 内部两个循环非常容易矢量化:

      tmp = double(im(x +(0:2),y +(0:2)))。* kernel;
    IM2(y,x)= sum(tmp(:));
     

    或最近版本的Matlab,

      im2(y,x)= sum(double(im(x +(0:2),y +(0:2)))。* kernel, '全部');
     

    (并在此处注意sum函数的需求!)

Your bug is in this line:

sum = sum + im(yy,xx)*kernel(ky,kx);

This is not obvious, but MATLAB makes a strange choice when doing arithmetic with different data types. In MATLAB, by default all numeric arrays (all values) are doubles. sum is double* when you initialize it (sum = 0), as are kernel and im2. But im is an 8-bit unsigned integer array. So im(yy,xx)*kernel(ky,kx) does a multiplication of a uint8 with a double. This is the strange case of combining different data types in an operation.

When doing arithmetic with an integer array, the other operand must be of the same type, unless it is a double scalar (a 1x1 double array). In this case, the scalar value is converted to the integer type, then the operation is applied. Also, integer arithmetic is saturated, meaning that any result outside of the integer range is clamped to the range (there is no overflow as in other languages).

So im(yy,xx)*kernel(ky,kx) results in a uint8. Next, sum + <uint8 result> is also a uint8 value, which is assigned to sum. Now sum is uint8!

To fix this, do

sum = sum + double(im(yy,xx)) * kernel(ky,kx);

* Also note that everything is an array. 0 is a 1x1 array.


Unsolicited advice:

  1. You should not scale the im2 image, you should directly cast it to uint8. MATLAB will clamp the values to the [0,255] range for you. Scaling causes loss of contrast.

  2. Don't use sum as a variable name. sum is a built-in function, which you shadow (make unavailable) with this variable. After running your code, you can no longer do sum(im(:)), for example.

  3. The inner two loops are very easily vectorized:

    tmp = double(im(x + (0:2), y + (0:2))) .* kernel;
    im2(y,x) = sum(tmp(:));
    

    or, in very recent versions of MATLAB,

    im2(y,x) = sum(double(im(x + (0:2), y + (0:2))) .* kernel, 'all');
    

    (And note the need for the sum function here!)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文