多相機系統#
多攝影機配置在工業應用中相當常見,例如檢測、3D 重建以及同步資料擷取。當單一攝影機不足以擷取所有所需資訊時,便會採用此類配置。
典型使用案例:
- 捕捉物體的不同視角
- 擴大視野範圍
- 提高吞吐量
- 多個物件的並行檢查
根本性挑戰#
使用多台攝影機會帶來幾項挑戰:
- 同步(時序)
- 頻寬限制(特別是在使用 GigE 攝影機時)
- CPU 負載(處理多個串流)
- 裝置識別與映射
裝置識別#
每台攝影機都必須擁有一個唯一的識別碼,通常是其序號。
映射範例:
請避免使用諸如 devices[0] 因為相機的枚舉順序可能會改變。如需更多詳細資訊,請參閱 清點攝影機.
建立多個相機實例#
from pypylon import pylon
factory = pylon.TlFactory.GetInstance()
device_info_list = factory.EnumerateDevices()
cameras = []
for device_info in device_info_list:
camera = pylon.InstantCamera(factory.CreateDevice(device_info))
camera.Open()
cameras.append(camera)
這會針對每台裝置建立並開啟一個相機實例。
取得方法#
當使用多台攝影機時,必須決定採用何種擷取方式:依序擷取或並行擷取。
循序漸進的收購#
這表示影像處理是依序由一台相機接下一台相機進行的。
此方法的主要特點:
- 實施起來很簡單
- 未進行時間同步
- 整體速度較慢
並行收購#
這表示來自多台攝影機的影像會一併進行處理。
此方法的主要特點:
- 攝影機同時進行影像擷取
- 同步所需
- 對 CPU 和頻寬的需求更高
同步方法#
要同步相機,您可以選擇軟體同步或硬體同步。其優缺點與軟體觸發與硬體觸發的比較類似。
軟體同步#
此方法的主要特點:
- 透過軟體觸發相機
- 精度有限
- 受作業系統調度影響
範例:
硬體同步(建議)#
此方法的主要特點:
- 精準的時機
- 確定性行為
- 立體聲或測量系統所需
頻寬考量(GigE)#
多台 GigE 攝影機共用同一網路頻寬。
潛在問題:
- 封包遺失
- 丟幀
- 延遲增加
您可以採用以下其中一種策略來減輕潛在問題:
- 使用專用網路介面卡(NIC)
- 啟用巨型幀(MTU 9000)
- 降低 ROI 或幀率
- 設定封包延遲
處理架構#
單執行緒#
- 簡單
- 可擴展性有限
多執行緒(建議)#
- 可擴展性
- 更佳的 CPU 利用率
- 實作起來較為複雜
範例模式#
基本多攝影機迴圈(順序輪詢)#
from pypylon import pylon
def process(image):
print(image.shape)
factory = pylon.TlFactory.GetInstance()
device_info_list = factory.EnumerateDevices()
cameras = [pylon.InstantCamera(factory.CreateDevice(device_info)) for device_info in device_info_list]
for camera in cameras:
camera.Open()
camera.StartGrabbing()
while any(camera.IsGrabbing() for camera in cameras):
for camera in cameras:
if camera.IsGrabbing():
with camera.RetrieveResult(1000) as grab_result:
if grab_result.GrabSucceeded():
image = grab_result.Array
# Do processing on image here, e.g. call a function.
process(image)
進階方法:InstantCameraArray(建議使用)#
pypylon 為多攝影機配置提供了專用的抽象層: InstantCameraArray.
此類別負責管理多台攝影機,並提供一個 單一統一的 RetrieveResult() 呼叫,其中包括有關該影像由哪台相機拍攝的資訊。
from pypylon import pylon
def process(image):
print(image.shape)
COUNT_OF_IMAGES_TO_GRAB = 100
RETRIEVE_TIMEOUT_MS = 5000
factory = pylon.TlFactory.GetInstance()
device_info_list = factory.EnumerateDevices()
with pylon.InstantCameraArray(len(device_info_list)) as cameras:
for i, camera in enumerate(cameras):
camera.Attach(factory.CreateDevice(device_info_list[i]))
print("Using device:", camera.DeviceInfo.ModelName)
cameras.StartGrabbing()
for i in range(COUNT_OF_IMAGES_TO_GRAB):
if not cameras.IsGrabbing():
break
with cameras.RetrieveResult(
RETRIEVE_TIMEOUT_MS,
pylon.TimeoutHandling_ThrowException
) as grab_result:
if grab_result.GrabSucceeded():
cam_idx = grab_result.CameraContext
print(f"Camera {cam_idx}: {cameras[cam_idx].DeviceInfo.ModelName}")
image = grab_result.Array
# Do processing on image here, e.g. call a function.
process(image)
else:
print("Error:", grab_result.ErrorDescription)
為什麼 InstantCameraArray 很重要
與手動迴圈相比,此方法具有以下優勢:
- 適用於所有攝影機的單一擷取迴路
- 自動相機情境追蹤 (
camera.CameraContext) - 更簡便的同步處理方式
- 更有效率的執行緒使用
從概念上來說:
實用設計指南#
- 請務必透過序號來辨識攝影機。
- 較傾向採用硬體同步。
- 盡可能降低頻寬(例如:指定感興趣區域(ROI)或降低幀率)。
- 為提升可擴展性,請使用獨立的處理執行緒。
- 監控系統負載(CPU、網路)。
常見的陷阱#
- 依據裝置索引。
- 超過網路頻寬。
- 忽略同步要求。
- 阻斷了擷取迴路的處理。
心智模型#
重點摘要#
- 多鏡頭系統需要仔細設計。
- 對於許多應用程式而言,同步至關重要。
- 必須在早期階段就將頻寬和 CPU 納入考量。
- 可擴展的架構採用並行處理。