單元 2 · 影像感測器基礎

Bayer、global shutter、OV9281

感測器把光變成 RAW

光子像素增益ADCRAW

Bayer CFA

OV9281 / OV5640 都是標準 Bayer 排列,由 ISP demosaic 重建全彩。

Global shutter(OV9281)

型態特性OV9281OV5640
Rolling逐列曝光
Global全像素同時曝光
為什麼工業愛用 OV9281:global shutter 無高速扭曲,適合條碼、機器視覺。

OV9281 完整規格(公開)

項目規格
解析度1 MP(1280×800)
像素3.0 µm
快門Global shutter
輸出MIPI CSI-2
I2C 位址0x36
ID register0x300A=0x92 / 0x300B=0x81
看完這單元你應該能說出:
  • 感測器光→RAW 流程。
  • Bayer 排列。
  • Global shutter 對機器視覺的意義。
  • OV9281 規格與 ID register。

2.5 深入原理:光電轉換與 ADC

每個像素 = 微透鏡 + 彩色濾波片(CFA)+ 光電二極體 + 讀出電路。光打到二極體產生電子,累積成電壓,再由 ADC 量化成 RAW 數字。

光子電子累積電壓增益ADCRAW(10-bit)
對調校的意義:RAW 值 = 光的強度 × 曝光時間 × 增益。你在 Argus 設的曝光/增益,最終都落在「每個像素累積多少電子」這條式子上。

2.6 深入原理:Bayer CFA 的排列與位元深

標準 Bayer 2×2 塊有 RGGB / BGGR / GRBG / GBRG 四種起點。OV9281 的 Bayer order 決定 RAW 要怎麼 demosaic;設錯整個色彩翻轉。

位元深用途Orin 上的表示
8-bit最終輸出NV12 / YUV
10-bit感測器原始(OV9281 主流)SRGGB10(依 order)
12-bit高階感測器SRGGB12

10-bit RAW 在 CSI-2 以「10-bit packing」傳輸(每 4 像素塞 5 bytes),解析時若當成 8-bit 或 12-bit 讀,會看到條紋狀假影。

2.7 深入原理:Rolling vs Global Shutter 的曝光差異

Rolling shutter(OV5640/IMX219)逐列開始曝光,高速物體會扭曲;Global shutter(OV9281)全像素同時曝光,無扭曲但低光靈敏度較低(通常 pixel 較大補償)。

曝光設定的影響:OV9281 的曝光時間 register 用「曝光行數 × 每行時間」換算;改解析度/幀率會改變每行時間,同一 register 值對應的實際毫秒數會不同——這是「換模式後曝光變了」的常見來源。

2.8 Worked Example:讀 IMX219 與 OV9281 的 ID

兩顆感測器 ID 對照
# OV9281(位址 0x36,ID register 0x300A/0x300B)
sudo i2cget -y 0 0x36 0x300a     # 0x92
sudo i2cget -y 0 0x36 0x300b     # 0x81

# IMX219(位址 0x10,ID register 0x0000/0x0001)
sudo i2cget -y 0 0x10 0x00       # 0x02
sudo i2cget -y 0 0x10 0x01       # 0x19

讀到「0x92 0x81」與「0x02 0x19」就代表兩顆感測器都活著——這是平台能力的第一個證明。

2.9 常見錯誤 / 陷阱

陷阱 ①:誤把「8MP 的 IMX219」與「1MP 的 OV9281」當成同解析度——imager 解析度決定 RAW 大小與 CSI 頻寬需求。
陷阱 ②:IMX219 的 ID 是 8-bit register 位址(0x00/0x01),OV9281 是 16-bit register 位址(0x300A)——用錯位址格式會讀錯或讀不到。

2.10 練習

  1. 分別讀出 OV9281 與 IMX219 的 ID,記錄位址與值。
  2. 拍一張 RAW,確認 Bayer order 是哪一種。
  3. 解釋為什麼同一顆感測器換模式後「曝光感」會變。

2.11 進階:感測器時序與曝光行的關係

感測器把影像時間切成「行」。一幀 = 有效行 + vertical blanking;曝光時間通常以「行數」設定,實際秒數 = 行數 × 每行時間。每行時間又受輸出解析度與時脈影響。

關係除錯意義
每行時間由解析度/時脈決定換模式後曝光感變 = 每行時間變
垂直 blanking留給讀出與曝光調度影響可達最大幀率
最大曝光≈ 幀時間 − 讀出時間低幀率才能長曝光

2.12 快速參考:感測器規格小抄

項目OV9281OV5640IMX219
解析度1280×8002592×19443280×2464
像素3.0 µm1.4 µm1.12 µm
快門GlobalRollingRolling
I2C 位址0x360x3C0x10
ID register0x300A/B0x300A/B0x0000/1

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

RAW = 光 × 曝光 × 增益,雜訊與品質都從這裡開始。
Global shutter 無扭曲、Rolling 低光較好——依應用選。
每顆感測器的 I2C 位址與 ID register 是 bring-up 的第一把鑰匙。

2.14 Worked Example:比較 OV9281 與 IMX219 的取樣

兩顆感測器各自的 RAW 檢查
# 各自取一幀 RAW(回顧單元 8)
# OV9281: 1280x800 10-bit, I2C 0x36
# IMX219: 3280x2464 10-bit, I2C 0x10
python3 - <<'EOF'
import numpy as np
for name, f, w, h in [('ov9281','ov.raw',1280,800),
                      ('imx219','imx.raw',3280,2464)]:
    raw = np.fromfile(f, dtype=np.uint16).reshape(h, w)
    print(name, 'min', raw.min(), 'max', raw.max(),
          'mean', round(raw.mean(),1))
EOF
比較重點:兩者解析度差異 → 記憶體與頻寬需求不同(回顧單元 11 幀率/頻寬);IMX219 滾動快門對運動物體會扭曲,OV9281 不會——依應用選。

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

光 → 電子 → RAW,一切品質由此展開。
Global vs Rolling 依運動場景選。
每顆感測器有獨立的位址與 ID——bring-up 從讀 ID 開始。

延伸閱讀

2.13 進階真實情境 Worked Example:OV9281 在 Orin Nano 上做 Line-Scan 模擬

場景:工業傳送帶需要「線掃描」(line-scan)效果來檢測產品表面缺陷。OV9281 是 area sensor,但利用其 global shutter 特性,可以用軟體模擬 line-scan:只取每幀的中間一行 pixel。

模擬 line-scan 工作流
# 1. 設定 OV9281 為全解析度 1280x800, 120fps
v4l2-ctl -d /dev/v4l-subdev0 --set-fmt-video=width=1280,height=800,pixelformat=GREY
# 2. 用 GStreamer 擷取並只取中間行(800/2=400)
gst-launch-1.0 v4l2src device=/dev/video0 ! \
  video/x-raw,format=GRAY8,width=1280,height=800,framerate=120/1 ! \
  videobox left=0 right=0 top=399 bottom=-400 ! \
  multifilesink location=line_%04d.raw
# 3. 逐行拼成完整影像(Python)
python3 - <<'EOF'
import numpy as np, glob
lines = [np.fromfile(f, dtype=np.uint8) for f in sorted(glob.glob('line_*.raw'))]
np.array(lines).tofile('linescan.raw')
print(f'拼接完成:{len(lines)} 行 x {lines[0].shape[0]} 像素')
EOF

設計決策:OV9281 的 global shutter 確保每幀的行間無果凍效應(rolling shutter 會扭曲),120fps 提供高密度取樣。Orin 的 VI channel 只需一路,ISP 不必啟用(直接取灰階 RAW)。

2.14 深入原理擴充:Global Shutter 的「同時曝光」不是「同時讀出」

Global shutter 感測器的每個 pixel 同時開始曝光、同時結束曝光(這是它比 rolling shutter 的優勢),但讀出(readout)仍然是逐列依次進行的。讀出速度受感測器內部 ADC 與匯流排頻寬限制。

概念Global ShutterRolling Shutter
曝光起始所有 pixel 同時逐列遞延
曝光結束所有 pixel 同時逐列遞延
讀出逐列依次(但曝光已結束)逐列同時曝光+讀出
對運動物體整幀一致,無果凍果凍效應(skew/rolling)
陷阱:「Global shutter 就不會有運動模糊」是錯的——它消除的是「果凍/skew」,不是「模糊」。曝光時間長時,運動物體仍然會 blur(只是整幀 blur 一致)。

2.15 診斷式疑難排解表

症狀可能原因解決方案
OV9281 出圖有明顯果凍(直線彎曲)感測器並非真的 global shutter 模式(DTB mode 設定錯)確認 OV9281 的 mode 設為 global shutter(register 0x0106);用高速運動物體測試
Bayer 偽影(灰卡拍出彩色)DTB 或 Argus 設定的 Bayer order 與感測器實際不符查感測器 datasheet 的輸出格式;嘗試 4 種 Bayer 起點(RGGB/BGGR/GRBG/GBRG)
暗部雜訊嚴重感測器增益過高 或 黑位偏高用全遮測黑位(參照單元 8);降低 analog gain 設定
不同 mode 切換後色彩偏差binning/crop 改變了 effective Bayer pattern 或 lens shading每次切 mode 後重新做白平衡校正;鎖定調校用的 mode
OV9281 在低光下幀率驟降auto exposure 拉長曝光時間以補償亮度固定曝光時間(手動 AE);或接受低光降幀是正常行為

2.16 進階挑戰題

  1. 設計一個測試流程,量化 OV9281 在不同 gain 設定下的 SNR 曲線(提示:拍灰卡、計算亮部/暗部 σ/mean ratio)。
  2. 若你的應用需要同時使用 OV9281(global shutter)和 OV5640(rolling shutter),規劃一張「特性比較表」涵蓋:時序特性、適用場景、DTB 配置差異、ISP 調校注意事項。
  3. 嘗試用 Argus 的 `--exposure-time` 參數固定不同曝光值,觀察 OV9281 在「運動物體」下的果凍變化,寫出你的觀察結論。

2.17 專案級端到端 Worked Example:感測器特性實驗台專案

場景:你負責驗收一批新的 OV9281 模組,需要建立一座「感測器特性實驗台」,把單元 2 的光→RAW、Bayer、global shutter 知識變成可重複的量測流程,最終產出一份「每顆模組的感測器特性報告」。

實驗台流程
# Step 1 · 上電 + 讀 ID(驗證感測器活著)
sudo i2cget -y 0 0x36 0x300a   # 0x92
sudo i2cget -y 0 0x36 0x300b   # 0x81
# Step 2 · 全遮鏡頭:量黑位
argus_camera --mode 0 --capture-auto 1 --raw-file blk.raw --duration 1
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('blk.raw', dtype=np.uint16)
print('黑位 mean', round(raw.mean(),1), 'max', raw.max())  # 預期接近 datasheet 標稱
EOF
# Step 3 · 雷射亮點:判定 Bayer order(回顧 8.17 方法)
# Step 4 · 高速轉盤:確認 global shutter 無果凍
#   (若出現傾斜/彎曲 → 可能被切成 rolling 模式)
# Step 5 · 曝光階梯:確認響應線性(回顧 10.9)
for e in 1000 2000 4000 8000 16000; do
  v4l2-ctl -d /dev/v4l-subdev0 -c exposure=$e
  argus_camera --mode 0 --capture-auto 1 --raw-file e$e.raw --duration 1
done

專案輸出:每顆模組一份 sensor_report.csv(ID、黑位、Bayer order、shutter 型態、曝光線性斜率)。這份報告就是後續 ISP 調校(單元 11–14)的「感測器本質」基線。

2.18 量測/驗證 SOP:感測器基本特性驗證

  1. ID 驗證:讀 ID register 與 datasheet 比對(OV9281 → 0x92 0x81)。
  2. 黑位量測:全遮鏡頭取 RAW,記錄 min/mean;與 datasheet 標稱差 > 10% 需追查。
  3. Bayer order:雷射亮點法判定起點;設錯 → 色彩全錯(回顧 8.17)。
  4. Shutter 型態:高速移動物體下檢查有無果凍;確認 DTB mode 與感測器實際模式一致。
  5. 曝光線性:固定增益逐級拉曝光,檢查 RAW 亮度是否線性。
  6. 雜訊基線:量各增益的 σ,找出「甜蜜點」與上限(回顧 13.6)。
驗收指標:ID 相符、黑位在標稱 ±10%、Bayer 判定成功、global shutter 無果凍、曝光線性 R² > 0.98。

2.19 平台間對照:感測器基本特性

面向Orin NanoRPi5Orange PiThor
讀 ID 工具i2cget / i2ctransferi2ctransferi2ctransferi2ctransfer
取 RAWargus --raw-filerpicam --rawv4l2-ctl --stream-toargus / Holoscan
曝光控制tegracam exposurelibcamera ExposureTimeV4L2 exposureSensorMode
感測器 register完全相同(0x300A ID、0x3500 曝光、0x350A 增益)
特性分析RAW 分析腳本可 100% 共用(平台無關)
重點:感測器特性是「平台無關」的——換平台只換取 RAW 的指令,分析腳本與判讀標準全部沿用。

2.20 互動式檢核清單:感測器特性驗收

2.21 Register 位元級完整工作流:OV9281 ID 讀取與曝光設定

步驟操作暫存器Bit FieldMaskExpected
1. 讀 chip ID 高位i2cget0x300Achip_id[15:8]0xFF0x92
2. 讀 chip ID 低位i2cget0x300Bchip_id[7:0]0xFF0x81
3. 設曝光高位i2cset0x3500exp[19:16]0x0F依需求
4. 設曝光中位i2cset0x3501exp[15:8]0xFF依需求
5. 設曝光低位i2cset0x3502exp[7:4]0xF0依需求
6. 設曝光手動模式i2cset0x3503aec_manual0x010x01
Read → Modify → Write → Verify(曝光設定範例)
# Step 1: Read — 讀目前曝光高位
cur=$(i2ctransfer -y 0 w2@0x36 0x35 0x00 r1)
echo "current exp hi = 0x$cur"

# Step 2: Modify — 曝光 = 0x0500(5 行)
exp_hi=0x05; exp_mid=0x00; exp_lo=0x00

# Step 3: Write — 依序寫入三個位元組
i2ctransfer -y 0 w2@0x36 0x35 0x00 r1   # 確認讀回
i2ctransfer -y 0 w3@0x36 0x35 0x00 $exp_hi
i2ctransfer -y 0 w3@0x36 0x35 0x01 $exp_mid
i2ctransfer -y 0 w3@0x36 0x35 0x02 $exp_lo

# Step 4: Verify — 回讀三個位元組組合成完整值
r_hi=$(i2ctransfer -y 0 w2@0x36 0x35 0x00 r1)
r_mid=$(i2ctransfer -y 0 w2@0x36 0x35 0x01 r1)
r_lo=$(i2ctransfer -y 0 w2@0x36 0x35 0x02 r1)
echo "verify: 0x$r_hi 0x$r_mid 0x$r_lo"

2.22 多層疑難排解決策樹

決策樹 A:Bayer 色彩全錯
1. 灰卡拍出彩色?
   ├─ 是 ┐
   │   2. 嘗試 4 種 Bayer 起點(RGGB/BGGR/GRBG/GBRG)
   │      ├─ 有一種正確 → DTB pixel_phase 設錯
   │      └─ 全部不對 ┐
   │      3. 感測器實際輸出格式與 DTB 宣告不符?
   │         ├─ 是 → 查 datasheet 確認真正的 Bayer order
   │         └─ 否 → ISP demosaic 問題(回歸單元 7)
   └─ 否 → 色彩正常
決策樹 B:Global Shutter 仍有果凍
1. 高速移動物體拍出有果凍(直線彎曲)?
   ├─ 是 ┐
   │   2. OV9281 register 0x0106 設定為 global shutter 模式?
   │      ├─ 否 → 設為 0x01(global 模式)
   │      └─ 是 ┐
   │      3. DTB mode 是否宣告正確的 shutter 型態?
   │         ├─ 否 → DTB mode 改為 global
   │         └─ 是 → 硬體問題:serializer 或 GMSL link 延遲
   └─ 否 → 無果凍

2.23 量測驗證完整 SOP

  1. ID 驗證i2ctransfer -y 0 w2@0x36 0x30 0x0a r1 → 預期 0x92;r1 at 0x300B → 0x81。
  2. 黑位量測:全遮鏡頭取 RAW → raw.min();與 datasheet 黑位標稱差 > 10% 需追查。
  3. Bayer order 判定:雷射亮點法——照亮點位置,取 RAW,四個 2×2 通道各取 max,哪個通道最亮即為該色的 Bayer 通道。
  4. Shutter 型態:高速移動物體(>1m/s)拍照;有果凍 → rolling,無果凍 → global。
  5. 曝光線性:固定增益,曝光從 1000→32000 逐級拍 RAW,計算 mean vs exposure 之 R²;R² > 0.98 = 線性良好。
  6. 雜訊基線:各增益(1/2/4/8)下取 RAW,量平坦區 σ;找出 σ 暴增點 → 定增益上限。
  7. 位元深驗證:RAW 檔案大小 = width × height × 2(10-bit unpacked 用 16-bit 存)。
判讀標準:ID 正確、黑位在標稱 ±10%、Bayer 判定成功、global shutter 無果凍、曝光線性 R² > 0.98、σ vs gain 曲線無異常暴增。

2.24 四平台终极對照

面向Orin NanoRPi5Orange PiThor推薦
讀 ID 工具i2cget / i2ctransferi2ctransferi2ctransferi2ctransferi2ctransfer 全平台共通
取 RAWargus --raw-filerpicam --rawv4l2-ctl --stream-toargus / Holoscan依平台選工具
曝光控制tegracam exposurelibcamera ExposureTimeV4L2 exposureSensorMode寄存器相同,介面不同
Bayer 驗證雷射亮點法全平台共用平台無關
Global Shutter 驗證高速物體拍照全平台共用平台無關
雜訊分析Python / numpy 全平台共用平台無關
感測器特性報告格式相同(ID/黑位/Bayer/shutter/線性斜率)可跨平台攜帶

2.25 完整 Bring-up 專案 Checklist