單元 13 · 雜訊與降噪

NVIDIA NR

雜訊來源

雜訊來源
shot noise光子隨機性
read noise讀出電路
dark current高溫/長曝光
hot pixel缺陷像素

NVIDIA 的降噪

取捨紀律:先確認感測器增益沒拉太高(源頭),再讓 ISP 降噪收尾。

13.6 雜訊預算(Worked Example)

判斷「補光還是接受雜訊」
# 目標 SNR >= 30dB(σ/S < 3.2%)
# gain 高時量測:σ=20, 訊號=400
SNR = 20*log10(400/20) = 26 dB   # 不達標
# 補光 + 降增益:訊號 800, σ≈18 → SNR 33 dB ✓
# 結論:補光 + 降增益 優於 硬拉增益
工程判斷:用 SNR 預算量化,先定可接受的 SNR,再決定曝光/增益/補光組合。

13.7 DPC 與 NR 順序

13.6 深入:雜訊量測與增益上限

量 σ vs gain
python3 - <<'EOF'
import rawpy, numpy as np, subprocess
for g in [1, 2, 4, 8]:
    # 用平台指令取 RAW(OV9281)
    raw = rawpy.imread(f'g{g}.dng').raw_image
    roi = raw[500:1500,500:1500].astype(float)
    print(f'gain={g}  σ={roi.std():.1f}')
EOF
判讀:σ 暴增的增益區間 = 不可接受 → 設定增益上限,改用曝光補。

13.7 練習

  1. 量測各增益 σ。
  2. 決定增益上限並記錄。
看完這單元你應該能說出:
  • 四種雜訊來源。
  • NVIDIA 空間+時間降噪。
  • 「先源頭後收尾」策略。
  • 降噪與細節取捨。

13.8 深入原理:SNR 與增益的數學

影像雜訊以 SNR(dB) 度量:SNR = 20·log10(訊號/σ)。訊號隨曝光與增益上升;shot noise 隨訊號平方根上升——所以「增益補曝光」會讓 SNR 惡化,而「加光」讓訊號與雜訊一起升、SNR 反而變好。

兩種補光策略的 SNR 對比
# 方案 A:增益 ×4 補曝光(訊號 4x,σ 約 2x)
SNR_A = 20*log10(400/20) ≈ 26 dB
# 方案 B:補光讓光多 4x、增益不變(訊號 4x,σ 約 2x 同 shot noise)
# 但 B 的 σ 起點低,且不放大 read noise:
SNR_B ≈ 20*log10(1600/32) ≈ 34 dB   # 高出 8 dB
# 結論:光源 → 曝光 → 類比增益 → 數位增益,順序不可反

13.9 深入原理:DPC 與 NR 的交互

缺陷像素(hot/dead pixel)是「確定性」異常,統計性 NR 會把它擴散成亮斑;因此管線必須先 DPC(defect pixel correction)修缺陷、再 NR 降統計雜訊

處理處理什麼放哪裡
DPC固定缺陷像素NR 之前
空間 NR隨機亮點DPC 之後
時間 NR跨幀穩定雜訊最後(動態場景小心鬼影)
驗證:拍黑框(蓋鏡頭),RAW 的 max 值應被 DPC 壓制;若仍有一堆亮點 → DPC 沒生效或缺陷表沒建。

13.10 疑難排解決策樹:影像顆粒感

決策樹
1. 增益是否過高?
   ├─ 是 → 補光 / 降增益 / 長曝光(先檢查 banding)
   └─ 否 ┐
2. 是固定亮點還是一般顆粒?
   ├─ 固定亮點 → DPC 沒處理 / 缺陷表
   └─ 一般顆粒 ┐
3. NR 已開?
   ├─ 未開 → 開 NR(空間+時間)
   └─ 已開仍粗 ┐
4. 動態場景有鬼影?
   ├─ 是 → 時間 NR 過強:調降
   └─ 否 → 檢查 NR 與 sharpening 平衡(單元 14)

13.11 常見錯誤 / 陷阱

陷阱 ①:「NR 開滿」掩蓋感測器增益問題——NR 過強會讓細節變塑膠感。先修源頭(增益),NR 只收尾。
陷阱 ②:拿 NV12 判斷 NR——用 RAW 量 σ 才準(回顧 13.6 的 script)。
陷阱 ③:時間 NR 在動態場景造成鬼影——速度優先的機器視覺要特別小心。

13.12 練習

  1. 量測你的感測器各增益的 σ,畫出 σ vs gain。
  2. 拍黑框驗證 DPC 是否壓制亮點。
  3. 寫下你平台的「增益上限」決策與理由。

13.13 進階:讀出雜訊與感測器增益結構

類比增益(AGC)放大「訊號+讀出雜訊」,數位增益只放大訊號數字——所以同一總增益下,類比優先通常比數位放大乾淨。但類比增益太高仍會放大熱雜訊;實際每顆感測器各有甜蜜點。

找出你感測器的甜蜜點
# 固定曝光,逐級類比增益量 σ
for g in 1 1.5 2 3 4 6 8; do
  v4l2-ctl -d /dev/v4l-subdev0 -c analogue_gain=$g
  argus_camera --mode 0 --capture-auto 1 --raw-file g$g.raw --duration 1
done
# σ 突增點 = 此後增益不可用 → 設為上限

13.14 快速參考:雜訊除錯小抄

症狀先查
整片顆粒增益過高 → 補光/曝光
固定亮點DPC / 缺陷表
暗處彩色雜訊暗部增益過高 + NR
長曝光亮點變多dark current → 降溫/減曝光
動態鬼影時間 NR 過強

13.15 看完本單元該記住的三件事

雜訊策略:光源 → 曝光 → 類比增益 → 數位增益 → NR 收尾。
DPC 修確定性缺陷,NR 修統計性雜訊,順序不可反。
用 RAW 量 σ 判斷,別拿 NV12 猜。

13.16 Worked Example:區分空間 / 時間 NR 的影響

兩種 NR 的辨別法
# 靜態場景:空間+時間 NR 都有效,畫質最好
# 放一個緩慢移動物體:
#   - 有鬼影/拖影 → 時間 NR 過強(試降時間強度)
#   - 移動體顆粒仍在 → 空間 NR 不足(試升空間強度)
# 高速運動:直接關時間 NR,只留空間 NR
取捨:靜態場景可以靠時間 NR 大幅降噪;動態場景時間 NR 是敵人。測試時一定包含「運動」場景,別只看靜態。

13.17 看完本單元該記住的三件事

先源頭(光源/曝光/增益)後收尾(NR)。
DPC 在 NR 前。
時間 NR 慎用於動態場景。

延伸閱讀

13.12 進階真實情境 Worked Example:OV9281 在低光下的 NR 與細節平衡

場景:OV9281 在昏暗工廠環境(~50 lux)下做缺陷檢測。降噪太強會抹掉缺陷細節,降噪太弱雜訊淹沒信號。

NR 參數調校實驗
# 1. 固定曝光(排除 AE 干擾)
argus_camera --mode 0 --ae-manual --exposure-time 20000 --gain 4.0
# 2. 關閉所有 NR,拍 baseline
argus_camera --mode 0 --nr-off --duration 2 --raw-file baseline.raw
# 3. 逐步開啟 2D NR,觀察 SNR 改善
for level in 1 2 3 4 5; do
  argus_camera --mode 0 --nr-2d $level --duration 2 --raw-file nr2d_L${level}.raw
done
# 4. 在 baseline 上分析 SNR
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('baseline.raw', dtype=np.uint16).reshape(800, 1280)
flat = raw[300:500, 500:800]
print(f'Baseline SNR: {20*np.log10(flat.mean()/flat.std()):.1f} dB')
for level in range(1, 6):
    nr = np.fromfile(f'nr2d_L{level}.raw', dtype=np.uint16).reshape(800, 1280)
    nf = nr[300:500, 500:800]
    print(f'NR 2D level {level}: SNR={20*np.log10(nf.mean()/nf.std()):.1f} dB, σ={nf.std():.1f}')
EOF
# 找到 SNR 改善最大但 σ 仍然合理的 level

設計決策:2D NR 處理空間雜訊(同幀內的 spatial noise),3D NR 處理時間雜訊(跨幀 temporal noise)。低光場景先開 2D NR,若畫面有動態再開 3D NR。NR level 選擇的原則:SNR 提升 ≥ 3dB 且缺陷細節不模糊

13.13 深入原理擴充:NR 對 DPC(缺陷像素校正)的影響

NR 和 DPC 有交互作用:NR 會「模糊」缺陷像素的特徵,使 DPC 更難偵測。

處理順序效果建議
DPC → NR先修缺陷再降噪(推薦)DPC 能清楚看到缺陷位置
NR → DPCNR 模糊了缺陷,DPC 漏檢避免此順序
DPC + NR 同時取決於 ISP 內部 pipeline 順序確認 Argus 的 pipeline 順序(DPC 通常在 NR 之前)
陷阱:「NR 開到最大就好」——NR 過強會把缺陷像素「抹平」,DPC 完全偵測不到,結果缺陷留在最終影像中(只是變模糊了)。先做 DPC,再做 NR。

13.14 診斷式疑難排解表

症狀可能原因解決方案
NR 開啟後缺陷更明顯(而非消失)DPC 在 NR 之後處理(pipeline 順序錯)確認 Argus pipeline:DPC 應在 NR 之前;調整 pipeline 順序
NR 過強導致邊緣模糊2D NR 的 spatial kernel 太大降低 2D NR level;或只對低頻區域開 NR(edge-aware NR)
3D NR 在快速運動時產生殘影3D NR 的 temporal kernel 跨幀對齊失敗在有運動的場景關閉 3D NR;或降低 temporal 強度
NR 在低光下幾乎無效雜訊太大,NR 的 threshold 被超過先提高 analog gain 以下的信號(降低 gain + 延長曝光)
NR 開啟後色彩偏移NR 對 R/G/B 通道的處理不均確認 NR 是 per-channel 處理;或在 RGB 空間做 NR 而非 YUV

13.15 進階挑戰題

  1. 在 OV9281 上做「NR level vs SNR」的系統化測試:固定曝光,從 NR level 0 到最大,每級拍一幀,畫出 SNR 曲線。找到「拐點」(SNR 提升趨緩的 level)。
  2. 設計一個「DPC + NR 調校」流程:先做 DPC(找到所有缺陷像素),再做 NR(降雜訊),確保兩者不互相干擾。
  3. 比較 2D NR 和 3D NR 在「靜態場景」和「動態場景」下的效果差異,寫出你的結論和建議的使用場景。

13.16 專案級端到端 Worked Example:雜訊預算與降噪調校專案

場景:低光缺陷檢測(回顧 13.12 場景)需要「雜訊可接受」與「缺陷細節保留」的平衡。專案目標:建立雜訊預算,從量測感測器本質 → 定增益上限 → 調 NR level,全流程量化。

專案流程
# Phase 1 · 感測器本質量測(回顧 13.6)
for g in 1 2 4 8; do
  v4l2-ctl -d /dev/v4l-subdev0 -c analogue_gain=$g
  argus_camera --mode 0 --capture-auto 1 --raw-file g$g.raw --duration 1
done
# 畫 σ vs gain → 找 σ 暴增點 → 定增益上限(例:max gain 4)
# Phase 2 · 定雜訊預算:目標 SNR ≥ 30dB(σ/S < 3.2%)
# Phase 3 · 補光 / 曝光調整,讓預算在正常場景達標
# Phase 4 · NR 階梯(回顧 13.12 方法)
for level in 0 1 2 3 4 5; do
  argus_camera --mode 0 --nr-2d $level --duration 2 --raw-file n$level.raw
done
# 找「SNR 提升 ≥ 3dB 且缺陷細節不模糊」的 level
# Phase 5 · DPC 驗證:黑框 RAW 的 max 應被壓制
# Phase 6 · 動態場景確認無鬼影(時間 NR 慎用)

專案輸出:σ vs gain 曲線、增益上限決策、NR level 選擇、DPC 驗證報告。這份「雜訊預算書」是影像品質的總依據。

13.17 量測/驗證 SOP:雜訊驗證

  1. σ vs gain:固定曝光逐級增益,量平坦區 σ。
  2. SNR 計算20·log10(訊號/σ),對照目標預算。
  3. DPC 驗證:黑框 RAW,統計固定亮點;max 應被壓制。
  4. NR 階梯:NR level vs SNR 曲線,找拐點。
  5. 動態測試:移動物體下檢查時間 NR 鬼影。
  6. 增益上限:把 σ 暴增點的增益寫成上限。
紀律:先源頭(光源 / 曝光 / 增益)後收尾(NR);用 RAW 量 σ,別拿 NV12 猜。

13.18 平台間對照:雜訊處理

面向Orin NanoRPi5Orange PiThor
空間 NR✅ ISP 內建✅ libcamera⚠️ 感測器✅ ISP 內建
時間 NR✅(可調強度)⚠️✅ + AI 降噪
DPC✅ 內建⚠️
NR 調校介面level 參數(有限)tuning file(完整)有限level + AI
量測方法RAW σ / SNR 全平台共用
重點:雜訊量測是平台無關的;NR 的「可調深度」RPi5 最深、Orin / Thor 用 level 參數、Orange Pi 最受限——但「先源頭後收尾」的紀律不變。

13.19 互動式檢核清單:雜訊驗收

13.12 Register 位元級完整工作流:雜訊量測——不同增益下的 σ

步驟Command量測目標預期
1. 增益 1x 出圖argus --gain-value 1.0基線 σσ ≈ 2-5
2. 增益 2x 出圖argus --gain-value 2.0σ 增加σ ≈ 4-10
3. 增益 4x 出圖argus --gain-value 4.0σ 增加σ ≈ 8-20
4. 增益 8x 出圖argus --gain-value 8.0σ 顯著增加σ ≈ 16-40
5. σ vs gain 曲線matplotlib plot線性關係σ ∝ gain(理想)
雜訊量測完整腳本:σ vs Gain 曲線
#!/usr/bin/env python3
# noise_vs_gain.py — 雜訊 vs 增益完整量測
import numpy as np, matplotlib.pyplot as plt, subprocess, glob

gains = [1.0, 2.0, 4.0, 8.0, 16.0]
results = []

for gain in gains:
    subprocess.run([
        "argus_camera", "--camera-id", "0", "--mode", "0",
        "--exposure-value", "0.016", "--gain-value", str(gain),
        "--capture-auto", "0", "--duration", "1",
        "--output-dir", f"/tmp/noise_g{int(gain)}"
    ], capture_output=True)
    
    raw = glob.glob(f"/tmp/noise_g{int(gain)}/*.raw")
    if raw:
        data = np.fromfile(raw[0], dtype=np.uint16).reshape(800, 1280)
        flat_region = data[350:450, 550:700]
        sigma = flat_region.std()
        mean = flat_region.mean()
        snr = mean / sigma if sigma > 0 else 0
        results.append({"gain": gain, "mean": mean, "sigma": sigma, "snr": snr})
        print(f"Gain {gain:.0f}x: mean={mean:.1f} sigma={sigma:.2f} SNR={snr:.1f}")

# Plot
gains_r = [r["gain"] for r in results]
sigmas = [r["sigma"] for r in results]
snrs = [r["snr"] for r in results]

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.plot(gains_r, sigmas, 'bo-', label='Measured')
ax1.plot(gains_r, [sigmas[0]*g for g in gains_r], 'r--', label='Ideal (σ ∝ gain)')
ax1.set_xlabel('Gain'); ax1.set_ylabel('σ (DN)'); ax1.set_title('Noise vs Gain')
ax1.legend(); ax1.grid(True, alpha=0.3)

ax2.plot(gains_r, snrs, 'go-')
ax2.set_xlabel('Gain'); ax2.set_ylabel('SNR'); ax2.set_title('SNR vs Gain')
ax2.grid(True, alpha=0.3)

plt.tight_layout(); plt.savefig('noise_analysis.png')
print("Saved: noise_analysis.png")

# Verdict
ideal_sigma = sigmas[0] * gains_r[-1]
actual_sigma = sigmas[-1]
deviation = abs(actual_sigma - ideal_sigma) / ideal_sigma * 100
print(f"\nIdeal σ at {gains_r[-1]}x: {ideal_sigma:.1f}")
print(f"Actual σ at {gains_r[-1]}x: {actual_sigma:.1f}")
print(f"Deviation: {deviation:.1f}%")
print(f"VERDICT: {'PASS' if deviation < 30 else 'CHECK SENSOR'}")

13.13 多層疑難排解決策樹

決策樹 A:σ vs gain 不是線性
1. σ 隨 gain 增加但不成正比?
   ├─ 是 → 感測器固定雜訊佔比高
   │       → 降曝光時間(短曝 + 高 gain 更糟)
   └─ 否 ┐
2. σ 在高 gain 暴增(非線性跳躍)?
   ├─ 是 → 感測器接近最大增益限制
   │       → 限制增益上限(如 8x → 16x 不建議)
   └─ 否 ┐
3. σ 隨 gain 不變?
   ├─ 是 → ISP 降噪已介入(或 gain 未生效)
   └─ 否 → 正常線性關係
決策樹 B:降噪後太模糊
1. 降噪後細節嚴重流失?
   ├─ 2D 降噪強度過高 → 降 spatial strength
   │  或改用 temporal(時域)降噪
   ├─ 是 ┐
   │   2. Temporal 降噪可用?
   │      ├─ 是 → 用 temporal(保細節更好)
   │      └─ 否 → 降 spatial strength + 開 edge preservation
   └─ 否 → 正常 tradeoff

13.14 量測驗證完整 SOP

  1. 基線量測:增益 1x、固定曝光,取 RAW → 平坦區 σ ≈ 基線。
  2. 增益階梯:1x/2x/4x/8x/16x 各取 RAW → 計算 σ。
  3. σ vs gain 曲線:畫圖 → 確認線性關係(σ ∝ gain)。
  4. SNR 計算:SNR = mean / σ → 各增益下的 SNR。
  5. 暗場量測:全遮鏡頭 → σ = 純感測器雜訊(應最低)。
  6. 降噪比較:開啟 ISP 降噪 → 重複步驟 1-4 → 比較改善。
  7. 細節保留:解析度板(ISO 12233)→ 降噪前後 MTF 比較。
判讀標準:σ ∝ gain(線性)✓、SNR 隨 gain 降低(正常)✓、降噪改善 σ 且細節保留 > 80% ✓。

13.15 四平台终极對照

面向Orin NanoRPi5Orange PiThor推薦
降噪方式ISP 2D/3D 降噪libcamera 簡化降噪感測器內建ISP + AI 降噪各有方案
AI 降噪✅ TensorRT有限✅ 更強高品質 → Orin/Thor
降噪 vs 細節可調平衡固定預設無控制AI 最佳平衡量產 → Orin
3D Temporal✅(需穩定場景)有限監控 → 3D
Edge Preservation✅ 可調自動✅ + AI邊緣重要 → Orin
雜訊模型shot + read + FPNshot + read依感測器完整模型全平台共通
降噪學習成本中高不需入門 → RPi5

13.16 完整 Bring-up 專案 Checklist