跳轉到

1.3 影像的取樣與量化#

概念說明#

真實世界的影像是連續的:光線的強度與顏色隨空間位置連續變化。要把這樣的連續訊號存進電腦,必須經過兩個步驟:

取樣 (Sampling):在空間上把影像切成離散的網格。相機感光元件的每個感光單元對應一個取樣點。網格越密(取樣率越高),解析度越高,細節越豐富。取樣率不足時,會出現「鋸齒狀」(aliasing/莫列波紋),例如拍攝細密的條紋襯衫時出現不規則的彩色波紋。

量化 (Quantization):把每個取樣點上連續變化的亮度,對應到有限的等級。8-bit 表示 256 個等級。位元數太少時,平緩的明暗漸層會變成一圈一圈的「色帶」(banding)。

Nyquist 取樣定理指出:若訊號中最高頻率成分為 f_max,取樣率必須至少為 2×f_max才能完整還原訊號。在影像中,「高頻」對應細密紋理與銳利邊緣。若影像中有超過取樣率一半以上的空間頻率成分,取樣後會摺疊成低頻的假紋理——這就是鋸齒的數學本質。

演算法步驟#

降低解析度(二次取樣):

  1. 理論上正確做法:先用低通濾波(如高斯模糊,見 3.2 節)把高頻成分壓掉,避免摺疊。
  2. 再依固定步距挑選像素(每隔 k 取一個),或平均 k×k 方塊。
  3. 直接跳著取(不先低通)是最快但會產生鋸齒的做法。

減少位元數(重新量化):

  1. 原影像值範圍 [0, 255] 除以 2^r,得到「量化編號」。
  2. 乘回 2^r,得到近似值。此步驟不可逆——資訊確實損失了。

Python 程式碼範例#

import numpy as np
from PIL import Image

# 產生一張細密條紋影像(極高頻)
H, W = 120, 120
y, x = np.mgrid[0:H, 0:W]
stripes = (((x + y) // 4) % 2).astype(np.uint8) * 255
Image.fromarray(stripes).save("stripes.png")

# 正確的縮小:先平均 4x4 方塊,再下取樣
blk = stripes.reshape(30, 4, 30, 4).mean(axis=(1, 3)).astype(np.uint8)
Image.fromarray(blk).save("stripes_small_good.png")

# 錯誤的縮小:直接每 4 取 1
bad = stripes[::4, ::4]
Image.fromarray(bad).save("stripes_small_bad.png")
print("平均法縮小後的灰階數(應只剩灰):", np.unique(blk)[:5])
print("直接取樣後仍保留黑白極端:", np.unique(bad)[:5])

# 量化:把 8-bit 減到 r bits
def quantize(img, bits):
    return ((img.astype(np.float64) / 256).astype(int) * 256 / (2**(8-bits))) \
        .astype(np.uint8) if bits < 8 else img

img16 = (np.linspace(0, 255, 256)).astype(np.uint8)
q4 = quantize(img16, 4)   # 只剩 16 個等級
q2 = quantize(img16, 2)   # 只剩 4 個等級
print("8-bit 等級數:", len(np.unique(img16)))
print("4-bit 等級數:", len(np.unique(q4)))
print("2-bit 等級數:", len(np.unique(q2)))

觀察輸出:先平均再縮小後,高頻條紋被壓成灰色(頻率被正確移除),直接取樣卻仍保留黑白極端,若條紋頻率與取樣網格「剛好錯位」,就會出現假低頻紋理。量化實驗則顯示位元數減少時等級數隨之以 2 的次方遞減。

複雜度分析#

下取樣(簡單間隔取樣):O(1)/輸出像素。含方塊平均的取樣:每輸出像素平均 k²個值,O(k²)。先高斯低通再取樣:與濾波核大小成正比,仍是線性於像素數。量化:O(N)(N 為像素數),可用查找表(LUT) 加速到每像素一次查表。

練習#

  1. 產生一張「黑白條紋寬度 3 像素」的影像,分別用「直接每 4 取 1」與「先平均再取樣」縮小,比較兩結果的平均值與直方圖。
  2. 寫一個 quant(img, bits) 函式,對彩色影像輸出 1、2、3-bit 的版本,並用 PIL 存檔。
  3. 用 Nyquist 定理解釋:為什麼拍攝電腦螢幕時常會出現彩虹波紋?相機與手機如何用硬體或軟體處理此問題?