Floyd Steinberg 抖动 Matlab - 我做错了什么?
Floyd Steinberg Dithering Matlab - What am I doing wrong?
我正在尝试使用维基百科页面上的伪代码在 MATLAB 中实现 Floyd Steinberg 抖动 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
;全零、量化图像和原始图像。 None 个正常工作
编辑 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)))
问题是您试图改进伪代码并删除 oldpixel
!请注意,该算法不计算量化像素与其在原始图像中的对应值之间的误差,而是计算量化像素与抖动图像中先前值之间的误差,该值可能在扫描先前像素时已更新。
将 oldpixel
带回来并再次回顾整个算法。
但即使在修改之后,您也不能期望结果与 MATLAB 输出匹配,这可能是两个实现细节差异的结果。
您在 image_quantized
而不是原始图像中传播错误。去掉这张量化图,它不是算法的一部分。
您需要量化一个像素,然后找到与原始值的差异,并将该误差传播到未来的像素。
请注意,维基百科伪代码会执行此操作 in-place,图像只有一个副本可同时用作输入和输出。
在 this old blog post of mine 上有 Floyd-Steinberg 抖动的 MATLAB 代码。
假设您首先按照 saastn 的回答(并回复它所说的关于这些图像之间的差异的内容):我想说的是,通过在 saastn 的图像中查看它们,Matlab 的模式看起来像是横向版本Floyd-Steinberg 在这里,要么通过旋转,要么更可能通过换位(将 x 与 y 交换,这是在 x+y 对角轴上的反射)。这不能仅仅通过改变系数来模仿,图像必须按列处理(“for x”在“for y”之外,等等)。
我正在尝试使用维基百科页面上的伪代码在 MATLAB 中实现 Floyd Steinberg 抖动 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
;全零、量化图像和原始图像。 None 个正常工作
编辑 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)))
问题是您试图改进伪代码并删除 oldpixel
!请注意,该算法不计算量化像素与其在原始图像中的对应值之间的误差,而是计算量化像素与抖动图像中先前值之间的误差,该值可能在扫描先前像素时已更新。
将 oldpixel
带回来并再次回顾整个算法。
但即使在修改之后,您也不能期望结果与 MATLAB 输出匹配,这可能是两个实现细节差异的结果。
您在 image_quantized
而不是原始图像中传播错误。去掉这张量化图,它不是算法的一部分。
您需要量化一个像素,然后找到与原始值的差异,并将该误差传播到未来的像素。
请注意,维基百科伪代码会执行此操作 in-place,图像只有一个副本可同时用作输入和输出。
在 this old blog post of mine 上有 Floyd-Steinberg 抖动的 MATLAB 代码。
假设您首先按照 saastn 的回答(并回复它所说的关于这些图像之间的差异的内容):我想说的是,通过在 saastn 的图像中查看它们,Matlab 的模式看起来像是横向版本Floyd-Steinberg 在这里,要么通过旋转,要么更可能通过换位(将 x 与 y 交换,这是在 x+y 对角轴上的反射)。这不能仅仅通过改变系数来模仿,图像必须按列处理(“for x”在“for y”之外,等等)。