Pylon SDK的C语言使用流程详解及代码示例

Source

目录

前言

1.Pylon SDK简介与基本运行流程

2.载入相机

3.流抓取器抓取对象

4.单帧或连续抓图过程

5.收尾工作

5.1卸载流抓取器

5.2卸载相机对象


前言

笔者采用的Pylon版本为Basler_pylon_5.2.0.13457的开发者版本。本文默认软件已安装完毕,VS项目中相关库项目配置完成。在首次介绍一个函数时,笔者会首先列出其在头文件的定义,然后列出其使用实例,实例大多来源Pylon C指导手册。

1.Pylon SDK简介与基本运行流程

首先,我们使用的是Pylon 5 Runtime开发组件包。官网关于该组件包的描述如下:

Basler pylon 5 Runtime(5.0.12版)- 包含适用于所有相机接口及适用于C++、.NET、GenTL、DirectShow/Twain编程语言的驱动程序。此组件包已包含全部在终端用户的PC上运行基于pylon的应用时所需的全部组件。

关于Pylon SDK的整体运行推荐对照以下链接的图解。

3.Pylon 以实时图像采集讲解PylonC SDK使用流程_文洲的专栏-CSDN博客

2.载入相机

在Pylon中,摄像机设备是通过“摄像机对象”来管理的,并由PYLON_DEVICE_HANDLE类型的句柄表示。相机设备由传输层提供动态检测。

在使用Pylon功能前,需要调用函数PylonInitialize()初始化Pylon Runtime环境。下列代码来自头文件定义。可以看出该函数为无参函数。

IDL_ENTRY(PYLONC_MODULE, "_PylonInitialize@0", "Initialize the pylon runtime system.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE_DOC
PylonInitialize(void);

然后,调用PylonEnumerateDevices()枚举所有连接的相机设备。PylonEnumerateDevices()函数返回值为所有接口检测到的摄像机设备的总数。需要注意的是,如果相机设备为两个,可以使用[0 ,1]索引访问每个相机,然后依次为每个索引值调用PylonGetDeviceInfo(),通过查看PylonDeviceInfo_t结构体的字段,可以识别每个单独的摄像机。然后调用PylonGetDeviceInfoHandle()将设备索引转换为可用于查询设备属性的PYLON_DEVICE_INFO_HANDLE

/* Device enumeration / creation */
IDL_ENTRY(PYLONC_MODULE, "_PylonEnumerateDevices@4", "Enumerate all devices.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonEnumerateDevices(RETVAL_PAR size_t *numDevices);

PylonEnumerateDevices()使用示例如下:

/* Enumerate all camera devices. You must call
PylonEnumerateDevices() before creating a device. */
res = PylonEnumerateDevices( &numDevices );//1.枚举
CHECK(res);
if ( 0 == numDevices )
{
fprintf( stderr, "No devices found.\n" );
PylonTerminate();
pressEnterToExit();
exit(EXIT_FAILURE);
}

在检测完相机设备后,可以通过调用PylonCreateDeviceByIndex()来创建相机对象(由PYLON_DEVICE_HANDLE表示)。

IDL_ENTRY(PYLONC_MODULE, "_PylonCreateDeviceByIndex@8", "Create a device object.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonCreateDeviceByIndex( size_t index, RETVAL_PAR PYLON_DEVICE_HANDLE *phDev);

实例如下,0代表第一个被检测的相机:

/* Get a handle for the first device found. */
res = PylonCreateDeviceByIndex( 0, &hDev );//2.CreateDeviceByIndex
CHECK(res);
/* ...The device is no longer used, destroy it. */
res = PylonDestroyDevice ( hDev );//3.与PylonCreateDeviceByIndex对应
CHECK(res);

相机对象创建完毕后,使用之前需要调用PylonDeviceOpen()初始化传输层,并且建立到物理相机设备的连接

/* Device operations */
IDL_ENTRY(PYLONC_MODULE, "_PylonDeviceOpen@8", "Open a device.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonDeviceOpen(PYLON_DEVICE_HANDLE hDev, int accessMode);

使用示例如下:

/* Before using the device, it must be opened. Open it for configuring
parameters and for grabbing images. */
res = PylonDeviceOpen( hDev, PYLONC_ACCESS_MODE_CONTROL | PYLONC_ACCESS_MODE_STREAM );
CHECK(res);

完成后,我们就可以设置参数和抓取图像了。

在设置参数时,使用PylonDeviceFeatureFromString()函数,关于该函数的其他特征参数设置这里不做详解。

IDL_ENTRY(PYLONC_MODULE, "_PylonDeviceFeatureFromString@12", "Set a feature's value from a string.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonDeviceFeatureFromString(PYLON_DEVICE_HANDLE hDev, STRING_PAR const char* pName, STRING_PAR const char* pValue);

Pylon中,相机可由软件触发器触发,因此相应地配置TriggerMode和TriggerSource摄像机参数。事实上,TriggerMode和TriggerSource都是Trigger Selector配置触发类型时的功能。这里官网介绍得很详细,有兴趣的读者可以去官网查看。本文仅列出TriggerMode和TriggerSource的配置方法及代码示例。

Trigger Mode

相机的 Trigger Mode 功能允许您为选定的触发类型启用或禁用触发图像采集。

设置触发模式:

  1. 将 TriggerSelector 参数设置为所需的 触发类型,例如 FrameStart
  2. 设置 TriggerMode 参数设置为以下值:
    • On:为选定的触发类型启用触发图像采集
    • Off:为所选触发类型禁用触发图像采集。触发信号由相机自动生成。 

默认情况下,所有触发类型的触发模式均设置为 Off。这意味着启用了自由运行图像采集。 

/* Macro to check for errors */
#define CHECK(errc) if (GENAPI_E_OK != errc) printErrorAndExit(errc)
GENAPIC_RESULT errRes = GENAPI_E_OK;  /* Return value of pylon methods */
/* Select the Frame Start trigger */
errRes = PylonDeviceFeatureFromString(hdev, "TriggerSelector", "FrameStart");
CHECK(errRes);
/* Enable triggered image acquisition for the Frame Start trigger */
errRes = PylonDeviceFeatureFromString(hdev, "TriggerMode", "On");
CHECK(errRes);

Trigger Source#

相机的 Trigger Source 功能允许您配置如何触发当前选定触发器

例如,您可以选择输入线路或软件命令作为触发源。

该功能的使用#

要配置触发器的触发方式:

  1. 将 TriggerSelector 参数设置为所需的 触发类型,例如 FrameStart
  2. 设置 TriggerSource 参数(如果可用)。
/* Macro to check for errors */
#define CHECK(errc) if (GENAPI_E_OK != errc) printErrorAndExit(errc)
GENAPIC_RESULT errRes = GENAPI_E_OK;  /* Return value of pylon methods */
/* Select the Frame Start trigger */
errRes = PylonDeviceFeatureFromString(hdev, "TriggerSelector", "FrameStart");
CHECK(errRes);
/* Set the trigger source to Line 1 */
errRes = PylonDeviceFeatureFromString(hdev, "TriggerSource", "Line1");
CHECK(errRes);

使用软件触发时,应使用连续帧模式,即将设备句柄和相机参数“AcquisitionMode”和“Continuous”作为参数传递给PylonDeviceFeatureFromString()。

使用示例如下:

/* Macro to check for errors */
#define CHECK(errc) if (GENAPI_E_OK != errc) printErrorAndExit(errc)
GENAPIC_RESULT errRes = GENAPI_E_OK;  /* Return value of pylon methods */
/* Configure single frame acquisition on the camera */
errRes = PylonDeviceFeatureFromString(hdev, "AcquisitionMode", "SingleFrame");
CHECK(errRes);
/* Switch on image acquisition */
errRes = PylonDeviceExecuteCommandFeature(hdev, "AcquisitionStart");
CHECK(errRes);
/* The camera waits for a trigger signal. */
/* When a Frame Start trigger signal has been received, */
/* the camera executes an Acquisition Stop command internally. */
/* Configure continuous image acquisition on the camera */
errRes = PylonDeviceFeatureFromString(hdev, "AcquisitionMode", "Continuous");
CHECK(errRes);
/* Switch on image acquisition */
errRes = PylonDeviceExecuteCommandFeature(hdev, "AcquisitionStart");
CHECK(errRes);
/* The camera waits for trigger signals. */
/* (...) */
/* Switch off image acquisition */
errRes = PylonDeviceExecuteCommandFeature(hdev, "AcquisitionStop");
CHECK(errRes);

至此,相机正式开始图像采集的工作,接下来就是获取图像信息。

3.流抓取器抓取对象

Pylon中,相机对象获得图像可以采用事件抓取器和流抓取器,这里仅介绍流抓取器的使用。

相机提供的流捕捉器的数量可以使用PylonDeviceGetNumStreamGrabberChannels()函数来确定。函数的作用是:返回一个PYLON_STREAMGRABBER_HANDLE。在检索流捕捉器句柄之前,必须已打开摄像机设备。注意,若相机无此功能,则返回值为0。

DL_ENTRY(PYLONC_MODULE, "_PylonDeviceGetNumStreamGrabberChannels@8", "Return the access mode flags for a device.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonDeviceGetNumStreamGrabberChannels(PYLON_DEVICE_HANDLE hDev, RETVAL_PAR size_t *pNumChannels);

使用流抓取器抓取图像时,对于每个相机设备,通过调用PylonDeviceGetStreamGrabber()并将设备句柄和流抓取器句柄作为参数传递来创建流抓取器。

IDL_ENTRY(PYLONC_MODULE, "_PylonDeviceGetStreamGrabber@12", "Obtain a stream grabber handle from a device.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonDeviceGetStreamGrabber(PYLON_DEVICE_HANDLE hDev, size_t index, RETVAL_PAR PYLON_STREAMGRABBER_HANDLE *phStg);

在使用之前,流捕获器必须通过调用PylonStreamGrabberOpen()来打开。当获取图像完成时,流捕捉器必须通过调用PylonStreamGrabberClose()关闭。

IDL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberOpen@4", "Open a stream grabber.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberOpen(PYLON_STREAMGRABBER_HANDLE hStg);
IDL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberClose@4", "Close a stream grabber.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberClose(PYLON_STREAMGRABBER_HANDLE hStg);

然后使用PylonStreamGrabberGetWaitObject()检索流抓取器的等待对象的句柄。等待对象等待缓冲区被抓取的图像数据填满。

IDL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberGetWaitObject@8", "Return a stream grabber's wait object.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberGetWaitObject(PYLON_STREAMGRABBER_HANDLE hStg, RETVAL_PAR PYLON_WAITOBJECT_HANDLE *phWobj);

使用示例如下:

/* Image grabbing is done using a stream grabber.
A device may be able to provide different streams. A separate stream grabber must
be used for each stream. In this sample, we create a stream grabber for the default
stream, i.e., the first stream ( index == 0 ).
*/
/* Get the number of streams supported by the device and the transport layer. */
res = PylonDeviceGetNumStreamGrabberChannels( hDev, &nStreams );
if ( nStreams < 1 )
{
PylonTerminate();
}
/* Create and open a stream grabber for the first channel. */ 流是在相机句柄之上的新句柄
res = PylonDeviceGetStreamGrabber( hDev, 0, &hGrabber );
res = PylonStreamGrabberOpen( hGrabber );
/* Get a handle for the stream grabber's wait object. The wait object allows waiting for buffers to be filled with grabbed data. */
res = PylonStreamGrabberGetWaitObject( hGrabber, &hWait );
CHECK(res);

我们还必须告诉流抓取器我们正在使用的缓冲区的数量和大小。这是通过PylonStreamGraberSetMaxNumbuffer()PylonStreamGraberSetMaxBufferSize()完成的。

IDL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberSetMaxNumBuffer@8", "Set the maximum number of data buffers for a stream grabber to use.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberSetMaxNumBuffer(PYLON_STREAMGRABBER_HANDLE hStg, size_t numBuffers );
IDL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberSetMaxBufferSize@8", "Set the maximum data buffer size for a stream grabber.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberSetMaxBufferSize(PYLON_STREAMGRABBER_HANDLE hStg, size_t maxSize );

通过调用PylonStreamGrabberPrepareGrab(),我们可以分配抓取所需的资源。在此之后,在调用PylonStreamGrabberFinishGrab()之前,不得更改影响有效负载大小的关键参数(只读)。

IDL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberPrepareGrab@4", "Prepare a stream grabber for grabbing.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberPrepareGrab(PYLON_STREAMGRABBER_HANDLE hStg);

使用示例如下:

/* Allocate memory for grabbing. */
for ( i = 0; i < NUM_BUFFERS; ++i )//分配NUM_BUFFERS个缓冲区
{
buffers[i] = (unsignedchar*) malloc ( payloadSize );
if ( NULL == buffers[i] )
{
PylonTerminate();
}
}
/* We must tell the stream grabber the number and size of the buffers we are using. */
/* .. We will not use more than NUM_BUFFERS for grabbing. */
res = PylonStreamGrabberSetMaxNumBuffer( hGrabber, NUM_BUFFERS );//buffer的个数
CHECK(res);
/* .. We will not use buffers bigger than payloadSize bytes. */
res = PylonStreamGrabberSetMaxBufferSize( hGrabber, payloadSize );//buffer的大小
CHECK(res);
/* Allocate the resources required for grabbing. After this, critical parameters
that impact the payload size must not be changed until FinishGrab() is called. */
res = PylonStreamGrabberPrepareGrab( hGrabber );//分配 grabbing所需要的资源
CHECK(res);

每个stream grabber有两个不同的缓冲区队列,输入队列和输出队列。用于grab的缓冲区必须放到输入队列中。

在使用缓冲区进行抓取之前,必须将它们注册并排入流抓取器的输入队列。这是通过PylonStreamGrabberRegisterBuffer()PylonStreamGrabberQueueBuffer()完成的。

PYLONC_API GENAPIC_RESULT PYLONC_CC PylonStreamGrabberRegisterBuffer(PYLON_STREAMGRABBER_HANDLE hStg, void* pBuffer, size_t BufLen, PYLON_STREAMBUFFER_HANDLE *phBuf);
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE_DOC
PylonStreamGrabberQueueBuffer(PYLON_STREAMGRABBER_HANDLE hStg, PYLON_STREAMBUFFER_HANDLE hBuf, const void * pContext);

使用实例如下:

/* Before using the buffers for grabbing, they must be registered at
the stream grabber. For each registered buffer, a buffer handle
is returned. After registering, these handles are used instead of the
raw pointers. */
for ( i = 0; i < NUM_BUFFERS; ++i )
{
res = PylonStreamGrabberRegisterBuffer( hGrabber, buffers[i], payloadSize, &bufHandles[i] ); //注册每个缓冲区,返回句柄
CHECK(res);
}
/* Feed the buffers into the stream grabber's input queue. For each buffer, the API
allows passing in a pointer to additional context information. This pointer
will be returned unchanged when the grab is finished. In our example, we use the index of the
buffer as context information. */
for ( i = 0; i < NUM_BUFFERS; ++i )
{
res = PylonStreamGrabberQueueBuffer( hGrabber, bufHandles[i], (void*) i );
CHECK(res);

4.单帧或连续抓图过程

首先调用PylonDeviceExecuteCommandFeature()启动图像采集,注意该函数也可用于结束图像采集。

DL_ENTRY(PYLONC_MODULE, "_PylonDeviceExecuteCommandFeature@8", "Execute a command.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonDeviceExecuteCommandFeature(PYLON_DEVICE_HANDLE hDev, STRING_PAR const char *pName);

调用该函数将并将设备句柄和AcquisitionStart参数作为每个摄像头上的参数,以启动图像采集。

使用示例如下:

/* Let the camera acquire images. */
res = PylonDeviceExecuteCommandFeature( hDev, "AcquisitionStart");
CHECK(res);

调用PylonStreamGrabberGetWaitObject()等待缓冲区被图像填充,然后调用PylonStreamGrabberRetrieveResult()检索被流抓取器抓取的图像。可以使用PylonImageWindowDisplayImageGrabResult()显示图像。

PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE_DOC
PylonStreamGrabberRetrieveResult(PYLON_STREAMGRABBER_HANDLE hStg, PylonGrabResult_t * pGrabResult, PINVOKE_RETVAL_PAR _Bool * pReady);

处理完成后,我们通过调用PylonStreamGrabberQueueBuffer()将当前抓取的缓冲区重新排队以再次填充。该过程反复即可实现连续抓图。

使用示例如下:

/* Grab NUM_GRABS images */
nGrabs = 0; /* Counts the number of images grabbed */
while ( nGrabs < NUM_GRABS )        //已经采集的图像个数少于规定的个数
{
size_t bufferIndex; /* Index of the buffer */
unsignedchar min, max;
/* Wait for the next buffer to be filled. Wait up to 1000 ms. */
res = PylonWaitObjectWait( hWait, 1000, &isReady );  //1.使用等待句柄判断有无图像来。
CHECK(res);
if ( ! isReady )
{
/* Timeout occurred. */
fprintf(stderr, "Grab timeout occurred\n");
break; /* Stop grabbing. */
}
/* Since the wait operation was successful, the result of at least one grab operation is available. Retrieve it. */
res = PylonStreamGrabberRetrieveResult( hGrabber, &grabResult, &isReady ); //2.等待成功,从输出队列中获取图像
CHECK(res);
if ( ! isReady )
{
/* Oops. No grab result available? We should never have reached this point.
Since the wait operation above returned without a timeout, a grab result
should be available. */
fprintf(stderr, "Failed to retrieve a grab result\n");
break;
}
nGrabs++;                            //3.成功采集的图像个数加1
/* Get the buffer index from the context information. */
bufferIndex = (size_t) grabResult.Context;  //4. 刚采集到的图像的索引
/* Check to see if the image was grabbed successfully. */
if ( grabResult.Status == Grabbed )        //5.检查刚采集到的图像是否是成功的?
{
/* Success. Perform image processing. Since we passed more than one buffer
to the stream grabber, the remaining buffers are filled while
we do the image processing. The processed buffer won't be touched by
the stream grabber until we pass it back to the stream grabber. */
unsignedchar* buffer; /* Pointer to the buffer attached to the grab result. */指向我们要处理的缓冲区
/* Get the buffer pointer from the result structure. Since we also got the buffer index,
we could alternatively use buffers[bufferIndex]. */
buffer = (unsignedchar*) grabResult.pBuffer;   //6.将当前图像赋给用户自定义的指针
/* Perform processing. */
getMinMax( buffer, grabResult.SizeX, grabResult.SizeY, &min, &max );
printf("Grabbed frame %2d into buffer %2d. Min. gray value = %3u, Max. gray value = %3u\n",nGrabs, (int) bufferIndex, min, max);
#ifdef GENAPIC_WIN_BUILD
/* Display image */
res = PylonImageWindowDisplayImageGrabResult(0, &grabResult);
CHECK(res);
#endif
}
elseif ( grabResult.Status == Failed )
{
fprintf( stderr, "Frame %d wasn't grabbed successfully. Error code = 0x%08X\n",
nGrabs, grabResult.ErrorCode );
}
/* Once finished with the processing, requeue the buffer to be filled again. */  //7.图像结束后再次将该缓冲区入队
res = PylonStreamGrabberQueueBuffer( hGrabber, grabResult.hBuffer, (void*) bufferIndex );
CHECK(res);
}

采集完成后,停止图像采集

/* ... Stop the camera. */
res = PylonDeviceExecuteCommandFeature( hDev, "AcquisitionStop");
CHECK(res);

5.收尾工作

当图像采集停止时,我们必须对所有相机进行清理,即必须移除所有等待对象,释放所有分配的缓冲内存,关闭并销毁流抓取器以及相机设备句柄。

5.1卸载流抓取器

停止相机采集后,需要将所有还在输入队列等待的缓冲区移动到输出队列,实现该功能需要调用PylonStreamGrabberCancelGrab()

DL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberCancelGrab@4", "Cancel grab operation.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberCancelGrab(PYLON_STREAMGRABBER_HANDLE hStg);

依旧调用PylonStreamGrabberRetrieveResult(),将输出队列的数据全部取出。再调用PylonStreamGrabberDeregisterBuffer()注销分配的缓冲区。

IDL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberDeregisterBuffer@8", "Detach an image data buffer from a stream grabber.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberDeregisterBuffer(PYLON_STREAMGRABBER_HANDLE hStg, PYLON_STREAMBUFFER_HANDLE hBuf);

缓冲区注销后,调用PylonStreamGrabberFinishGrab()释放为缓冲区分配的资源。

IDL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberFinishGrab@4", "Shut down a stream grabber.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberFinishGrab(PYLON_STREAMGRABBER_HANDLE hStg);

最后,调用PylonStreamGrabberClose()关闭流抓取器。

IDL_ENTRY(PYLONC_MODULE, "_PylonStreamGrabberClose@4", "Close a stream grabber.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonStreamGrabberClose(PYLON_STREAMGRABBER_HANDLE hStg);

使用示例如下:

/* ... We must issue a cancel call to ensure that all pending buffers are put into the
stream grabber's output queue. */
res = PylonStreamGrabberCancelGrab( hGrabber );
CHECK(res);
/* ... The buffers can now be retrieved from the stream grabber. */
do
{
res = PylonStreamGrabberRetrieveResult( hGrabber, &grabResult, &isReady );
CHECK(res);
} while ( isReady );
/* ... When all buffers have been retrieved from the stream grabber, they can be deregistered.
After that, it is safe to free the memory. */
for ( i = 0; i < NUM_BUFFERS; ++i )
{
res = PylonStreamGrabberDeregisterBuffer( hGrabber, bufHandles[i] );
CHECK(res);
free( buffers[i] );
}
/* ... Release grabbing related resources. */
res = PylonStreamGrabberFinishGrab( hGrabber );
CHECK(res);
/* After calling PylonStreamGrabberFinishGrab(), parameters that impact the payload size (e.g.,
the AOI width and height parameters) are unlocked and can be modified again. */
/* ... Close the stream grabber. */
res = PylonStreamGrabberClose( hGrabber );
CHECK(res);

5.2卸载相机对象

调用PylonDeviceClose()PylonDestroyDevice()关闭并销毁相机对象。

IDL_ENTRY(PYLONC_MODULE, "_PylonDeviceClose@4", "Close a device.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE
PylonDeviceClose(PYLON_DEVICE_HANDLE hDev);
IDL_ENTRY(PYLONC_MODULE, "_PylonDestroyDevice@4", "Delete a device object.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE_DOC
PylonDestroyDevice(PYLON_DEVICE_HANDLE hDev);

最后,我们通过调用PylonTerminate()关闭pylon runtime系统。

IDL_ENTRY(PYLONC_MODULE, "_PylonTerminate@0", "Shut down the pylon runtime system.")
PYLONC_API GENAPIC_RESULT PYLONC_CC PINVOKE_DOC
PylonTerminate(void);

使用示例如下:

/* ... Close and release the pylon device. The stream grabber becomes invalid
after closing the pylon device. Don't call stream grabber related methods after
closing or releasing the device. */
res = PylonDeviceClose( hDev );
CHECK(res);
/* ...The device is no longer used, destroy it. */
res = PylonDestroyDevice ( hDev );//与PylonCreateDeviceByIndex对应
CHECK(res);
/* ... Shut down the pylon runtime system. Don't call any pylon method after
calling PylonTerminate(). */
PylonTerminate();