單元 14 · 清晰度、動態範圍與調校工作流

後處理與調校流程

清晰度與對比

動態範圍與 HDR

調校工作流(照做)

  1. 拍灰卡/色卡,固定光源。
  2. 校正黑位、曝光基準、白平衡。
  3. 色彩喜好微調。
  4. 降噪 vs 細節平衡。
  5. 不同場景回歸。
紀律:一次只改一個參數、記錄前後、統一場景比較。先 RAW 對、再後處理。

14.6 動態範圍與 HDR(本平台)

工程取捨:先量測場景動態範圍需求(亮/暗是否同時爆掉)再決定 HDR 或 tone mapping。

14.7 每次改動的記錄範本

tuning 改動 log
日期: ____  場景: ____
改動: 參數 A → B
原因: ____
結果: ____(量化)
回歸: ____ ✓/✗
附圖: ____
紀律:可重現的調校 = 完整 log。一次只改一個參數、統一場景比較。

14.6 深入:調校工作流與記錄

  1. 校正順序:黑位 → LSC → AWB/CCM → 曝光基準。
  2. 動態:AE/AWB convergence、banding。
  3. 美化:NR ↔ Sharpen。
  4. 回歸:室內/日光/逆光。
tuning log 範本
日期/場景/改動/原因/結果(量化)/回歸 ✓✗/附圖
紀律:一次只改一個參數、統一場景比較、完整記錄。

14.8 深入原理:動態範圍、位元深與 tone mapping

「動態範圍」是場景最亮與最暗可同時保留的範圍。RAW 的 DR 上限 ≈ 20·log₁₀(FullWell / ReadNoise);輸出受限於位元深(10-bit → 60dB 的量化上限)。

技術原理trade-off
單幀 + tone mapping壓縮亮部曲線犧牲對比,運動無假影
DOL HDR(多幀)短/長曝光合併動態範圍↑,但運動 ghost
Sensor HDR雙增益/雙曝光硬體依感測器支援

判斷要不要 HDR:量場景「最亮/最暗 ROI 的 RAW 值」。若亮部已 1023、暗部仍貼近黑位,表示超過單幀 DR → 才考慮 HDR。若兩端都還在範圍內,HDR 只是徒增 ghost 風險。

tone mapping 與 gamma 的差別:gamma 是固定曲線(標準顯示轉換);tone mapping 是場景自適應曲線(壓縮動態範圍)。後處理時兩者可疊加。

14.9 完整 Worked Example:調校工作流一輪

步驟 1|黑位校正(RAW 起點)
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('dark.raw', dtype=np.uint16).reshape(720,1280)
ob = np.median(raw[600:700, 400:880])     # 蓋鏡頭拍的暗幀
print('OB =', ob)
np.save('ob.npy', ob)
EOF
步驟 2|LSC(來自單元 12 的增益圖)
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('shot.raw', dtype=np.uint16).reshape(720,1280)
ob  = np.load('ob.npy')
flat = (raw - ob).clip(0)                 # 先減黑位
for name, sl in {'R':(slice(0,None,2),slice(0,None,2)),
                 'Gr':(slice(0,None,2),slice(1,None,2)),
                 'Gb':(slice(1,None,2),slice(0,None,2)),
                 'B':(slice(1,None,2),slice(1,None,2))}.items():
    flat[sl] = flat[sl] * np.load(f'gain_{name}.npy')
flat.tofile('shot_lsc.raw')
EOF
步驟 3|曝光基準(單元 10)與 AWB(單元 11)
# 用灰卡定曝光,讓灰卡 Y ≈ 目標值;再調 red/blue gains
v4l2-ctl -d /dev/v4l-subdev0 -c auto_exposure=0 -c auto_n_white_balance=0
v4l2-ctl -d /dev/v4l-subdev0 -c exposure=2000
v4l2-ctl -d /dev/v4l-subdev0 -c red_balance=140 -c blue_balance=110
步驟 4|美化與回歸
# 後處理 NR(單元 13)+ 輕度 sharpen,同場景前後各一張
python3 - <<'EOF'
import cv2
img = cv2.imread('shot.png')
nr  = cv2.fastNlMeansDenoisingColored(img, None, 6, 6, 7, 21)
sharp = cv2.addWeighted(nr, 1.0, cv2.GaussianBlur(nr,(0,0),1.5), -0.3, 0)
cv2.imwrite('shot_tuned.png', sharp)
EOF
完成標準:一輪「黑位→LSC→曝光/AWB→NR/Sharpen」跑完,每個步驟有記錄,同一場景校正前後各存一張可比較。

14.10 疑難排解決策樹:工作流卡關

現象方向
黑位減錯 → 畫面偏暗OB 在中間區算,別用邊角(shading)
LSC 後仍偏色先確認 AWB 已做,LSC 與 AWB 順序別亂
HDR 有 ghost場景有運動 → 改 tone mapping
調一個參數全畫面變參數間耦合 → 回歸對照組
無法重現上次結果沒記錄 → 補齊 tuning log
常見錯誤與陷阱:① 校正順序錯亂(先 AWB 再 LSC → 色差污染白平衡);② 每個步驟都「順手加一點」,改動無法歸因——一次只改一個並記錄;③ 用不同場景比較——必須同場景同光源;④ 只留「改完的最終圖」不留「原始 RAW」。

14.11 練習

  1. 完成一輪完整調校工作流,產出 tuning log。
  2. 建立版本管理資料夾(v1/v2…),各存 RAW + 參數。
  3. 量測一個逆光場景的 RAW 亮暗值,判斷要不要 HDR。
  4. 對同一 RAW 跑 tone mapping vs DOL HDR,比較 ghost 與細節。

14.12 回顧練習

  1. 建立 tuning 版本管理資料夾。
  2. 完成一輪「校正→美化→回歸」並記錄。

14.13 進階真實情境 Worked Example:RK3588 ISP3 DOL HDR vs 單幀 Tone Mapping

場景:Orange Pi 5 Plus(RK3588)接 OV5640,在高動態範圍場景(窗戶逆光)下比較 DOL HDR 與單幀 + tone mapping 的效果。

步驟 1|量測場景動態範圍
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('scene.raw', dtype=np.uint16).reshape(1080, 1920)
bright = raw[100:200, 800:1120].mean()   # 窗戶區
dark   = raw[800:900, 800:1120].mean()   # 室內暗區
dr_db = 20 * np.log10(bright / max(dark, 1))
print(f'DR = {dr_db:.1f} dB  (10-bit 上限 ≈ 60 dB)')
EOF
步驟 2|DOL HDR(若驅動支援)
# 需要 OV5640 DOL 模式 + RK3588 ISP3 HDR 管線
media-ctl -d /dev/media0 -V "'rkisp-isp':0[hdr_mode=dol]"
v4l2-ctl -d /dev/video0 --stream-mmap=3 --stream-count=1 --stream-to=hdr.yuv
步驟 3|單幀 + tone mapping
python3 - <<'EOF'
import cv2, numpy as np
img = cv2.imread('single_frame.png', 0).astype(float)
# 簡易 tone mapping: 雙曲正切壓縮
mapped = np.tanh(img / img.max() * 3) / np.tanh(3) * 255
cv2.imwrite('tonemapped.png', mapped.astype(np.uint8))
EOF
設計決策:DOL HDR 動態範圍更高但有 ghost(運動假影);單幀 tone mapping 無 ghost 但犧牲對比。在靜態場景(如監控)用 HDR;在運動場景(如車載)用 tone mapping。

14.14 深入原理擴充:RK3588 ISP3 的 Tone Mapping 硬體模組

RK3588 ISP3 內建硬體 tone mapping,但它不是「萬能的」:

技術硬體支援?限制
單幀 tone mapping✅ ISP3 硬體曲線固定;無法場景自適應
DOL HDR✅ ISP3 + OV5640 DOL需要感測器驅動支援;有 ghost
Stagger HDR❌ OV5640 不支援需更高端感測器
後處理 tone mapping⚠️ CPU/GPU可自適應;但非即時

容易忽略的邊界案例:ISP3 的 tone mapping 預設曲線是針對「平均場景」設計的——在極端逆光(如直視太陽)下,它可能把天空完全壓成灰色而失去所有高光細節。後處理 tone mapping 可以用場景自適應曲線(如 Reinhard/ACES)來改善,但需要先量測場景的 histogram。

14.15 診斷式疑難排解表

症狀可能原因解決方案
HDR 有 ghost(運動物體殘影)DOL 多幀合併時物體移動改用單幀 + tone mapping;或設 ghost reduction 參數
ISP3 tone mapping 天空全灰預設曲線不適合極端逆光後處理用場景自適應曲線(Reinhard/ACES)
調校順序錯(先 AWB 再 LSC)LSC 色差污染白平衡基準校正順序:黑位 → LSC → AWB/CCM
每次改動無法重現沒記錄 tuning log建立版本管理資料夾,每改動一參數就記錄
後處理 sharpen 後雜訊暴增sharp 強度過高放大雜訊先 NR 再 sharpen;降低 sharp 強度

14.16 進階挑戰題

  1. 在 RK3588 上,量測 DOL HDR 的端到端延遲(從觸發到輸出可播放),與單幀 + tone mapping 比較。找出「什麼延遲閾值以下該用哪個」。
  2. 實作一個 Python 版本的「場景自適應 tone mapping」:先算 histogram,再動態調整曲線。比較與 ISP3 預設曲線的 PSNR 差異。
  3. 設計一個完整的 tuning log 系統(含版本管理、raw 存檔、參數 JSON),寫進你的 team repo 成為標準流程。

14.17 專案級 Worked Example:完整調校工作流自動化專案

把單元 14 的工作流知識做成自動化調校專案:把「黑位 → LSC → AWB/CCM → 曝光 → NR/Sharpen」串成一支可重複執行的腳本,自動產出校正前後對比與 tuning log。這是把「會調」升級成「可重現調」的關鍵。

階段 1|建立專案結構
mkdir -p tuning_v1/{raw,params,out,log}
cd tuning_v1
階段 2|自動採集基準資料
#!/bin/bash
# 蓋鏡頭拍黑幀定黑位
v4l2-ctl -d /dev/video0 --set-fmt-video=pixelformat=SRGGB10 \
  --stream-mmap=3 --stream-count=1 --stream-to=raw/dark.raw
# 均勻亮場定 LSC
v4l2-ctl -d /dev/video0 --stream-count=1 --stream-to=raw/flat.raw
# 灰卡定 AWB + 曝光
v4l2-ctl -d /dev/video0 --set-fmt-video=pixelformat=YUYV \
  --stream-count=1 --stream-to=raw/gray.yuv
# 實拍場景(前後對比用)
v4l2-ctl -d /dev/video0 --stream-count=1 --stream-to=raw/scene.yuv
階段 3|自動執行校正鏈(單元 14.9)
python3 - <<'EOF'
import numpy as np, cv2, json
# 黑位
dark = np.fromfile('raw/dark.raw', dtype=np.uint16).reshape(720,1280)
ob = np.median(dark[600:700,400:880])
# LSC(分通道增益圖)
flat = np.fromfile('raw/flat.raw', dtype=np.uint16).reshape(720,1280) - ob
gains = {}
for name, sl in {'R':(slice(0,None,2),slice(0,None,2)),
                 'Gr':(slice(0,None,2),slice(1,None,2)),
                 'Gb':(slice(1,None,2),slice(0,None,2)),
                 'B':(slice(1,None,2),slice(1,None,2))}.items():
    c = flat[sl].astype(float)
    gains[name] = cv2.GaussianBlur(c[100:260,200:440].mean()/(c+1e-6), (21,21), 0)
# 儲存參數
np.save('params/ob.npy', ob)
for k,v in gains.items(): np.save(f'params/gain_{k}.npy', v)
json.dump({'ob': float(ob)}, open('params/meta.json','w'))
print('校正參數已儲存:', json.load(open('params/meta.json')))
EOF
階段 4|套用 + 產出 log
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('raw/scene.raw', dtype=np.uint16).reshape(720,1280)
out = (raw - np.load('params/ob.npy')).clip(0).astype(float)
for name, sl in {'R':(slice(0,None,2),slice(0,None,2)),
                 'Gr':(slice(0,None,2),slice(1,None,2)),
                 'Gb':(slice(1,None,2),slice(0,None,2)),
                 'B':(slice(1,None,2),slice(1,None,2))}.items():
    out[sl] *= np.load(f'params/gain_{name}.npy')
np.clip(out,0,1023).astype(np.uint16).tofile('out/scene_tuned.raw')
print('校正完成,log 寫入 log/tuning_v1.txt')
EOF
專案完成標準:你有一支 tune.sh + 專案目錄結構(raw/params/out/log),任何時刻都能重跑並產出可比較的結果。調校從「手動藝術」變成「可重現工程」——這是團隊協作的基礎。

14.18 量測/驗證 SOP:調校成果驗收與回歸

步驟作法通過判據
1. 校正前後對比同一場景前後各存一張畫質指標改善(亮度/色準/SNR)
2. 中性灰檢查灰卡 ROI 的 R=G=B色偏 < 5%
3. 曝光基準灰卡 Y 達目標Y 落在目標區間
4. 動態範圍檢查亮/暗 ROI 未爆亮部 < 1023、暗部 > 黑位
5. 場景回歸室內/日光/逆光各測無新缺陷(過曝/偏色/雜訊)
6. 可重現性重跑 tune.sh輸出一致(無隨機差異)
SOP 紀律:回歸是調校的最後一關——「這場景好了」≠「全部場景都好」。校正順序(黑位→LSC→AWB→曝光)不可顛倒,每次改動都要回到同場景同光源比較。

14.19 平台間對照:調校工作流

面向Orange PiRPi5Orin NanoThor
校正層級RAW/後處理為主libcamera tuningNVIDIA tuningNVIDIA tuning
HDROV5640 DOL(依驅動)libcamera HDRNVIDIA HDRNVIDIA HDR
參數管理自建 JSON/CSVlibcamera tuning fileNVIDIA 工具NVIDIA 工具
回歸工具自寫腳本libcamera testNVIDIA testNVIDIA test
自動化程度完全自建中(半自動)高(封閉)高(封閉)
核心領悟:調校工作流(採集 → 校正 → 美化 → 回歸)四平台相同。Orange Pi 的一切都要自己寫——這份「從零建立」的經驗,正是看懂其他平台 tuning 工具的鑰匙。

14.20 互動式檢核清單:本單元進階驗收

checklist
- [ ] 我能完成 tune.sh 自動化調校專案並產出 log。
- [ ] 我已建立 raw/params/out/log 的專案結構。
- [ ] 我遵守「黑位→LSC→AWB/CCM→曝光→美化」的順序。
- [ ] 我能量測場景動態範圍並判斷要不要 HDR。
- [ ] 我已跑過至少三個場景的回歸並記錄結果。
- [ ] 我理解「可重現調校 = 完整 log + 版本管理」。

14.21 Register 位元級完整工作流

清晰度/HDR/調校工作流的「讀→改→寫→驗證」是影像品質的關鍵:

步驟暫存器/位址位元欄位操作預期值
1. 開啟 sharpen0x5308[0] sharpen enablei2cset -y 3 0x3c 0x5308 0x01sharpen 開啟
2. 設定 sharpen 強度0x5309[7:0] strengthi2cset ... 0x5309 0x20依需求
3. 開啟 gamma0x5300[0] gamma enablei2cset ... 0x5300 0x01gamma 開啟
4. 設定 contrast0x5301[7:0] contrasti2cset ... 0x5301 0x20依需求
5. 回讀驗證0x5308 / 0x5309[7:0]i2cget ... 0x5308; i2cget ... 0x5309兩者皆正確
6. 取幀對比v4l2-ctl拍兩幀(sharpen on/off)清晰度改善
位元級關鍵: sharpen 會放大雜訊。必須先降噪(NR)再 sharpen。順序:DPC → NR → Sharpen → Contrast。這是調校工作流的「鐵律順序」。

14.22 多層疑難排解決策樹

決策樹 A:影像模糊

決策樹 A
影像模糊?
├─ sharpen 未開啟 → 0x5308=0x01
├─ sharpen 強度不足 → 增加 0x5309 值
├─ NR 抹掉細節 → 減少 NR 強度
└─ 對焦問題 → 物理對焦(不是 ISP 問題)

決策樹 B:HDR 效果不明顯

決策樹 B
HDR 效果不明顯?
├─ 場景動態範圍不夠大
│  └─ 測試高對比場景(逆光/窗戶)
├─ 曝光包圍不夠 → 增加 EV 檔數
│  └─ 嘗試 -2EV/0EV/+2EV
├─ 合成方法問題 → 換 HDR 合成算法
└─ OV5640 DOL HDR 未啟用
   └─ 檢查 DT 與驅動支援

14.23 量測驗證完整 SOP

步驟指令預期輸出判讀標準
1. 關閉 sharpeni2cset ... 0x5308 0x00無 sharpen基準清晰度
2. 開啟 sharpeni2cset ... 0x5308 0x01; i2cset ... 0x5309 0x20sharpen on清晰度改善
3. 量測 MTFPython script(邊緣擴散)MTF 值sharpen 後提升
4. 測動態範圍灰階圖 + PythonDR 值(EV)依場景
5. 測 HDR高對比場景HDR 影像亮暗細節保留
6. 測調校工作流照順序執行五步最終影像品質最佳

14.24 四平台終極對照

面向Orange PiRPi5Orin NanoThor推薦
SharpenOV5640 內建ISP 內建NVIDIA sharpenNVIDIA sharpen學習→OV5640
HDROV5640 DOL(有限)ISP HDRNVIDIA HDRNVIDIA HDR量產→NVIDIA
調校工具自建 JSON/CSVlibcamera tuningNVIDIA 工具NVIDIA 工具底層→自建
回歸工具自寫腳本libcamera testNVIDIA testNVIDIA test底層→自寫
自動化完全自建半自動高(封閉)高(封閉)學習→自建

14.25 完整 Bring-up 專案 Checklist

checklist
- [ ] 完成「tune.sh 自動化調校專案」並產出 log
- [ ] 建立 raw/params/out/log 專案結構
- [ ] 遵守「黑位→LSC→AWB/CCM→曝光→美化」的順序
- [ ] 量測場景動態範圍並判斷要不要 HDR
- [ ] 跑過至少三個場景的回歸並記錄結果
- [ ] 驗證「可重現調校 = 完整 log + 版本管理」
- [ ] 測試 sharpen 對清晰度的影響(含雜訊副作用)
- [ ] 測試 contrast 對動態範圍的影響
- [ ] 產出「tuning workflow report」(含五步序列/回歸/品質)
- [ ] 用「先 RAW 對、再後處理」原則驗證
看完這單元你應該能說出:
  • Sharpen/Contrast 後處理調校。
  • OV5640 DOL HDR 與驅動現況。
  • 五步調校工作流。
  • 「先 RAW 對、再後處理」原則。

延伸閱讀