多相机系统#
多相机设置常见于工业应用,例如检测、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。
- 可扩展架构使用并行处理。