多相機系統#
多相機設置在工業應用中很常見,例如檢測、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、網路)。
常見陷阱#
- 依賴裝置索引。
- 超出網路頻寬。
- 忽略同步要求。
- 在擷取迴圈中阻斷處理。
Mental Model#
重點整理#
- 多相機系統需要周密的設計。
- 同步對許多應用至關重要。
- 必須及早考慮頻寬和 CPU。
- 可擴展架構採用並行處理。