尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

大恒水星相机Python SDK实战:从环境搭建到图像采集

大恒水星相机Python SDK实战:从环境搭建到图像采集 简介面向大恒水星系列工业相机如MER-500-14GM的Python SDK资源包为有Python基础的开发人员提供从相机控制、图像采集到二次开发的完整工具链尤其适用于自动化产线、科研实验、质量检测与机器视觉项目。压缩包总共包含15个文件其中8个py源码脚本负责核心控制逻辑5个pyc编译模块用于预加载加速1张jpg图片可作测试样本1份txt说明文档指导环境配置整体包体仅99KB轻量且便于部署。目前已有2539人学习下载参考价值较高。资源内gxipy封装了底层相机交互接口并附有软触发采集示例、彩色相机与单色相机的独立控制示例涵盖参数设置、图像捕获等完整流程示例代码简洁稍作调整即可嵌入实际项目帮助开发者规避复杂的硬件通讯细节快速搭建实时图像分析、自动检测等定制化视觉应用。1. 大恒水星相机 Python SDK先让第一张图出来很多人第一次拿到大恒水星系列相机时会误以为官方只提供 C/C# SDK。等看到 SDK 包里的python/gxipy目录又卡在import gxipy之后的一连串 DLL 报错上。这个“最后一步”其实和相机本身无关而是 Python 3.8 之后 Windows 的动态库搜索路径变得更严格。这篇文章顺着“初始化 gxipy → 枚举设备 → 打开相机 → 配置参数 → 采集图像”的最小路径走一遍覆盖水星系列的软触发、参数访问器和 OpenCV 显示的常见做法。无论刚从海康、康耐视还是巴斯勒转过来还是第一次用大恒的 Python SDK按这个顺序都能在一个小时内出图。2. 大恒水星 Python SDK 环境搭建从 DLL 路径到设备枚举2.1 驱动还是第一道门槛水星系列包含 USB3 Vision 和 GigE Vision 两种接口SDK 只是应用层系统层没有合适的驱动时update_device_info()怎么刷也看不到设备。USB3 相机在 SDK 包Driver目录下找 USB3 Vision 驱动并安装插入后设备管理器里应能看到“大恒图像”相关设备。GigE 相机需要本机网卡与相机 IP 能在同一网段必要时用 SDK 附带的 IP 配置工具修改相机地址。如果设备管理器中能看到硬件但 Python 枚举不到可以先跑一遍相机厂商的调试工具确认设备状态。问题若出在驱动层Python 代码再怎么调整都无法解决。这个环节最容易被项目里新接手的人跳过一上来就把时间花在查get_number_of_devices()为什么返回 0方向反了。2.2 把 gxipy 和底层库放进项目大恒 Python SDK 的常见形态是若干.py文件组成的gxipy包外加一个动态库GxIAPI.dllWindows或libGxIAPI.soLinux。不需要 pip 安装官方样例里大多是直接把gxipy文件夹复制到工程目录下。我一般按下面的方式组织grab_with_mercury/ ├── gxipy/ │ ├── GxIAPI.py │ ├── GxWrapper.py │ └── ... ├── GxIAPI.dll ├── main.py └── requirements.txtWindows 上有一个经常被忽略的步骤Python 3.8 及以后版本默认不再把当前目录放进 DLL 搜索路径必须在 import gxipy 之前显式声明否则程序会在调用底层接口时直接崩溃import os import sys # 把本项目所在目录加入 Windows DLL 搜索路径 SDK_DIR os.path.dirname(os.path.abspath(__file__)) if os.name nt and hasattr(os, add_dll_directory): os.add_dll_directory(SDK_DIR) import gxipy as gx逻辑说明add_dll_directory会临时修改当前进程的动态库查找目录和修改PATH环境变量相比作用范围更可控放在import gxipy之前是为了让 gxipy 在加载GxIAPI.dll时能找到依赖文件。Linux 环境下通常需要通过export LD_LIBRARY_PATH/path/to/sdk/lib或先用ctypes.CDLL(/path/to/libGxIAPI.so)加载动态库再 import gxipy。注意直接复制 DLL 到site-packages也能生效但升级 SDK 和切换相机型号时容易留下旧文件项目内单独放一份更干净。2.3 用最小脚本验证设备枚举完成路径配置后可以先跑一段只读脚本确认 gxipy 真的已经能访问相机import gxipy as gx device_manager gx.DeviceFactory() device_manager.update_device_info() num device_manager.get_number_of_devices() print(online devices:, num) for i in range(num): info device_manager.get_device_info(i) print(findex{i}, {info})逻辑说明DeviceFactory负责创建设备管理器update_device_info()重新扫描一次总线上所有符合 Vision 标准协议的设备get_number_of_devices()返回发现的设备数量。get_device_info(index)返回的是设备信息对象可以直接打印也能用类似info.get(serial_number)的字典方式读取字段。注意这只是“让 SDK 看到设备”并不代表驱动一定正确有时能看到设备但打开失败后面第三章会说明。设备信息里比较常用的字段如下字段类型用途indexint按扫描顺序生成的序号插拔后会变化display_namestr型号名例如水星系列某型号serial_numberstr相机序列号多相机场景下最可靠mac / ipstr主要出现在 GigE 相机回调信息中如果运行后 num 为 0优先确认驱动和接口不要急着改代码。USB3 相机插在机箱前置接口或扩展卡上时经常出现供电不足导致反复掉线这也是枚举不到的常见原因。3. 水星系列相机参数设置用序列号打开并用访问器调参3.1 通过序列号而不是 index 打开相机多相机系统中设备扫描顺序和操作系统加载顺序强相关同一个index在下次开机后可能指向另一台相机。代码里用serial_number定位相机要可靠得多。完整打开流程如下def open_camera(device_manager, target_snNone): device_manager.update_device_info() num device_manager.get_number_of_devices() for i in range(num): info device_manager.get_device_info(i) sn info.get(serial_number, None) if target_sn is None or sn target_sn: if sn: cam device_manager.open_device_by_sn(sn) else: cam device_manager.open_device_by_index(i) return cam return None逻辑说明先扫描设备列表把序列号与目标值比较找到后优先使用open_device_by_sn只有当序列号字段为空时退回索引方式。open_device_by_sn在大恒 SDK 中会做更严格的设备匹配不会因为插拔顺序变化而打开错相机open_device_by_index更简单适合临时测试、单相机或快速原型验证。使用示例manager gx.DeviceFactory() cam open_camera(manager, target_snNone)target_snNone表示打开第一台设备适合开发初期。生产环境一定要把目标 SN 传到参数里同时在相机外壳标签上核对这个 SN避免项目交付后现场有两台同型号相机时程序认错设备。3.2 读写参数水星 SDK 的访问器风格大恒 Python SDK 的参数访问方式和 OpenCV 那种set(propId, value)的命名风格不同它把每个相机属性包装成了对象的方法。读取曝光时间用的是cam.ExposureTime.get()写入用的是cam.ExposureTime.set(2000.0)。下面是常见参数的读写方式# 曝光时间单位微秒 cam.ExposureTime.set(2000.0) exposure cam.ExposureTime.get() print(exposure:, exposure) # 增益单位 dB cam.Gain.set(6.0) gain cam.Gain.get() print(gain:, gain) # 像素格式使用 SDK 提供的枚举常量 cam.PixelFormat.set(gx.GxPixelFormatEntry.RGB8)逻辑说明cam.ExposureTime这个属性对象内部绑定了相机的寄存器地址和底层读写逻辑因此不需要传入字符串名编辑期更不容易拼错。set写入的是物理量对应的真实值不是寄存器原始值写超出型号范围的值时大恒 SDK 通常会按硬件能力做截断但不同固件版本行为不完全一致必要时先用get_range()查范围expo_range cam.ExposureTime.get_range() print(expo_range)get_range()返回像(min, max, step)这样的元组调参之前先打印一次可以避免把 0 写进曝光时间这类低级错误。提示有些参数在start_acquisition()之后无法修改必须在停止采流状态配置后再开流。如果 IDE 里能导入 gxipy但找不到GxPixelFormatEntry这样的枚举多半是当前环境里混入了其他同名包确认解释器加载的 gxipy 与GxIAPI.dll来自同一个 SDK 目录。3.3 调参三个必设项水星系列的参数很多但第一步只需要关注下面的参数参数常见取值说明PixelFormatMono8 / RGB8 / BayerRG8决定图像转 numpy 后排列方式ExposureTime100 ~ 100000us曝光时间越长帧率上限越低Gain0 ~ 20dB增益越大噪点越明显TriggerModeOn / Off采集前必须明确触发方式TriggerSourceSoftware / Hardware触发源同 TriggerMode 配合使用一个比较稳妥的调试顺序cam.TriggerMode.set(gx.GxTriggerModeEntry.Off) cam.PixelFormat.set(gx.GxPixelFormatEntry.RGB8) cam.ExposureTime.set(10000) cam.Gain.set(0)逻辑说明先把触发关掉保证后面的测试都是自由运行模式能简化问题设置 RGB8 是为了后续用 OpenCV 直接显示不需要自己处理 Bayer 插值曝光时间 10ms 是室内正常亮度光源下比较安全的起点增益归零以便观察曝光是否足够。当画面过暗或者过亮时优先调节曝光时间而不是加增益。这一步完成之后水星相机就处于“能够出图”的状态。下一章开始真正的采集循环。4. 软触发与连续采集把水星相机图像接到 OpenCV 显示4.1 连续采集的完整流程水星相机在 Python SDK 里的采集流程可以理解为三步设置触发模式调用start_acquisition()循环取图。结束后记得stop_acquisition()和close_device()否则下一次运行可能因为资源未释放报错。import cv2 import gxipy as gx def stream(cam): # 1. 设为连续采集 cam.TriggerMode.set(gx.GxTriggerModeEntry.Off) cam.PixelFormat.set(gx.GxPixelFormatEntry.RGB8) # 2. 开流 cam.start_acquisition() # 3. 主循环 for _ in range(200): frame cam.get_image(timeout500) if frame is None: continue # 转 numpy ndarray raw frame.get_numpy_array() if raw is None: continue # RGB - BGR 以便 cv2.imshow 正常显示 bgr cv2.cvtColor(raw, cv2.COLOR_RGB2BGR) cv2.imshow(mercury, bgr) if cv2.waitKey(1) 0xFF ord(q): break # 4. 释放资源 cam.stop_acquisition() cv2.destroyAllWindows()逻辑说明get_image(timeout500)是阻塞式取帧超过 500ms 没有帧会返回None所以要判空。get_numpy_array()把大恒图像对象转成 numpy 数组不再需要手动拷贝内存。RGB8 排列顺序是 R、G、BOpenCV 默认 BGR所以需要COLOR_RGB2BGR否则图像颜色会整体偏色。注意get_image返回的帧对象内部引用了一块内存在下一帧到来之前必须完成get_numpy_array()或者复制数据否则该内存可能被 SDK 内部循环缓冲区覆盖。4.2 软触发的设置与踩坑调试视觉算法时软触发比连续采集更好控制测试流程。软触发模式下相机不会自主出图而是等软件送一个触发信号才输出一帧。设置方式# 软触发模式 cam.TriggerMode.set(gx.GxTriggerModeEntry.On) cam.TriggerSource.set(gx.GxTriggerSourceEntry.Software) cam.start_acquisition() # 触发一帧 cam.trigger_software() frame cam.get_image(timeout1000) # 完成后恢复 cam.stop_acquisition() cam.TriggerMode.set(gx.GxTriggerModeEntry.Off)逻辑说明TriggerSource和TriggerMode必须成对设置。只开TriggerMode不设TriggerSource或者TriggerSource指向Hardware却调用trigger_software()都会导致取不到图。典型表现是get_image()一直超时。遇到这种问题时优先用 SDK 自带调试工具看触发状态再回到代码里核对这两个参数。软触发适合帧率不高的场景比如每次收到 PLC 信号后取一帧做定位。需要满帧率连续采集时应改用自由运行模式即TriggerMode.Off。如果你的处理逻辑比帧间隔慢软触发反而能起到限流作用把相机当成一个由软件按需出图的传感器这也是视觉检测项目里比较推荐的做法。4.3 从 raw 到 numpy 再到 OpenCV 的颜色顺序水星系列黑白相机的PixelFormat常常是Mono8此时get_numpy_array()返回二维数组宽度和高度对应着图像的宽高直接cv2.imshow即可。彩色相机默认可能是BayerRG8此时数据是单通道 Bayer 排列直接显示会是马赛克图。如果 SDK 没有提供 RGB 转换可以在 OpenCV 侧做# 假设 camera 的 PixelFormat 为 BayerRG8 frame cam.get_image() bayer frame.get_numpy_array() bgr cv2.cvtColor(bayer, cv2.COLOR_BayerRG2BGR)逻辑说明COLOR_BayerRG2BGR中的RG表示 Bayer 矩阵的排列起点是 R 行 G 列如果颜色偏色可以依次尝试BG、GB、GR三种排列OpenCV 的转换宏足以覆盖大多数传感器。把格式设置交给 SDK 的 RGB8比自己在应用层做 Bayer 插值要快得多也更省心。5. 长时间运行的丢帧处理与自动重连水星 Python SDK 收尾技巧5.1 丢帧先看链路再看代码跑长任务时最典型的现象是“隔一段时间少一帧”或者相机彻底掉线。此时不必急着改程序按顺序排查USB3 数据线和主机接口。过长、劣质的数据线会导致传输误码换官方线或短线测试。供电是否充足。部分水星型号长时间运行后面临供电波动尽量使用独立供电或带供电能力的接口。是否开了满帧率。视觉处理耗时大于帧间隔时底层缓冲会堆积表现为延迟越来越大丢帧在所难免在AcquisitionFrameRateEnable里把帧率限制在处理能力以内。缓存与超时。get_image(timeout)超时设得太短也会被误判为丢帧先增大到 1000ms 观察。5.2 相机掉线自动重连按照长年跑项目的经验USB3 相机长时间运行偶尔会出现底层链接断掉。最实用的兜底策略是“检测到错误后重开设备”。可以在采集循环外加一个重试逻辑import time def safe_stream(open_camera_func, retry3): for attempt in range(retry): cam open_camera_func() try: cam.start_acquisition() while True: frame cam.get_image(timeout1000) if frame is not None: yield frame except Exception: pass finally: try: cam.stop_acquisition() cam.close_device() except Exception: pass time.sleep(0.5) raise RuntimeError(camera retry failed)逻辑说明yield把正常帧抛给调用方一旦get_image抛出异常就进入 finally 清理设备等待 500ms 后重新打开。重试了几次仍然失败就抛错由上层决定是否需要停机报警。注意重连后要重新设置曝光、增益和像素格式不能假设上次的配置在重开之后仍然保留。5.3 Python 侧不要做的三件事采集循环里避免在每帧里做耗时的文件写入、避免频繁地print、避免在回调线程中直接操作 GUI。这三件事会拉长单帧处理时间让底层缓冲区被填满。对 30fps 的相机Python 侧只要把单帧处理控制在 33ms 内再用 5.2 的重连逻辑兜底就能在绝大多数产线场景里吃到完整帧流。本文还有配套的精品资源点击获取
返回列表