10.1 曝光三要素(含位元級)
| 要素 | register | 位元/公式 |
| 快門(曝光行數) | 0x3500–0x3503 | 值 = (0x3501<<12)|(0x3502<<4)|(0x3503>>4) − 1(依 datasheet 位元布局) |
| 類比增益 | 0x350A–0x350B | 對應 datasheet gain map(非線性) |
| 數位增益 | ISP 端 | 最後手段 |
讀目前曝光三 register
for r in 0x3501 0x3502 0x3503; do
h=${r:2:2}; l=${r:4:2}
printf "%s: " "$r"; sudo i2ctransfer -y 22 w2@0x36 0x$h 0x$l r1
done
調適順序鐵則:先快門 → 類比增益 → 數位增益。用增益「補」曝光會犧牲畫質(shot noise 等比放大)。
10.2 Worked Example:從 register 算出曝光
假設讀回
0x3501 = 0x01 # 高位
0x3502 = 0xE4 # 中位
0x3503 = 0x10 # 低位(僅 bit[7:4] 有效)
# 曝光行數(依位元布局)
exposure = (0x01 << 12) | (0xE4 << 4) | (0x10 >> 4)
= 4096 + 3648 + 1
= 7745 行
# 實際時間 = 行數 × row_time
# row_time ≈ 影像行週期(由 PLL/時序決定,datasheet 可查)
這是理解「曝光 register」的練習;正式流程由 libcamera 以 µs 為單位控制(下一節)。
10.3 用 libcamera/picamera2 控制(正確方式)
AE 相關控制全表
picam2.set_controls({
"AeEnable": False, # 關自動
"ExposureTime": 20000, # 快門 µs(與 AnalogueGain 併用)
"AnalogueGain": 2.0,
"AeMeteringMode": 1, # 1=矩陣 2=中心加權 3=點測光
"ExposureCompensation": 0.0, # EV 補償
"AeConstraintMode": 0, # 約束(正常/高光優先)
})
測光模式:矩陣=全畫面平均;中心加權=中間重要;點測光=單點。背光場景用點測光中心人物才不會過曝。EV 補償整體偏移曝光目標。
10.4 banding:50/60Hz 與曝光
成因:室內光源(日光燈/LED)以市電頻率閃爍(50Hz 或 60Hz)。曝光若不是「半週期的整數倍」,各列累積的光量不同 → 明暗條紋。
| Register | 功能 |
| 0x3A00–0x3A03 | banding filter 設定(auto) |
| 0x3A02/0x3A03 | 50/60Hz 對應的曝光行數 |
libcamera 層的 banding
# 固定曝光時,選 50/60Hz 的整數倍
# 50Hz: 10ms 半週期 → ExposureTime=10000/20000...
# 60Hz: 8.33ms → ExposureTime=8333/16666...
picam2.set_controls({"ExposureTime": 20000}) # 50Hz 整數倍
10.5 AE 收斂與除錯
觀察 AE 狀態
rpicam-still --info -o /dev/null | grep -E "Exposure|Gain|Colour"
| 症狀 | 檢查方向 |
| AE 到極限仍暗 | 快門上限太低?增益上限太低?→ 補光或放寬上限 |
| 收斂慢 / 閃爍 | 測光區域、EV、convergence 速度參數 |
| banding | 曝光非 50/60Hz 整數倍 |
| 高光爆掉 | AE 只看平均 → 改高光優先約束或點測光 |
除錯核心:先判斷 AE 是否「受限」。受限 → 物理補光或放寬範圍;不受限 → 才查測光/收斂參數。不要一上來就亂調增益。
10.6 深入:測光模式的實務差異
| 模式 | 演算法 | 適用 | 陷阱 |
| 矩陣 | 全畫面加權平均 | 一般 | 大亮區誤導 |
| 中心加權 | 中間權重高 | 人物置中 | 主角不在中間 |
| 點測光 | 單點 | 精準主體 | 點選錯就全錯 |
實務:逆光場景 → 點測光對準主體,或 EV 補償 + 高光優先。沒有「最佳模式」,只有「最適合場景」。
10.7 Worked Example:banding 的曝光計算
50Hz 場景
# 市電 50Hz → 半週期 10ms
曝光 = 10000 * N µs (N = 1,2,3...)
例如 10000 / 20000 / 30000 µs
# 若設 15000µs(非整數倍)→ 出現 banding
# libcamera 有 banding 支援;手動固定曝光時要自己算
10.8 練習
- 在日光燈下拍一張,觀察是否有 banding。
- 固定曝光為 50Hz 整數倍,再拍一張比較。
- 用 --info 觀察 AE 收斂的曝光/增益值。
看完這單元你應該能說出:
- 曝光三要素 register 位元級與公式。
- Worked example 從 register 算曝光。
- libcamera 測光模式與 EV。
- banding 成因與 50/60Hz。
- AE 受限判斷與除錯方向。
進階真實情境 Worked Example:在日光燈下拍攝並分析 banding 的精確週期
場景:你在室內日光燈環境下拍攝,畫面出現明顯的水平明暗條紋。需要確認是 50Hz 還是 60Hz 的 banding,並計算正確的曝光值。
banding 週期分析
# 1. 用不同曝光拍攝,觀察條紋變化
for EXP in 8000 8333 10000 16666 20000 33333; do
rpicam-still --raw --shutter $EXP --gain 1 \
--awb off --awbgains 1,1 -o band_${EXP}us.dng 2>/dev/null
done
# 2. 分析各曝光下的亮度週期性
python3 - <<'EOF'
import rawpy, numpy as np
for exp in [8000,8333,10000,16666,20000,33333]:
raw = rawpy.imread(f'band_{exp}us.dng').raw_image
roi = raw[900:1100, 500:2000] # 橫向 ROI
row_means = roi.mean(axis=1)
std = row_means.std()
print(f"曝光{exp}µs: 行間亮度標準差={std:.2f} (越大=banding越嚴重)")
EOF
為什麼選這條路徑:用不同曝光拍攝同一場景,可以找出 banding 最嚴重的曝光值——那就是「非半週期整數倍」的曝光。50Hz 的半週期是 10ms(10000µs),60Hz 是 8.33ms(8333µs)。若 10000µs 的 std 最小,代表是 50Hz 環境;若 8333µs 最小,代表是 60Hz。這個方法比「看起來有沒有條紋」更精確。
深入原理擴充:OV5647 的 AEC 暫存器與行曝光時序
OV5647 的曝光是行級(line-based)的,不是微秒級的:
- 曝光行數:由 0x3501(高 8 位)和 0x3502(低 8 位)控制,共 16 位。實際曝光時間 = 曝光行數 × row_time。
- row_time:取決於 PLL 配置和像素時鐘。2592×1944@30fps 時,row_time ≈ 11.6µs。所以 libcamera 的 ExposureTime=20000µs 換算成行數約 20000/11.6 ≈ 1724 行。
- frame length(VTS):2592×1944 模式下 VTS ≈ 1968 行。若曝光行數 > VTS,感測器會「卡在曝光」→ 幀率下降或全黑。
- 曝光與行同步:每行的曝光起點由 Timing Generator 控制,行與行之間的曝光起點差為 1 row_time。這就是 Rolling Shutter 的「行間時間差」。
大家以為沒问题但其實是陷阱:很多人以為「libcamera 設 ExposureTime=20000µs 就真的曝光 20000µs」,但 libcamera 內部會向上取整到 row_time 的整數倍。若 row_time=11.6µs,20000/11.6=1724.1,libcamera 會取 1725 行 × 11.6µs = 20010µs——微小的偏差在高精度場景(如 banding 分析)可能有意義。
診斷式疑難排解表
| 症狀 | 可能原因 | 解決方案 |
| 室內日光燈下有水平明暗條紋 | 曝光時間非光源半週期的整數倍(50Hz→10ms, 60Hz→8.33ms) | 固定曝光為半週期整數倍(如 10000/20000µs for 50Hz) |
| AE 模式下 banding 消失但固定曝光時出現 | AE 的 banding filter 自動同步了;手動曝光時需自行同步 | 啟用 libcamera 的 auto-banding 或手動設整數倍曝光 |
| 曝光設為 10000µs 但仍有輕微條紋 | 光源非純正弦波閃爍(LED 可能有高諧波) | 嘗試 5000µs(半半週期)或用全局快門感測器 |
| AE 收斂後畫面過暗 | 場景亮度低,AE 已達曝光上限或增益上限 | 放寬 AE 範圍(增大 max_shutter/max_gain)或補光 |
| 戶外日光下也有輕微水平條紋 | 非 banding——可能是 rolling shutter 與 PWM 光源(如 LED 車燈)的交互 | 確認光源類型;PWM 光源需用全局快門或同步觸發 |
進階挑戰題
- 用示波器量測 OV5647 的 frame sync 訊號(若可接觸),驗證 row_time 是否與 PLL 配置一致。
- 設計一個「自動 banding 偵測」腳本:拍一張 RAW,分析行間亮度的週期性,自動判斷光源是 50Hz/60Hz/DC。
- 若場景中同時有 50Hz 日光燈和 60Hz LED 燈,會出現什麼症狀?如何處理?
延伸閱讀
專案級端到端 Worked Example:多場景曝光策略專案
場景:監控攝影機要在室內日光燈、室外日光、夜晚低光三種場景自動切換曝光策略,並避免 banding。本專案整合單元 10(AE/banding)、2(SNR)、13(雜訊)、14(回歸)知識,建立一套可驗證的曝光策略表。
exposure_strategy.py:三場景策略
from picamera2 import Picamera2
# 場景定義:增益上限、快門上限、banding 頻率
SCENES = {
"indoor_fluorescent": dict(max_gain=8.0, max_shutter=30000, banding=50),
"outdoor_day": dict(max_gain=2.0, max_shutter=8000, banding=None),
"night_lowlight": dict(max_gain=12.0,max_shutter=66000, banding=50),
}
def apply(picam2, scene):
s = SCENES[scene]
ctrl = {
"AeEnable": True,
"AeConstraintMode": 0,
"ExposureCompensation": 0.0,
"AnalogueGain": s["max_gain"] / 2,
}
# 若設 banding:曝光以半週期整數倍為準
picam2.set_controls(ctrl)
picam2 = Picamera2()
picam2.configure(picam2.create_still_configuration())
apply(picam2, "indoor_fluorescent")
驗證 banding 已消除
# 在日光燈下拍兩張:20000µs(50Hz OK)vs 15000µs(非整數倍)
rpicam-still --raw --shutter 20000 --gain 2 -o ok50.dng
rpicam-still --raw --shutter 15000 --gain 2 -o bad15.dng
python3 - <<'EOF'
import rawpy, numpy as np
for f in ['ok50.dng','bad15.dng']:
roi = rawpy.imread(f).raw_image[900:1100, 500:2000]
print(f, "行間σ =", round(roi.mean(axis=1).std(),2))
EOF
# 預期:ok50 行間σ 明顯小於 bad15(banding 消除)
專案規模與跨單元整合:曝光策略把單元 10 的 AE 知識變成「產品設定」:banding 用 50/60Hz 週期(單元 10.4)、gain 上限來自 SNR 量測(單元 2/13)、場景回歸用單元 14 的清單。策略表放進設定檔,AE 就從「碰運氣」變成「可驗證的工程決策」。
量測/驗證 SOP:AE 與 banding 驗證
- 在目標光源下跑 AE,用
--info 記錄收斂後的曝光/增益。
- 檢查收斂時間:換場景後 AE 應在 <2 秒內穩定。
- 用行間 σ 量測確認 banding 消失(<閾值)。
- 檢查高光:逆光場景高光不爆(用 AeConstraintMode=高光優先)。
- 在低光確認增益未超過 SNR 決定的上限。
- 三場景各錄一輪,存 log。
判讀指標:行間 σ 在固定曝光整數倍下應比非整數倍小 50%+;AE 收斂後曝光/gain 落在策略表設定範圍內;增益超過上限 = 場景亮度不足,需補光或放寬。
平台間對照:曝光控制
| 面向 | RPi5 | Orange Pi | Orin Nano | Thor |
| 曝光介面 | ExposureTime(µs) + AeEnable | v4l2 exposure(驅動單位) | SensorMode exp_time | SensorMode / Holoscan |
| banding 支援 | libcamera 自動 + 手動整數倍 | 感測器 banding filter | NVIDIA 自動 | NVIDIA 自動 |
| 測光模式 | 矩陣/中心/點 + EV | 有限 | 多模式可選 | 多模式 |
| 坑 | 曝光被 row_time 取整 | 單位模糊 | 自動收斂快但黑箱 | 生態新 |
互動式檢核清單
- - [ ] 能從 register 算出曝光行數(0x3501-0x3503)。
- - [ ] 已建立並驗證三場景曝光策略表。
- - [ ] 能用行間 σ 定量驗證 banding。
- - [ ] 能說出 50Hz/60Hz 的曝光整數倍。
- - [ ] 能判斷 AE 是否「受限」並採取正確行動。
- - [ ] 已記錄各場景的 AE 收斂 log。
第 3 輪深度加深
① Register 位元級完整工作流:OV5647 手動曝光設定與驗證
| 步驟 | 暫存器 | 值 | 位元級說明 |
| 1. 解除 AE | 0x3503 | 0x03 | bit[0]=1(manual AEC), bit[1]=1(manual AGC) |
| 2. 設定曝光高位 | 0x3500 | 0x00 | bit[3:0] = 曝光 bit[19:16] |
| 3. 設定曝光中位 | 0x3501 | 0x64 | bit[7:0] = 曝光 bit[15:8] |
| 4. 設定曝光低位 | 0x3502 | 0x00 | bit[7:4] = 4-bit 小數位 |
| 5. 設定增益 | 0x350A | 0x00 | bit[1:0] = analog gain 高位 |
| 6. 設定增益低位 | 0x350B | 0x10 | bit[7:0] = digital gain × 16 (0x10 = 1.0×) |
| 7. 驗證 | read-back 0x3500-0x3503 | — | 確認回讀值 = 寫入值 |
曝光計算公式:曝光時間(s) = (曝光行數 × 行時間) / 平台時脈。OV5647 在 24MHz MCLK 下,一行 ≈ 22.2μs。
② 多層疑難排解決策樹
決策樹 A:AE 收斂過慢或震盪
AE 異常
├─ 檢查 A:AE target brightness 是否合理
│ ├─ 太高(>200) → 曝光拉到最大仍不夠 → 降低 target
│ └─ 太低(<50) → 曝光壓到最低仍太亮 → 提高 target
├─ 檢查 B:AE convergance speed 設定
│ ├─ 太快 → 震盪 → 降低 step size
│ └─ 太慢 → 逐步增加 step size
├─ 檢查 C:場景是否有大量高動態範圍
│ ├─ 是 → AE 加權區域設定問題 → 調整 metering mode
│ └─ 否 → 繼續
└─ 檢查 D:50Hz/60Hz banding 是否造成行間差異
├─ 是 → 曝光行數非整數倍 → 調整為 100/120 的整數倍
└─ 否 → AE 算法本身問題
③ 量測驗證完整 SOP:AE 收斂時間量測
- 方法:LED 切換光源亮度 + 影像亮度 log
- 步驟:
a. LED 亮度 Level 1 → 等 AE 收斂 → 記錄穩定 brightness
b. 切換到 Level 2(突變)
c. 每幀記錄 brightness,直到收斂(±5% 以内)
- 量測條件:3 個亮度等級(暗/中/亮),每次切換測 5 回
- 統計:平均收斂幀數、最差收斂幀數
- 判讀:收斂 <30 幀 @30fps = <1s 正常;>60 幀 = 需優化 AE 參數
- 常見偏差:開場景 histogram 分佈極端 → AE target 誤判
④ 四平台終極對照
| 面向 | RPi5 | Orange Pi | Orin Nano | Thor | 推薦 |
| AE 控制方式 | libcamera 自動 | V4L2 exposure control | Argus AE 算法 | Holoscan + AI AE | 各有特色 |
| 曝光範圍 | 1-65535 行 | 依 sensor | 更寬範圍 | 更寬範圍 | Orin/Thor 範圍更寬 |
| 收斂速度 | 可調(tuning) | 固定 | 可調 | AI 自適應 | Thor 最快 |
| Metering 模式 | 全域/中心 | 全域 | 全域/中心/自訂 | 全域/中心/AI | Thor 最豐富 |
| 手動/自動切換 | ✓ tuning 檔 | V4L2 控制 | Argus API | Holoscan API | RPi5 最直觀 |
⑤ 完整 Bring-up 專案 Checklist
- - [ ] 確認 sensor 曝光暫存器可讀寫
- - [ ] 手動設定曝光並驗證影像亮度變化
- - [ ] 啟用 AE 並驗證自動收斂
- - [ ] 測試暗→亮→暗場景的 AE 收斂時間
- - [ ] 測試 50Hz/60Hz 下的 banding 行為
- - [ ] 調整 AE target brightness 並記錄效果
- - [ ] 測試 metering 模式切換
- - [ ] 記錄 AE 參數表存入 tuning 文件