4.18. 多個感測器¶
少數幾款 OpenMV Cam 在同一塊開發板上配對了兩個影像感測器——最常見的是一台彩色相機搭配一個 FLIR® Lepton® 熱感測器,但同樣的形式也適用於彩色加事件型開發板,以及任何未來的雙感測器硬體。每個感測器都有自己的像素陣列、自己的控制匯流排,並以自己的影格率運行自己的管線。CSI API 透過讓應用程式為每個實體感測器各實例化一個 CSI 物件,將支援範圍延伸到涵蓋它們。
4.18.1. 選擇使用哪一個感測器¶
CSI 建構子接受一個 cid 引數,用以指名開發板上的某個特定感測器。cid=-1(預設值)選擇主感測器;具名的 cid 常數則依晶片 ID 選擇某個次級感測器:
import csi
csi_rgb = csi.CSI() # primary colour sensor
csi_thermal = csi.CSI(cid=csi.LEPTON) # FLIR® Lepton®
每個實例都擁有自己的設定——像素格式、影格大小、曝光/增益旋鈕、影格緩衝區池——並且獨立於其他實例進行重置、設定與讀取。支援的次級感測器所對應的常數(LEPTON、GENX320,以及 CSI 參考文件中列出的其他常數)指名應用程式預期在次級埠上的晶片;若實際的晶片不相符,驅動程式便會讓建構失敗。
4.18.2. 從兩個感測器擷取¶
每個感測器都獨立於其他感測器運行自己的擷取管線——彩色感測器可能每秒提供三十張影格,而 Lepton® 每秒提供九張。處理這種不匹配最直截了當的方式,是讓較快的感測器驅動迴圈,並以非阻塞方式讀取較慢的感測器,取走任何已就緒的影格,並在沒有任何影格時跳過該次迭代:
import csi
csi_rgb = csi.CSI()
csi_thermal = csi.CSI(cid=csi.LEPTON)
csi_rgb.reset() # powers the rail, pulses RESET
csi_rgb.pixformat(csi.RGB565)
csi_rgb.framesize(csi.QVGA)
csi_thermal.reset(hard=False) # I2C reconfigure only
csi_thermal.pixformat(csi.GRAYSCALE)
csi_thermal.framesize(csi.QQVGA)
while True:
rgb_img = csi_rgb.snapshot() # blocks for next colour frame
thermal_img = csi_thermal.snapshot(blocking=False) # returns None if not ready
if thermal_img is not None:
# process aligned colour + thermal pair
pass
else:
# process colour only on this iteration
pass
阻塞式的 snapshot() 為迴圈定速;非阻塞式的那個則在自上次呼叫以來有新影格送達時回傳最近的一張熱影格,否則回傳 None。應用程式持續以彩色感測器的影格率運行,並在 Lepton® 每產生一張熱影格時就取得一張。
相反的模式——背靠背的兩次阻塞式快照——同樣可行,但這樣一來迴圈就會以兩個感測器中較慢的那個速率運行,較快的感測器管線會在各次迭代之間停滯。請挑選應用程式的下游處理實際想要驅動的那個速率。
4.18.4. 選擇串流來源¶
具備兩個感測器的相機有兩個 CSI 實例,但兩者之間仍只共用一個串流影格緩衝區。一個建構子引數會挑選哪個感測器的影格饋送至預覽:
csi_rgb = csi.CSI() # primary
csi_thermal = csi.CSI(cid=csi.LEPTON,
stream=True) # preview source
stream=True 使具名的實例成為來源。在沒有 stream= 引數時,主感測器(cid=-1,即預設值)便是來源;以某個次級感測器的 cid= 建構出來的實例,除非明確傳入 stream=True,否則在預覽上保持靜默。對未被選中的感測器呼叫 snapshot() 仍會照常將影格擷取進該感測器的影格緩衝區——它們只是不會更新預覽。