3.2 平滑濾波與高斯濾波#
概念說明#
平滑 (smoothing) 或模糊 (blurring) 的目的:抑制雜訊、去除細節、為後續運算(如邊緣偵測前的降雜)鋪路。平滑濾波分兩大家族:
盒狀濾波 (box filter):核心所有權重相等,如 3×3 全 1/9。輸出就是鄰域平均。缺點:每個鄰居不分遠近一視同仁,且方形核心會讓斜線與邊緣產生方塊狀痕跡。
高斯濾波 (Gaussian filter):權重按二維高斯函數分布:
G(x, y) = (1 / 2πσ²) · exp(−(x² + y²) / 2σ²)
離中心越近權重越大,呈鐘形遞減。核心尺寸 k 與 σ 的關係:通常取 k ≈ 6σ+1 以涵蓋 99.7% 的能量;固定 k 時 σ 越大越模糊,固定 σ 時 k 太小會截斷高斯尾部。
高斯濾波優於盒狀濾波的三個理由:
- 各向同性:對水平、垂直、斜向的平滑程度一致,不留方向性痕跡。
- 可分離:二維高斯 = 兩個一維高斯的卷積,速度從 k² 降到 2k。
- 連續卷高斯仍是高斯:模糊多次不會產生奇怪的形狀,σ 的合成是 √(σ₁²+σ₂²)。
從訊號處理觀點,高斯濾波是低通濾波器:保留緩慢變化的大結構,壓制快速變化的高頻成分(雜訊、細紋理、邊緣)。σ 就是「截止頻率」的旋鈕——σ 越大,通過的高頻越少。這個頻域觀點在第 5 章會用傅立葉轉換嚴格證明。
權衡:模糊在降雜訊的同時也把邊緣抹鈍了。雜訊抑制與邊緣保留是平滑濾波永恆的兩難,中值濾波(下一節)與邊緣保留濾波(bilateral filter)是此兩難的其他解。
演算法步驟#
- 選定 σ 與核心尺寸 k(奇數)。
- 產生一維高斯核心:對 i = −r…r(r = k//2),g[i] ∝ exp(−i²/2σ²),並正規化使總和為 1。
- (可分離加速)先對每列做一維水平卷積,再對結果每行做垂直卷積。
- 邊界用複製或鏡射填充。
- 輸出即平滑影像。
Python 程式碼範例#
import numpy as np
from PIL import Image
# 100x100 影像:平滑背景 128 + 高斯雜訊 + 一個亮方塊
rng = np.random.default_rng(1)
img = np.full((100, 100), 128.0) + rng.normal(0, 25, (100, 100))
img[40:60, 40:60] = 200
img = np.clip(img, 0, 255).astype(np.uint8)
print("雜訊影像標準差:", img.std().round(1))
def gaussian_kernel1d(k, sigma):
r = k // 2
x = np.arange(k) - r
g = np.exp(-x**2 / (2 * sigma**2))
return g / g.sum()
def gaussian_blur(img, k=5, sigma=1.5):
g = gaussian_kernel1d(k, sigma)
# 水平卷積
tmp = np.apply_along_axis(
lambda row: np.convolve(row, g, mode="same"), 1, img.astype(np.float64))
# 垂直卷積
out = np.apply_along_axis(
lambda col: np.convolve(col, g, mode="same"), 0, tmp)
return out
blur = gaussian_blur(img, 5, 1.5)
print("模糊後標準差:", blur.std().round(1), "(雜訊被壓低)")
# 比較不同 σ 的模糊程度:看亮方塊邊緣的過渡寬度
for sigma in [0.5, 1.5, 3.0]:
b = gaussian_blur(img, 11, sigma)
row = b[50, 34:48].round(1) # 穿過方塊左邊緣的一列
print(f"σ={sigma}: 邊緣剖面 {row}")
# 盒狀 vs 高斯:同一列的比較
box = np.apply_along_axis(
lambda row: np.convolve(row, np.ones(5)/5, mode="same"), 1,
img.astype(np.float64))
print("盒狀5 邊緣:", box[50, 34:48].round(1))
執行後可見:雜訊影像的標準差從約 25 掉到個位數,而方塊位置仍在;σ=0.5 時邊緣剖面仍在 2~3 個像素內完成過渡,σ=3.0 時過渡拉長到近十個像素——這就是「模糊程度」的數值化。盒狀與高斯的邊緣剖面形狀不同:高斯的過渡是平滑的 S 形,盒狀則較為線性且有小幅度震盪。
複雜度分析#
直接二維卷積:O(H·W·k²)。可分離後:水平 + 垂直各 O(H·W·k),總計 O(H·W·k),對 k=51 從 2601 次乘加/像素降到 102 次。用 numpy 向量化或 OpenCV 可再快一個數量級。產生核心本身 O(k)。空間:O(H·W)(含中間暫存)。若需對多種 σ 反覆模糊,可預先產生核心重用。
練習#
- 驗證高斯可分離性:對一張小影像分別做「二維核心一次」與「兩次一維」,比較輸出是否在浮點誤差內相同。
- 對含雜訊影像連續套兩次 σ=1 的高斯模糊,結果是否等於 σ=√2 的一次模糊?用邊緣剖面數值驗證。
- 討論:為什麼「先模糊再縮圖」比「直接縮圖」能減少鋸齒?用 2×2 縮小一張斜線影像的數值實驗支持你的論點。