影像處理:頻率域的直覺理解
核心概念
空間域看的是「每個位置的像素值」
頻率域看的是「影像變化的快慢」
🎵 用聲音類比
想像聲音的兩種呈現方式:
空間域(時域)= 看波形圖
- 顯示:每個時間點的振幅
- 特點:看到聲波的起伏
- 缺點:很難看出「有哪些音高」
頻率域 = 看頻譜圖
- 顯示:有哪些音高/頻率
- 特點:可以分辨不同樂器
- 優點:一目瞭然看出音色組成
實際例子
一首歌的分析:
波形圖(空間域):
複雜的上下震盪,很難理解
頻譜圖(頻率域):
├─ 低頻:有一根很高的柱子 → 低音鼓
├─ 中頻:有連續的波動 → 人聲
└─ 高頻:有一些尖峰 → 鈸聲、沙鈴
關鍵領悟:
同樣的聲音,用不同角度看會有不同的理解方式!
📸 影像的頻率
低頻 = 變化慢 = 平滑區域
特徵:
- 相鄰像素的值很接近
- 顏色或亮度緩慢變化
- 大面積的均勻區域
實際例子:
- 🌤️ 藍天
- 🧱 牆壁
- 👤 臉部膚色
- 🌊 平靜的海面
- 📄 白紙背景
視覺效果: 看起來平滑、柔和、沒有明顯邊界
高頻 = 變化快 = 細節/邊緣
特徵:
- 相鄰像素的值差異很大
- 顏色或亮度急劇變化
- 有明顯的輪廓或紋理
實際例子:
- 💇 頭髮絲
- 📝 文字邊緣
- 🧵 布料紋理
- 🌲 樹葉細節
- 📐 物體輪廓
視覺效果: 看起來銳利、清晰、有邊界感
💡 具體例子:人臉照片
假設一張照片內容:
空間域看到:
一個人的臉 + 背景牆 + 頭髮細節
頻率域分解:
├─ 低頻成分:
│ ├─ 臉部大致輪廓
│ ├─ 整體光線明暗
│ └─ 背景牆的顏色
│
├─ 中頻成分:
│ ├─ 五官的形狀(眼睛、鼻子、嘴巴)
│ ├─ 臉部明暗過渡
│ └─ 膚色的漸層變化
│
└─ 高頻成分:
├─ 皮膚的毛孔
├─ 頭髮的細絲
├─ 眼睫毛
└─ 瞳孔邊緣
視覺化理解
| 頻率 | 保留後的效果 |
|---|---|
| 只保留低頻 | 模糊的大致輪廓,像是近視看到的 |
| 只保留高頻 | 只剩邊緣線條,像是素描 |
| 全部保留 | 完整清晰的照片 |
🔧 實際應用
1. 模糊與銳化
低通濾波器(Low-pass Filter)
- 操作:保留低頻,去除高頻
- 效果:影像變模糊
- 應用:
- 去除雜訊(高頻雜點)
- 平滑處理
- 磨皮美肌
原圖 → [低通濾波] → 模糊、柔和的影像
高通濾波器(High-pass Filter)
- 操作:保留高頻,去除低頻
- 效果:強調邊緣和細節
- 應用:
- 銳化影像
- 邊緣檢測
- 增強細節
原圖 → [高通濾波] → 只剩輪廓和邊緣
2. 影像壓縮(JPEG)
原理
人眼對高頻細節不敏感 → 可以丟棄部分高頻資訊
過程
1. 將影像轉換到頻率域(DCT 變換)
2. 量化高頻係數(允許較大誤差)
3. 壓縮編碼
4. 轉回空間域
結果
- 檔案大小:縮小到原本的 1/10 或更小
- 視覺效果:人眼幾乎看不出差異
- 缺點:過度壓縮會產生「方塊效應」(還是高頻資訊流失)
3. 去摩爾紋
問題
用相機拍螢幕或網狀物時出現的波紋圖案
原因
摩爾紋是「特定頻率的干涉」現象
解決方法
1. 轉換到頻率域
2. 找出摩爾紋對應的頻率(會在頻譜中出現異常的峰值)
3. 用帶阻濾波器消除那個特定頻率
4. 轉回空間域
在頻率域處理比在空間域容易得多!
4. 影像浮水印
隱藏浮水印
- 在頻率域的中頻區域嵌入資訊
- 人眼看不出來,但頻譜分析能找到
- 抗壓縮、抗裁切
為什麼用中頻?
- 低頻:太容易被修改
- 高頻:容易在壓縮時流失
- 中頻:穩定且不顯眼
🎯 關鍵概念:傅立葉轉換
核心思想
任何影像都可以看成「一堆不同頻率、不同方向的正弦波疊加而成」
數學表達(簡化版)
影像(x,y) = Σ [振幅 × cos(頻率×位置 + 相位)]
不同頻率
傅立葉轉換就是找出:
- 每個頻率的「振幅」有多大
- 每個頻率的「相位」是多少
直覺理解
樂高積木比喻
空間域:
- 看到完成的樂高作品(城堡)
- 描述每個位置有什麼顏色的積木
頻率域:
- 看到用了哪些種類的積木
- 1×1 小積木(高頻):用來做細節
- 2×4 中積木(中頻):用來做主結構
- 大底板(低頻):用來做基礎
轉換的意義:
- 正向轉換:從「作品」分析「用了哪些材料」
- 反向轉換:從「材料清單」組裝出「作品」
波的疊加原理
一維例子(聲音)
簡單的聲音 = 單一頻率的波
~~~~~~~~~
複雜的聲音 = 多個頻率疊加
~~~~~~~~~ (低頻:基音)
+ ~~~~ (高頻:泛音1)
+ ~~ (更高頻:泛音2)
= ~∼~∼~∼~ (複雜波形)
二維例子(影像)
簡單的影像 = 單一方向、單一頻率的條紋
||||||||||||
複雜的影像 = 多個方向、多個頻率疊加
|||||||||||| (垂直低頻)
+ ━━━━━━━━━━ (水平低頻)
+ ////// (斜向高頻)
= 實際的照片
頻譜圖的閱讀
轉換到頻率域後,會得到一張「頻譜圖」:
頻譜圖特徵:
┌─────────────────┐
│ ★ │ ← 中心:低頻(DC 分量,平均亮度)
│ ● ★ ● │ ← 中間:中頻
│● ● ★ ● ● │ ← 邊緣:高頻
│ ● ★ ● │
│ ★ │
└─────────────────┘
★ = 最亮的點(能量最集中的頻率)
● = 較亮的點(次要頻率)
= 較暗的區域(很少能量)
判讀方法
- 中心很亮:影像有大片平坦區域
- 中心周圍有環:影像有週期性紋理(如柵欄)
- 十字形亮線:影像有水平或垂直的強烈邊緣
- 分散的亮點:影像紋理複雜且多變
🧮 數學補充(選讀)
一維離散傅立葉轉換(DFT)
正向轉換(時域 → 頻域):
F(k) = Σ f(n) × e^(-2πikn/N)
n=0 到 N-1
反向轉換(頻域 → 時域):
f(n) = (1/N) × Σ F(k) × e^(2πikn/N)
k=0 到 N-1
二維離散傅立葉轉換(2D-DFT)
F(u,v) = Σ Σ f(x,y) × e^(-2πi(ux/M + vy/N))
x y
f(x,y) = (1/MN) × Σ Σ F(u,v) × e^(2πi(ux/M + vy/N))
u v
不用怕複雜! 實務上都是呼叫函式庫(如 NumPy 的 fft.fft2)
🐍 Python 實作範例
基礎範例:頻域濾波
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 讀取灰階影像
img = cv2.imread('photo.jpg', 0)
# === 1. 轉換到頻率域 ===
# 進行傅立葉轉換
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
# 將零頻率移到中心(方便觀察)
dft_shift = np.fft.fftshift(dft)
# 計算頻譜(用於顯示)
magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:,:,0], dft_shift[:,:,1]))
# === 2. 創建濾波器遮罩 ===
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2 # 中心點
# 低通濾波器(保留低頻)
mask_low = np.zeros((rows, cols, 2), np.uint8)
r = 30 # 半徑
mask_low[crow-r:crow+r, ccol-r:ccol+r] = 1
# 高通濾波器(保留高頻)
mask_high = np.ones((rows, cols, 2), np.uint8)
mask_high[crow-r:crow+r, ccol-r:ccol+r] = 0
# === 3. 應用濾波器 ===
# 低通濾波
fshift_low = dft_shift * mask_low
f_ishift_low = np.fft.ifftshift(fshift_low)
img_low = cv2.idft(f_ishift_low)
img_low = cv2.magnitude(img_low[:,:,0], img_low[:,:,1])
# 高通濾波
fshift_high = dft_shift * mask_high
f_ishift_high = np.fft.ifftshift(fshift_high)
img_high = cv2.idft(f_ishift_high)
img_high = cv2.magnitude(img_high[:,:,0], img_high[:,:,1])
# === 4. 顯示結果 ===
plt.figure(figsize=(15, 10))
plt.subplot(2, 3, 1), plt.imshow(img, cmap='gray')
plt.title('原始影像'), plt.axis('off')
plt.subplot(2, 3, 2), plt.imshow(magnitude_spectrum, cmap='gray')
plt.title('頻譜'), plt.axis('off')
plt.subplot(2, 3, 3), plt.imshow(mask_low[:,:,0], cmap='gray')
plt.title('低通濾波器遮罩'), plt.axis('off')
plt.subplot(2, 3, 5), plt.imshow(img_low, cmap='gray')
plt.title('低通濾波結果(模糊)'), plt.axis('off')
plt.subplot(2, 3, 6), plt.imshow(img_high, cmap='gray')
plt.title('高通濾波結果(邊緣)'), plt.axis('off')
plt.tight_layout()
plt.show()
進階範例:去除週期性雜訊
import cv2
import numpy as np
def remove_periodic_noise(image_path):
"""去除影像中的週期性雜訊(如掃描線)"""
# 讀取影像
img = cv2.imread(image_path, 0)
# 傅立葉轉換
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# 計算頻譜大小(用於找雜訊峰值)
magnitude = cv2.magnitude(dft_shift[:,:,0], dft_shift[:,:,1])
# 找出異常高的頻率峰值(雜訊)
# 這裡簡化處理:手動標記要去除的頻率位置
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
# 假設雜訊在 (crow-100, ccol) 和 (crow+100, ccol) 這兩個位置
# 創建帶阻濾波器
mask = np.ones((rows, cols, 2), np.uint8)
r = 10 # 阻擋半徑
# 在雜訊位置創建凹陷
mask[crow-100-r:crow-100+r, ccol-r:ccol+r] = 0
mask[crow+100-r:crow+100+r, ccol-r:ccol+r] = 0
# 應用濾波器
fshift = dft_shift * mask
# 反轉換回空間域
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0], img_back[:,:,1])
return img, img_back
# 使用範例
original, filtered = remove_periodic_noise('noisy_image.jpg')
# 顯示結果
cv2.imshow('Original', original)
cv2.imshow('Filtered', filtered)
cv2.waitKey(0)
cv2.destroyAllWindows()
實用函式:分析影像頻率特性
def analyze_frequency_content(img):
"""分析影像的頻率內容分佈"""
# 轉換到頻率域
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# 計算幅度譜
magnitude = cv2.magnitude(dft_shift[:,:,0], dft_shift[:,:,1])
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
# 定義頻率環
def get_ring_energy(inner_r, outer_r):
"""計算特定頻率環的能量"""
y, x = np.ogrid[:rows, :cols]
dist = np.sqrt((x - ccol)**2 + (y - crow)**2)
ring_mask = (dist >= inner_r) & (dist < outer_r)
return np.sum(magnitude[ring_mask])
# 計算不同頻率範圍的能量
low_freq = get_ring_energy(0, 30)
mid_freq = get_ring_energy(30, 100)
high_freq = get_ring_energy(100, min(rows, cols)//2)
total = low_freq + mid_freq + high_freq
print(f"低頻能量: {low_freq/total*100:.1f}%")
print(f"中頻能量: {mid_freq/total*100:.1f}%")
print(f"高頻能量: {high_freq/total*100:.1f}%")
# 判斷影像特性
if low_freq/total > 0.8:
print("→ 這是一張平滑的影像(少細節)")
elif high_freq/total > 0.3:
print("→ 這是一張細節豐富的影像")
else:
print("→ 這是一張平衡的影像")
# 使用範例
img = cv2.imread('test.jpg', 0)
analyze_frequency_content(img)
🎓 深入理解:常見問題
Q1: 為什麼頻譜圖看起來是對稱的?
答: 因為實數影像的傅立葉轉換具有「共軛對稱性」
F(u, v) = F*(-u, -v)
意思是:頻譜的左半邊和右半邊是鏡像關係
所以我們只需要看一半的頻譜就夠了
Q2: DC 分量是什麼?
答: DC (Direct Current) 分量是頻率為 0 的成分
- 位置:頻譜圖的正中心
- 意義:整張影像的「平均亮度」
- 特點:最大的值,通常要取 log 才能看清其他頻率
# 取得 DC 分量
dc_value = dft_shift[crow, ccol]
# DC 分量越大 → 影像整體越亮
# DC 分量越小 → 影像整體越暗
Q3: 為什麼要用 log 尺度顯示頻譜?
答: 因為頻率分佈的動態範圍太大
DC 分量的值可能是 10^6
高頻成分的值可能只有 10^1
如果不取 log,高頻成分會完全看不見(都是黑色)
magnitude_spectrum = 20 * np.log(cv2.magnitude(...) + 1)
↑
取 log 壓縮動態範圍
Q4: 快速傅立葉轉換(FFT)比 DFT 快多少?
答: 快非常多!
| 影像大小 | DFT 複雜度 | FFT 複雜度 | 速度提升 |
|---|---|---|---|
| 64×64 | O(N⁴) | O(N² log N) | ~100倍 |
| 512×512 | O(N⁴) | O(N² log N) | ~1000倍 |
| 1024×1024 | O(N⁴) | O(N² log N) | ~5000倍 |
實務建議: 永遠使用 FFT,不要用 DFT
Q5: 彩色影像怎麼做頻域處理?
答: 有兩種方法
方法 1:分別處理三個通道
b, g, r = cv2.split(img)
# 對每個通道分別做 FFT
dft_b = cv2.dft(np.float32(b), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_g = cv2.dft(np.float32(g), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_r = cv2.dft(np.float32(r), flags=cv2.DFT_COMPLEX_OUTPUT)
# ... 濾波處理 ...
# 合併回彩色影像
result = cv2.merge([b_filtered, g_filtered, r_filtered])
方法 2:轉到 HSV,只處理 V 通道(推薦)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
# 只對明度(V)做頻域處理
v_filtered = frequency_filter(v)
# 合併回去
hsv_filtered = cv2.merge([h, s, v_filtered])
result = cv2.cvtColor(hsv_filtered, cv2.COLOR_HSV2BGR)
🚀 延伸學習
相關主題
-
小波轉換(Wavelet Transform)
- 比傅立葉轉換更靈活
- 同時提供時間和頻率資訊
- 用於 JPEG2000 壓縮
-
離散餘弦轉換(DCT)
- JPEG 壓縮的核心
- 只用實數(比 FFT 簡單)
- 能量集中度更好
-
加伯濾波器(Gabor Filter)
- 模擬人類視覺系統
- 同時具有空間和頻率選擇性
- 用於紋理分析和人臉識別
-
短時傅立葉轉換(STFT)
- 分段做傅立葉轉換
- 可以看到頻率隨時間的變化
- 用於語音處理
📚 學習資源推薦
書籍
- 《數位影像處理》(Rafael C. Gonzalez) - 第 4 章頻域處理
- 《Fundamentals of Digital Image Processing》(Chris Solomon)
線上課程
- Coursera: Image and Video Processing (Duke University)
- YouTube: 3Blue1Brown 的傅立葉級數視覺化
實作練習
# 練習 1: 觀察不同影像的頻譜差異
# - 拍一張天空的照片(低頻為主)
# - 拍一張樹葉的照片(高頻豐富)
# - 比較兩者的頻譜
# 練習 2: 實作理想低通濾波器
# - 嘗試不同的截止頻率
# - 觀察「振鈴效應」(Ringing)
# 練習 3: 影像壓縮實驗
# - 手動設定頻率閾值
# - 看看要丟掉多少高頻才會明顯失真
🎁 總結
核心記憶點
-
空間域 vs 頻率域
- 空間域 = 每個像素的值
- 頻率域 = 變化的快慢
-
頻率的意義
- 低頻 = 平滑、輪廓、整體
- 高頻 = 細節、邊緣、紋理
-
轉換的目的
- 某些操作在頻域更容易(如濾波、壓縮)
- 頻域看到空間域看不到的資訊(如週期性)
-
實務應用
- 模糊/銳化 → 濾波器
- 壓縮 → 丟棄高頻
- 去雜訊 → 帶阻濾波器
- 浮水印 → 中頻嵌入
最後的比喻
影像處理就像聽音樂:
- 空間域 = 聽歌詞(一個字一個字聽)
- 頻率域 = 聽旋律(整體感受和聲、節奏)
兩種方式都重要,但有時候頻域能讓你「聽出」空間域聽不到的東西!
記住:理解比記憶重要,實作比理解重要! 🚀
馬上打開 Python,試試看把你的照片轉到頻率域吧!