NVIDIA LSC
鏡頭邊緣光量低於中心(cos⁴),造成四周暗角、角落偏色。
python3 - <<'EOF' import numpy as np # raw = 讀取的 RAW(分通道 R/Gr/Gb/B) # center = 中央區均值;gain = center / cell(四周>1) # 需分通道各自計算;對純灰卡才準 EOF
鏡頭邊緣光量低於中心,主因是 cos⁴ 定律:離軸角度 θ 造成 cos⁴θ 的光量衰減。這影響是「幾何的」而非感測器問題。另一個成因是 光線斜射通過濾色片,使邊緣光譜偏移 → R/B 通道 shading 不一致 → 角落偏色。
視場角 30°(θ=30°): cos(30°) ≈ 0.866 cos⁴(30°) ≈ 0.866⁴ ≈ 0.562 → 邊緣光量只有中心的 56% → 需要 gain ≈ 1/0.562 ≈ 1.78 視場角 20°: cos⁴(20°) ≈ 0.78 → gain ≈ 1.28
python3 - <<'EOF'
import numpy as np
raw = np.load('grey_raw.npy') # 分好通道的 R/Gr/Gb/B
h, w = raw.shape
center = raw[h//2-50:h//2+50, w//2-50:w//2+50].mean()
corner = raw[50:150, 50:150].mean()
print('center', center, 'corner', corner)
print('gain ', center/corner) # 角落要乘的增益
EOF1. 是「整體暗」還是「角落特別暗」? ├─ 角落特別暗 → LSC 未校正 / 未更新 └─ 整體暗 → 曝光(unit-10) 2. LSC 已開仍暗角? ├─ 換過鏡頭/感測器?→ 重新校正(組合特有) └─ 網格解析度不足?→ 提高網格密度 3. 角落偏色(非暗)? └─ color shading 校正(分通道網格)
LSC 不是把四角任意拉亮,而是為每個 Bayer 通道建立空間增益場。實際像素落在網格節點之間時,ISP 以雙線性插值取得增益;因此網格太粗會留下波紋,太細則對校正圖雜訊與灰卡不均勻更敏感。
| 校正項 | 代表問題 | 驗證 |
|---|---|---|
| luma shading | 角落暗 | 灰卡亮度徑向曲線 |
| color shading | 角落偏色 | R/Gr/Gb/B 四通道曲線 |
| 高增益限制 | 角落雜訊被放大 | LSC 前後 SNR |
中心基準:R=800, Gr=820, Gb=815, B=780 左上 cell:R=600, Gr=650, Gb=640, B=560 gain_R = 800 / 600 = 1.333 gain_Gr = 820 / 650 = 1.262 gain_Gb = 815 / 640 = 1.273 gain_B = 780 / 560 = 1.393 限制最大 gain(例如 1.5)後,與鄰近節點平滑, 再由 ISP 在 cell 內插值。若單一節點跳變,輸出可能出現棋盤或光暈。
實驗時要拍多張取平均,排除灰卡反光與 temporal noise;比較 LSC 前後時要固定 AE,否則亮度變化會掩蓋校正效果。
1. 校正圖與產品 mode/解析度相同? ├─ 否 → 重新拍該 mode 的灰卡 └─ 是 ─┐ 2. 是亮度暗角還是色彩暗角? ├─ 亮度 → 查 luma gain、曝光一致性、鏡頭光圈 └─ 色彩 → 查 R/Gr/Gb/B 分通道網格 3. LSC 前後角落變亮但雜訊爆? ├─ 是 → 限制最大 gain、改善光源或重新選鏡頭 └─ 否 ─┐ 4. 出現棋盤/波紋?→ 查網格密度、節點平滑與 stride
場景:Thor T5000 接 3 顆 OV9281(前視 + 左右側視),每顆搭配不同鏡頭(前視 2.8mm 廣角、側視 6mm 標準)。三顆的 lens shading 特性完全不同。
# 前視(2.8mm 廣角): # 視場角 120°,θ_max = 60°,cos⁴(60°) = 0.0625 # → 角落 gain 最高可達 16x(非常大) # → 雜訊在角落被嚴重放大 # → 限制最大 gain ≤ 4x,接受角落 slight 暗角 # 左/右側視(6mm 標準): # 視場角 50°,θ_max = 25°,cos⁴(25°) = 0.67 # → 角落 gain ≈ 1.49x(合理範圍) # → LSC 全補償,無雜訊放大問題 # 校正流程: 1. 三顆各自拍灰卡(同一光源、同一亮度) 2. 各自產生 LSC 網格(格式相同、參數不同) 3. 前視 LSC 限制最大 gain(防角落雜訊爆) 4. 側視 LSC 正常全補償 5. 驗證:拍均勻灰卡,三顆的四角亮度差 < 5% # 設計決策: # 1. 每顆感測器 + 鏡頭組合必須獨立校正——不能共用 # 2. 廣角鏡頭的 LSC gain 要設上限——否則角落 SNR 崩壞 # 3. LSC 網格密度要夠高——廣角鏡頭的 shading 變化更快
LSC 在 ISP 管線中位於 NR 之前(unit-07 管線順序)。這代表:LSC 增益會先放大角落的雜訊,然後 NR 再嘗試壓制。若 LSC 增益過高(> 4x),NR 可能把放大後的雜訊當成「正常」訊號而保留,造成角落「有雜訊但 NR 沒完全壓制」的尷尬狀態。
| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| LSC 開啟後角落反而更暗 | LSC 網格的增益方向搞反(衰減變放大) | 檢查網格增益值:角落應 > 1.0(補償衰減);若 < 1.0 → 方向反了 |
| 換鏡頭後 LSC 效果變差但網格未更新 | LSC 是「鏡頭+感測器」組合特有 | 換鏡頭後必須重新拍灰卡校正 LSC 網格 |
| 廣角鏡頭的 LSC 開啟後角落雜訊明顯增加 | LSC gain 過高(> 4x),放大了角落雜訊 | 限制 LSC 最大 gain;或在 LSC 後增強角落 NR 強度 |
| LSC 網格在低光場景產生棋盤格效應 | 網格過粗 + 增益高 → 插值誤差被放大 | 提高網格密度(32×32);或用更平滑的插值方法 |
| 只校正亮度不分通道導致角落偏色 | Color shading 需要 R/Gr/Gb/B 各自網格 | 重新拍灰卡,分四通道各產生獨立 LSC 網格 |
場景:Thor 多感測器系統(廣角 + 標準鏡頭混用),需要為每顆建立 LSC 網格並部署到 ISP。
M1 拍攝條件 ├─ 均勻光源 + 灰卡 + 固定光圈/焦距/曝光 ├─ 固定 AWB(避免通道比例干擾) └─ 通過:多張灰卡亮度一致 M2 資料收集 ├─ 每顆感測器拍 10–20 張灰卡 └─ 通過:取平均排除 temporal noise M3 網格計算 ├─ 分四通道算 cell mean → gain = center/cell ├─ 限制最大 gain(廣角 ≤ 4x) └─ 通過:網格值合理、無跳變 M4 網格驗證 ├─ 套入 ISP,重拍灰卡 ├─ 量四角亮度差 + 四通道比例 └─ 通過:四角亮度差 < 5%、無偏色 M5 雜訊檢查 ├─ 檢查角落 SNR(高增益區) └─ 通過:SNR 可接受(或調整 max gain 限制) M6 多感測器部署 └─ 通過:每顆獨立網格 + 驗證表進 repo 驗證: 四角亮度差 = (邊緣均亮 − 中心均亮) / 中心均亮
Step 1 固定條件 均勻光源箱 + 灰卡 + 固定光圈/曝光/焦距 + 固定 AWB Step 2 拍攝 10–20 張灰卡,取平均 Step 3 計算網格 分通道 cell mean → gain;限制 max gain Step 4 套用 載入 ISP LSC 網格 Step 5 復驗 重拍灰卡 → 四角亮度差 < 5%、四通道比例一致 Step 6 記錄 光圈/焦距/模式條件 + 網格 + 結果進 repo 判讀指標: 四角仍暗 → 網格未生效 / 解析度模式不符 出現棋盤/波紋 → 網格過粗 角落雜訊大 → max gain 太高 角落偏色 → 分通道網格未正確套用
| 面向 | Thor T5000 | RPi5 | Orange Pi | Orin Nano |
|---|---|---|---|---|
| LSC 引擎 | NVIDIA ISP 網格 | libcamera tuning | 感測器內建(有限) | NVIDIA ISP 網格 |
| 校正工具 | NVIDIA 工具 | libcamera tuning 工具 | 手動 register | NVIDIA 工具 |
| 分通道網格 | ✅ R/Gr/Gb/B | ✅ | ⚠️ | ✅ |
| 網格密度 | 可設定 | 可設定 | 固定 | 可設定 |
| 多感測器獨立 LSC | ✅ | ⚠️(單一 camera) | ❌ | ✅ |
本單元涉及的關鍵 register,以及「讀→改→寫→驗證」的完整位元級操作序列:
| Register | 位址 | 功能 | Bit Field 說明 |
|---|---|---|---|
LSC_TABLE_ADDR | 0x00140300 | LSC table 載入位址 | bit[15:0] = table offset, write 0x01 to trigger load |
LSC_STRENGTH | 0x00140304 | LSC 強度控制 | bit[7:0] = strength (0=off, 255=full) |
# Step 1: 讀取目前值 $ devmem2 0x00140300 w # 記錄 current_value # Step 2: 計算新值(設定 bit[0]=1) $ new_value=$((current_value | 0x0001)) # Step 3: 寫入 $ devmem2 0x00140300 w $new_value # Step 4: 驗證 $ devmem2 0x00140300 w # 確認 bit[0] = 1,其餘 bit 不變 # Step 5: 進階 — bitmask 操作 $ read_val=$(devmem2 0x00140300 w | grep "Read" | awk '{print $NF}') $ mask=0x0001 $ expected=0x0001 $ [ $(($read_val & $mask)) -eq $expected ] && echo "PASS" || echo "FAIL: bit[0] not set"
1. 四角仍暗? ├─ LSC table 未載入 → 確認 LSC_TABLE_ADDR trigger bit └─ table 與 lens 不匹配 → 重新拍白板生成 table 2. 中心過亮(over-correction)? └─ LSC_STRENGTH 太高 → 降到 0x80–0xC0
1. 白板有陰影? ├─ 光源不均勻 → 用 diffuser 或 lightbox └─ 白板有紋路 → 用專業 white target 2. 四角量測值不合理? └─ ROI 選取不對 → 確認選在四角角落、避開邊緣 dark frame
LSC 完整校正與驗證 SOP:
| 步驟 | 動作 | 指令/方法 | 預期輸出 |
|---|---|---|---|
| Step 1 | 拍攝白板 | 均勻光源(lightbox),全畫面白色 | 曝光不飽和 |
| Step 2 | 量測四角 + 中心 | ROI 各取 100×100 pixel 平均值 | 記錄 DN 值 |
| Step 3 | 計算暗角比 | (center - corner) / center × 100% | 期望 < 20% |
| Step 4 | 生成 LSC table | ISP Visualizer 或腳本自動生成 | 5×5 grid × 4 channels |
| Step 5 | 載入 table | 寫入 LSC_TABLE_ADDR + trigger | table 載入成功 |
| Step 6 | 驗證修正效果 | 重拍白板,重複 Step 2 | 四角差 < 5% |
| Step 7 | 強度微調 | 調 LSC_STRENGTH,找最佳值 | 中心不過亮、四角不暗 |
| 面向 | Thor T5000 | RPi5 | Orange Pi | Orin Nano |
|---|---|---|---|---|
| LSC grid 大小 | 5×5 × 4ch(可調) | 17×13(固定) | N/A | 16×12(固定) |
| LSC table 生成 | ISP Visualizer(GUI) | `raspistill` 以 12-bit 抓 | N/A | ISP Visualizer |
| LSC 強度控制 | ✅ | ✅ | N/A | ✅ |
| 自動 LSC 校正 | ✅ | ❌ | N/A | ✅ |
| LSC + lens profiles | ✅ | ❌ | N/A | ⚠️ |
| 驗證工具 | ColorChecker + 角落量測 | 白板 DN 比較 | N/A | ColorChecker + 角落量測 |
針對「鏡頭陰影校正(LSC)」主題的完整 bring-up 步驟清單: