13.3.1.3. 串流影格¶
在相機上擷取影格的指令碼可以透過 USB 將每個影格串流回主機。其模式是在 openmv.Camera 實例上呼叫兩個方法:以 streaming() 開啟或關閉串流,並以 read_frame() 從通道中取出下一個影格。
13.3.1.3.1. 最簡單的串流與顯示迴圈¶
相機端的指令碼就是一般的快照迴圈;新增的部分是主機開啟串流並將結果讀回:
from openmv import Camera
script = """
import csi
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
while True:
csi0.snapshot()
"""
with Camera('/dev/ttyACM0') as cam:
cam.stop()
cam.exec(script)
cam.streaming(True)
while True:
if frame := cam.read_frame():
print(f"{frame['width']}x{frame['height']}, "
f"{frame['raw_size']} bytes")
相機持續擷取影格;主機在每個影格抵達時將其從串流緩衝區中取出。相機在每次新的快照時都會覆寫串流緩衝區,因此輪詢速度比相機擷取速度慢的主機會默默地丟棄影格——對於檢視器類型的使用情境而言,這正是正確的行為。
13.3.1.3.2. 影格字典¶
read_frame() 會回傳 None(沒有影格在等待)或一個包含五個項目的 dict:
鍵 |
意義 |
|---|---|
|
影格寬度(以像素為單位)。 |
|
影格高度(以像素為單位)。 |
|
相機所宣告的像素格式識別碼(來自相機 |
|
對於壓縮格式(JPEG、PNG),這是壓縮影像的位元組大小。未壓縮格式不使用此項。 |
|
影格以 RGB888 的 |
|
相機在解碼前透過 USB 傳送的位元組數。用於實際的吞吐量計算。 |
套件會在回傳前將相機的原生格式(GRAYSCALE、RGB565、JPEG)轉換為 RGB888,因此主機永遠不必自行處理位元封裝的 RGB565 或 JPEG 解壓縮流程。灰階影格回傳時,會將其亮度值複製到全部三個通道。
data 緩衝區是逐列由上而下排列的;將它直接餵給顯示函式庫或將其儲存為原始 RGB 檔案皆可運作,無需任何額外的重排。
13.3.1.3.3. 原始串流模式¶
在預設情況下,相機會先將每個擷取的影格進行 JPEG 壓縮,再放入串流通道,而 read_frame() 則在主機端解壓縮。在沒有硬體 JPEG 支援的相機上,軟體壓縮是迴圈中最慢的步驟。傳入 raw=True 可略過此步驟:
cam.streaming(True, raw=True, resolution=(320, 240))
相機接著會以未壓縮的方式傳送像素緩衝區。未壓縮的影格比其 JPEG 對應版本大得多,因此相機會在傳送前將每個擷取的影格縮小以符合串流通道;resolution=(width, height) 引數設定該目標。主機端仍會在 data 欄位中收到 RGB888——套件會從相機在 format 中所回報的任何像素格式進行轉換。
13.3.1.3.4. 讓事件驅動迴圈¶
若輪詢迴圈呼叫 read_frame() 的速度比相機產生影格的速度還快,那麼它大部分的時間都在取回 None。當主機還有其他工作要做(要更新的 UI、要輪詢的其他通道)時,read_status() 是更省成本的檢查方式:它會回傳一個字典,將每個已註冊的通道名稱對應到一個布林值,表示「資料是否就緒」:
while True:
status = cam.read_status()
if status.get('stream'):
frame = cam.read_frame()
# ... process the frame ...
if status.get('stdout'):
text = cam.read_stdout()
print(text, end='')
if status.get('my_channel'):
data = cam.channel_read('my_channel')
# ... process custom-channel data ...
這正是 CLI 檢視器本身所使用的迴圈形式。
13.3.1.3.5. 停止串流¶
以 enable=False 呼叫 streaming() 即可停止。相機會繼續執行其指令碼,但不再填入串流緩衝區;從那一刻起,read_frame() 只會回傳 None。呼叫 stop() 會藉由停止指令碼而隱含地達到相同的效果。