NVIDIA LSC
鏡頭邊緣光量低於中心(cos⁴),造成四周暗角、角落偏色。
python3 - <<'EOF' import numpy as np # raw = 讀取的 RAW(分通道 R/Gr/Gb/B) # center = 中央區均值;gain = center / cell(四周>1) # 需分通道各自計算;對純灰卡才準 EOF
鏡頭邊緣光量依視角的 cos⁴ 衰減——視角越大,四角越暗。若感測器各通道(R/Gr/Gb/B)衰減速度不同,還伴隨「角落偏色」。LSC 用一張增益網格補償:
python3 - <<'EOF'
import numpy as np
# raw: 均勻灰卡 RAW(已確認 Bayer 與黑位)
h, w = raw.shape
def block(cx, cy):
return raw[cy-50:cy+50, cx-50:cx+50].mean()
corners = [block(w//4,h//4), block(3*w//4,h//4),
block(w//4,3*h//4), block(3*w//4,3*h//4)]
center = block(w//2, h//2)
print('中央 vs 角落比:', [round(c/center,3) for c in corners])
# 例:[0.78, 0.80, 0.79, 0.81] → 需 ~1.27x 角落增益
EOF1. 四角均暗、中央正常? ├─ 是 → 需要 LSC:拍灰卡生成網格 └─ 否 ┐ 2. 角落偏色(如紅角)? ├─ 是 → 分通道 shading 不同:分通道 LSC └─ 否 ┐ 3. LSC 後仍不均? ├─ 是 → 網格太疏 / 灰卡不均勻 / 光源不均 └─ 否 ─→ 均勻 → ✅
鏡頭光學衰減對不同波長不同——所以四角的「暗」其實伴隨「偏色」(例如角落偏紅)。LSC 必須分通道(R/Gr/Gb/B)給不同增益,才能同時消除暗角與偏色。
| 通道 | 角色 | 校正重點 |
|---|---|---|
| R / B | 紅藍通道 | 色彩 shading(偏色) |
| Gr / Gb | 綠色雙通道 | 亮度 shading(暗角) |
| 時機 | 動作 |
|---|---|
| 換鏡頭 | 重校(shading 是組合特有) |
| 換感測器板 | 重校 |
| 換模式(binning) | 檢查並重校 |
| 多感測器 | 每顆獨立 |
| 邊緣比值變 >5% | 重校 |
Bayer 的兩個綠色通道(Gr 在 R 列、Gb 在 B 列)理論上相同,但感測器製程與微透鏡會讓兩者產生細微差異——不均勻時畫面出現「棋盤格」亮暗紋(maze pattern)。
python3 - <<'EOF'
import numpy as np
# raw: 均勻灰卡 RAW(BGGR 範例)
# 抽 Gr / Gb 兩通道均值
gr = raw[0::2, 1::2].mean() # 依 Bayer 起點調整
gb = raw[1::2, 0::2].mean()
print('Gr/Gb 差:', round((gr-gb)/gb*100, 2), '%') # >2% → 需分開校正
EOF場景:OV9281 搭配 120° 廣角鏡頭,邊緣失光嚴重(中心亮度是邊緣的 3 倍)。需要做 LSC 校正使全畫面亮度均勻。
# 1. 拍均勻白牆(確保光線均勻、無陰影) argus_camera --mode 0 --raw-file whitewall.raw --duration 1 # 2. 分析中心 vs 邊緣亮度比 python3 - <<'EOF' import numpy as np raw = np.fromfile('whitewall.raw', dtype=np.uint16).reshape(800, 1280) center = raw[300:500, 500:800].mean() edge_top = raw[0:100, 500:800].mean() edge_left = raw[300:500, 0:200].mean() print(f'中心: {center:.0f}, 上邊緣: {edge_top:.0f}, 左邊緣: {edge_left:.0f}') print(f'邊緣/中心比: 上={edge_top/center:.2f}, 左={edge_left/center:.2f}') EOF # 3. 用 NVIDIA tuning tool 產生 LSC 校正表 # 產生 33×33 的增益表(每個 grid cell 的亮度補償倍數) # 4. 載入 Argus ISP argus_camera --mode 0 --lsc-file lsc_table.bin --duration 5
設計決策:120° 廣角鏡頭的光學特性決定 LSC 必須做——邊緣失光是物理定律(cos⁴ law),不是缺陷。LSC 校正的關鍵是「拍攝條件要均勻」:白牆、正對、無反光。
LSC 校正表把畫面分成 grid(例如 33×33),每個 grid cell 有一個增益值(1.0 = 不調整,>1.0 = 補亮)。
| Grid 大小 | 精細度 | 記憶體 | 適用場景 |
|---|---|---|---|
| 17×17 | 粗 | 小 | 鏡頭 shading 平滑(簡單鏡頭) |
| 33×33 | 中 | 中 | 多數工業鏡頭 |
| 65×65 | 細 | 大 | 非對稱 shading(例如側面補光) |
| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| LSC 校正後邊緣反而更暗 | 校正表的增益方向搞反(<1.0 而非 >1.0) | 確認增益表中「邊緣 cell」的值 > 1.0;翻轉表值 |
| LSC 校正後四角過亮 | 校正表過度補償(增益值過大) | 降低邊緣 cell 的增益值;確認拍攝時光線真的均勻 |
| LSC 校正後中心與邊緣亮度一致但色彩不均 | LSC 只補償亮度,不補償色彩(色溫差異) | LSC 是 per-channel 校正(RGB 各自獨立);確認 LSC 校正表是 per-channel |
| 換鏡頭後 LSC 校正表失效 | 不同鏡頭的 shading 特性不同 | 每顆鏡頭獨立做 LSC 校正;不可共用 |
| LSC 校正表在低光下效果差 | 低光下雜訊放大,LSC 補亮的同時也放大雜訊 | 在低光下降低 LSC 補償上限;或搭配 NR 同時調校 |
場景:量產時每台設備的「鏡頭 + 感測器」組合都有個體差異,需要逐台做 LSC。專案目標:把單元 12 的 LSC 校正流程自動化:一鍵「拍白牆 → 分析 → 生成校正表 → 驗證」,產出每台設備專屬的 LSC 檔。
#!/bin/bash
set -e
echo "== [1/4] 拍白牆 =="
argus_camera --mode 0 --raw-file white.raw --duration 1
echo "== [2/4] 分析並生成校正表 =="
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('white.raw', dtype=np.uint16).reshape(800, 1280)
gx, gy = 32, 32 # 33x33 grid
h, w = raw.shape
grid = np.zeros((gx, gy))
for i in range(gx):
for j in range(gy):
ys = slice(i*h//gx, (i+1)*h//gx)
xs = slice(j*w//gy, (j+1)*w//gy)
grid[i, j] = raw[ys, xs].mean()
center = grid[gx//2, gy//2]
lsc = center / np.maximum(grid, 1e-6) # 增益表:角落 > 1
np.save('lsc_table.npy', lsc)
print('生成 33x33 增益表,範圍', round(lsc.min(),2), '-', round(lsc.max(),2))
EOF
echo "== [3/4] 驗證:套用後重拍,角落比應接近 1 =="
# (載入 LSC 後重拍白牆,四角/中央比 < 1.05)
echo "== [4/4] 存檔 =="
mv lsc_table.npy lsc_$(date +%Y%m%d_%H%M%S).npy專案輸出:自動化腳本 + 每台設備的 LSC 檔 + 驗證報告。產線 QA 只要跑一鍵流程。
| 面向 | Orin Nano | RPi5 | Orange Pi | Thor |
|---|---|---|---|---|
| LSC 支援 | ✅ ISP 內建網格 | ✅ libcamera tuning | ⚠️ 依感測器 | ✅ ISP 內建 |
| 校正表格式 | NVIDIA 工具格式 | tuning file(JSON) | 感測器 / 驅動 | NVIDIA 格式 |
| 生成工具 | NVIDIA tuning tool | 開源工具 / 自寫 | 自寫 | NVIDIA tuning tool |
| 網格密度 | 依工具(17-65) | 可自訂 | 有限 | 依工具 |
| 校正方法 | 白牆 / 積分球 + 分通道增益,全平台相同 | |||
| 步驟 | Command / 量測 | 預期 |
|---|---|---|
| 1. 白牆/白紙出圖 | argus + 均勻白光源 | 中心與角落亮度一致 |
| 2. 暗角量測 | 中心 mean / 角落 mean | 比值 < 1.2 |
| 3. 色偏量測 | 角落 R/G/B ratio vs 中心 | 偏離 < 5% |
| 4. 增益表視覺化 | plt.imshow(gain_map) | 中心 1.0,邊緣 > 1.0 |
#!/usr/bin/env python3 # lsc_verify.py — 驗證鏡頭陰影校正 import numpy as np, matplotlib.pyplot as plt # 假設已有白牆 RAW(mode 0, SRGGB10) raw = np.fromfile("white_wall.raw", dtype=np.uint16).reshape(800, 1280) # 四通道分離 R = raw[0::2, 0::2].astype(float) Gr = raw[0::2, 1::2].astype(float) Gb = raw[1::2, 0::2].astype(float) B = raw[1::2, 1::2].astype(float) # 亮度圖(四通道平均) luma = (R + Gr + Gb + B) / 4 # 暗角量測 center = luma[350:450, 550:700].mean() corner_tl = luma[0:100, 0:100].mean() corner_tr = luma[0:100, -100:].mean() corner_bl = luma[-100:, 0:100].mean() corner_br = luma[-100:, -100:].mean() corners = np.mean([corner_tl, corner_tr, corner_bl, corner_br]) vignetting = corners / center print(f"Center: {center:.1f}") print(f"Avg corner: {corners:.1f}") print(f"Vignetting ratio: {vignetting:.3f} ({(1-vignetting)*100:.1f}% loss)") print(f"VERDICT: {'PASS' if vignetting > 0.85 else 'NEEDS LSC'}") # 色偏 rg_center = R[350:450, 550:700].mean() / Gr[350:450, 550:700].mean() bg_center = B[350:450, 550:700].mean() / Gb[350:450, 550:700].mean() rg_corner = R[0:100, 0:100].mean() / Gr[0:100, 0:100].mean() bg_corner = B[0:100, 0:100].mean() / Gb[0:100, 0:100].mean() print(f"Center R/G: {rg_center:.3f}, Corner R/G: {rg_corner:.3f}") print(f"Center B/G: {bg_center:.3f}, Corner B/G: {bg_corner:.3f}") color_shift = abs(rg_center - rg_corner) + abs(bg_center - bg_corner) print(f"Color shift: {color_shift:.3f} ({'PASS' if color_shift < 0.05 else 'NEEDS CORRECTION'})") # Gain map gain_map = center / np.where(luma > 10, luma, 1) plt.figure(figsize=(10, 4)) plt.subplot(121); plt.imshow(luma, cmap='gray'); plt.title('Luma (uncorrected)') plt.subplot(122); plt.imshow(gain_map, cmap='hot', vmin=1, vmax=2); plt.title('LSC Gain Map') plt.colorbar(); plt.tight_layout(); plt.savefig('lsc_analysis.png') print("Saved: lsc_analysis.png")
1. 暗角比值 < 0.85(> 15% loss)? ├─ 是 ┐ │ 2. 用 f/4.0 重拍?暗角改善? │ ├─ 是 → 純光學暗角(正常) │ │ → 用 LSC 補償 │ └─ 否 → 感測器微透鏡問題 │ → 需要光機調整(鏡頭位置) └─ 否 ┐ 2. 中心與角落色偏 > 5%? ├─ 是 → LSC 未啟用或增益表有誤 └─ 否 → 無暗角問題
1. LSC 後角落更暗? ├─ 增益表方向反轉 → 中心值 / 角落值 改為 角落值 / 中心值 └─ 正常 → ✅
| 面向 | Orin Nano | RPi5 | Orange Pi | Thor | 推薦 |
|---|---|---|---|---|---|
| LSC 實作 | tegracam tuning | libcamera tuning | 無 | tegracam + Holoscan | 各有格式 |
| 增益表來源 | 校正工具生成 | 自動偵測 | 無 | 自動 + AI | 校正 → 最準 |
| 即時 LSC | ✅ 硬體加速 | ✅ | ❌ | ✅ | 全平台可選 |
| 校正需求 | 每顆鏡頭獨立 | 每顆鏡頭獨立 | 不支援 | 每顆鏡頭獨立 | 鏡頭 ↔ 感測器配對 |
| 暗角容忍度 | < 5%(量產) | < 10%(原型) | N/A | < 3%(高階) | 依應用 |
| LSC 增益表格式 | 16-bit grid | JSON 陣列 | 無 | 16-bit grid | 平台專屬 |
| 全平台共通知識 | 暗角原理 + 增益表計算 + 中心/角落比值 | 原理最重要 | |||