2. pylon SDK与相机配置基础

pylon 是 Basler 相机的官方 SDK,它把 GigE、USB3 Vision、CoaXPress 等不同接口的相机统一到同一套 API 之下。无论你后续用 C++、C# 还是 Python 开发,调优与排障的起点都是同一件事:让 pylon 能稳定地找到相机、打开相机、把参数写进去、再把图像取出来。这一节围绕这条最小可用链路展开,给出可复现的操作与代码骨架。

一、安装 pylon:选对组件,装完先验证

从 Basler 官网下载 pylon 时,注意区分 pylon Camera Software Suite(完整套件)与单独的驱动包。完整套件包含运行时(Runtime)、pylon Viewer 图形化工具、SDK 头文件与示例代码,建议开发机直接装完整版。安装过程中有两个选项值得留意:

  • pylon IP Configurator:GigE 相机必备,用于查看和修改相机 IP、子网掩码、网关,以及启用巨帧(Jumbo Frame)。
  • USB 驱动与过滤器驱动:USB3 Vision 相机需要安装 pylon USB 驱动,否则系统可能以普通 UVC 设备识别,导致无法访问 GenICam 功能。

安装完成后不要急着写代码,先用 pylon Viewer 验证链路。打开 Viewer,左侧设备树应能列出已连接的相机;双击打开,点击连续采集(Continuous Grab),若能看到实时画面,说明驱动、网络/总线、供电都正常。这一步把“环境问题”和“代码问题”提前分离开,是后续排障的重要基线。

若 GigE 相机在 Viewer 中显示但无法打开,优先检查:相机与网卡是否同网段、是否启用了巨帧、防火墙是否拦截了 GVCP/GVSP 端口。这些是现场最高频的三类原因。

二、枚举设备:从设备信息到唯一标识

pylon 的枚举接口会返回一个设备信息列表,每个条目包含厂商名、型号、序列号、用户自定义名、设备类(BaslerGigE / BaslerUsb 等)以及当前 IP。实际工程中不要用“列表第 0 个”来选相机,而应使用序列号或用户自定义名作为唯一标识,否则多相机场景下顺序变化会导致取错设备。

枚举的典型流程是:创建传输层工厂(TlFactory)→ 获取传输层 → 枚举设备 → 遍历并打印信息 → 按序列号匹配目标相机。下面给出 Python 版(pylon 通过 pypylon 提供)的核心代码:

from pypylon import pylon

tl_factory = pylon.TlFactory.GetInstance()
devices = tl_factory.EnumerateDevices()

for dev in devices:
    print("Model:", dev.GetModelName())
    print("Serial:", dev.GetSerialNumber())
    print("Class :", dev.GetDeviceClass())
    print("User  :", dev.GetUserDefinedName())

# 按序列号精确匹配
target = None
for dev in devices:
    if dev.GetSerialNumber() == "40123456":
        target = dev
        break

if target is None:
    raise RuntimeError("未找到目标相机")

camera = pylon.InstantiateCamera(target)
camera.Open()

若使用 C++,对应的是 CTlFactory::GetInstance().EnumerateDevices(list) 与 InstantiateCamera,逻辑完全一致。枚举阶段还应记录设备类,因为 GigE 与 USB 在后续的包大小、带宽参数上处理方式不同。

三、配置相机参数:先读后写,注意节点可用性

pylon 的参数访问基于 GenICam 节点树。每个参数(如 Width、ExposureTime、Gain、PixelFormat)都有可读、可写、最小值、最大值、增量等属性。直接赋值前应先判断节点是否可写,否则会抛出逻辑错误。一个稳健的配置顺序是:

  1. 设置 PixelFormat(如 Mono8 / BayerRG8),它会影响后续 Width 的对齐约束。
  2. 设置 Width / Height,注意增量(Inc)通常为 2 或 4 的倍数。
  3. 设置 OffsetX / OffsetY,用于 ROI 裁剪。
  4. 设置曝光与增益:ExposureAuto = Off 后再写 ExposureTime,否则手动值会被自动算法覆盖。
  5. 若需外部触发,设置 TriggerMode = On、TriggerSource(Line1 / Software)。
camera.PixelFormat.Value = "Mono8"
camera.Width.Value = 1280
camera.Height.Value = 1024
camera.OffsetX.Value = 0
camera.OffsetY.Value = 0

camera.ExposureAuto.Value = "Off"
camera.ExposureTime.Value = 8000.0   # 单位 us
camera.GainAuto.Value = "Off"
camera.Gain.Value = 6.0              # 单位 dB

camera.TriggerMode.Value = "Off"     # 自由运行

这里 8000 μs 与 6 dB 是教学示例值,实际应根据光源亮度、运动速度与目标灰度动态调整。判断配置是否生效,最直接的方式是回读参数并打印,或在 pylon Viewer 中同步观察。若写入被拒绝,先检查 IsWritable,再检查是否与当前采集状态冲突——部分参数在采集进行中不可修改。

四、采集图像:从 GrabResult 到可用数据

pylon 提供两种取图方式:连续采集(StartGrabbing + RetrieveResult 循环)和单帧采集(GrabOne)。连续采集适合产线持续检测,单帧适合标定或调试。核心对象是 GrabResult,它携带图像缓冲、时间戳、帧号以及状态码。必须检查 GrabSucceeded(),失败时读取 GetErrorCode() 与 GetErrorDescription(),这是排障的第一手信息。

camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)

while camera.IsGrabbing():
    result = camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)
    if result.GrabSucceeded():
        img = result.Array          # numpy 数组
        print("Frame:", result.ImageNumber,
              "W x H:", result.Width, result.Height,
              "Mean:", img.mean())
    else:
        print("Error:", result.ErrorCode, result.ErrorDescription)
    result.Release()

camera.StopGrabbing()
camera.Close()

GrabStrategy_LatestImageOnly 只保留最新帧,适合实时性优先的场景;若需逐帧不丢,应改用 GrabStrategy_OneByOne 并配合足够的缓冲数量。RetrieveResult 的超时时间(示例 5000 ms)应根据帧率设置,过短会频繁抛超时,过长会掩盖真实的丢帧问题。

pylon 相机配置与采集最小链路 ① 安装与验证 pylon Suite + 驱动 IP Configurator Viewer 连续采集验证 基线:能出图 ② 枚举设备 TlFactory → Enumerate 读取序列号 / 设备类 按序列号匹配 唯一标识,避免取错 ③ 配置参数 PixelFormat → ROI ExposureAuto=Off ExposureTime / Gain 先读后写,查 IsWritable ④ 采集图像 StartGrabbing RetrieveResult GrabSucceeded 判断 Release → Stop 关键对象与数据流 CDeviceInfo 序列号 / 型号 / IP InstantCamera Open / 参数节点树 GrabResult 缓冲 / 帧号 / 时间戳 numpy 数组 后续处理 / 显示 异常与判断依据 枚举为空 驱动 / 网段 / 供电 写入参数报错 IsWritable / 采集状态 GrabSucceeded=false ErrorCode / 超时 / 带宽

五、把链路串起来:一个可复用的最小程序

把上述四步合并,就得到一个可复用的最小采集程序。它的价值在于:任何调优或排障都可以在这个骨架上加日志、加参数回读、加异常分支。建议在工程中固定以下习惯:

  • 枚举后打印全部设备信息,便于现场核对序列号。
  • 打开相机后立即回读关键参数,确认写入生效。
  • 采集循环中记录帧号与时间戳,用于判断是否丢帧。
  • 退出时按 StopGrabbing → Close → Destroy 顺序释放,避免相机被占用。
常见误区:在 ExposureAuto 仍为 Continuous 时手动写 ExposureTime,参数会被自动算法覆盖,表现为“设了没用”。正确做法是先把自动模式关掉,再写手动值。

完成这一节后,你已经具备用 pylon 完成“找到相机—配置相机—取到图像”的完整能力。后续的曝光调优、带宽优化、触发同步与故障诊断,都是在这条最小链路上逐段加深:参数怎么调、数据怎么流、异常怎么定位。把这条链路跑通并留下日志,是后面所有工作的基础。