您的位置:首页 > 编程语言 > C语言/C++

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