
影像遞色是什麼?Bayer矩陣、Floyd–Steinberg誤差擴散與GIF、ASCII藝術
可用的顏色太少時,漸層可能變成一條條明顯的色帶。遞色(dithering,也稱抖色)透過改變點的排列,讓人感覺到中間的亮度或色彩。它不會增加儲存的顏色數,而是以空間紋理換取視覺上較平滑的階調。
不過,GIF不一定使用遞色,ASCII藝術也不一定使用誤差擴散。本文以公式比較Bayer有序遞色與Floyd–Steinberg誤差擴散,分別說明色盤選擇、GIF壓縮及字元對應的角色。
日文原文發布: 2026-04-26
量化與遞色有什麼不同?
量化是把輸入對應到有限輸出值的處理。例如黑白二值影像中,每個像素只能輸出黑或白。若一律以同一個臨界值判斷,平緩的漸層也可能被分成大片的黑色與白色區域。
遞色可以依位置改變臨界值,也可以把量化誤差傳給尚未處理的像素,以點的密度表現中間調。在細小紋理能被視覺混合的觀看距離,階調可能顯得更平滑;放大後則可能看見顆粒或規則圖案。細節與文字有時不加遞色反而更清楚,因此它不是必然提升畫質的處理。
常見用途包括黑白印刷、色盤影像及降低位元深度。即使以PNG等無損壓縮格式儲存,若之前已經減色,相對於原始影像仍然是有損轉換。遞色也不是能還原原始像素值的可逆編碼。
有序遞色:Bayer矩陣
B. E. Bayer在1973年的文獻探討如何以兩個輸出階調呈現連續階調影像。這裡使用把4×4臨界值矩陣重複鋪在影像上的黑白教學模型。輸入範圍為0~255,白色為255,黑色為0。以下是說明用的虛擬碼,不能直接當作JavaScript執行。座標從0開始,x向右增加、y向下增加,%表示餘數。
D4 = [[0, 8, 2, 10],
[12, 4, 14, 6],
[3, 11, 1, 9],
[15, 7, 13, 5]]
threshold = (D4[y % 4][x % 4] + 0.5) / 16
output = (input / 255 > threshold) ? 255 : 0這裡以16個區間的中心作為臨界值,不是直接把0~15的兩端對齊到0~255。輸入0時全部為黑,255時全部為白,127.5時一個區塊內有一半、也就是8個白色像素。均勻輸入時,區塊內的白色像素數可以是0~16,共17種覆蓋程度;每個像素本身仍只有兩種值。這是數值比例的模型,不代表編碼後RGB的50%就是物理光量的50%。
D1 = [[0]]
D(2n) = [[4*Dn, 4*Dn + 2*Un],
[4*Dn+3*Un, 4*Dn + Un]]
Un = 所有元素皆為1的 n × n 矩陣遞迴式的每一項都是n×n矩陣,方括號表示將這些矩陣上下左右拼接的分塊矩陣。依此可擴展為2×2、4×4及8×8。各像素只依賴座標與輸入,適合在GPU上平行運算。不過,即使把矩陣固定在螢幕座標,移動的影像或改變的顏色仍可能跨過臨界值,讓圖案改變;這並不保證影片不會閃爍。
Floyd–Steinberg誤差擴散:權重與影像邊界
Floyd與Steinberg在1976年的論文是空間誤差擴散的原始文獻之一。由左至右、由上至下處理時,先將包含先前接收誤差的目前值v量化為q,再把e = v − q傳給後續尚未處理的像素。
(x+1, y) += e * 7/16
(x-1, y+1) += e * 3/16
(x, y+1) += e * 5/16
(x+1, y+1) += e * 1/16權重總和為1,但不是平均分配。只有在所有接收位置都存在,且中途不取整、不將數值限制在某個範圍內時,計算上才會把這份誤差全部傳出。若實作直接捨棄落在影像外的分量,邊界就會流失誤差,因此有限大小影像的輸出平均值未必與輸入完全相同。
例如2×1輸入[100, 100],大於127.5時輸出白,否則輸出黑,並捨棄影像外的誤差。第一個像素變成黑色0,誤差為100。右邊的像素變成100 + 100×7/16 = 143.75,因此輸出白色255。結果是[0, 255],其總和不等於輸入總和200。「權重和為1,就能完全保留整張影像的平均亮度」是錯誤的理解。
應使用浮點數等適當表示法保存累積誤差。若每一步都存回8位元陣列而截斷數值,或限制在0~255,結果可能不同。處理順序、邊界處理與取整方式都是演算法的條件。
衍生方法:誤差傳到哪裡、傳出多少?
Jarvis–Judice–Ninke、Stucki、Burkes、Sierra及Atkinson等方法,傳遞誤差的位置與權重各不相同。不要只按名稱或發表年份判定優劣,應比較實際的擴散核心與輸出。下表對照gif.js的GIFEncoder.js中三種方法,數值都假設接收位置完整落在影像內。
表格若超出畫面寬度,可左右捲動。
| 方法 | 接收位置 | 權重總和 | 可由核心看出的特性 |
|---|---|---|---|
| Floyd–Steinberg | 4個像素;目前列與下一列 | 16/16 = 1 | 分配到較小的鄰近範圍 |
| Stucki | 12個像素;目前列與後續兩列 | 42/42 = 1 | 分配到較大的鄰近範圍 |
| Atkinson | 6個像素;目前列與後續兩列 | 6/8 = 3/4 | 各接收1/8,其餘1/4不再傳遞 |
表格來源:GitHub: gif.js/src/GIFEncoder.js at master · jnordberg/gif.js。這是實作權重的比較,不是對各方法發明年份的認定。
擴散範圍較大,代表要讀取與更新更多像素,但不一定更好看。Atkinson這類只擴散部分誤差的方法,可能失去細微的明暗階調。應以照片、輪廓及想呈現的復古風格實際比較。
彩色量化與GIF:先選色盤,再對應顏色
使用任意色盤減色時,先選擇可用的顏色,再把各像素對應到色盤項目。若只將RGB各通道獨立取整,可能產生不在色盤內的顏色組合。這與「從色盤選出輸出色,再將差異作為色彩向量擴散」是不同的處理。
採用單純RGB距離或考慮感知的距離,以及在線性光或編碼後RGB中計算誤差,都會影響結果。只指定CIEDE2000或OKLab的名稱,不代表減色一定更自然;仍須進行正確的色彩空間轉換,並依用途評估。色彩空間可參考CSS color-mix()與OKLCH文章。
pngquant結合色盤生成與適應性遞色。單純的「RGB最近鄰+標準Floyd–Steinberg」四步驟,不能直接當成其完整實作說明。
GIF色彩表最多有256個項目。使用區域色彩表的影像可以有自己的色盤,因此整段動畫不一定只使用同一組256色。遞色不是GIF規格的必要步驟,也與LZW壓縮分開。GIF與LZW專利文章有更詳細的說明。
NanToo的GIF製作工具使用gif.js,但目前呼叫時未指定遞色,預設值是false。函式庫支援Floyd–Steinberg等方法,不等於工具已啟用該功能。
ASCII藝術:字元對應不等於誤差擴散
把字元從視覺上較密到較疏排列,就能把亮度對應到字元選擇。不過,字元看起來多深,取決於字型、字距、文字顏色與背景色。N個字元不保證形成感知上等距的N個階調。僅憑字元密度讓影像看起來可辨識,不能認定使用了Floyd–Steinberg。
NanToo的ASCII藝術轉換工具先將透明像素合成到白色背景,並將各通道取整,再使用下列權重與索引對應。這同樣是虛擬碼。N是字元集合的元素數,至少為2;idx是從0開始的索引,floor表示向下取整。R、G、B是合成後0~255的值。
L = 0.299*R + 0.587*G + 0.114*B
mapped = invert ? 255-L : L
idx = min(N-1, max(0, floor(mapped/255 * (N-1))))這是採用BT.601之luma係數的明亮程度近似值。把這些係數套用在Canvas RGB上,不代表實作了完整的BT.601訊號處理,也不等於線性光的物理輝度。
黑色對應第一個字元,白色對應最後一個;反轉設定會反轉亮度對應。目前的轉換處理沒有誤差擴散,而且可用的字元集合不只一種,因此不能說它「永遠用70個字元忠實重現256階調」。應同時檢查字元排列與字型的實際顯示。
圖案、掃描方向與壓縮大小的取捨
誤差擴散也可能產生規則紋理或條紋。蛇形掃描逐列交替左右方向,由右向左處理的列也必須鏡射擴散核心的水平位移。這有助於減少單一方向的偏差,但不保證消除所有圖案。
有序遞色可以在相同座標重複使用同一個臨界值,但也容易看出重複的區塊紋理。藍雜訊的臨界值排列,以及沿曲線傳遞誤差的Riemersma等,都是其他選擇。ImageMagick提供Riemersma、Floyd–Steinberg誤差擴散及有序遞色的設定。不能只憑產品名稱,就推定每種模式都使用相同核心與掃描方式。
遞色在平坦區域加入細微變化時,壓縮後的檔案可能變大。它是在視覺階調、輪廓、顆粒感、處理時間及檔案大小之間取捨,並不是無代價地增加資訊。
降低位元深度與GPU運算
將高精度影像量化到較低位元深度時,遞色是讓色帶較不明顯的選項之一。不過,HDR轉SDR的色調映射是在改變亮度範圍,不等於將數值精度從16位元改為8位元。應把色調映射、色域轉換、量化與遞色視為不同處理階段。
Bayer公式由各像素的座標與輸入決定,因此可在GPU上平行運算。一般的誤差擴散則讓後續像素依賴先前的結果。這個差異會影響實作方式的選擇。
影像的空間遞色、時間方向取樣,以及機器學習模型的INT8量化,都涉及有限的表示方式,但不是同一套演算法。不能因此推論Floyd–Steinberg或Bayer普遍用於AI推論,也不能據此宣稱它們接近資訊理論上的最佳解。
重點整理:改變點的排列,而不是增加顏色數
- 量化限制輸出值;遞色改變紋理配置,調整中間階調的視覺感受。
- Bayer使用依座標而定的臨界值;Floyd–Steinberg先量化含累積誤差的值,再以不同權重擴散新誤差。
- 即使權重和為1,影像邊界、取整與範圍限制仍可能使整體平均值不完全保留。
- GIF的色盤限制、減色時的遞色與LZW壓縮,是不同機制。
- ASCII字元對應也不同於誤差擴散,需確認實作、設定及字型。
- 依用途,以實際影像比較顆粒感、輪廓、處理速度及儲存大小。
參考資料與來源
- JST J-GLOBAL: An adaptive algorithm for spatial greyscale. ↗(Floyd與Steinberg,1976年,Proc. SID 17(2):75–77。這是書目資訊,不是論文全文閱覽頁面。)
- Wikipedia: Ordered dithering - Wikipedia ↗
- Computer Graphics and Image Processing: A survey of techniques for the display of continuous tone pictures on bilevel displays ↗
- Wikipedia: Error diffusion ↗
- mitpress.mit.edu: Digital Halftoning ↗
- ACM Transactions on Graphics: Digital halftones by dot diffusion ↗
- ITU: BT.601 : Studio encoding parameters of digital television for standard 4:3 and wide screen 16:9 aspect ratios ↗
- Network: Computation in Neural Systems: Kohonen neural networks for optimal colour quantization ↗
- NDL Search: An Optimum Method for Two-Level Rendition of Continuous-Tone Pictures ↗(Bayer,1973年。這是書目資訊,不是論文全文。)
- CompuServe: Graphics Interchange Format, Version 89a ↗
- GitHub: gif.js/src/GIFEncoder.js at master · jnordberg/gif.js ↗
- pngquant: pngquant ↗
- ImageMagick: Command-line Options ↗
- Joel Yliluoma: Joel Yliluoma's arbitrary-palette positional dithering algorithm ↗
編輯說明
本文使用 AI 協助編輯,並於發布前由編輯確認。內容仍可能包含事實、解讀或時效上的錯誤;進行重要判斷前,請查閱所列的一手資料或官方文件。

