【问题标题】:Floyd Steinberg Dithering Matlab - What am I doing wrong?Floyd Steinberg Dithering Matlab - 我做错了什么?
【发布时间】:2021-02-01 08:15:16
【问题描述】:

我正在尝试在 MATLAB 中实现 Floyd Steinberg Dithering,使用维基百科页面上的伪代码 https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering

我的代码在下面

image = double(imread("dithering.jpg")) ./ 255;
levels = 2;

image_quantised = round(image .* (levels - 1)) ./ (levels - 1);
error = image - image_quantised;

height = size(image(:, :, 1), 1);
width = size(image(:, :, 1), 2);

image_dithered = image_quantised;

for y = 1:height - 1
    for x = 2:width - 1
                
        image_dithered(y    , x + 1, :) = image_dithered(y    , x + 1, :) + error(y, x, :) .* 7 / 16;
        image_dithered(y + 1, x - 1, :) = image_dithered(y + 1, x - 1, :) + error(y, x, :) .* 3 / 16;
        image_dithered(y + 1, x    , :) = image_dithered(y + 1, x    , :) + error(y, x, :) .* 5 / 16;
        image_dithered(y + 1, x + 1, :) = image_dithered(y + 1, x + 1, :) + error(y, x, :) .* 1 / 16;
        
    end
end

imshow(image_dithered)  % Image 1
imshow(dither(mean(image, 3)))  % Image 2

图片 1

图片 2

我期待图像 2 中的结果,但我得到的是图像 1。看起来算法没有做任何事情。有任何想法吗? :)

编辑:我尝试使用不同的值初始化image_dithered;全零,量化图像和原始图像。它们都不能正常工作

编辑 2:我现在计算循环内的误差和量化越来越接近。然而仍然没有发现。

for y = 1:height - 1
    for x = 2:width - 1
        new_pixel = round(image_dithered(y, x, :) .* (levels - 1)) ./ (levels - 1);
        image_dithered(y, x, :) = new_pixel;

        error = image(y, x, :) - new_pixel;

        image_dithered(y    , x + 1, :) = image_dithered(y    , x + 1, :) + error .* 7 / 16;
        image_dithered(y + 1, x - 1, :) = image_dithered(y + 1, x - 1, :) + error .* 3 / 16;
        image_dithered(y + 1, x    , :) = image_dithered(y + 1, x    , :) + error .* 5 / 16;
        image_dithered(y + 1, x + 1, :) = image_dithered(y + 1, x + 1, :) + error .* 1 / 16;
    end
end

编辑 3:感谢 @saastn 和 @Cris Luengo,这两个答案都帮助我找出了哪里出了问题,而且现在似乎正在按预期工作!

为了完整起见,下面是固定代码。

height = size(image(:, :, 1), 1);
width = size(image(:, :, 1), 2);

image_dithered = image;

for y = 1:height - 1
    for x = 2:width - 1
        old_pixel = image_dithered(y, x, :);
        new_pixel = round(image_dithered(y, x, :) .* (levels - 1)) ./ (levels - 1);
        
        image_dithered(y, x, :) = new_pixel;
        
        error = old_pixel - new_pixel;
        
        image_dithered(y    , x + 1, :) = image_dithered(y    , x + 1, :) + error .* 7 / 16;
        image_dithered(y + 1, x - 1, :) = image_dithered(y + 1, x - 1, :) + error .* 3 / 16;
        image_dithered(y + 1, x    , :) = image_dithered(y + 1, x    , :) + error .* 5 / 16;
        image_dithered(y + 1, x + 1, :) = image_dithered(y + 1, x + 1, :) + error .* 1 / 16;
        
    end
end

imshow(image_dithered)
imshow(dither(mean(image, 3)))

【问题讨论】:

    标签: matlab image-processing dithering


    【解决方案1】:

    问题是你试图改进伪代码并删除oldpixel!请注意,该算法不计算量化像素与其在原始图像中的对应值之间的误差,而是计算量化像素与抖动图像中先前值之间的误差,该误差可能在扫描先前像素时已经更新。 将oldpixel 带回并再次查看整个算法。

    但即使经过修改,您也不能指望结果与 MATLAB 输出匹配,这可能是两种实现细节不同的结果。

    【讨论】:

      【解决方案2】:

      您在image_quantized 中而不是在原始图像中传播错误。移除这个量化的图像,它不是算法的一部分。

      您需要量化一个像素,然后找到与原始值的差异,并将该误差传播到未来的像素中。

      请注意,Wikipedia 伪代码就地执行此操作,只有一个图像副本可用作输入和输出。

      this old blog post of mine 上有用于 Floyd-Steinberg 抖动的 MATLAB 代码。

      【讨论】:

        【解决方案3】:

        假设您首先遵循 saastn 的回答(并回复它所说的关于这些图像之间差异的内容):我想说的是,只要在 saastn 的图像中查看它们,Matlab 的模式看起来就像是弗洛伊德的侧面版本-Steinberg 在这里,要么通过旋转,要么更可能通过转置(将 x 与 y 交换,这是跨 x+y 对角轴的反射)。这不能通过仅仅改变系数来模仿,图像必须按列处理(“for x”在“for y”之外,等等)。

        【讨论】:

          猜你喜欢
          • 2014-06-01
          • 2019-09-16
          • 1970-01-01
          • 1970-01-01
          • 2010-12-14
          • 2014-10-13
          • 2011-06-01
          • 1970-01-01
          • 2021-04-14
          相关资源
          最近更新 更多