Qt(C++)项目中使用 Basler 工业相机(1)
2017-07-06 22:14
429 查看
Qt(C++)项目中使用 Basler 工业相机(1 枚举相机)
最近的一个项目中用到Basler 的GigE 接口的工业相机。为此花了好几天时间研究了pylon 的用法。本文就是学习过程中做的笔记。Pylon 的结构可以参考下图。
图 1 Pylon 的结构
整个pylon 对 GenICam 接口进行了封装,但是这个封装并不是特别的彻底。只有理解了GenICam 的设计思想才能真正明白pylon 是怎么回事。GenICam 是Generic Interface for Cameras 的缩写,GenICam 的目标就是建立一个统一的 API接口,用这个接口可以操作 GigE、USB、Camera Link 等各种类型的工业相机。
GenApi 是GenICam 的一个模块。这个模块的作用就是用来描述相机的功能和控制方法。最核心的就是保存在相机中的一个 xml 文件,这个 xml 文件称为相机的描述文件,记录了这台相机对外都有哪些功能接口,如何去访问这些功能接口。
在 pylon 中这个描述文件被解析为所谓的GenApi Node Maps。相机的每个具体的参数对应一个Node。
GenTL 是GenICam 的另一个重要模块。这里 TL 是 transport layer 的缩写。所谓传输层就是对具体的物理层面的传输(比如GigE传输、USB传输)的一种抽象。这个模块规范了如何去发现枚举系统中的相机、如何获取相机图像等。
pylon 就是将GenApi 和 GenTL 进一步封装了一下,使得用起来更方便。
传输层(transport layer)与传输层工厂(transport layer factory)
Pylon 支持四种传输层:1. PylonGigE
2. Pylon1394
3. PylonUsb
4. PylonCLSer
对应的C++接口是Pylon::ITransportLayer,这个是个接口类,无法直接生成。需要用传输层工厂(Pylon::CTlFactory)来获取。例如下面的代码:
CTlFactory& TlFactory = CTlFactory::GetInstance(); ITransportLayer* pTl = TlFactory.CreateTl( CBaslerGigECamera::DeviceClass() );
执行之后 pTl 就指向一个 PylonGigE 类型的Pylon::ITransportLayer 了。上述代码的 CBaslerGigECamera::DeviceClass()实际上返回的是一个字符串 “BaslerGigE”。
利用 Pylon::CTlFactory 我们还可以枚举系统中支持的所有的传输层,下面是示例代码:
Pylon::CTlFactory &TlFactory = CTlFactory::GetInstance(); TlInfoList_t lstInfo; int n = TlFactory.EnumerateTls(lstInfo); TlInfoList_t::const_iterator it; for ( it = lstInfo.begin(); it != lstInfo.end(); ++it ) { qDebug() << "FriendlyName: " << it->GetFriendlyName (); qDebug() << "FullName: " << it->GetFullName(); qDebug() << "VendorName: " << it->GetVendorName() ; qDebug() << "DeviceClass: " << it->GetDeviceClass() ; qDebug() << ""; }
这个代码在我的电脑上执行的结果是:
FriendlyName: USB FullName: USB/BaslerUsb 5.0.9.10388 VendorName: Basler DeviceClass: BaslerUsb FriendlyName: GigE FullName: GigE/BaslerGigE 5.0.9.10388 VendorName: Basler DeviceClass: BaslerGigE
可以看到我的电脑支持两种传输层。分别是 USB和GigE。
上面的代码中其实还涉及另一种类:Pylon::CTlInfo。这个类顾名思义是用来获取传输层的信息的。通过这个类可以获取传输层的Full Name、DeviceClass 等信息。当然这个类还有其他的方法,不过对于我们来说知道这些也就够了。
获得了一个传输层对象后就可以枚举这个传输层上的相机了。枚举过程与枚举传输层很类似。下面是代码片段:
Pylon::CTlFactory &TlFactory = CTlFactory::GetInstance(); ITransportLayer * pTl = TlFactory.CreateTl("BaslerGigE"); DeviceInfoList_t lstDevices; int n = pTl->EnumerateDevices(lstDevices); if(n == 0) { qDebug() << "Cannot find any camera!"; return; } DeviceInfoList_t::const_iterator it; for ( it = lstDevices.begin(); it != lstDevices.end(); ++it ) { qDebug() << "SerialNumber : " << it->GetSerialNumber (); qDebug() << "UserDefinedName: " << it->GetUserDefinedName(); qDebug() << "ModelName: " << it->GetModelName() ; qDebug() << "DeviceVersion: " << it->GetDeviceVersion() ; qDebug() << "DeviceFactory: " << it->GetDeviceFactory() ; qDebug() << "XMLSource: " << it->GetXMLSource() ; qDebug() << "FriendlyName: " << it->GetFriendlyName() ; qDebug() << "FullName: " << it->GetFullName() ; qDebug() << "VendorName: " << it->GetVendorName() ; qDebug() << "DeviceClass: " << it->GetDeviceClass() ; qDebug() << ""; }
我的电脑上只接了一个相机,所以显示结果是这样的:
SerialNumber : 22099564 UserDefinedName: ModelName: acA2440-20gc DeviceVersion: 107213-06 DeviceFactory: GigE/BaslerGigE 5.0.9.10388 XMLSource: N/A FriendlyName: Basler acA2440-20gc (22099564) FullName: Basler acA2440-20gc#00305320096C#192.168.1.98:3956 VendorName: Basler DeviceClass: BaslerGigE
上面的代码只是枚举了一个传输层的相机。如果我们要枚举所有传输层的相机,还可以利用传输层工厂,下面是代码:
Pylon::CTlFactory &TlFactory = CTlFactory::GetInstance(); DeviceInfoList_t lstDevices; TlFactory.EnumerateDevices( lstDevices ); if ( ! lstDevices.empty() ) { DeviceInfoList_t::const_iterator it; for ( it = lstDevices.begin(); it != lstDevices.end(); ++it ) { qDebug() << "SerialNumber : " << it->GetSerialNumber (); qDebug() << "UserDefinedName: " << it->GetUserDefinedName(); qDebug() << "ModelName: " << it->GetModelName() ; qDebug() << "DeviceVersion: " << it->GetDeviceVersion() ; qDebug() << "DeviceFactory: " << it->GetDeviceFactory() ; qDebug() << "XMLSource: " << it->GetXMLSource() ; qDebug() << "FriendlyName: " << it->GetFriendlyName() ; qDebug() << "FullName: " << it->GetFullName() ; qDebug() << "VendorName: " << it->GetVendorName() ; qDebug() << "DeviceClass: " << it->GetDeviceClass() ; qDebug() << ""; } } else qDebug() << "No devices found!" << endl;
有时,我们的系统里有很多个相机,我们又只想枚举其中的某类相机。这时可以用EnumerateDevices() 函数的第二个参数传进一个filter。比如下面的例子,我们只枚举型号为”SCA750-60FC” 和 “SCA780-54FC” 的相机。
CTlFactory& TlFactory = CTlFactory::GetInstance(); DeviceInfoList_t filter; filter.push_back( CDeviceInfo().SetModelName( "SCA750-60FC")); filter.push_back( CDeviceInfo().SetModelName( "SCA780-54FC")); DeviceInfoList_t lstDevices; TlFactory.EnumerateDevices( lstDevices, filter ); if ( ! lstDevices.empty() ) { DeviceInfoList_t::const_iterator it; for ( it = lstDevices.begin(); it != lstDevices.end(); ++it ) qDebug() << it->GetFullName(); } else qDebug() << "No devices found!" << endl;
我们知道在 Qt 中有两个类 QCamera 和 QCameraInfo 用来访问相机。这里也仿照这个模式。将 pylon 的相关功能封装到 BaslerCameraInfo 和 BaslerCamera 两个类中。
BaslerCameraInfo 用来返回相机的信息,其实就是对 CDeviceInfo 的一个封装。封装之后我们就不用与传输层打交道了。下面是类的声明:
class BaslerCameraInfo { friend class BaslerCamera; public: BaslerCameraInfo(); explicit BaslerCameraInfo(const BaslerCamera &camera); BaslerCameraInfo(const BaslerCameraInfo &other);// explicit BaslerCameraInfo(Pylon::CDeviceInfo deviceInfo);// QString description() const;// QString deviceName() const;// bool isNull() const {return m_deviceInfo == Pylon::CDeviceInfo();} int orientation() const {return 0;} bool operator!=(const BaslerCameraInfo &other) const;// BaslerCameraInfo & operator=(const BaslerCameraInfo &other);// bool operator==(const BaslerCameraInfo &other) const;// static QList<BaslerCameraInfo> availableCameras();// static BaslerCameraInfo defaultCamera();// /// 下面是 Basler 相机 CDeviceInfo 的接口,QCameraInfo 类没有这些接口 QString serialNumber(); QString userDefinedName(); QString modelName () ; QString deviceVersion (); QString deviceFactory (); QString XMLSource (); QString friendlyName (); QString fullName () ; QString vendorName (); QString deviceClass () ; bool setSerialNumber (QString serialNumberValue); ~BaslerCameraInfo(){} private: Pylon::CDeviceInfo m_deviceInfo; };
之后是具体的实现代码:
BaslerCameraInfo::BaslerCameraInfo() { } BaslerCameraInfo::BaslerCameraInfo(const BaslerCamera &camera) { Pylon::IPylonDevice * pDevice = camera.m_device; m_deviceInfo = pDevice->GetDeviceInfo(); } BaslerCameraInfo::BaslerCameraInfo(const BaslerCameraInfo &other) { m_deviceInfo = other.m_deviceInfo; } BaslerCameraInfo::BaslerCameraInfo(CDeviceInfo deviceInfo) { m_deviceInfo = deviceInfo; } QString BaslerCameraInfo::description() const { return QString(m_deviceInfo.GetFullName()); } QString BaslerCameraInfo::deviceName()const { return QString(m_deviceInfo.GetModelName()); } QString BaslerCameraInfo::serialNumber() { return QString(m_deviceInfo.GetSerialNumber()); } bool BaslerCameraInfo::setSerialNumber (QString serialNumberValue) { if(m_deviceInfo.IsSerialNumberAvailable()) { m_deviceInfo.SetSerialNumber(serialNumberValue.toLocal8Bit()); return true; } return false; } QString BaslerCameraInfo::userDefinedName() { return QString(m_deviceInfo.GetModelName()); } QString BaslerCameraInfo::modelName () { return QString(m_deviceInfo.GetModelName()); } QString BaslerCameraInfo::deviceVersion () { return QString(m_deviceInfo.GetDeviceVersion()); } QString BaslerCameraInfo::deviceFactory () { return QString(m_deviceInfo.GetDeviceFactory()); } QString BaslerCameraInfo::XMLSource () { return QString(m_deviceInfo.GetXMLSource()); } QString BaslerCameraInfo::friendlyName () { return QString(m_deviceInfo.GetFriendlyName ()); } QString BaslerCameraInfo::fullName () { return QString(m_deviceInfo.GetFullName()); } QString BaslerCameraInfo::vendorName () { return QString(m_deviceInfo.GetVendorName()); } QString BaslerCameraInfo::deviceClass () { return QString(m_deviceInfo.GetDeviceClass()); } BaslerCameraInfo BaslerCameraInfo::defaultCamera() { Pylon::CTlFactory& TlFactory = CTlFactory::GetInstance(); Pylon::DeviceInfoList_t lstDevices; TlFactory.EnumerateDevices( lstDevices ); BaslerCameraInfo info; if(!lstDevices.empty() ) { info = BaslerCameraInfo(lstDevices[0]); } return info; } bool BaslerCameraInfo::operator!=(const BaslerCameraInfo &other) const { return !(m_deviceInfo == other.m_deviceInfo); } BaslerCameraInfo & BaslerCameraInfo::operator=(const BaslerCameraInfo &other) { m_deviceInfo = other.m_deviceInfo; return *this; } bool BaslerCameraInfo::operator==(const BaslerCameraInfo &other) const { return (m_deviceInfo == other.m_deviceInfo); } QList<BaslerCameraInfo> BaslerCameraInfo::availableCameras() { Pylon::CTlFactory& TlFactory = CTlFactory::GetInstance(); Pylon::DeviceInfoList_t lstDevices; TlFactory.EnumerateDevices( lstDevices ); QList<BaslerCameraInfo> info; if ( !lstDevices.empty() ) { DeviceInfoList_t::const_iterator it; for ( it = lstDevices.begin(); it != lstDevices.end(); ++it ) { info.append(BaslerCameraInfo(*it)); } } return info; }
相关文章推荐
- Qt(C++)项目中使用 Basler 工业相机(图像获取策略)
- Qt(C++)项目中使用 Basler 工业相机(2 参数设置)
- Qt(C++)调用工业相机Basler的SDK简单使用示例
- 使用VS2010在项目中编写C++头文现出"PCH 警告:标头停止点不能位于宏或#if块中"错...
- C++ VS 2008中ATL的创建,使用。并在C++项目以及C#项目中进行调用测试
- 如何使用C++制作WPF项目
- VS2010中的C++项目无法使用智能感知
- MSBuild使用3——构建C/C++项目
- VS2008项目使用C++连接MySQL
- 正则表达式使用学习(C++、Qt、Python)
- Qt中使用的C++知识和技能
- VS2008创建C++项目——使用dll文件
- 使用distcc和ccache缩短C/C++项目编译时间
- 使用distcc和ccache缩短C/C++项目编译时间
- 初次使用VS2010基于C++开发项目碰到的问题及解决方法
- C++项目通过JNI使用Java第三方jar包
- 使用LuaPlus在C++项目中集成Lua脚本
- 使用LuaPlus在C++项目中集成Lua脚本
- 使用NDK开发C/C++项目规则(ZT)
- 学习参考资料:使用QT/C++为BlackBerry 10开发native应用