單元 2 · 影像感測器基礎

Bayer、快門型態、OV5640 規格

感測器把光變成 RAW

光子像素增益ADCRAW

Bayer CFA(OV5640 = RGGB)

RGrRGr
GbBGbB
意義:RAW 每像素單色,demosaic 才變全彩;Bayer order 錯 → 色彩全錯(單元 8)。

快門型態

型態特性OV5640
Rolling逐列曝光,高速扭曲✅ 預設
Global全像素同時曝光—(OV9281)

OV5640 完整規格(公開)

項目規格
解析度5 MP(2592×1944)
像素1.4 µm
輸出MIPI CSI-2(2-lane)/ DVP
內建功能AEC/AGC/AWB、DPC、內建 ISP
I2C 位址0x3C(寫)/ 0x3D(讀),可切 0x21
感測器 ID0x300A=0x56 / 0x300B=0x40

2.5 深入原理:從光子到數位的位元級旅程

感測器輸出的 RAW 不是「照片」,而是一串 依 Bayer order 排列的單色強度。理解這層,之後的 RAW 驗證(單元 8)才有基礎。

光子photodiode 累積電荷CDS(消除復位雜訊)類比增益ADC數位 RAW
位元深與後處理:10-bit RAW 若要後處理(LSC、NR),最好在 RAW 位域上做,最後才 quantize 成 8-bit YUV。先壓成 8-bit 再處理,會放大 banding 與斷階。

2.6 完整 Worked Example:驗證 OV5640 的 Bayer order

光看規格表說 RGGB 不夠——實際「拍出來的 RAW 是 RGGB」要驗證。最可靠的方法:拍單色色卡,再檢查 RAW 四通道的強度分佈。

步驟 1|設定 RAW 格式並取一幀
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=SRGGB10 \
  --stream-mmap=3 --stream-count=1 --stream-to=raw.bin
步驟 2|用 Python 檢查四通道均值
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('raw.bin', dtype=np.uint16).reshape(720, 1280)
r  = raw[0::2, 0::2]    # R  位置(假設 RGGB 起點)
gr = raw[0::2, 1::2]    # Gr
gb = raw[1::2, 0::2]    # Gb
b  = raw[1::2, 1::2]    # B
print('R Gr Gb B =', r.mean(), gr.mean(), gb.mean(), b.mean())
EOF
判讀:拍「純紅」色卡時,四個均值中 R 應最高;拍純藍時 B 最高;拍灰卡時四者應接近。若 R/B 對調,Bayer order 就是 BGGR(或設定錯)。

2.7 疑難排解決策樹:RAW 驗證不通過

現象可能原因檢查
四通道全接近 0鏡頭蓋著/曝光太低/黑位開蓋、開自動曝光、確認有光
R 與 B 對調Bayer order 假設錯換成 BGGR 重算
Gr 與 Gb 明顯不同灰卡不均或 shading拍中央小區塊、之後做 LSC(單元 12)
數值跳動、非整數步階10-bit 被當 8-bit 讀確認 packing 與 dtype
常見錯誤與陷阱:① 把 SRGGB10np.uint8 讀——packing 完全不同;② 鏡頭蓋著就開始驗證 Bayer——先確認曝光正常;③ 用 JPEG/PNG 來判斷 Bayer order——有損壓縮會污染資料,必須用 RAW。

2.8 練習

  1. 重現 Worked Example:取一張 RAW,計算四通道均值並判讀 order。
  2. v4l2-ctl --list-formats-ext 記錄你的板卡支援哪些 RAW fourcc 與位元深。
  3. 查 OV5640 的 full well / ADC bit 數值,寫出「最高數位值」應是多少。
  4. 說明為什麼「先量化成 8-bit 再後處理」會劣化畫質。

2.9 進階真實情境 Worked Example:OV9281 IR 感測器的 Bayer 驗證

場景:在 Orange Pi 5 Plus(RK3588)上接 OV9281(960p IR 感測器),驗證其 Bayer order 與 OV5640 不同的影響。

步驟 1|取 OV9281 RAW(RGGB 8-bit)
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=SRGGB8
v4l2-ctl -d /dev/video0 --stream-mmap=3 --stream-count=1 --stream-to=ov9281.raw
步驟 2|比較 OV5640 與 OV9281 的 RAW 值域
python3 - <<'EOF'
import numpy as np
raw_9281 = np.fromfile('ov9281.raw', dtype=np.uint8).reshape(720, 1280)
raw_5640 = np.fromfile('ov5640.raw', dtype=np.uint16).reshape(720, 1280)
print('OV9281 8-bit max:', raw_9281.max(), '  OV5640 10-bit max:', raw_5640.max())
print('OV9281 R:', raw_9281[0::2,0::2].mean(), ' B:', raw_9281[1::2,1::2].mean())
EOF
設計決策:OV9281 輸出 8-bit 而非 10-bit,動態範圍比 OV5640 少約 12dB。在 IR 場景(低對比)中這會讓暗部雜訊更明顯——這是選擇感測器時必須考慮的 trade-off。

2.10 深入原理擴充:RK3588 ISP 的 Bayer 處理流程

RK3588 的 ISP3 對 RAW 資料的處理與感測器內 ISP 完全不同:

RAW (SRGGB10)BLC(黑位)LSCDPCC(壞點)Bayer DenoiseDemosaicAWBCCM

容易忽略的邊界案例:RK3588 ISP3 在 demosaic 階段支援「自適應邊緣感知」(edge-aware interpolation),但預設值對高紋理場景(如磚牆)容易產生 false color——需要手動調 demosaic_th 參數。這在 Allwinner 平台上完全不存在,因為 CIF 沒有 demosaic 模組。

為什麼重要:如果你從 Allwinner 板卡換到 RK3588,不能假設「Bayer order 對了就沒問題」——RK3588 的 demosaic 品質高度依賴 tuning 參數。

2.11 診斷式疑難排解表

症狀可能原因解決方案
拍灰卡時 Gr ≠ Gb(差距 >5%)亮場不均勻或 LSC 未校正用更 diffuse 的光源(如陰天窗邊)重拍;或先套 LSC 增益圖再驗證
10-bit RAW 用 uint8 讀,出現規律條紋SRGGB10 與 SRGGB10P 的 packing 不同確認 fourcc:SRGGB10 是 16-bit 容器存 10-bit;SRGGB10P 是 packed 連續位元
換了解析度後 Bayer order 變了binning 模式改變了 pixel 排列每次換解析度/binning 都要重新驗證 Bayer order
OV9281 8-bit RAW 暗部全 0黑位偏高或曝光不足先量測黑位(OB),確認暗部有足夠值域;必要時補光
RAW 檔案 size 不符預期bytesperline 對齊 paddingv4l2-ctl --get-fmt-video 取得實際 bytesperline 與 sizeimage

2.12 進階挑戰題

  1. 用 OV9281(8-bit)和 OV5640(10-bit)在同一場景各拍一張 RAW,量化兩者的動態範圍差異(用 max-min / σ 比值),寫出結論。
  2. 在 RK3588 上,手動切換 ISP3 的 demosaic 參數,對比高紋理場景(磚牆)的 false color 差異,記錄最佳參數。
  3. 設計一個 Python 腳本,自動從 RAW 檔案推斷 Bayer order(不用假設),方法是分析相鄰像素的互相關。

2.13 專案級 Worked Example:感測器 RAW 品質檢驗專案 — 從取 RAW 到全頻譜驗證

把單元 2、8、12、13 串成一個感測器品質檢驗專案:對同一顆 OV5640 完整驗證「Bayer order、位元深、黑位、雜訊、shading」五項規格。這是任何調校開始前必做的「感測器體檢」。

階段 1|拍三張基準 RAW(單元 8)
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=SRGGB10 \
  --stream-mmap=3 --stream-count=1 --stream-to=dark.raw    # 蓋鏡頭
v4l2-ctl -d /dev/video0 --stream-count=1 --stream-to=flat.raw   # 均勻亮場
v4l2-ctl -d /dev/video0 --stream-count=1 --stream-to=color.raw  # 色卡
階段 2|全頻譜分析腳本
python3 - <<'EOF'
import numpy as np
def analyze(fn):
    raw = np.fromfile(fn, dtype=np.uint16).reshape(720,1280)
    return dict(R=raw[0::2,0::2], Gr=raw[0::2,1::2],
                Gb=raw[1::2,0::2], B=raw[1::2,1::2])
dark = analyze('dark.raw');  flat = analyze('flat.raw');  color = analyze('color.raw')
ob = np.median(dark['R'])
print('黑位 OB =', ob)
print('亮場 corner/center ratio:',
      round(flat['R'][350:420,500:780].mean()/flat['R'][10:80,10:80].mean(),3))
print('色卡四通道:', {k: round(v.mean(),1) for k,v in color.items()})
EOF
階段 3|記錄並判定
# 判定標準:
# Bayer order: 拍純紅/純藍時 R/B 通道應分別最高
# 位元深: 亮場峰值應接近 1023(10-bit 滿量程)
# 黑位: dark 中位數應落在 0–64 之間(>64 可能黑位偏高)
# 雜訊: 灰卡暗部 σ 應在合理範圍(單元 13 詳細量)
專案完成標準:你產出一張「感測器體檢表」,記錄五項規格的量測值與判定結果。這張表是之後所有調校(黑位、LSC、AWB、NR)的基準線。

2.14 量測/驗證 SOP:感測器規格驗證

步驟作法通過判據
1. 驗證 Bayer order拍純紅/純藍色卡,比較四通道均值純紅時 R 最高、純藍時 B 最高
2. 驗證位元深拍亮場看峰值10-bit 峰值 ≈ 1023;用對應 dtype 讀
3. 量黑位蓋鏡頭拍暗幀,取中位數OB 落在 0–64(10-bit)合理範圍
4. 量雜訊基底灰卡中低光 ROI 的 σσ 隨增益上升而上升(單元 13)
5. 量 shading亮場 corner/center 比值比值 < 1,記錄供單元 12 用
SOP 紀律:每次換解析度 / binning / 鏡頭都要重跑一遍——規格是「組合特有」的,不能跨模式共用。

2.15 平台間對照:影像感測器基礎

面向Orange PiRPi5Orin NanoThor
取得 RAWv4l2-ctl SRGGB10rpicam --rawargus raw captureHoloscan capture
常見感測器OV5640 / OV9281IMX219 / OV5647IMX219 / OV9281IMX 系列高階
RAW 位元深8/10/12 依 fourcc10/1210/12/1410/12/14
Bayer 驗證工具自行寫 Pythonlibcamera + rpicam-appsNVIDIA 工具 + ArgusHoloscan 範例
感測器內 ISPOV5640 內建IMX 內建(有限)感測器直出 RAW感測器直出 RAW
核心共通點:不管哪個平台,「RAW 是影像品質分析的唯一真相」——Bayer order、黑位、雜訊都必須在 RAW 上驗證,這是四平台通用的第一條鐵律。

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

checklist
- [ ] 我能用四通道均值驗證 OV5640 的 RGGB order。
- [ ] 我能說明 SRGGB10 與 SRGGB8 的位元深差異與讀取方式。
- [ ] 我已量測並記錄本平台的黑位 OB 值。
- [ ] 我能解釋 rolling 與 global shutter 的取捨。
- [ ] 我已跑完 2.13 專案並產出「感測器體檢表」。
- [ ] 我能指出「RAW 驗證」為何是四平台通用的第一鐵律。

2.17 Register 位元級完整工作流

感測器的核心秘密在 register。以下是以 OV5640 為例的「讀→改→寫→驗證」位元級完整序列:

步驟暫存器/位址位元欄位操作預期值
1. 讀感測器 ID0x300A[7:0] chip ID highi2cget -y 3 0x3c 0x300a0x56
2. 讀感測器 ID0x300B[7:0] chip ID lowi2cget -y 3 0x3c 0x300b0x40
3. 讀 SCCL0x3040[7:0] sccb modei2cget ... 0x30400x00(標準 I2C)
4. 驗證 OV 輸出格式0x3808~0x380B[15:0] width, [15:0] heighti2cget ... 0x3808; i2cget ... 0x3809依 init 設定
5. 讀 OB 值0x3B07[7:0] black leveli2cget ... 0x3b07~0x10(黑位偏移)
6. 驗證 PLL0x3035[7:4] PLL predivi2cget ... 0x3035依 target fps
位元級關鍵: OV5640 的 0x300A/0x300B 是感測器身份的「出生證明」。0xFF = I2C 無回應(硬體問題);0x56/0x40 = 正常。這是所有感測器除錯的第一步。

2.18 多層疑難排解決策樹

決策樹 A:感測器 ID 讀不到

決策樹 A
i2cget 0x300a 回什麼?
├─ 0xFF → I2C 無回應
│  ├─ i2cdetect -y 3 → 0x3c 出現嗎?
│  │  ├─ 不出現 → I2C bus 問題(上拉/時序)
│  │  └─ 出現 → 位址正確但 register 讀失敗 → 檢查 power-on 時序
│  └─ 嘗試 i2cget -y 3 0x3c 0x300a(其他位址)
├─ 0x00 → 感測器 reset 未釋放 → 檢查 reset-gpios
├─ 0x30/0x31 → 不同感測器(如 OV9281)→ 確認模組型號
└─ 0x56 → 正常!繼續讀 0x300B 確認低 byte

決策樹 B:感測器 ID 正確但無 RAW 輸出

決策樹 B
stream-on 後有資料嗎?
├─ 無 → DPHY 訊號問題
│  ├─ 檢查 dmesg csi 錯誤 → 時序/頻寬
│  └─ 嘗試降低解析度 → 是否能輸出
├─ 有但全黑 → sensor 無曝光
│  ├─ 讀 0x3500/0x3501/0x3502 → 驗證 AEC 行為
│  └─ 手動設 0x3503=0x08 → 覆蓋自動曝光
└─ 有但全白 → sensor 過曝
   ├─ 減少 analog gain:0x350a → 降低值
   └─ 減少 exposure:0x3500~0x3502 → 減少值

2.19 量測驗證完整 SOP

步驟指令預期輸出判讀標準
1. 讀感測器 IDi2cget -y 3 0x3c 0x300a0x56OV5640 正常回應
2. 讀 0x300Bi2cget -y 3 0x3c 0x300b0x40完整 ID = 0x5640
3. 輸出格式i2cget -y 3 0x3c 0x3808依解析度width 高 byte
4. 黑位 OBi2cget -y 3 0x3c 0x3b07~0x10感測器基準黑位
5. PLL 設定i2cget -y 3 0x3c 0x3035依 fpsPLL 與 clock 一致
6. 嘗試手動曝光i2cset -y 3 0x3c 0x3503 0x08覆蓋自動曝光可手動控制

2.20 四平台終極對照

面向Orange PiRPi5Orin NanoThor推薦
感測器支援OV/OV5640 為主IMX/OV 全系列IMX 系列高階IMX 系列高階畫質→IMX
RAW 位元深8/10/1210/1210/12/1410/12/14動態範圍→14-bit
感測器內 ISPOV5640 內建IMX 內建(有限)感測器直出 RAW感測器直出 RAW畫質→直出
Bayer 驗證工具自寫 Pythonlibcamera + rpicamNVIDIA 工具Holoscan 範例學習→Python
I2C 位址0x3c0x3c0x360x36跨平台先 i2cdetect

2.21 完整 Bring-up 專案 Checklist

checklist
- [ ] 確認感測器型號(OV5640 / OV9281 / IMX219)
- [ ] 讀取 0x300A + 0x300B 確認完整 ID
- [ ] 記錄感測器支援的四種 Bayer 位元深
- [ ] 產出「感測器規格表」(型號/ID/格式/最大解析度)
- [ ] 確認 I2C 位址(0x3c vs 0x36)並記錄
- [ ] 測量黑位 OB 值並記錄
- [ ] 產出「感測器體檢表」(含所有關鍵 register 值)
- [ ] 驗證 Bayer order(RGGB / GRBG / GBRG / BGGR)
- [ ] 確認 rolling vs global shutter 行為
- [ ] 用四通道均值法驗證 Bayer order
看完這單元你應該能說出:
  • 感測器光→RAW 流程。
  • OV5640 RGGB 與 5MP 規格。
  • Rolling/Global 差異。
  • OV5640 完整規格與 I2C 位址。
  • full well / ADC bit 的意義。
  • 用 RAW 四通道驗證 Bayer order。

延伸閱讀