3、相机SDK开发:Basler相机SDK调用、海康相机SDK调用、多相机同步采集
相机SDK开发,说白了就是让我们的工控机能听懂相机在说什么。我做了这么多年视觉集成,发现很多新手一上来就对着SDK文档硬啃,结果被各种API搞得晕头转向。其实没那么复杂,你想想看,相机SDK无非就是三件事:找相机、连相机、拿图像。
今天咱们就聊聊市面上最常用的两款相机——Basler和海康威视。这两家的SDK我都调过无数次,踩过的坑也不少。嗯,咱们一个一个来。
3.1 Basler相机SDK调用
Basler的Pylon SDK,我个人觉得是工业相机里做得最舒服的。文档清晰,API设计也符合直觉。我最早接触工业相机就是用的Basler,那时候还是老版的Pylon 4,现在都到Pylon 7了。
先说说环境配置。下载Pylon SDK后,安装完记得把开发包路径加到项目里。我习惯用C++开发,但Python版本也挺好用,适合快速验证。
核心流程:
- 初始化Pylon运行时环境
- 枚举所有可用相机
- 创建相机对象并连接
- 配置参数(曝光、增益、触发模式等)
- 开始采集图像
- 处理图像数据
- 停止采集并释放资源
下面是一个典型的Basler相机初始化代码片段:
// 初始化Pylon运行时
PylonInitialize();
try {
// 枚举相机
CTlFactory& tlFactory = CTlFactory::GetInstance();
DeviceInfoList_t devices;
tlFactory.EnumerateDevices(devices);
if (devices.size() == 0) {
throw RUNTIME_EXCEPTION("没有找到相机");
}
// 创建并连接第一个相机
CInstantCamera camera(tlFactory.CreateDevice(devices[0]));
camera.Open();
// 设置采集参数
camera.ExposureTime.SetValue(5000.0); // 5ms曝光
camera.Gain.SetValue(0); // 增益设为0
// 开始采集
camera.StartGrabbing();
// 获取图像
CGrabResultPtr ptrGrabResult;
while (camera.IsGrabbing()) {
camera.RetrieveResult(5000, ptrGrabResult, TimeoutHandling_ThrowException);
if (ptrGrabResult->GrabSucceeded()) {
uint8_t* pImageBuffer = (uint8_t*)ptrGrabResult->GetBuffer();
// 处理图像...
}
}
}
catch (const GenericException& e) {
cerr << "错误: " << e.GetDescription() << endl;
}
我的经验:记得在程序退出前调用 PylonTerminate()。我曾经在一个项目中忘了这步,结果相机资源一直没释放,第二次启动时直接报错说相机被占用。排查了半天才发现是这个小问题。
3.2 海康相机SDK调用
海康的MVS SDK,说实话早期版本做得一般,但最近几年进步很大。尤其是他们的网络相机,稳定性已经相当不错了。我在一个物流分拣项目里用过海康的500万像素相机,连续跑了三个月没出过问题。
海康SDK的架构和Basler不太一样。它用的是设备句柄的方式,操作起来更接近Windows API的风格。我个人觉得上手难度比Basler稍高一点,但熟悉了也就那样。
核心步骤其实差不多:
// 初始化SDK
MV_CC_Initialize();
// 枚举设备
MV_CC_DEVICE_INFO_LIST stDeviceList;
memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
if (stDeviceList.nDeviceNum == 0) {
printf("没有找到相机\n");
return -1;
}
// 创建句柄
void* handle = NULL;
MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[0]);
// 打开设备
MV_CC_OpenDevice(handle);
// 设置参数
MVCC_FLOATVALUE stExposureTime;
stExposureTime.fCurValue = 5000.0f;
MV_CC_SetFloatValue(handle, "ExposureTime", &stExposureTime);
// 开始采集
MV_CC_StartGrabbing(handle);
// 获取一帧图像
MV_FRAME_OUT stImageInfo;
memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT));
MV_CC_GetImageBuffer(handle, &stImageInfo, 1000);
// 处理图像...
// 记得释放图像缓冲区
MV_CC_FreeImageBuffer(handle, &stImageInfo);
// 停止并关闭
MV_CC_StopGrabbing(handle);
MV_CC_CloseDevice(handle);
MV_CC_DestroyHandle(handle);
MV_CC_Finalize();
注意:海康SDK中,获取图像后一定要调用 MV_CC_FreeImageBuffer 释放缓冲区。我见过有人忘了这步,结果内存泄漏,程序跑了半天就崩了。嗯,这个坑我踩过。
3.3 多相机同步采集
多相机同步采集,这才是真正考验功力的地方。你想想看,如果两个相机采集的时间差了几毫秒,对于高速运动的物体来说,图像可能就完全对不上了。
我做过一个项目,需要4个相机同时拍摄一个PCB板的不同角度。当时试了好几种方案,最后用的是硬件触发同步。
常见的同步方案有三种:
| 方案 | 精度 | 复杂度 | 适用场景 |
|---|---|---|---|
| 软件触发 | 低(ms级) | 低 | 静态物体、低速场景 |
| 硬件触发 | 高(μs级) | 中 | 高速运动、多相机拼接 |
| IEEE 1588(PTP) | 极高(ns级) | 高 | 分布式系统、超高速场景 |
我个人最推荐硬件触发。说白了就是用一个外部信号源(比如PLC或者专用的脉冲发生器)同时给所有相机发触发信号。这样所有相机在同一时刻开始曝光,同步精度可以做到微秒级。
下面是一个多相机硬件触发的伪代码思路:
// 假设有3个相机
const int CAMERA_COUNT = 3;
CInstantCamera cameras[CAMERA_COUNT];
// 初始化所有相机
for (int i = 0; i < CAMERA_COUNT; i++) {
cameras[i].Open();
// 设置为硬件触发模式
cameras[i].TriggerSelector.SetValue(TriggerSelector_AcquisitionStart);
cameras[i].TriggerMode.SetValue(TriggerMode_On);
cameras[i].TriggerSource.SetValue(TriggerSource_Line1);
// 设置触发延迟(如果需要微调)
cameras[i].TriggerDelay.SetValue(0); // 0延迟
cameras[i].StartGrabbing();
}
// 等待外部触发信号
// 当PLC发出触发脉冲时,所有相机同时开始采集
// 分别获取图像
for (int i = 0; i < CAMERA_COUNT; i++) {
CGrabResultPtr ptrResult;
cameras[i].RetrieveResult(5000, ptrResult);
// 处理第i个相机的图像
}
关键点:多相机同步采集时,每个相机的曝光时间要一致。如果曝光时间不同,即使触发信号同时到达,图像采集的结束时间也会不同。这在某些应用场景下会影响后续的图像拼接或分析。
3.4 避坑指南
做相机SDK开发这么多年,我总结了几条血泪教训:
- 网络相机一定要做带宽评估。 我曾经在一个项目中用了4台500万像素的千兆网相机,结果带宽不够,图像一直丢包。后来换成万兆网才解决。
- USB相机注意线缆长度。 USB3.0的线缆超过3米就容易出问题。我建议超过3米就用光纤延长或者转成网口。
- 多相机采集时,别忘了给每个相机分配独立的缓冲区。 如果共用缓冲区,数据会互相覆盖,图像就花了。
- SDK版本要统一。 不同版本的SDK可能存在兼容性问题。我习惯把所有相机都用同一版本的SDK,省心。
一个小技巧:调试多相机同步时,可以先让所有相机拍一个快速运动的物体(比如一个旋转的风扇),然后检查每张图像中叶片的位置是否一致。如果位置有偏差,说明同步有问题,需要调整触发延迟。
好了,关于相机SDK开发就聊这么多。Basler和海康的SDK各有千秋,选哪个主要看项目需求和预算。多相机同步这块,硬件触发是最稳妥的方案,别图省事用软件触发,到时候图像对不上就麻烦了。
下一章咱们聊聊图像预处理,包括滤波、增强、ROI提取这些基本功。嗯,到时候再细说。