Floyd Steinberg Dithering Matlab-我在做什么错?

问题描述

我正在尝试使用Wikipedia页面https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering

上的伪代码在MATLAB中实现Floyd Steinberg 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(:,2);

image_dithered = image_quantised;

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

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

图片1

Image 1,incorrectly dithered

图片2

Image 2,correct dithering result

我期望在图像2中得到结果,但是得到图像1。看起来该算法没有执行任何操作。有任何想法吗? :)

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

编辑2:现在,通过计算循环中的误差和量化,我已经接近了。但是仍然没有发现。

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

        error = image(y,:) - new_pixel;

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

编辑3:感谢@saastn和@Cris Luengo,这两个答案都帮助我弄清了哪里出了问题,现在看来它正在按预期工作!

以下是固定代码,以确保完整性。

height = size(image(:,2);

image_dithered = image;

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

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

Almost working dithering image,however not exactly the result that is expected

解决方法

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

enter image description here

但是即使进行了修改,您也不能期望结果与MATLAB输出匹配,这可能是两个实现细节不同的结果。 enter image description here

,

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

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

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

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

,

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