废话不多说,先贴上变换的代码。
void applyDithering(Image& image, int width, int height) {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
// 原像素值
int oldPixel = image[y][x];
// 量化为0或255(即黑与白)
int newPixel = oldPixel < 128 ? 0 : 255;
image[y][x] = newPixel;
// 计算误差
int error = oldPixel - newPixel;
// 误差扩散到相邻像素
if (x + 1 < width) {
image[y][x + 1] += error * 7 / 16;
clamp(image[y][x + 1]);
}
if (x - 1 >= 0 && y + 1 < height) {
image[y + 1][x - 1] += error * 3 / 16;
clamp(image[y + 1][x - 1]);
}
if (y + 1 < height) {
image[y + 1][x] += error * 5 / 16;
clamp(image[y + 1][x]);
}
if (x + 1 < width && y + 1 < height) {
image[y + 1][x + 1] += error * 1 / 16;
clamp(image[y + 1][x + 1]);
}
}
}
}
解释一下什么是误差扩散。顾名思义,就是要将我们计算得到的误差扩散到相邻的像素去。同时,我们遵循以下原则:
右侧像素的误差为 7/16;
左下方像素的误差为 3/16;
正下方像素的误差为 5/16;
右下方像素的误差为 1/16。
具体到代码(取其中一段为例子):
if (x + 1 < width) {
image[y][x + 1] += error * 7 / 16;
clamp(image[y][x + 1]);
}
我们就将右侧的像素加上之前计算得到误差的7/16。至于之后是如何判断得到左下/下方/右下像素的,相信一眼就能看明白。我们依次按照系数进行如上计算即可。