Pylon C++ Programmer's Guide

paw5zx Lv4

Getting Started

pylon编程指南是一个关于如何使用Basler pylon C++ API进行编程的快速指南。它可以与pylon示例代码一起使用,以帮助初学者入门。此外,API renfence提供了有关Basler pylon C++接口的描述。接口的描述也可在pylon的头文件中找到。在使用Microsoft Visual Studio 时,右键点击所需的方法或类,并从上下文菜单中选择“转到声明”,以访问相关的文档。

对于为Basler blaze相机编程的信息,请参考pylon为blaze提供的补充包(可在Basler网站上下载)。这包括了一个C++ API和一个.NET API,以及示例代码。

Common Settings for Building Applications with pylon (Linux)

这一部分展示了使用pylon和GNU工具链构建应用程序的最常见的Linux构建设置。有关更多信息,请查阅Advanced Topics部分。

为了集中管理负责构建基于pylon的应用程序所需的所有参数,我们创建了pylon-config工具。它的工作方式类似于pkg-config,您可以调用pylon-config --help来获取支持的参数列表。

在典型的基于GNU Make的项目中,您可以在Makefile中添加以下行:

1
2
3
4
PYLON_ROOT ?= /opt/pylon
CPPFLAGS += $(shell $(PYLON_ROOT)/bin/pylon-config --cflags)
LDFLAGS += $(shell $(PYLON_ROOT)/bin/pylon-config --libs-rpath)
LDLIBS += $(shell $(PYLON_ROOT)/bin/pylon-config --libs)

如有需要,您现在可以使用环境变量<PYLON_ROOT>覆盖默认的安装路径。例如:

1
PYLON_ROOT=/path/to/your/pylon/install make

Initialization/Uninitialization of the pylon Runtime Library

在使用pylon API前必须初始化pylon运行时系统。基于pylon的应用程序在使用pylon运行时系统的任何其他功能之前必须调用PylonInitialize()。应用程序退出前,必须调用PylonTerminate()方法以释放pylon运行时系统分配的资源。

Pylon::PylonAutoInitTerm便利类有助于执行上述操作。Pylon::PylonAutoInitTerm的构造函数调用PylonInitialize(),析构函数调用PylonTerminate()。这确保了在Pylon::PylonAutoInitTerm类型对象的生命周期内,pylon运行时系统被初始化。

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
#include <pylon/PylonIncludes.h>
using namespace Pylon;

int main(int argc, char* argv[])
{

Pylon::PylonAutoInitTerm autoInitTerm; // PylonInitialize() will be called now

// Use pylon
// ..

} // autoInitTerm's destructor calls PylonTerminate() now

Advanced Topics包含MFC用户的附加信息

Error Handling

在出现错误的情况下,pylon类中的方法可能会抛出C++异常。pylon C++ API抛出的异常类型为GenericException或其子类。您应该使用捕获GenericException的异常处理程序来保护pylon调用。例如:

1
2
3
4
5
6
7
8
9
try
{
camera.Width.SetValue(640);
}
catch (const GenericException & e)
{
cerr << "设置AOI宽度失败。原因:"
<< e.GetDescription() << endl;
}

Creating a pylon Device

在 pylon 中,物理相机设备由pylon Devices表示。以下示例展示了如何创建一个pylon设备:

1
CInstantCamera camera(CTlFactory::GetInstance().CreateFirstDevice());

创建第一个找到的相机设备,例如用于仅使用一个相机的视觉系统。Advanced Topics展示了如何处理多个相机设备以及如何找到特定的相机设备。

The Instant Camera Classes

即时相机(Instant Camera)类使得仅通过几行代码就可以抓取图像,将编程工作量降至最低。即时相机类内部使用一个pylon设备(ptlon Device)。需要创建pylon设备并将其附加到即时相机对象上以进行操作。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Create an instant camera object with the camera device found first.
CInstantCamera camera( CTlFactory::GetInstance().CreateFirstDevice() );

// Print the model name of the camera.
cout << "Using device " << camera.GetDeviceInfo().GetModelName() << endl;

// Start the grabbing of c_countOfImagesToGrab images.
// The camera device is parameterized with a default configuration which
// sets up free-running continuous acquisition.
camera.StartGrabbing( c_countOfImagesToGrab );

// This smart pointer will receive the grab result data.
CGrabResultPtr ptrGrabResult;

// Camera.StopGrabbing() is called automatically by the RetrieveResult() method
// when c_countOfImagesToGrab images have been retrieved.
while (camera.IsGrabbing())
{
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
camera.RetrieveResult( 5000, ptrGrabResult, TimeoutHandling_ThrowException );

// Image grabbed successfully?
if (ptrGrabResult->GrabSucceeded())
{
// Access the image data.
cout << "SizeX: " << ptrGrabResult->GetWidth() << endl;
cout << "SizeY: " << ptrGrabResult->GetHeight() << endl;
const uint8_t* pImageBuffer = (uint8_t*) ptrGrabResult->GetBuffer();
cout << "Gray value of first pixel: " << (uint32_t) pImageBuffer[0] << endl << endl;

}
else
{
cout << "Error: " << std::hex << ptrGrabResult->GetErrorCode() << std::dec << " " << ptrGrabResult->GetErrorDescription() << endl;
}
}

上述代码可以在示例代码中的Grab Sample中找到。

The Main Features of an Instant Camera Class

即时相机类为访问相机设备提供了便捷的途径,同时具有高度的可定制性。以下列表展示了即时相机类的主要功能:

  • 它作为单一访问点用于访问相机功能。
  • 它可以“开箱即用”,无需设置任何参数。相机使用设备的默认配置。默认配置可以被覆盖。
  • 它管理pylon设备的生命周期。
  • 它自动打开和关闭pylon设备。
  • 它处理缓冲区的创建、重用和销毁。
  • 如有需要,它提供一个抓取循环线程。
  • 它可以检测相机设备的移除。
  • 它支持高级相机功能,如块模式和事件报告(相机事件)。
  • 可以通过派生来扩展。
  • 可以通过注册额外的事件处理器对象来扩展。

Types of Instant Camera Classes

在开始编程之前,你需要确定要使用哪种即时相机类。下表显示了可用的即时相机类:

Name of Class Usable for Device Type Device-specific
Pylon::CInstantCamera (推荐) All cameras No
Pylon::CBaslerUniversalInstantCamera (新手推荐) All cameras No

CInstantCameraCBaslerUniversalInstantCamera允许你操作所有类型的相机设备。

CBaslerUniversalInstantCamera类是CInstantCamera类的一个特化,它通过一个参数类对其进行了扩展。参数类为每个相机参数提供了一个成员。附加的参数类提供了IDE自动补全功能(例如,Visual Studio中的IntelliSense),在开发应用程序时非常有帮助。虽然这会增加一点运行时开销,但这种开销非常小,可以忽略不计。

Instant Camera Event Handler Basics

即时相机类允许注册事件处理器对象,以定制相机对象的行为,如处理抓取结果和处理相机事件。以下列表显示了可用的事件处理器类型。

注意:

对于CBaslerUniversalInstantCamera,有单独的事件处理器基类可用。这些类使用CBaslerUniversalInstantCamera类和相应的抓取结果智能指针类。

自定义的事件处理器类可以重写基类的一个或多个虚函数。例如,每当Pylon::CConfigurationEventHandler::OnOpened被即时相机对象调用时,就是设置相机参数的正确时机。以下代码片段展示了一个使用配置事件处理器设置图像感兴趣区域(Image AOI)和像素格式的示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class CPixelFormatAndAoiConfiguration : public Pylon::CConfigurationEventHandler
{
public:
void OnOpened( Pylon::CInstantCamera& camera )
{
try
{
// Allow all the names in the namespace GenApi to be used without qualification.
using namespace Pylon;

// Get the camera control object.
GenApi::INodeMap& nodemap = camera.GetNodeMap();

// Get the parameters for setting the image area of interest (Image AOI).
CIntegerParameter width( nodemap, "Width" );
CIntegerParameter height( nodemap, "Height" );
CIntegerParameter offsetX( nodemap, "OffsetX" );
CIntegerParameter offsetY( nodemap, "OffsetY" );

// Maximize the Image AOI.
offsetX.TrySetToMinimum(); // Set to minimum if writable.
offsetY.TrySetToMinimum(); // Set to minimum if writable.
width.SetToMaximum();
height.SetToMaximum();

// Set the pixel data format.
CEnumParameter( nodemap, "PixelFormat" ).SetValue( "Mono8" );
}
catch (const Pylon::GenericException& e)
{
throw RUNTIME_EXCEPTION( "Could not apply configuration. const GenericException caught in OnOpened method msg=%hs", e.what() );
}
}
};

可以在即时相机对象上注册一个或多个事件处理器对象。以下代码片段展示了如何注册并将上例中事件处理器添加到配置事件处理器列表。

1
2
3
4
// Register an additional configuration handler to set the image format and adjust the AOI.
// By setting the registration mode to RegistrationMode_Append, the configuration handler is added instead of replacing
// the already registered configuration handler.
camera.RegisterConfiguration( new CPixelFormatAndAoiConfiguration, RegistrationMode_Append, Cleanup_Delete );

有关注册和注销事件处理器的更多信息,请参阅Types of Instant Camera Classes以及以下示例的代码:ParametrizeCamera_ConfigurationsGrab_UsingGrabLoopThread SampleGrab_CameraEvents

可以在不使用事件处理器对象的情况下使用即时相机对象。

Configurations

配置事件处理器类也简称为“配置(configurations)”,因为它们封装了某些相机配置。pylon C++ API提供了以下配置类:

这些类以头文件的形式提供。这使得用户可以查看哪些相机参数被更改了。代码可以被复制和修改,以创建自己的配置类。
例如:

  • Pylon::CSoftwareTriggerConfiguration仅需要很少修改,就可以用做创建硬件触发配置的基础。
  • Pylon::CAcquireContinuousConfiguration在创建即时相机类时就已注册(??默认??待确认),提供了一个适用于大多数相机的默认设置。

以下示例显示了如何应用软件触发配置:

1
2
3
4
// Register the standard configuration event handler for enabling software triggering.
// The software trigger configuration handler replaces the default configuration
// as all currently registered configuration handlers are removed by setting the registration mode to RegistrationMode_ReplaceAll.
camera.RegisterConfiguration( new CSoftwareTriggerConfiguration, RegistrationMode_ReplaceAll, Cleanup_Delete );

代码ParametrizeCamera_Configurations提供了更多示例,展示了配置的使用。

Handling Multiple Cameras Using Instant Camera Arrays

即时相机数组类有助于管理系统中的多台相机。即时相机数组代表了一个即时相机对象的数组。它提供了与即时相机几乎相同的抓取接口。CInstantCameraArray的主要目的是简化以在一个线程中等待多个相机的图像和相机事件。这是通过为数组中的所有相机提供单一的 RetrieveResult方法来实现的。以下类是可用的:

示例Grab_MultipleCameras展示了CInstantCameraArray类的使用。

Paw5zx注:

这里应该是简化为在单线程中等待,而不需要为每台相机分别编写和管理监听代码以及分配单独的线程,类似IO多路复用。一旦图像到达,再利用其他线程进行图像的处理。


这可以加入框架的设计思路。

Accessing Parameters

对于相机配置和访问其他参数,pylon API使用由GenICam标准定义的技术。GenICam规范 定义了相机参数描述文件的格式。这些文件描述了符合GenICam标准相机的配置接口。描述文件用可扩展标记语言(XML)编写,描述了相机寄存器、它们的相互依赖关系,以及通过低级寄存器读写操作访问高级特征(如增益、曝光时间或图像格式)所需的所有其他信息。

相机描述文件中的元素对应在软件中的对象称为节点(Nodes)。例如,一个节点可以代表单个相机寄存器,一个相机参数(如增益),一组可用的参数值等。每个节点都实现了GenApi::INode接口。

节点有不同的类型。例如,有代表整数值的节点和代表字符串的节点。对于每种类型的参数,GenApi中都有一个接口。pylon提供了额外的接口和参数类来简化对GenApi接口的访问。这些接口和参数类在ParameterTypes部分中有描述。AccessModes部分介绍了参数访问模式的概念。访问模式属性用于确定参数是否可用、可读或可写。

完整的节点集合存储在称为节点映射(node map)的数据结构中。

注意:

不仅相机设备使用GenICam节点映射进行参数化,大多数pylon对象也提供节点映射以访问它们的参数。因此,建立了一种常用的访问参数的方式。

Opening and Closing a Camera

在读取或写入相机参数之前,必须初始化相关的驱动程序并建立与物理相机设备的连接。这是通过调用Open()方法完成的。可以使用Close()方法关闭相机。

Native Parameter Access

pylon提供了编程接口类,这些类是通过代码生成器从参数描述文件创建的。这些类由Universal Instant Camera类导出。这为每个可用参数提供了一个成员。Pylon::CBaslerUniversalInstantCamera类扩展了GenApi接口以简化参数化。这是访问参数的最简单方式。

示例:

1
2
3
4
5
6
7
8
// Maximize the image area of interest (Image AOI).
camera.OffsetX.TrySetToMinimum();
camera.OffsetY.TrySetToMinimum();
camera.Width.SetToMaximum();
camera.Height.SetToMaximum();

// Set the pixel data format.
camera.PixelFormat.SetValue( PixelFormat_Mono8 );

示例ParametrizeCamera_NativeParameterAccess展示了如何通过Pylon::CBaslerUniversalInstantCamera类访问参数。

Generic Parameter Access

完整的节点集存储在节点映射中。在运行时,节点映射是根据XML描述实例化的。必须使用节点映射对象以及基于Pylon::CParameter的pylon参数类来访问参数或节点。

示例(设置与上例相同的参数):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Allow all the names in the namespace GenApi to be used without qualification.
using namespace Pylon;

// Get the camera control object.
GenApi::INodeMap& nodemap = camera.GetNodeMap();

// Get the parameters for setting the image area of interest (Image AOI).
CIntegerParameter width( nodemap, "Width" );
CIntegerParameter height( nodemap, "Height" );
CIntegerParameter offsetX( nodemap, "OffsetX" );
CIntegerParameter offsetY( nodemap, "OffsetY" );

// Maximize the Image AOI.
offsetX.TrySetToMinimum(); // Set to minimum if writable.
offsetY.TrySetToMinimum(); // Set to minimum if writable.
width.SetToMaximum();
height.SetToMaximum();

// Set the pixel data format.
CEnumParameter( nodemap, "PixelFormat" ).SetValue( "Mono8" );

示例ParametrizeCamera_GenericParameterAccess展示了如何使用通用的参数访问方法。

Where to Find Information About Camera Parameters

可以使用以下资源获取相机参数信息:

Parameter Types

Integer Parameters

GenApi::IInteger接口(可由Pylon::IIntegerExPylon::CIntegerParameter扩展)用于访问整数参数。整数参数代表一个可以设置为整数的特征,例如相机的图像宽度或高度(以像素为单位)。整数参数的当前值由最小值和最大值限制,定义了参数允许的值范围,并通过增量来充当参数值变化的“步长”。因此,整数参数的所有允许值集合可以表示为x:={minimum}+N*{increment},其中N=0,1,2…, x<={maximum}。当前值、最小值、最大值和增量都可以作为64位值访问。以下示例打印Width参数的所有有效值:

1
2
3
4
5
6
7
camera.Width = camera.Width.GetMin();
int64_t w = camera.Width.GetMin();
while ( w <= camera.Width.GetMax() )
{
cout << w;
w += camera.Width.GetInc();
}

使用GenApi::IInteger接口设置值有两种等效的方法:

  • 使用赋值运算符,例如:camera.Width = 500;
  • 使用SetValue()方法,例如camera.Width.SetValue( 500 );

获取参数当前值也有两种等效的方法:

  • 使用函数调用运算符,例如t = camera.Width();
  • 使用GetValue()方法,例如t = camera.Width.GetValue();

Floating Point Parameters

浮点参数由GenApi::IFloatPylon::IFloatExPylon::CFloatParameter对象表示。浮点参数代表一个可以通过浮点值设置的特征,例如以秒为单位表示的相机曝光时间。浮点参数与整数参数类似,但有两个例外:

  • 类型:所有值都是“double”类型(由IEEE 754标准定义的双精度浮点数)
  • 没有增量值。

因此,浮点参数允许从区间{minimum} <= x <= {maximum}取任何值。

Boolean Parameters

布尔参数代表一个可以启用或禁用的二值特征。它由GenApi::IBoolean接口以及Pylon::IBooleanExPylon::CBooleanParameter对象表示。例如:任何用于启用或禁用功能的“开关”,如相机的外部触发输入。设置和获取操作类似于GenApi::IInteger接口所使用的操作。

Enumeration Parameters

GenApi::IEnumeration接口(可选地由Pylon::IEnumerationExPylon::CEnumParameterGenApi::IEnumerationT扩展)用于表示可以从预定义集合中取值的相机参数。例如:像PixelFormatTestImageSelector这样的参数。

示例:

1
camera.PixelFormat.SetValue( PixelFormat_Mono16 );

Command Parameters

命令参数(GenApi::ICommandPylon::ICommandExPylon::CCommandParameter)对应的参数是用于触发相机内部某个动作或某个操作,例如,发出软件触发。该动作通过调用GenApi::ICommand::Execute()方法来发出。GenApi::ICommand::IsDone()方法可用于判断正在进行的操作是否已完成。

String Parameters

GenApi::IString接口以及Pylon::IStringExPylon::CStringParameter对象提供了对字符串参数的访问。[GenICam::gcstring]类用来表示字符串。GenICam::gcstring类与C++标准库中的std::string类相似。pylon通过提供Pylon::String_t类型定义来使用GenICam::gcstring

Access Modes for Parameters

每个参数都有一个访问模式,用于描述一个特征是否已实现(支持)、是否可用、是否可读和是否可写。对于给定的相机:

  • 某个功能可能根本没有实现(不支持)。例如,单色相机将不包括白平衡功能。
  • 根据相机的状态,某个功能可能暂时不可用。例如,当相机处于自由运行模式时,与外部触发相关的参数可能不可用。可用的功能可以是只读的、只写的,或者既可读又可写。

可以通过调用参数的GetAccessMode()方法来查询参数的当前状态,该方法返回GenApi::EAccessMode枚举值,如下表所述:

EAccessMode Implemented Available Readable Writable
NI No No No No
NA Yes No No No
WO Yes Yes No Yes
RO Yes Yes Yes No
RW Yes Yes Yes Yes

通常情况下,检查参数是否可读或可写就足够了。为此,所有pylon参数接口和类都实现了IsReadable()IsWritable()方法。

Handling Differences Between Different Cameras Models

大多数特征,例如增益(Gain),都根据GenICam Standard Feature Naming Convention(SFNC)进行命名的。SFNC定义了一组常见的特征、它们的行为以及相关的参数名称。所有的Basler USB 3.0和CoaXPress以及大多数GigE相机,例如ace 2 GigE,都基于SFNC 2.0或更高版本。然而,较旧的Basler GigE相机型号则基于早期的SFNC版本。相应地,这些相机的行为和一些参数名称将会有所不同。以下部分将展示如何处理这些差异。

Try Methods

pylon参数接口和类提供了以Try为前缀的方法,例如IEnumerationEx::TrySetValue(int64_t)。对于这些方法,如果参数是可写的,写操作就会被执行。有时,值也必须是可设置的。

示例展示了如果相机提供了自动增益控制(GainAuto),如何关闭它:

1
2
CEnumParameter gainAuto(nodemap, "GainAuto");
gainAuto.TrySetValue("Off");

要了解Try方法的确切语义,请查阅其文档。

OrDefault Methods

带有OrDefault后缀的方法,例如GetValueOrDefault(),可以用来读取参数值(如果参数是可读的)或者返回一个默认值。

示例:

1
2
3
4
5
//code that runs for cameras with and without chunk support.
if (camera.ChunkModeActive.GetValueOrDefault(false))
{
//do something if chunk mode is active
}

这段代码演示了如何使用GetValueOrDefault()方法来判断相机是否启用了块模式。如果ChunkModeActive参数是可读的,它将返回该参数的实际值;如果不可读,则返回默认值。这样可以确保代码即使在不支持块模式的相机上也能正常运行,不会因为尝试访问不可用的参数而产生错误。

Checking the SFNC Version

如果你的代码需要与支持不同SFNC版本的多种相机设备类型协作,你可以使用GetSfncVersion()方法来处理参数名称和行为上的差异。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Check to see which Standard Feature Naming Convention (SFNC) is used by the camera device.
if (camera.GetSfncVersion() >= Sfnc_2_0_0)
{
// Access the Gain float type node. This node is available for USB camera devices.
// USB camera devices are compliant to SFNC version 2.0.
CFloatParameter gain( nodemap, "Gain" );
if (gain.TrySetValuePercentOfRange( 50.0 ))
{
cout << "Gain (50%) : " << gain.GetValue() << " (Min: " << gain.GetMin() << "; Max: " << gain.GetMax() << ")" << endl;
}
}
else
{
// Access the GainRaw integer type node. This node is available for GigE camera devices.
CIntegerParameter gainRaw( nodemap, "GainRaw" );
if (gainRaw.TrySetValuePercentOfRange( 50.0 ))
{
cout << "Gain (50%) : " << gainRaw.GetValue() << " (Min: " << gainRaw.GetMin() << "; Max: " << gainRaw.GetMax() << "; Inc: " << gainRaw.GetInc() << ")" << endl;
}
}

Grabbing Images

本节展示了如何使用即时相机类抓取图像。在抓取图像之前,必须使用以下一种或多种方法设置相机参数:

  • 注册配置对象来配置相机。
  • 在调用Open() 之后,在程序流程中使用代码设置相机。
  • 相机预配置,例如使用pylon Viewer。这些设置存储在相机的用户设置(user set)中,并在相机启动时生效,前提是已将该用户设置选为“startup set”。
  • 从磁盘加载参数。在Saving and Restoring Camera Features to/from Files部分展示了如何做到这一点。

注意:

使用后三种方法可能需要在创建即时相机对象后移除默认配置。以下示例展示了如何进行此操作。必须在调用Open()方法之前移除配置。

1
2
3
4
// Create a camera object
CInstantCamera camera;
// Remove the default configuration
camera.RegisterConfiguration( (CConfigurationEventHandler*) NULL, RegistrationMode_ReplaceAll, Cleanup_None);

Acquire, Transfer, and Grab Images

在本文档中,我们区分了图像采集(image acquisition)、图像数据传输(image data transfer)和图像抓取(image grabbing)这几个概念。理解这些术语的确切含义是至关重要的。

我们将相机内部执行的操作以产生单一图像的过程称为图像采集。当相机开始图像采集时,传感器会被曝光。曝光完成后,图像数据从传感器读出。这一过程最终导致相机准备将图像数据从相机传输到计算机。

图像数据传输指的是将获得的数据从相机的内存通过相机的接口(例如USB或千兆以太网)传输到计算机的过程。

将图像数据写入计算机主内存的过程称为图像抓取。

The Grab Result

抓取到的图像数据由Grab Result Data对象持有。无法直接访问Grab Result Data对象。它总是被抓取结果智能指针持有,例如基本抓取结果智能指针 CGrabResultPtr。智能指针和Grab Result Data对象的组合也被称为抓取结果(grab result)。智能指针控制着Grab Result Data对象及其关联的图像缓冲区的重用和生命周期。当引用Grab Result Data对象的所有智能指针都超出作用域时,抓取结果的图像缓冲区将被重用于抓取。由于智能指针的概念,Grab Result Data对象和相关的图像缓冲区可以比用于抓取图像数据的相机对象存在更长时间。CBaslerUniversalInstantCamera类有一个特定的Grab Result Data对象和一个特定的抓取结果智能指针。特定的抓取结果智能指针可以通过复制或赋值转换为或来自基本抓取结果智能指针CGrabResultPtr

注意:

当抓取结果没有及时释放时,例如放入容器中,抓取将因缓冲区不足而停止。

抓取结果智能指针类提供了一个转换操作符,允许将抓取结果智能指针直接传递给接受 const Pylon::IImage&参数的函数或方法,例如图像保存功能。

注意:

返回的Pylon::IImage引用仅在来源的抓取结果智能指针未被销毁时有效。如果该智能指针被销毁,那么任何从它获取的Pylon::IImage引用都将变得无效,尝试访问这样的引用可能会导致程序错误或崩溃。

Paw5zx注:

Grab Result Data对象和相关的图像缓冲区可以比用于抓取图像数据的相机对象存在更长时间。这意味着即使相机对象已经被销毁或者关闭,通过智能指针管理的图像数据和缓冲区仍然可以保持有效,因为智能指针控制着这些数据的生命周期。这种设计提高了程序的灵活性和数据处理的安全性,不会因相机的销毁或关闭而导致未处理图像数据的丢失。


这可以加入框架的设计思路。

Buffer Handling

每次开始使用[StartGrabbing()]启动抓取会话时,都会自动为其分配新的缓冲区。抓取到的图像所在的缓冲区由Grab Result Data对象持有。

  • 在抓取过程中,当Grab Result Data对象被抓取结果智能指针释放时,缓冲区会被重用。
  • 如果在抓取停止后释放Grab Result Data对象,则缓冲区将被释放。

可以使用MaxNumBuffer参数设置使用的图像数据缓冲区的数量。默认用于抓取的缓冲区数量是10个。抓取所需的缓冲区大小会自动确定。

如果抓取的图像数量定义少于MaxNumBuffer的值,例如 5,分配的缓冲区数量会自动减少。

注意:

可以将缓冲区工厂附加到即时相机对象上,以使用用户提供的缓冲区。

使用缓冲区工厂是可选的,仅用于高级用例。有关更多信息,请参阅Instant Camera Class and User Provided Buffers

The Grab Engine

即时相机抓取引擎由一个空缓冲区队列、一个输出队列和一个抓取线程组成。抓取引擎使用Low Level API的流抓取器来抓取图像。空缓冲区队列和输出队列可以容纳由MaxNumBuffer参数定义的缓冲区数量。任何时候都有MaxNumQueuedBuffer个缓冲区被传递给Low Level API流抓取器。所有队列都以FIFO模式工作。抓取引擎线程确保只要空缓冲区队列中有可用缓冲区,流抓取器就不会耗尽缓冲区。

Paw5zx注:

这可以加入框架的设计思路。

The Default Grab Strategy One By One

即时相机支持不同的抓取策略。默认策略是One By One。使用One By One抓取策略时,图像按照它们被采集的顺序进行处理。

  • 即时相机抓取引擎从空缓冲区队列中取出缓冲区,并将空缓冲区入队到Low Level API流抓取器(1);
  • 相机设备被触发(2)。一个图像被相机设备获取,并被传输到计算机,然后被抓取到一个空缓冲区中;
  • 即时相机抓取引擎线程收到通知:有已填充的缓冲区可用。已填充的缓冲区由抓取引擎线程检索(3)并放入输出队列;
  • 阻塞(等待)在RetrieveResult()的应用程序线程得到通知,它停止等待抓取结果,并检索已填充的缓冲区(4)作为抓取结果数据对象的一部分;
  • 抓取结果数据对象由抓取结果智能指针持有。应用程序处理完图像数据后,已填充的缓冲区被返回到空缓冲区队列(5)。这是通过抓取结果智能指针的析构函数或当抓取结果数据对象被显式释放时完成的。返回的缓冲区将再次用于抓取。

有关抓取策略的更多信息可以在Grab Strategies找到。

Grabbing Images in a Loop

下述示例展示了一个简单的抓取循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Create an instant camera object with the camera device found first.
CInstantCamera camera( CTlFactory::GetInstance().CreateFirstDevice() );

// Print the model name of the camera.
cout << "Using device " << camera.GetDeviceInfo().GetModelName() << endl;

// Start the grabbing of c_countOfImagesToGrab images.
// The camera device is parameterized with a default configuration which
// sets up free-running continuous acquisition.
camera.StartGrabbing( c_countOfImagesToGrab );

// This smart pointer will receive the grab result data.
CGrabResultPtr ptrGrabResult;

// Camera.StopGrabbing() is called automatically by the RetrieveResult() method
// when c_countOfImagesToGrab images have been retrieved.
while (camera.IsGrabbing())
{
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
camera.RetrieveResult( 5000, ptrGrabResult, TimeoutHandling_ThrowException );

// Image grabbed successfully?
if (ptrGrabResult->GrabSucceeded())
{
// Access the image data.
cout << "SizeX: " << ptrGrabResult->GetWidth() << endl;
cout << "SizeY: " << ptrGrabResult->GetHeight() << endl;
const uint8_t* pImageBuffer = (uint8_t*) ptrGrabResult->GetBuffer();
cout << "Gray value of first pixel: " << (uint32_t) pImageBuffer[0] << endl << endl;

}
else
{
cout << "Error: " << std::hex << ptrGrabResult->GetErrorCode() << std::dec << " " << ptrGrabResult->GetErrorDescription() << endl;
}
}
  • 相机对象被创建。
  • 调用StartGrabbing()开始抓取。由于相机尚未打开,StartGrabbing()方法会自动打开相机。
  • 默认配置事件处理器被调用,它使用默认配置。
  • 即时相机对象持续抓取图像,并将抓取结果按照相机获取的顺序放入即时相机的输出队列中(抓取策略One By One)。
  • 使用RetrieveResult()方法等待抓取结果,并从输出队列中检索缓冲区。
  • 在检索后,部分抓取结果数据被打印到屏幕上。当检索到指定数量的图像后,RetrieveResult()方法会自动调用StopGrabbing()。while 语句的条件用于检查抓取是否已停止。

通过在StartGrabbing()调用中省略最大图像抓取数量(不传参数,使用默认值),可以开始抓取无限数量的图像,并在抓取循环内部手动调用StopGrabbing()来结束抓取。

上述代码片段可以在Grab Sample中找到。

Grabbing Images Using the Grab Loop Thread Provided by the Instant Camera

即时相机类提供了一个可选的抓取循环线程。该线程运行一个抓取循环,循环中调用RetrieveResult()。当使用提供的抓取循环线程时,需要一个图像事件处理器来处理抓取结果。

使用以下图像事件处理器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class CImageEventPrinter : public CImageEventHandler
{
public:

virtual void OnImageGrabbed( CInstantCamera& camera, const CGrabResultPtr& ptrGrabResult )
{
std::cout << "OnImageGrabbed event for device " << camera.GetDeviceInfo().GetModelName() << std::endl;

// Image grabbed successfully?
if (ptrGrabResult->GrabSucceeded())
{
std::cout << "SizeX: " << ptrGrabResult->GetWidth() << std::endl;
std::cout << "SizeY: " << ptrGrabResult->GetHeight() << std::endl;
const uint8_t* pImageBuffer = (uint8_t*) ptrGrabResult->GetBuffer();
std::cout << "Gray value of first pixel: " << (uint32_t) pImageBuffer[0] << std::endl;
std::cout << std::endl;
}
else
{
std::cout << "Error: " << std::hex << ptrGrabResult->GetErrorCode() << std::dec << " " << ptrGrabResult->GetErrorDescription() << std::endl;
}
}
};

下面的示例展示了如何使用即时相机对象提供的抓取循环线程进行抓取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// The image event printer serves as sample image processing.
// When using the grab loop thread provided by the Instant Camera object, an image event handler processing the grab
// results must be created and registered.
camera.RegisterImageEventHandler( new CImageEventPrinter, RegistrationMode_Append, Cleanup_Delete );

// Start the grabbing using the grab loop thread, by setting the grabLoopType parameter
// to GrabLoop_ProvidedByInstantCamera. The grab results are delivered to the image event handlers.
// The GrabStrategy_OneByOne default grab strategy is used.
camera.StartGrabbing( GrabStrategy_OneByOne, GrabLoop_ProvidedByInstantCamera );

// Wait for user input to trigger the camera or exit the program.
// The grabbing is stopped, the device is closed and destroyed automatically when the camera object goes out of scope.

bool runLoop = true;
while (runLoop)
{
cout << endl << "Enter \"t\" to trigger the camera or \"e\" to exit and press enter? (t/e) "; cout.flush();

string userInput;
getline(cin, userInput);

for (size_t i = 0; i < userInput.size(); ++i)
{
char key = userInput[i];
if ((key == 't' || key == 'T'))
{
// Execute the software trigger. Wait up to 1000 ms for the camera to be ready for trigger.
if (camera.WaitForFrameTriggerReady( 1000, TimeoutHandling_ThrowException ))
{
camera.ExecuteSoftwareTrigger();
}
}
else if ((key == 'e') || (key == 'E'))
{
runLoop = false;
break;
}
}

// Wait some time to allow the OnImageGrabbed handler print its output,
// so the printed text on the console is in the expected order.
WaitObject::Sleep( 250 );
}
  • 首先,注册图像事件处理器。它会在每次抓取图像时在屏幕上打印一条消息。在此示例中,它充当图像处理的角色。
  • 使用StartGrabbing()开始抓取无限数量的图像,并通过将第二个参数设置为GrabLoop_ProvidedByInstantCamera来使用即时相机对象提供的抓取循环线程。
  • 使用主线程来查询用户输入,以触发图像或退出输入循环。在此示例中,抓取没有显式停止,可以通过调用StopGrabbing()来停止抓取。

上述代码片段可以在Grab_UsingGrabLoopThread代码示例中找到。

Grabbing a Single Image

为了方便,可以使用GrabOne()方法来抓取单张图像。以下代码显示了所做操作的简化版本:

1
2
3
4
5
//grab one image
StartGrabbing( 1, GrabStrategy_OneByOne, GrabLoop_ProvidedByUser);

//grab is stopped automatically due to maxImages = 1
return RetrieveResult( timeoutMs, grabResult, timeoutHandling) && grabResult->GrabSucceeded();

注意:

当pylon设备已经打开,使用GrabOne()更有效,否则每次调用pylon设备都会自动打开和关闭。


如果你想最大化帧率,推荐使用软件触发(CSoftwareTriggerConfiguration)来抓取单张图像。这是因为与单帧采集相比,每张抓取图像的开销减少了(因为单帧采集通常涉及到每次触发后的一系列初始化和反初始化过程,这些都会增加时间开销。而使用软件触发,系统可以保持就绪状态,只在需要时通过软件指令立即触发相机,从而减少了每次抓取所需的准备时间,提高了整体的帧率)。

上述方案的步骤为:

Using Advanced Camera Features

Handling Camera Events

Basler的GigE Vision和USB3 Vision相机可以发送事件消息。例如,当传感器曝光结束时,相机可以向计算机发送曝光结束事件。可以通过在即时相机类中注册一个图像事件处理器来接收事件。有关更多信息,请参阅Handling Camera Events

Accessing Chunk Features

Basler相机能够发送额外的信息,这些信息作为所谓的数据块附加到图像数据中,例如帧计数器、时间戳或CRC校验和。如果激活了数据块功能,即时相机类会自动解析这些数据块。有关更多信息,请参阅Accessing Chunk Features

Getting Informed About Camera Device Removal

要获得有关相机设备移除的信息,可以查询IsCameraDeviceRemoved()方法或注册一个配置事件处理器。如果相机设备被移除,虚函数OnCameraDeviceRemoved()将被调用。有关更多信息,请参见Getting Informed About Camera Device Removal

注意:

OnCameraDeviceRemoved()的调用是从一个单独的线程中进行的。

GigE Multicast/Broadcast: Grab Images of One Camera on Multiple Computers

Basler GigE相机可以配置为将图像数据流发送到多个目的地。可以使用IP组播或IP广播。有关更多信息,请参阅Grab Images of One Camera on Multiple Computers

Image Handling and Image Display

除了用于抓取图像的即时相机类之外,pylon还提供了额外的图像处理支持,用于处理抓取到的图像。这包括一个图像类,Windows位图图像支持,图像格式转换器,图像窗口以及图像的加载和保存。

The pylon Image Class

在处理图像数据时,缓冲区大小和生命周期的管理通常涉及大量编码。Pylon::CPylonImage类简化了这一过程。它还可以绑定一个存有抓取结果的缓冲区,防止其在需要(保持图像数据)时被重新使用。此外,Pylon::CPylonImage允许用户连接自定义的缓冲区或者第三方软件提供的缓冲区。除此之外,pylon图像类在处理图像平面或AOIs时也很有帮助,使得对特定部分的图像进行操作和分析变得更加简单。示例Utility_Image展示了pylon图像类的使用。

The pylon Bitmap Image Class

Pylon::CPylonBitmapImage类简化了用于显示图像数据的Windows位图图像的创建过程。示例Utility_Image展示了pylon位图图像类的使用。

The Image Format Converter

Pylon::CImageFormatConverter类通过将源图像转换为不同的格式来创建新图像。一旦格式转换器配置完成,它几乎可以转换Basler相机设备支持的所有图像格式。如果您想使用多线程来加速转换过程,可以通过[Pylon::CImageFormatConverter::MaxNumThreads]参数指定所需的线程数量。示例Utility_ImageFormatConverter展示了图像格式转换器类的使用。

The AVI Writer

Pylon::CAviWriter可用于创建AVI格式的视频文件。示例Utility_GrabAvi展示了AVI Writer类的使用。

The Video Writer

Pylon::CVideoWriter可用于创建MP4格式的视频文件。示例Utility_GrabVideo展示了Video Writer类的使用。

Loading and Saving Images

Pylon::CImagePersistence类支持将图像加载和保存到磁盘。pylon图像类在内部使用这个接口,并提供了加载和保存图像的方法。示例Utility_ImageLoadAndSave展示了如何加载和保存图像。

pylon Image Window

  • 标题: Pylon C++ Programmer's Guide
  • 作者: paw5zx
  • 创建于 : 2024-11-18 18:34:51
  • 更新于 : 2024-11-20 15:22:25
  • 链接: https://paw5zx.github.io/pylon-cpp-programmer-guide/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论