作者:billy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处
开发环境
操作系统:Windows 10 1903 18362.778
相机型号:BASLER acA 1300-60gm
相机软件:pylon_Runtime_6.0.0.17906,Basler_pylon_5.0.10.10613
软件版本:Qt 5.12.8, vs2017 Community
通信方式:GigE - 千兆以太网通信协议
驱动与SDK
开发包和驱动下载地址
提取码:lg0i
驱动安装完成之后需要完成一些配置才能成功连接相机:
- 将相机通电,使用网线将相机与电脑连接。确保相机与电脑处于连接状态。可以观察网
络连接中,本地连接的状态;

- 网络连接中,右键本地连接,选择属性。在属性界面中点击”配置”按钮,进入”高级”选项卡,设置 Jumbo Packet (巨型帧)为当前可设置的最大值。点击确定保存参数;


- 在网络连接中,右键”本地连接”,双击 “Internet 协议版本 4”,在弹出界面中勾选 “自动获得 IP 地址”
,点击确定保存参数;


- 打开 “Pylon IP Configurator”工具,在列表中选择当前连接的相机。选择相机后,选择 “DHCP”,点击保存。”Refresh” 确保相机的 “Status” 为 ”OK”,并且界面右下角没有警告;

安装驱动和开发包完成之后,可以找到以下目录:
- C:\Program Files\Basler\pylon 5

- Applications - 应用程序 pylon Viewer 和 pylon IP Configurator;
- Development - 开发文档、头文件、库文件、示例程序源代码等等;
- License - 开发许可证;
- Runtime - 运行时需要的依赖库(打包程序时需要包含);
- Release Notes.txt - 发行笔记;
巴斯勒相机介绍
巴斯勒相机实时获取图像的原理就是对每一帧数据的处理,即 拍照 - 处理数据 - 拍照 - 处理数据 …
SDK中提供了两种方式来处理图像,我们先来看一下最主要的开始抓取图像的函数 StartGrabbing:
virtual void StartGrabbing( EGrabStrategy strategy = GrabStrategy_OneByOne,
EGrabLoop grabLoopType = GrabLoop_ProvidedByUser);
来看一下函数的两个参数代表什么含义:
-
One by One Grab Strategy
这种模式是最简单的,也是 CInstantCamera 默认的图像获取策略。
获取到的图像放到一个FIFO 队列中。每次我们从队列中取的(RetrieveResult)都是最早放到队列中的图像。 -
Latest Image Only Grab Strategy
这个策略下只有最新到的图像保存在输出队列中。
如果一份旧图像还没被读取新图像就又来了,那么旧图像就被舍弃。这样可以保证读取到图像永远都是读取时刻最新的。 -
Latest Images Grab Strategy
这个模式下输出队列可以保存不止一张图像,具体最多能保存几张图象由 CInstantCamera::OutputQueueSize 来指定。
当新的图像来了,而队列已满时,旧的图像被舍弃。
当 CInstantCamera::OutputQueueSize 为 1 时就是 Latest Image Only Grab Strategy。
当 CInstantCamera::OutputQueueSize = CInstantCamera::MaxNumBuffer,就和 One by One Grab Strategy 一样了。 -
Upcoming Image Grab Strategy
这个模式很特别,只有当 CInstantCamera::RetrieveResult() 被调用后才会采集图像。USB 相机不支持这种策略。 -
GrabLoop_ProvidedByUser
用户在代码中循环调用RetrieveResult() 来处理抓取的图像和相机事件。默认使用这种模式。 -
GrabLoop_ProvidedByInstantCamera
抓取循环线程由即时相机提供。它会不断循环调用RetrieveResult()。抓取的图像由注册的图像事件处理程序处理。抓取循环线程在抓取启动时启动。
StartGrabbing的第一个参数代表获取图像的策略,第二个参数代表的是使用哪个循环线程来抓取图像。由第二个参数我们就可以分两种方式来处理图像数据:
- 用户自己处理,步骤如下:
- 调用 StartGrabbing 开始抓取图像
m_baslerCamera.StartGrabbing(GrabStrategy_OneByOne, GrabLoop_ProvidedByUser); - 用户自己循环调用 RetrieveResult
m_baslerCamera.RetrieveResult(1000, ptrGrabResult, TimeoutHandling_ThrowException); - 处理数据 ptrGrabResult
CImagePersistence::Save(ImageFileFormat_Bmp, filename, ptrGrabResult);
- 使用相机的循化线程,步骤如下:
- 注册图像事件处理程序
m_baslerCamera.RegisterImageEventHandler(this, RegistrationMode_Append, Cleanup_Delete); - 重写图像处理函数 OnImageGrabbed
virtual void OnImageGrabbed(CInstantCamera &camera, const CGrabResultPtr &grabResult) override; - 调用 StartGrabbing 开始抓取图像
m_baslerCamera.StartGrabbing(GrabStrategy_OneByOne, GrabLoop_ProvidedByInstantCamera); - 注意事项:相机获取到图像就会调用回调函数 OnImageGrabbed,图像处理是在不同的线程所以需要加锁
我的代码
实现功能:相机图像的实时显示,并且可以在需要的时候获取当前帧数据,用于分析或者保存;
首先需要在pro中配置头文件和库文件
INCLUDEPATH += $$PWD/include/ \$$PWD/include/pylonwindows {contains(DEFINES, WIN64) {LIBS += -L$$PWD/lib/x64/ -lGCBase_MD_VC120_v3_0_Basler_pylon_v5_0LIBS += -L$$PWD/lib/x64/ -lGenApi_MD_VC120_v3_0_Basler_pylon_v5_0LIBS += -L$$PWD/lib/x64/ -lPylonBase_MD_VC120_v5_0LIBS += -L$$PWD/lib/x64/ -lPylonC_MD_VC120LIBS += -L$$PWD/lib/x64/ -lPylonGUI_MD_VC120_v5_0LIBS += -L$$PWD/lib/x64/ -lPylonUtility_MD_VC120_v5_0} else {LIBS += -L$$PWD/lib/Win32/ -lGCBase_MD_VC120_v3_0_Basler_pylon_v5_0LIBS += -L$$PWD/lib/Win32/ -lGenApi_MD_VC120_v3_0_Basler_pylon_v5_0LIBS += -L$$PWD/lib/Win32/ -lPylonBase_MD_VC120_v5_0LIBS += -L$$PWD/lib/Win32/ -lPylonC_MD_VC120LIBS += -L$$PWD/lib/Win32/ -lPylonGUI_MD_VC120_v5_0LIBS += -L$$PWD/lib/Win32/ -lPylonUtility_MD_VC120_v5_0}
}
自定义相机基类 Camera
#ifndef CAMERA_H
#define CAMERA_H#include <QObject>
#include <QImage>
#include <QTimer>
#include <QMutex>#include <opencv2/opencv.hpp>class Camera : public QObject
{Q_OBJECTpublic:enum CameraType {Basler = 1, // 巴斯勒相机IC_Imaging, // 映美精相机MV, // 海康威视相机Virtual // 虚拟相机};explicit Camera(CameraType type = Basler) : m_type(type) {}virtual void initCamera() = 0; // 初始化相机virtual void destroyCamera() = 0; // 销毁相机virtual void openCamera() = 0; // 打开相机virtual void closeCamera() = 0; // 关闭相机virtual void startWork() = 0; // 开始工作virtual void stopWork() = 0; // 停止工作virtual cv::Mat takeAPic() = 0; // 获取当前图像void start() { m_timer.start(); }void stop() { m_timer.stop(); }void setInterval(int time) { m_timer.setInterval(time); }CameraType getCameraType() { return m_type; }signals:void updateImage(QImage image);protected:CameraType m_type;QMutex m_mutex;QTimer m_timer;
};#endif // CAMERA_H
自定义 BBaslerCamerControl 相机控制类
#ifndef BBASLERCAMERCONTROL_H
#define BBASLERCAMERCONTROL_H#include "../camera.h"
#include "PylonIncludes.h"using namespace std;
using namespace Pylon;
using namespace GenApi;class BBaslerCamerControl : public Camera
{Q_OBJECT
public:enum BaslerCameraProperty {DeviceModelName, // 相机名称DeviceID, // 相机SN号ResultingFrameRateAbs, // 相机帧率AcquisitionFrameRateAbs, // 相机频率Freerun, // 相机内触发Line1, // 相机外触发ExposureTimeAbs, // 相机曝光时间GainRaw, // 相机增益SensorWidth, // 传感器宽度SensorHeight, // 传感器高度Width, // 图片宽度Height, // 图片高度PixelFormat, // 图片的格式};explicit BBaslerCamerControl(Camera::CameraType type = Camera::CameraType::Basler);virtual void initCamera() override;virtual void destroyCamera() override;virtual void openCamera() override;virtual void closeCamera() override;virtual void startWork() override;virtual void stopWork() override;virtual cv::Mat takeAPic() override;QString getCameraProperty(BBaslerCamerControl::BaslerCameraProperty type); // 获取相机参数void setCameraProperty(BBaslerCamerControl::BaslerCameraProperty type, double value = 0.0); // 设置相机参数public slots:void updateFrame();private:CInstantCamera m_baslerCamera; // 实例化相机对象INodeMap *m_nodeMap; // 相机属性节点QString m_currentMode; // 相机触发模式
};#endif // BBASLERCAMERCONTROL_H
#include "bbaslercamercontrol.h"
#include "globalfun.h"BBaslerCamerControl::BBaslerCamerControl(Camera::CameraType type) : Camera(type)
{m_timer.setInterval(GlobalValue::cam_itl);connect(&m_timer, &QTimer::timeout, this, &BBaslerCamerControl::updateFrame);
}void BBaslerCamerControl::initCamera()
{try {Pylon::PylonInitialize(); // 调用其他 pylon 函数之前必须调用 PylonInitialize 完成初始化} catch (GenICam::GenericException &e) {qDebug() << "initCamera error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::destroyCamera()
{try {stopWork();closeCamera();Pylon::PylonTerminate(); // 释放 pylon 运行时系统分配的资源} catch (GenICam::GenericException &e) {qDebug() << "destroyCamera error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::openCamera()
{try {m_baslerCamera.Attach(CTlFactory::GetInstance().CreateFirstDevice()); //实例化找到的第一个相机m_baslerCamera.Open(); // 打开相机m_nodeMap = &m_baslerCamera.GetNodeMap(); // 获取相机属性节点m_currentMode = getCameraProperty(Line1); // 获取相机触发模式} catch (GenICam::GenericException &e) {qDebug() << "openCamera error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::closeCamera()
{try {if ( m_baslerCamera.IsOpen() ) {m_baslerCamera.DetachDevice(); // 分离连接的 pylon 设备m_baslerCamera.Close(); // 关闭连接的 pylon 设备m_nodeMap = nullptr; // 相机属性节点置空m_currentMode = ""; // 相机触发模式置空}} catch (GenICam::GenericException &e) {qDebug() << "closeCamera error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::startWork()
{// Check if camera is open.if ( !m_baslerCamera.IsOpen() ) {return;}try {m_baslerCamera.StartGrabbing(GrabStrategy_LatestImageOnly, GrabLoop_ProvidedByUser); // 开始抓取图像m_timer.start();} catch (GenICam::GenericException &e) {qDebug() << "startWork error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::stopWork()
{try {if ( m_baslerCamera.IsGrabbing() ) {m_baslerCamera.StopGrabbing(); // 停止抓取图像m_timer.stop();}} catch (GenICam::GenericException &e) {qDebug() << "stopWork error: " + QString::fromLocal8Bit(e.what());}
}cv::Mat BBaslerCamerControl::takeAPic()
{// Check if camera is open.if ( !m_baslerCamera.IsOpen() ) {return cv::Mat();}QMutexLocker locker(&m_mutex);try {CGrabResultPtr ptrGrabResult;m_baslerCamera.RetrieveResult(1000, ptrGrabResult, TimeoutHandling_ThrowException);if ( ptrGrabResult->GrabSucceeded() ) {CPylonImage pylogimage;CImageFormatConverter formatconverter;formatconverter.OutputPixelFormat = PixelType_RGB8packed;formatconverter.Convert(pylogimage, ptrGrabResult);cv::Mat mat = cv::Mat(int( ptrGrabResult->GetHeight() ),int( ptrGrabResult->GetWidth() ),CV_8UC3,static_cast< uchar* >( pylogimage.GetBuffer() ));return mat.clone();} else {return cv::Mat();}} catch (GenICam::GenericException &e) {qDebug() << "takeAPic error: " + QString::fromLocal8Bit(e.what());return cv::Mat();}
}QString BBaslerCamerControl::getCameraProperty(BBaslerCamerControl::BaslerCameraProperty type)
{// Check if camera is open.if ( !m_baslerCamera.IsOpen() ) {return "";}QString ret = "";try {switch (type) {case DeviceModelName: {const CStringPtr deviceModelName = m_nodeMap->GetNode("DeviceModelName");ret = QString::fromLocal8Bit(deviceModelName->ToString().c_str());} break;case DeviceID: {const CStringPtr deviceID = m_nodeMap->GetNode("DeviceID");ret = QString::fromLocal8Bit(deviceID->ToString().c_str());} break;case ResultingFrameRateAbs: {const CFloatPtr resultingFrameRateAbs = m_nodeMap->GetNode("ResultingFrameRateAbs");ret = QString::number(resultingFrameRateAbs->GetValue());} break;case AcquisitionFrameRateAbs: {const CBooleanPtr acquisitionFrameRateEnable = m_nodeMap->GetNode("AcquisitionFrameRateEnable");acquisitionFrameRateEnable->SetValue(TRUE);const CFloatPtr acquisitionFrameRateAbs = m_nodeMap->GetNode("AcquisitionFrameRateAbs");ret = QString::number(acquisitionFrameRateAbs->GetValue());} break;case Freerun:case Line1: {const CEnumerationPtr triggerSelector = m_nodeMap->GetNode("TriggerSelector");triggerSelector->FromString("FrameStart");CEnumerationPtr triggerSource = m_nodeMap->GetNode("TriggerSource");ret = QString::fromLocal8Bit(triggerSource->ToString().c_str());} break;case ExposureTimeAbs: {const CFloatPtr exposureTimeAbs = m_nodeMap->GetNode("ExposureTimeAbs");ret = QString::number(exposureTimeAbs->GetValue());} break;case GainRaw: {const CIntegerPtr gainRaw = m_nodeMap->GetNode("GainRaw");ret = QString::number(gainRaw->GetValue());} break;case SensorWidth: {const CIntegerPtr sensorWidth = m_nodeMap->GetNode("SensorWidth");ret = QString::number(sensorWidth->GetValue());} break;case SensorHeight: {const CIntegerPtr sensorHeight = m_nodeMap->GetNode("SensorHeight");ret = QString::number(sensorHeight->GetValue());} break;case Width: {const CIntegerPtr width = m_nodeMap->GetNode("Width");ret = QString::number(width->GetValue());} break;case Height: {const CIntegerPtr height = m_nodeMap->GetNode("Height");ret = QString::number(height->GetValue());} break;case PixelFormat: {const CEnumerationPtr pixelFormat = m_nodeMap->GetNode("PixelFormat");ret = QString::fromLocal8Bit(pixelFormat->ToString().c_str());} break;default: ret = ""; break;}} catch (GenICam::GenericException &e) {qDebug() << "getCameraProperty error: " + QString::fromLocal8Bit(e.what());}return ret;
}void BBaslerCamerControl::setCameraProperty(BBaslerCamerControl::BaslerCameraProperty type, double value)
{// Check if camera is open.if ( !m_baslerCamera.IsOpen() ) {return;}try {switch (type) {case AcquisitionFrameRateAbs: {const CBooleanPtr acquisitionFrameRateEnable = m_nodeMap->GetNode("AcquisitionFrameRateEnable");acquisitionFrameRateEnable->SetValue(TRUE);const CFloatPtr acquisitionFrameRateAbs = m_nodeMap->GetNode("AcquisitionFrameRateAbs");acquisitionFrameRateAbs->SetValue(value);} break;case Freerun: {CEnumerationPtr triggerSelector = m_nodeMap->GetNode("TriggerSelector");triggerSelector->FromString("FrameStart");CEnumerationPtr triggerMode = m_nodeMap->GetNode("TriggerMode");triggerMode->SetIntValue(1);CEnumerationPtr triggerSource = m_nodeMap->GetNode("TriggerSource");triggerSource->FromString("Software");} break;case Line1: {CEnumerationPtr triggerSelector = m_nodeMap->GetNode("TriggerSelector");triggerSelector->FromString("FrameStart");CEnumerationPtr triggerMode = m_nodeMap->GetNode("TriggerMode");triggerMode->SetIntValue(1);CEnumerationPtr triggerSource = m_nodeMap->GetNode("TriggerSource");triggerSource->FromString("Line1");} break;case ExposureTimeAbs: {const CFloatPtr exposureTimeAbs = m_nodeMap->GetNode("ExposureTimeAbs");exposureTimeAbs->SetValue(value);} break;case GainRaw: {const CIntegerPtr gainRaw = m_nodeMap->GetNode("GainRaw");gainRaw->SetValue(value);} break;case Width: {const CIntegerPtr width = m_nodeMap->GetNode("Width");width->SetValue(value);} break;case Height: {const CIntegerPtr height = m_nodeMap->GetNode("Height");height->SetValue(value);} break;default: break;}} catch (GenICam::GenericException &e) {qDebug() << "setCameraProperty error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::updateFrame()
{QMutexLocker locker(&m_mutex);try {CGrabResultPtr ptrGrabResult;m_baslerCamera.RetrieveResult(1000, ptrGrabResult, TimeoutHandling_ThrowException);if ( ptrGrabResult->GrabSucceeded() ) {CPylonImage pylogimage;CImageFormatConverter formatconverter;formatconverter.OutputPixelFormat = PixelType_RGB8packed;formatconverter.Convert(pylogimage, ptrGrabResult);cv::Mat mat = cv::Mat(int( ptrGrabResult->GetHeight() ),int( ptrGrabResult->GetWidth() ),CV_8UC3,static_cast< uchar* >( pylogimage.GetBuffer() ));QImage image((const unsigned char *)(mat.data), mat.cols, mat.rows, mat.cols * 3, QImage::Format_RGB888);emit updateImage(image.rgbSwapped());}} catch (GenICam::GenericException &e) {qDebug() << "updateFrame error: " + QString::fromLocal8Bit(e.what());}
}
其他请参考
- Qt调用工业相机之映美精相机
- Qt调用工业相机之海康威视相机



















