跳至内容
返回

屏幕不够,算法来凑(一):Ditherpunk 抖动算法原理与 JS 实时演示

更新于:  at  09:40 下午

背景

在嵌入式开发领域,我们经常会遇到色彩位数极低的显示设备:

如果直接将 24 位真彩图片进行量化处理,其结果往往如同烧焦的木炭,细节丢失殆尽。但若引入 抖动算法(Dithering),这些 1-Bit 屏幕便能模拟出细腻的灰度感。

此前我曾尝试用 Rust 实现过一个版本,但作为博客演示,使用 JavaScript 与 Canvas 在浏览器中直接进行仿真最为直观。本文将介绍几种主流抖动算法的原理及其 JS 实现。


实验室控制台

在此上传图片,下文的所有算法演示将同步生效。建议开启 Gamma 校正观摩图像暗部细节的差异。

* 图片将仅在本地处理,不会上传服务器

0x01 线性空间 (Linear Space)

这是本文最重要的核心内容。

很多开发者在处理图像时会直接进行 if (gray > 0.5) 的判断。 这是错误的。

sRGB 的非线性特性

主流图像格式通常存储在 sRGB 空间中。sRGB 为了适配人眼对暗部细节的敏感性,采用了非线性映射(约 Gamma 2.2)。

为什么我们需要如此麻烦地进行 Gamma 校正?这源于人类进化的结果:我们的眼睛对暗部变化的敏感度远高于亮部。在物理世界中,光子数量增加一倍,能量就增加一倍;但在人类感知中,亮度并不是线性增加的。sRGB 标准通过一条幂律曲线(约 )将更多的位深分配给了暗部信息。如果我们在处理抖动时不进行 De-gamma,算法会错误地将“感知上的中灰”当作“物理上的中灰”来分摊误差,导致图像在 1-bit 屏幕上看起来比原图暗得多,阴影细节会像沉入黑洞一样消失。

如果在 sRGB 空间直接进行误差扩散或加减运算,会导致以下问题:

  1. 亮度不守恒:计算出的灰度值与物理亮度不符。
  2. 图像偏暗:阴影部分会由于缺乏补偿而变成死黑。

因此,处理前必须先进行 De-gamma 转换。

function srgbToLinear(v) {
  v /= 255;
  return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
}

0x02 阈值裁剪 (Thresholding)

这是最原始、最简单的方案:设定一个固定阈值(通常为 0.5),高于该值设为 1(白),低于则设为 0(黑)。

结果: 细节丢失严重。由于强制舍弃了所有中间调,会导致严重的量化噪声,图像面貌全非。

演示:阈值裁剪 (Fixed Threshold 0.5)

0x03 随机抖动 (Random Dithering)

为了缓解量化误差,最直观的方法是在对比前引入随机噪声。

let newPixel = oldPixelLinear + (Math.random() - 128) / 255 > 0.5 ? 1.0 : 0.0;

结果: 虽然保留了部分细节,但图像布满了均匀分布的“雪花点”。这种 白噪声 (White Noise) 在视觉上非常刺眼,因为它在所有频率上都有能量分布。

演示:随机白噪声抖动

0x04 有序抖动 (Ordered Dithering)

有序抖动不再依赖随机性,而是使用特定的阈值矩阵进行循环铺设。最典型的是 Bayer 矩阵

Bayer 矩阵原理

Bayer 矩阵是一种分形结构。其核心设计目标是:在空间上尽可能均匀地分散不同等级的阈值点。

演示:Bayer 4x4 有序抖动

0x05 误差扩散 (Error Diffusion)

这是目前 1-Bit 图像处理的通用方案。其核心逻辑是:将当前像素量化产生的误差,按照特定权重分摊给邻近尚未处理的像素。

Floyd-Steinberg 算法

这是最知名的误差扩散算子。它将误差以 7/16、3/16、5/16、1/16 的比例分摊至右方和下方的四个邻居。

演示:Floyd-Steinberg 误差扩散

Atkinson 算法

由 Apple 工程师 Bill Atkinson 在早期麦金塔开发中提出。它只分摊 75% 的误差,且扩散范围更广(影响 6 个邻居)。这使得图像对比度更高,视觉上更清晰。

演示:Atkinson (Macintosh 风格)

0x06 蓝噪声 (Blue Noise)

如果你追求艺术级质感,蓝噪声是终极答案。

使用蓝噪声纹理作为阈值图,可以产生类似电影胶片颗粒的效果,完全消除了规律性网点。

演示:基于 R2 序列模拟的蓝噪声

总结

算法名称核心特征视觉风格计算复杂度适合场景
Threshold固定阈值高对比度、块状极低纯文本、高反差 Logo
Bayer矩阵映射规律网格、像素风动态 UI、复古游戏
Floyd-S误差扩散细腻、类素描摄影照片、电子相框
Atkinson局部扩散干净、高细节艺术扫描、低分辨率屏
Blue Noise空间排斥胶片颗粒感极高高级滤镜、印刷出版

从原始的阈值裁剪到精密的误差扩散,抖动算法在显示资源受限的情况下寻找到了人类视觉审美的平衡点。随着硬件资源的丰富,这些算法已经从“不得不选”变成了提升质感的“艺术风格”。

下一篇我们将深入讨论硬件实战:如何在内存资源匮乏的 ESP32 上实时生成高分辨率图像的抖动输出?

环境

Browser: Chrome Engine (Any)
Language: JavaScript (ES6+)
Framework: Vanilla JS / HTML5 Canvas
Target: PC / Embedded (SSD1306/EPD)

参考资料


在以下平台分享此文章: