單元 8 · RAW 擷取與資料格式

Bayer format、bit depth、RAW 分析

8.1 V4L2 Bayer format 與 fourcc

fourcc排列起點OV5647
SRGGB10R 起點、10-bit✅ RAW(實際)
SGBRG10Gb 起點CSI 傳輸層呈現
YUYV/NV12YUV(ISP 輸出)
order 迷思:libcamera 顯示 SGBRG10_CSI2P 是 CSI 傳輸層排列;OV5647 實際 RGGB。驅動處理轉換;但你手動解析 RAW 檔時以 RGGB 為準——這是新手最常搞混的點。

8.2 驗證 Bayer order(關鍵實作)

用 DNG 檢查四通道位置
python3 - <<'EOF'
import rawpy, numpy as np
raw = rawpy.imread('t.dng').raw_image
h, w = raw.shape
roi = raw[h//4:3*h//4, w//4:3*w//4]
cells = [roi[0::2,0::2].mean(), roi[0::2,1::2].mean(),
         roi[1::2,0::2].mean(), roi[1::2,1::2].mean()]
print('R=%.1f Gr=%.1f Gb=%.1f B=%.1f' % tuple(cells))
EOF

判別法:純紅色光源/卡片拍 RAW——R 位置(若 order 正確)應最亮。若 B 位置最亮 → order 是反的。

症狀:order 錯 → 色彩全亂(紅↔藍、綠誤配)。別急著改 CCM,先驗 order。

8.3 bit depth 與動態範圍

位元灰階數意義
8256常見輸出
101024OV5647 RAW
124096高動態需要
陷阱:RAW 10-bit → 輸出 8-bit 時,tone mapping / gamma 決定暗部細節去留——這是「看起來有階調 vs 一片黑」的分界(單元 14)。

8.4 ROI / binning

指定解析度
rpicam-still --width 1296 --height 972 -o half.jpg

8.5 RAW 分析的標準流程(總結)

  1. 固定參數拍 RAW(單元 5 範本)。
  2. 驗證 Bayer order(本單元)。
  3. 統計黑位與缺陷像素(單元 7/13)。
  4. 之後的 LSC/CCM/NR 校正都以這份「乾淨 RAW」為輸入。

8.6 DNG 檔結構(RAW 封裝)

DNG 是 Adobe 的 RAW 封裝(TIFF 基底)。調校時透過 rawpy/dcraw 讀,但理解結構有助除錯:

DNG 欄位意義
CFAPattern / raw_patternBayer order(驗證用)
BlackLevel各通道黑位
WhiteLevel飽和值(10-bit → 1023)
AsShotNeutralAWB gains
ColorMatrix色彩矩陣
用 rawpy 讀 metadata
python3 - <<'EOF'
import rawpy
raw = rawpy.imread('t.dng')
print('Bayer pattern:', raw.raw_pattern)          # 驗證 order
print('BlackLevel:', raw.black_level_per_channel)
print('WhiteLevel:', raw.white_level)
EOF

8.7 常見 RAW 格式錯誤

錯誤症狀檢查
Bayer order 錯色彩全亂raw_pattern + 純色卡
bit depth 錯讀暗部階調斷裂/過曝white_level 是否 1023
ROI 錯影像偏移/錯位width/height 與 mode 一致
packing 錯(10-bit 當 8-bit)條紋狀假影用支援 10-bit 的解碼器

8.8 多模式 RAW 的一致性(調校前必修)

重要:同一顆感測器在不同解析度(2592 vs 1296)的 Bayer order 與 binning 行為不同。調校與回歸必須鎖定單一模式,否則 LSC 網格、CCM 在不同 size 下會不一致。
列出模式並鎖定
rpicam-hello --list-cameras          # 記錄要調校的 mode
rpicam-still --width 2592 --height 1944 --raw -o full.dng   # 固定全解析

8.9 深入:10-bit RAW 的 packing 與解包

10-bit 資料在記憶體中的 packing 方式影響解碼:

packing說明
Unpacked(16-bit)每像素 2 byte,低 6 bit 無效
Packed(MIPI CSI-2)5 byte 塞 4 像素(4×10=40 bit)
常見錯誤:把 packed 的 10-bit 當 8-bit 解 → 出現「條紋狀假影」與錯誤色彩。rawpy/dcraw 會自動處理;手寫解析時要留意。

8.10 深入:Bayer order 在 DNG 的驗證

用 raw_pattern 一錘定音
python3 - <<'EOF'
import rawpy
r = rawpy.imread('t.dng')
print('raw_pattern:')
for row in r.raw_pattern:
    print(' ', row)   # 0=R,1=G,2=B(依 libraw 慣例)
EOF

比對 datasheet 的 RGGB 起點,確認平台設定一致。

8.11 練習

  1. 用 test.dng 驗證 Bayer order(raw_pattern)。
  2. 量測黑位與 white_level。
  3. 記錄「本平台 RAW 的正確解析參數」。
看完這單元你應該能說出:
  • fourcc 與 CSI/Sensor order 的關係。
  • 用 DNG 驗證 Bayer order(純色判別)。
  • bit depth 對動態範圍的影響。
  • ROI/binning 對調校的影響。
  • RAW 分析標準流程。

進階真實情境 Worked Example:用 v4l2-ctl 直接擷取未經 libcamera 處理的原始 RAW

場景:你要驗證「rpicam-still 的 DNG 是否真的包含原始 Bayer 資料」,需要從 V4L2 層直接擷取。

V4L2 原始 RAW 擷取
# 1. 確認 V4L2 裝置與 format
v4l2-ctl -d /dev/video0 --list-formats-ext
# 找到 SGBRG10_1X10 或 SRGGB10_1X10

# 2. 設定 format 並單次擷取
v4l2-ctl -d /dev/video0 \
  --set-fmt-video=width=2592,height=1944,pixelformat=SBGGR10 \
  --stream-mmap --stream-count=1 --stream-to=raw_v4l2.bin

# 3. 用 rawpy 驗證
python3 - <<'EOF'
import rawpy, numpy as np
# 注意:V4L2 輸出可能是 packed 10-bit,rawpy 可能無法直接讀
# 需要先確認 packing 格式
data = np.fromfile('raw_v4l2.bin', dtype=np.uint8)
print(f"原始資料大小: {len(data)} bytes")
print(f"期望大小 (2592*1944*10/8): {2592*1944*10//8}")
EOF
為什麼選這條路徑:用 v4l2-ctl 而非 rpicam-still 擷取,是為了確認「原始資料到達 V4L2 層時的狀態」。這能幫助你判斷「Bayer order 問題是感測器端還是 libcamera 端造成的」。若 v4l2-ctl 擷取的 raw 資料 order 對了但 DNG 的 order 錯了,問題就在 libcamera 的 metadata 寫入——而非感測器。

深入原理擴充:10-bit MIPI CSI-2 packing 與 byte 對齊

OV5647 輸出 10-bit RAW,但 MIPI CSI-2 傳輸層以 byte 為單位,packing 方式影響資料解讀:

大家以為沒问题但其實是陷阱:很多人以為「Bayer order 在所有 mode 下都是 RGGB」,但 OV5647 在 binning 模式(1296×972)下,像素合併方式可能改變 effective Bayer order——例如 2×2 binning 後,Gr 和 Gb 被平均,effectively 變成 RGGB 但 Gr/Gb 的 ratio 已改變。若你在 binning 模式下量測 Gr/Gb 不平衡,可能低估了問題。

診斷式疑難排解表

症狀可能原因解決方案
DNG 的 raw_pattern 顯示的 order 與預期不符libcamera metadata 寫入錯誤,或感測器 init table 的 order 設定有誤對照 v4l2-ctl 直接擷取的原始資料確認;查 ov5647.c 的 format 設定
用 rawpy 讀 DNG 時色彩通道全是灰色bit depth 設定錯誤(10-bit 當 8-bit 讀)或 black_level 設太高確認 raw.white_level 是否為 1023;調整 raw.black_level_per_channel
V4L2 擷取的 raw 檔大小與預期不符packing 格式不匹配(packed vs unpacked)確認 V4L2 format 的 pixelformat;計算期望大小 vs 實際大小
不同解析度下 DNG 的 Bayer order 不同binning 模式改變了 effective pixel order鎖定單一解析度做調校;不同 mode 分別驗證 Bayer order
rawpy 讀出的通道均值全是 0DNG 的 black_level 設為 0,導致扣除後全負手動修正 DNG metadata 的 black_level;或用 dcraw 原始解碼

進階挑戰題

  1. 寫一個 Python 腳本,自動比較 rpicam-still 的 DNG 與 v4l2-ctl 的原始 raw 資料,量化兩者的差異(mean error、max error)。
  2. 若 OV5647 從 2592×1944 切到 640×480(跳過 binning,用 cropping),Bayer order 是否改變?設計實驗驗證。
  3. 研究 MIPI CSI-2 的 packed 10-bit 格式,寫一個解包函數將 packed 資料還原為 16-bit per pixel。

延伸閱讀

專案級端到端 Worked Example:自動化 RAW 健康報告專案

場景:每次拍攝後都要確認 RAW 是否「乾淨」:Bayer order 正確、bit depth 正確、黑位合理、無缺陷像素。本專案建一個 raw_report.py 一鍵產出 RAW 健康報告,整合單元 8(格式)、7(黑位)、13(缺陷像素)、5(拍攝)知識。

raw_report.py:一鍵 RAW 健康報告
#!/usr/bin/env python3
import sys, rawpy, numpy as np

def report(path):
    raw = rawpy.imread(path)
    img = raw.raw_image
    roi = img[img.shape[0]//4:3*img.shape[0]//4,
              img.shape[1]//4:3*img.shape[1]//4].astype(float)
    print(f"檔案: {path}")
    print(f"shape: {img.shape}  white_level: {raw.white_level}")
    print(f"Bayer pattern:\n{raw.raw_pattern}")
    print(f"BlackLevel/ch: {raw.black_level_per_channel}")
    cells = [roi[0::2,0::2].mean(), roi[0::2,1::2].mean(),
             roi[1::2,0::2].mean(), roi[1::2,1::2].mean()]
    print(f"通道均值: R={cells[0]:.0f} Gr={cells[1]:.0f} "
          f"Gb={cells[2]:.0f} B={cells[3]:.0f}")
    hot = (img > roi.mean() + 10*roi.std()).sum()
    print(f"hot pixels (>10σ): {hot}  max: {img.max()}")

report(sys.argv[1])
使用與預期輸出
./raw_report.py first.dng
# 預期:
# shape: (1944, 2592)  white_level: 1023
# Bayer pattern 顯示 0/1/2 排列(驗證 RGGB)
# BlackLevel/ch 四通道合理(~100)
# 通道均值差異不大、hot pixels 少
# 判讀:任一異常 → 回對應單元診斷
專案規模與跨單元整合:這份報告是每次拍攝後的第一道檢查:Bayer order 驗證用單元 8 的方法、黑位用單元 7、缺陷像素用單元 13。把它掛進 capture_pipeline.sh(單元 5)結尾,每拍一張自動產報告。raw_pattern 與預期不符 = 別急著改 CCM,先查 order(單元 8.2 陷阱)。

量測/驗證 SOP:RAW 完整性驗證

  1. --raw 拍攝基準 RAW(固定參數)。
  2. 執行 raw_report.py,檢查 shape 與 white_level(2592×1944 / 1023)。
  3. 核對 raw_pattern 與預期 Bayer order(RGGB)。
  4. 檢查四通道黑位(差異 <20 階)與均值合理性。
  5. 檢查 hot pixel 數量與 max 值。
  6. 存報告,與基準比較(回歸用)。
判讀指標:white_level 非 1023 = bit depth 解讀錯(單元 8.7);通道均值全 0 = black_level 誤設;order 錯 = 色彩全亂;hot pixels 暴增 = 溫度或缺陷擴散。

平台間對照:RAW 格式與解析

面向RPi5Orange PiOrin NanoThor
RAW 封裝DNG(含 metadata)裸 RAW(V4L2).nvraw(私有).nvraw / Holoscan
解析工具rawpy / dcrawnumpy 手解 packingNVIDIA 專用轉換NVIDIA 專用轉換
Bayer order 驗證raw_pattern 欄位自行判斷(純色卡)ISP 設定宣告ISP 設定宣告
metadata 可能誤寫10-bit packing 要手解格式不公開工具少

互動式檢核清單


第 3 輪深度加深

① Register 位元級完整工作流:OV5647 RAW 輸出格式設定

步驟暫存器位元級說明
1. 設定格式0x43000xF0bit[7:4]=1111 → RAW Bayer, bit[3:0]=0000 → 10-bit
2. 設定 Bayer 順序0x43010x00bit[1:0]=00 → GR/BG (RGGB), 01=BG/GR (BGGR)
3. 設定輸出 byte packing0x43020x00bit[0]=0 → 10-bit packed (4 byte/4 pixel)
4. 驗證dump 0x4300-0x4302確認值與設定一致

② 多層疑難排解決策樹

決策樹 A:RAW 檔解碼後全黑或全白

RAW 解碼異常
├─ 檢查 A:Bayer 順序是否正確
│  ├─ 不確定 → 依序嘗試 RGGB/BGGR/GRBG/GBRG,看哪個畫面正確
│  └─ 正確 → 繼續
├─ 檢查 B:位元深度是否匹配
│  ├─ 10-bit 用 8-bit 解讀 → 發暗 → 確認 unpack 設定
│  └─ 匹配 → 繼續
├─ 檢查 C:stride / padding 是否正確
│  ├─ stride 不對 → 行對齊錯誤 → 調整 bytes_per_line
│  └─ 正確 → 繼續
└─ 檢查 D:是否存在 data offset
   ├─ 有 → RAW data 前有 metadata header → 跳過 header
   └─ 無 → 格式設定問題

③ 量測驗證完整 SOP:RAW 資料完整性驗證

  1. 工具:rawpy, numpy, Python
  2. 步驟:
    a. 擷取 RAW 檔(遮光,短曝光)
    b. raw = rawpy.imread('test.raw')
    c. print(raw.shape, raw.dtype, raw.min(), raw.max(), raw.mean())
    d. 確認 dtype=uint16 (10-bit packed in 16-bit), shape[2]=width
  3. 驗證清單:
    a. 遮光 RAW:mean < 50 (10-bit scale 0-1023) → 黑位 OK
    b. 白卡 RAW:mean > 500 → 有光線到達 sensor
    c. 有 pattern 的測試圖:能辨識邊緣 → 解碼正確
    d. pixel 值 range:min ≥ 0, max ≤ 1023 (10-bit)
  4. 常見偏差:little-endian vs big-endian 位元反轉;packed vs unpacked 格式不符

④ 四平台終極對照

面向RPi5Orange PiOrin NanoThor推薦
RAW 格式10-bit packed Bayer8/10-bit Bayer10/12-bit packed12/14-bit packed各有不同
RAW 擷取工具rpicam-apps --rawv4l2-ctl --captureNV nvraw toolsHoloscan pipelineRPi5 最簡單
RAW 格式解析rawpy (Python)rawpy / dcrawNV toolsNV + Holoscanrawpy 最通用
Bayer 順序可調Device treeDevice treeNV tuningHoloscan config各有方式

⑤ 完整 Bring-up 專案 Checklist