Bayer format、V4L2 格式
| fourcc | 意義 |
|---|---|
YUYV / UYVY | YUV422(感測器內 ISP 出圖,最常見) |
SRGGB10 等 | RAW Bayer(10-bit) |
NV12 | 平台 ISP/後處理輸出 |
v4l2-ctl -d /dev/video0 --list-formats-ext
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=SRGGB10
RAW 是影像品質分析的根本:雜訊、黑位、Bayer order 都回 RAW。
| 錯誤 | 症狀 | 檢查 |
|---|---|---|
| Bayer order 錯 | 色彩全亂 | 拍純色卡判別四通道 |
| bit depth 錯讀 | 暗部階調斷裂 | 確認 RAW 位元深 |
| packing 錯 | 條紋狀假影 | 用對應位元深工具解析 |
RAW 不是「每個像素一個 16-bit 值」那麼單純——V4L2 用 pixelformat 的位元描述 packing:
| fourcc | 每像素位元 | packing |
|---|---|---|
| SRGGB8 | 8 | 每 byte 1 像素 |
| SRGGB10 | 10 | 16-bit 容器存 10-bit(低 6 bit 補 0) |
| SRGGB10P | 10 | packed,跨 byte 連續 |
| SRGGB12 | 12 | 16-bit 容器存 12-bit |
bytesperline 是「一列影像在記憶體佔多少 byte」,常因硬體對齊而大於「寬 × 每像素 bytes」。用 v4l2-ctl --get-fmt-video 可看到 bytesperline 與 sizeimage,程式必須用這兩個值而非「寬×高×bpp」去讀 buffer。
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=SRGGB10 \ --stream-mmap=3 --stream-count=1 --stream-to=raw.bin
v4l2-ctl -d /dev/video0 --get-fmt-video # 讀 bytesperline / sizeimage
python3 - <<'EOF'
import numpy as np, struct
# 假設 bytesperline=2560, height=720, bpp=2
raw = np.fromfile('raw.bin', dtype=np.uint16).reshape(720, 1280)
print('R/Gr/Gb/B =', raw[0::2,0::2].mean(), raw[0::2,1::2].mean(),
raw[1::2,0::2].mean(), raw[1::2,1::2].mean())
EOF--get-fmt-video 回傳的 bytesperline/sizeimage 配置讀取,不要手算。記錄你板卡的實際對齊值,寫進 team SOP。| 現象 | 原因 | 檢查 |
|---|---|---|
| 整圖斜掉/鋸齒 | bytesperline 對齊沒算 | 改用 get-fmt 回傳值 |
| 色彩全亂 | Bayer order 錯 | 拍色卡驗四通道 |
| 暗部斷階/條紋 | 位元深讀錯 | 確認 SRGGB10P vs SRGGB10 |
| 畫面偏綠 | 沒做黑位校正就看 | RAW 本來就該偏色——先校正再看 |
| 尺寸不對 | sizeimage 含 padding | 以 sizeimage 為準 |
SRGGB10 與 SRGGB10P 搞混——padded 與 packed 的位元佈局不同;③ 不同解析度/binning 下 Bayer order 可能不同——每次換模式都要重新確認。除了 RAW,Orange Pi 也可能輸出 YUV(感測器內 ISP)或 NV12(平台後處理)。布局完全不同:
| 格式 | 布局 | 每像素平均 |
|---|---|---|
| YUYV / UYVY | 交錯 Y0 U0 Y1 V0 | 2 byte |
| NV12 | 全部 Y 平面 + 交錯 UV 平面 | 1.5 byte |
| NV21 | 全部 Y 平面 + 交錯 VU 平面 | 1.5 byte |
1280×720 的 YUYV 大小 = 1280×720×2 = 1,843,200 byte;NV12 則是 1280×720×1.5 = 1,382,400 byte。兩者「同解析度但 sizeimage 不同」——所以永遠以 fourcc + get-fmt 的 sizeimage 為準。
# 比較實際檔案大小與兩種理論值
ls -l frame.bin
python3 - <<'EOF'
W,H = 1280,720
import os
n = os.path.getsize('frame.bin')
print('YUV422 =', W*H*2, ' NV12 =', W*H*3//2, ' actual =', n)
EOF--get-fmt-video 的 bytesperline 正確重組並印四通道均值。sizeimage,解釋差異。場景:Orange Pi 5 Plus(RK3588)接 OV5640,同一解析度下分別取 SRGGB10(16-bit 容器)與 SRGGB10P(packed),比較兩者的檔案大小與解析品質。
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=SRGGB10 \ --stream-mmap=3 --stream-count=1 --stream-to=raw10.bin v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=SRGGB10P \ --stream-mmap=3 --stream-count=1 --stream-to=raw10p.bin
ls -l raw10.bin raw10p.bin
python3 - <<'EOF'
import os
for f in ['raw10.bin', 'raw10p.bin']:
sz = os.path.getsize(f)
print(f'{f}: {sz} bytes (理論 SRGGB10={1920*1080*2} SRGGB10P≈{1920*1080*10//8+1})')
EOFAllwinner H618 的 CIF(Camera Interface)與 RK3588 的 MIPI CSI-2 接收器在 RAW 處理上有關鍵差異:
| 項目 | Allwinner CIF | RK3588 CSI-2 |
|---|---|---|
| 支援 RAW packing | 僅 8-bit / 10-bit(無 packed) | 支援 SRGGB10P(packed) |
| 最大 lane 數 | 2 lanes | 4 lanes per receiver |
| Virtual channel | 不支援 | 支援 VC0-VC3 |
| Bytesperline 對齊 | 通常 16-byte 對齊 | 通常 64-byte 對齊 |
容易忽略的邊界案例:H618 的 CIF 不支援 SRGGB10P(packed 10-bit),所以在 Allwinner 板卡上只能用 SRGGB10(16-bit 容器)。如果你的 Python 腳本在 RK3588 上用 SRGGB10P 測試通過,搬到 H618 上會直接失敗——format 不被支援。
| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| RAW 檔案 size 是預期的 2 倍 | 用 uint16 讀 8-bit RAW,多讀了一倍 | 確認 fourcc 對應的 dtype:SRGGB8=uint8, SRGGB10=uint16 |
| SRGGB10P 讀出全是 0 | H618 不支援 packed 格式 | 改用 SRGGB10(16-bit 容器) |
| RAW 四通道均值差距大 | Bayer order 假設錯誤或場景非均勻 | 拍灰卡驗證;或用自動推斷腳本 |
| 條紋狀假影 | bytesperline 對齊未處理 | 用 --get-fmt-video 的 bytesperline 重組 |
| NV12 檔案 size 是 YUYV 的 1.5 倍(而非預期) | sizeimage 含 padding | 以 --get-fmt-video 的 sizeimage 為準 |
ls -l 的檔案大小,推斷是 YUYV、NV12、SRGGB10 還是 SRGGB8,印出格式與解析度。v4l2-ctl --list-formats-ext 不支援 SRGGB10P,然後用 SRGGB10 取一幀,計算實際 bytesperline 與理論值的差異(padding 量)。把單元 8 的格式知識做成自動化 RAW 採集與驗證專案:自動抓取所有支援的 fourcc,驗證大小、bytesperline、Bayer order 一致性,產出一份「格式能力表」。這是後續所有調校與跨模式比較的基礎設施。
v4l2-ctl -d /dev/video0 --list-formats-ext
#!/bin/bash
for fmt in SRGGB8 SRGGB10 SRGGB10P YUYV NV12; do
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=$fmt \
--stream-mmap=3 --stream-count=1 --stream-to=fmt_$fmt.bin 2>/dev/null \
&& echo "$fmt 成功: $(stat -c%s fmt_$fmt.bin) bytes" \
|| echo "$fmt 不支援"
donev4l2-ctl -d /dev/video0 --get-fmt-video
python3 - <<'EOF'
import os
for fmt in ['SRGGB8','SRGGB10','YUYV','NV12']:
f=f'fmt_{fmt}.bin'
if os.path.exists(f):
print(fmt, 'actual =', os.path.getsize(f), '理論(1280x720) =', {'SRGGB8':1280*720,'SRGGB10':1280*720*2,'YUYV':1280*720*2,'NV12':1280*720*3//2}[fmt])
EOF# 輸出格式: # 格式 支援 sizeimage bytesperline Bayer order # SRGGB10 ✅ 1,843,200 2560 RGGB(驗證) # SRGGB10P ❌ — — —(H618 不支援) # YUYV ✅ 1,843,200 2560 — # NV12 ✅ 1,382,400 1280 —
format_capture.sh 可一鍵產出「格式能力表」。這張表是跨平台移植(單元 15)與調校 SOP 的第一份參考文件。| 步驟 | 作法 | 通過判據 |
|---|---|---|
| 1. sizeimage 驗證 | 比對檔案大小與理論值 | 匹配(含 padding 判斷) |
| 2. bytesperline 重組 | 用 get-fmt 的 bytesperline 讀取 | 影像不斜不鋸齒 |
| 3. Bayer order 驗證 | 拍純色卡看四通道 | RGGB 對應正確 |
| 4. 位元深驗證 | 亮場峰值對照位元深 | 10-bit → 峰值近 1023 |
| 5. packing 驗證 | SRGGB10 vs 10P 檔案大小 | 10P 約為 10 的 5/8 |
| 面向 | Orange Pi | RPi5 | Orin Nano | Thor |
|---|---|---|---|---|
| 常見 RAW 輸出 | SRGGB10(16-bit 容器) | RPi RAW(SBGGR10) | RAW10(packed) | RAW10/12 |
| 打包格式 | 支援 10P / 不支援依 SoC | 依 libcamera raw | packed 為主 | packed 為主 |
| bytesperline 對齊 | 16/64 byte | 16 byte 常見 | NVIDIA 對齊 | NVIDIA 對齊 |
| 取 RAW 方式 | v4l2-ctl pixelformat | rpicam --raw | argus / nvgstcapture | Holoscan capture |
| 格式工具 | V4L2 fourcc(標準) | libcamera 描述 | NVIDIA 專屬 | NVIDIA 專屬 |
- [ ] 我能跑 format_capture.sh 產出格式能力表。 - [ ] 我能用 bytesperline 正確重組 RAW 而不斜圖。 - [ ] 我能區分 SRGGB10 與 SRGGB10P 的檔案大小差異。 - [ ] 我明白 YUYV / NV12 / RAW 的 sizeimage 計算。 - [ ] 我已驗證本平台在主要解析度的 Bayer order 一致性。 - [ ] 我能用「位元深 + Bayer order」描述任何平台的 RAW 格式。
RAW 格式的「讀→改→寫→驗證」是影像品質分析的基礎。以下是完整的位元級序列:
| 步驟 | 暫存器/位址 | 位元欄位 | 操作 | 預期值 |
|---|---|---|---|---|
| 1. 讀輸出格式 | 0x3808~0x380B | [15:0] width, [15:0] height | i2cget ... 0x3808; i2cget ... 0x3809 | 依解析度 |
| 2. 設定 RAW 格式 | v4l2-ctl pixelformat | — | v4l2-ctl --set-fmt-video=pixelformat=SRGGB10 | 格式設定成功 |
| 3. 驗證 sizeimage | file size | — | ls -l stream.raw | = width × height × 1.25 |
| 4. 驗證 bytesperline | V4L2 format | — | v4l2-ctl --list-formats-ext | 依解析度對齊 |
| 5. 讀 Bayer order | 0x4300 | [3:0] format | i2cget ... 0x4300 | SRGGB10 |
| 6. 驗證 RAW 資料 | Python script | — | raw_verify.py stream.raw | Bayer 資料正確 |
決策樹 A:RAW 檔案大小異常
ls -l stream.raw ├─ 太大 → format 錯誤 │ ├─ 檢查 pixelformat 設定 │ └─ 換 SRGGB10P(packed)vs SRGGB10(unpacked) ├─ 太小 → format 錯誤 │ └─ 可能誤設 YUYV(4 bytes/pixel) └─ 正確 → 格式正確 └─ 繼續驗證 Bayer 資料
決策樹 B:RAW 斜圖或色偏
RAW 圖像異常? ├─ 斜圖 → bytesperline 對齊問題 │ ├─ 用 Python 確認 bytesperline │ └─ 調整 width 對齊(16/64 byte) ├─ 色偏 → Bayer order 錯誤 │ ├─ 嘗試四種 order(RGGB/GRBG/GBRG/BGGR) │ └─ 用四通道均值法驗證 └─ 正常 → 格式正確 └─ 進階:用 RAW 做 OB/黑位分析
| 步驟 | 指令 | 預期輸出 | 判讀標準 |
|---|---|---|---|
| 1. 列出格式 | v4l2-ctl --list-formats-ext | SRGGB10/8/12 | 依 sensor 能力 |
| 2. 設定格式 | v4l2-ctl --set-fmt-video=pixelformat=SRGGB10 | 格式設定成功 | match sensor |
| 3. 取 RAW | v4l2-ctl --stream-mmap=1 --stream-count=1 | RAW 檔 | sizeimage 正確 |
| 4. 驗證大小 | ls -l stream.raw | = W × H × 1.25 | SRGGB10 計算正確 |
| 5. 驗證 Bayer | python3 raw_check.py stream.raw | Bayer 資料正確 | 四通道均值合理 |
| 6. 測 bytesperline | v4l2-ctl --list-formats-ext | grep bytesperline | 依解析度 | 16/64 byte 對齊 |
| 面向 | Orange Pi | RPi5 | Orin Nano | Thor | 推薦 |
|---|---|---|---|---|---|
| RAW 位元深 | 8/10/12 | 10/12 | 10/12/14 | 10/12/14 | 動態範圍→14-bit |
| 取 RAW 方式 | v4l2-ctl pixelformat | rpicam --raw | argus / nvgst | Holoscan | 底層→v4l2-ctl |
| format 工具 | V4L2 fourcc | libcamera 描述 | NVIDIA 專屬 | NVIDIA 專屬 | 通用→fourcc |
| bytesperline | 16/64 byte | 16 byte | NVIDIA 對齊 | NVIDIA 對齊 | 依解析度 |
| Bayer 驗證 | 自寫 Python | libcamera | NVIDIA 工具 | Holoscan | 學習→Python |
- [ ] 用 v4l2-ctl --list-formats-ext 列出所有支援格式 - [ ] 設定 SRGGB10 格式取 RAW - [ ] 驗證 sizeimage = width × height × 1.25 - [ ] 用 Python 確認 bytesperline 對齊 - [ ] 用四通道均值法驗證 Bayer order - [ ] 測試 SRGGB10 vs SRGGB10P 的檔案大小差異 - [ ] 測試 YUYV / NV12 / RAW 的 sizeimage 計算 - [ ] 產出「格式能力表」(format/size/bytesperline) - [ ] 驗證本平台在主要解析度的 Bayer order 一致性 - [ ] 用「位元深 + Bayer order」描述任何平台的 RAW 格式