3.3 IMAQ、IMAQdx与图像采集
一旦安装完驱动,并在NI MAX中或使用系统配置函数完成对采集设备的配置后,就可以在程序中通过定义的接口打开设备,建立到设备的连接,并开始采集图像,直到采集任务完成,关闭设备为止。常见的图像采集方式包括Snap、Sequence、Grab、Ring和Event等几种,这些采集方式的工作特点各不相同,可分别用于不同场合。图3-11显示了几种采集方式的工作示意图。
图3-11 常见图像采集方式
总体来说,各种采集方式可以根据是否连续进行图像采集分为一次性采集(One-Shot)和连续采集(Continuous)两大类。Snap和Sequence方式属于One-Shot类,它们通常只需要在打开采集设备后,采集一帧或多帧图像到缓冲区即达到目的,随后关闭打开的设备完成采集任务。Grab、Ring和Event方式则属于Continuous类,它们通常要连续采集单帧或多帧图像到缓冲区,并在采集过程中对单帧或多帧图像进行分析处理,直到任务完成为止。相较而言,Continuous类采集更适合对实时性要求较高的场合。
Snap方式用于采集一帧图像到内存缓冲区中。每采集一帧图像前,都会打开图像采集设备并对其进行初始化。在获取一帧图像到内存中后,就关闭已经打开的图像采集设备。如果要再采集另一帧图像,就需要重复以上过程。由于抓取每一帧图像时都要打开、关闭图像采集设备,因此Snap方式仅用于对速度要求不高或只需逐帧分析图像的应用。
Sequence方式与Snap方式类似,但它每次并不是只采集一帧图像,而是在设备打开并初始化后,连续采集指定数目的多帧图像,并且可以设置跳过某些帧。在完成指定数目的图像帧采集后,图像设备被关闭。由于Sequence方式要连续采集多帧图像,所以需要事先为采集到的图像分配足以存储这些图像序列的内存空间。Sequence方式适合需要对多个连续的图像帧综合分析的应用。
Grab方式从速度上对Snap方式进行了优化,它并不在每帧图像采集时都重复地打开或关闭图像采集设备,而是在设备打开后,就一直连续、高速地采集图像,直到需要停止时才关闭图像采集设备。由于Grab方式并不在每帧图像采集时都重复地打开和关闭图像采集设备,因此图像采集的速度相对于Snap方式要快很多。然而,Grab方式通常只在计算机内存中分配一帧图像大小的缓冲区,每次新采集的图像帧总是要循环覆盖缓冲区中保存的前一帧图像数据。因此对于应用程序来说,通常要考虑是使用当前缓冲区中的图像数据,还是要等待全新的一帧图像。
Ring方式在Grab方式的基础上优化了缓冲区的管理。首先,缓冲区的大小从一帧图像大小增加到多帧图像大小。其次,在图像采集时,图像数据将按顺序逐帧写入缓冲区,当缓冲区被填满时,又会从缓冲区的起始位置,重新开始循环写入图像数据帧。也可以通过配置使Ring方式采集每帧图像或跳过固定数量的帧。Grab和Ring方式均适用于需要连续、高速采集图像的场合。然而由于Grab方式仅有一帧图像大小的缓冲,因此不仅容易丢失图像帧,而且在需要多次对连续多帧图像进行处理分析的情况下显得捉襟见肘。Ring方式有足够多的帧缓冲,可以极好地替代Grab方式连续对多帧图像进行分析。
在前面几种方式中,当某一帧图像采集完成后,驱动程序并不主动通知应用程序,而事件驱动的Event采集方式则可以进行主动通知。这就使得程序不必在图像采集过程中时刻检查图像帧采集是否完成,而只要等到通知事件发生时提取图像帧即可。Event方式可以极大地节省系统资源,提高实时性,然而,并不是所有驱动程序都支持这种采集方式。
NI-IMAQ和NI-IMAQdx是NI提供的图像采集软件,它可以与LabVIEW、LabWindows CVI、Visual C++、Visual Basic等开发工具兼容。使用NI-IMAQ和NI-IMAQdx提供的函数(图3-12)可以在这些开发工具中快速实现各种图像采集程序。其中,NI-IMAQ主要支持从模拟相机、并行数字相机、Camera Link或NI智能相机采集图像,而NI-IMAQdx则主要用于从GigE、IEEE 1394、DirectShow(USB)以及IP(Ethernet)相机获得图像。由于所支持的相机不同,两者也在相机属性设置上稍有差别。除此之外,NI-IMAQdx还增加了对Event采集方式的支持。
图3-12 NI-IMAQ和NI-IMAQdx函数
NI-IMAQ和NI-IMAQdx提供两种封装级别的函数,一种是高度封装的高层函数,另一种是涉及驱动和采集过程的低层函数。高层函数用于快速构建最基本类型的图像采集程序;而使用低层函数,则可以创建任何类型的图像采集程序。在需要对缓冲区、图像采集过程或相机进行更精细控制的场合,低层函数尤为适合,但代价是要详细了解相关的API和驱动程序。
图3-13显示了使用NI-IMAQ高层函数实现Snap采集方式的代码。它遵循“初始化设备并分配缓冲区→采集图像→关闭设备并释放缓冲区”的实现过程。IMAQ Init.vi用于打开采集设备并对其进行初始化。它需要图像采集设备的接口和通道信息IF Name作为输入参数。例如,若要使用系统中的第二个图像采集卡的第3个通道,且在NI-MAX中配置时均使用默认值,则可以用img1︰︰2作为IF Name的值。IMAQ Init.vi基于接口文件和相应的相机文件打开设备后,就返回一个到该设备的引用。由于NI-IMAQ和IMAQdx会基于该引用实现图像采集或与该接口设备相关的属性访问或操作,因此可以认为该引用代表了到采集设备的连接或会话(session)。
图3-13 使用IMAQ高层函数实现Snap方式图像采集
IMAQ Create函数在内存中为图像采集分配内存缓冲区,IMAQ Dispose则用于释放不再使用的图像缓冲。它们位于LabVIEW的Vision and Motion>Vision Utilities>Image Management函数选项中,可协同工作以实现对图像采集缓冲区的自动管理。在分配缓冲区时,需要为每个缓冲区指定一个独一无二的名字Image Name,并使用图像的类型Image Type信息来确定缓冲区中所存储数字图像的类型。IMAQ Create函数将根据图像的类型信息来确定缓冲区的大小。如果不知道所采集图像的类型,可以参考已建立的“引用”,使用属性结点来获知。关于采集的图像如何在内存中存放,将在第4章进行介绍。
图像类型由像素的位深度和编码方式决定。NI Vision不仅可直接支持8位、16位、32位的灰度图像,还支持32位和64位的RGB彩色图像、32位的HSL(色相Hue,饱和度Saturation,亮度Luminance)彩色图像以及复数图像,如表3-3所示。
表3-3 NI Vision支持的图像类型
灰度图像量化级数随着量化后的数据类型位深度而变化。例如,若使用8位无符号整数(U8)对灰度量化,则灰度范围为0~255。其中0代表黑色,255代表白色。如果使用16位的无符号整数(U16),则灰度范围扩展到0~65535。若使用16位带符号整数(I16),则灰度范围改变为-32768~32767。使用整数代表灰度时,灰度级的步长均为1。当然也可以使用32位单精度浮点数(SGL)来表示图像灰度,此时灰度值范围为-∞到+∞,灰度级的步长也为浮点数。
NI Vision支持RGB和HSL两个色彩空间的彩色图像,其中RGB空间可支持32位(U32)、64位(U64)RGB彩色图像,HSL空间可支持32位(U32)HSL彩色图像。在计算机内存中,彩色图像的每个像素都由3个分量和一个在机器视觉系统中不常用的Alpha值构成。例如64位无符号RGB图像的像素分别由闲置的16位Alpha值、代表红色的16位R分量、代表绿色的16位G分量和代表蓝色的16位B分量构成。RGB色彩空间可以极大地简化图像显示设备的设计,因此常用于图像显示。然而,RGB色彩空间能表示的颜色数少于人眼可辨识的颜色,且它必须使用3个颜色分量才能表示一种颜色,不仅不够直观,而且往往增大了彩色图像处理的难度。
HSL色彩空间使用色调、饱和度和亮度来表示颜色。色调对应于颜色的波长,也就是说它代表的是人眼所能感知的颜色,如红、黄、紫等。可以想象这些颜色分布在一个平面的色环上,0°~360°中的一个角度代表一种颜色。饱和度与色调中混入白色的多少成反比,100%饱和的颜色中未混入任何白色。亮度用于控制色彩的明暗变化,数值越小,色彩越暗(越接近于黑色);数值越大,色彩越亮(越接近于白色)。HSL色彩模型如图3-14所示。HSL的优点在于它易于被人眼辨认,且将色彩与亮度信息完全区分开来,互不干扰。也就是说即使在光线亮度不断变化的情况下,基于它开发的色彩匹配等机器视觉应用也会有很强的鲁棒性。
图3-14 HSL色彩模型(彩图见插页)
HSL色彩空间常用于各种图像处理算法设计,而RGB色彩空间则适用于图像显示。很多机器视觉应用在进行图像处理前都先将RGB图像转换至HSL色彩空间再进行处理,而在HSL色彩空间对图像处理完成后,会再将其转换至RGB色彩空间进行显示。RGB色彩空间到HSL色彩空间的相互转换可以通过以下公式进行:
HSL色彩空间到RGB色彩空间的转换可使用以下公式进行:
其中r、g、b的值可通过以下公式确定:
另外,为了便于在频率域对图像进行各种处理,NI Vision还支持64位复数(CSG)图像。对普通灰度图像或彩色图像的某个分量进行FFT操作就可以得到复数图像。复数灰度图像中的每个像素被编码为两个分别代表实部和虚部的32位的单精度浮点数。复数图像不仅便于提取像素的实部、虚部、相位和幅度,还极大地方便了在频率域对图像的各种操作。
除了以上支持的图像类型,在实际开发过程中,图像采集设备还经常会采集到其他NI Vision并不直接支持的图像类型。如8位以下的灰度图像、10~16位的灰度图像、不同于32位和64位的RGB图像、从YCbCr视频抓取到的图像以及从带有Bayer滤镜的相机获取的原始数据(Raw Data)的RGB图像等。对于这些图像类型,为了方便后续处理,NI图像采集软件所包含的驱动程序会先将其自动转换为NI Vision支持的格式,再传送给应用程序。这样NI Vision就可以通过直接或间接方式处理几乎所有常见的图像类型。当然,如果不希望驱动程序进行自动转换,则可以直接抓取原始数据,在程序中自行解码或完成各种色彩空间转化。表3-4显示了NI图像采集软件支持的图像类型及对各种不支持的图像类型进行自动转换的方法。
表3-4 NI图像采集软件对各种图像格式的自动转换
IMAQ Create的参数Border Size(图像边界大小)用于确定图像缓冲区的大小,参见图3-15。它是指沿着图像边缘应额外添加的像素行和列宽度。例如,如果图像尺寸为256×256,则当Border Size等于2时,单个图像的缓冲区尺寸就是258×258。IMAQ Create函数返回一个指向空缓冲区的引用New Image。IMAQ Create函数执行完成之初,其实只是锁定了缓冲区在内存中地址。只有当函数IMAQ Snap.vi运行时,程序才真正综合所采集图像的大小、图像边界大小以及图像类型等信息,锁定缓冲区。此后,程序会从设备抓取一帧图像到缓冲区中供进一步处理。当图像采集和处理任务完成时(不再需要从设备抓取图像,且不需要缓冲区中的图像数据),就可以使用IMAQ Close.vi和IMAQ Dispose关闭图像采集设备并释放图像缓冲区。
图3-15 缓冲区管理函数IMAQ Create和IMAQ Dispose
如果需要,也可以使用低层函数实现Snap方式的图像采集程序。使用低层函数可以在实现所需功能时直接对图像采集过程或缓冲区进行控制,从而赋予程序更强的灵活性。它通常用于以下场合:
需要对图像采集顺序进行定制。
需要对缓冲进行操作,如自行规定环状缓冲等。
需要通过“会话”设置所采集图像的属性,如大小等。
进行同步或异步图像采集等。
使用低层函数创建图像采集程序的步骤也遵循“初始化设备并分配缓冲区→采集图像→关闭设备并释放缓冲区”的实现过程,只是相对于使用高层函数来说,它对各个环节的控制更精细。图3-16显示了使用IMAQ低层函数实现的Snap方式图像采集的程序,同时说明了使用低层函数创建图像采集程序的方法。
图3-16 使用IMAQ低层函数实现Snap方式图像采集
程序开始先调用IMAQ Init.vi对设备进行初始化,并创建一个到设备的连接。接着调用IMAQ Configure List.vi配置缓冲区列表Buffer List,包括配置缓冲列表中应包含多少个独立的图像缓冲区、缓冲区在存放的位置、感兴趣的图像区域ROI(默认为整幅图像)以及采集时是否要连续不断地向缓冲区传送图像数据。对于Snap采集来说,由于只要采集一帧图像,所以缓冲列表中只需要包含1个图像缓冲区(Numbers of buffer=1),且不需要在一帧图像采集完成后再向缓冲区中继续传送后续图像帧(Continous=One-Shot)。缓冲区既可以在系统内存中分配(Memory Location=System),也可以在采集卡的板载缓存中分配,这里选择了在系统内存中分配缓冲区。
缓冲区列表配置完成后,就可以使用IMAQ Create和IMAQ Configure Buffer.vi对缓冲区列表中的每个独立图像缓冲区分别进行配置。IMAQ Create会在系统内存或板载缓存中为图像划定存放数据的位置,而IMAQ Configure Buffer.vi则可以将内存中由IMAQ Create划定的位置与缓冲区列表的编号一一关联,并指定从设备的哪个通道(NI PCI/PXI-1409和PCI-1410,其余设备无须指定)采集数据到各个图像缓冲区以及指定采集图像到缓冲区前需要跳过的帧数(线阵相机忽略此参数)。IMAQ Configure Buffer.vi和IMAQ Configure List.vi配合,共同实现了用索引表管理图像缓冲的方式,如图3-17所示。对于Snap方式采集来说,只要对列表中唯一的一个图像缓冲区划定位置即可。
和高层图像采集函数类似,一旦使用IMAQ Start.vi命令启动采集,程序就会锁定缓冲区列表中的各个图像缓冲区需要的实际大小,并命令驱动开始向缓冲区中传送数据。此后,可以针对不同情况使用IMAQ Get Buffer.vi、IMAQ Extract Buffer.vi或IMAQ Copy Acquired Buffer.vi(参见图3-18)从缓冲区中提取或复制图像。IMAQ Get Buffer.vi用于采集停止后才提取数据的场合,如Snap或Sequence方式下图像帧已经被完全抓取到缓冲区,或者Grab、Ring方式的采集过程已经被停止时,就可以使用该VI从缓冲区中获取图像。它可以在设定的超时范围内从缓冲区列表中提取某一帧或所有(=-1时)缓冲区列表中的图像。
图3-17 索引表方式管理图像缓冲区
图3-18 IMAQ提取或复制图像的VI
IMAQ Extract Buffer.vi用于在连续采集过程中从缓冲区中循环(到缓冲区中的最后一帧时,再从头开始)提取图像。例如某个采集过程正以Grab或Ring方式工作,图像帧被连续不断地传送至缓冲区,如果此时需要查看缓冲区中的某一帧图像,就可以通过参数Buffer to Extract来提取,函数通过该参数值与缓冲区长度的求余操作结果来索引要提取的图像。IMAQ Extract Buffer.vi工作时会暂时将需要访问的某一帧图像缓冲(与采集过程隔离开来,以避免其被后续图像帧重写)。直到再次调用IMAQ Extract Buffer.vi时,前一次被隔离的缓冲区又会再次与采集过程链接,继续接收数据。如果要访问的图像缓冲区被隔离很长时间,以至于后续图像帧都已经到达并准备写入该缓冲区,此时采集过程并不会覆盖被隔离的缓冲区,而是暂时丢弃当前帧,并不断累计所丢弃图像帧的数量,直到该缓冲区可以再次访问为止。所丢失帧的数量可以在程序中使用属性结点并选择Status Information>Lost Frames来查看。注意,当参数Buffer to Extract的值为-1时,函数只释放当前已经被提取的缓冲,而不再从缓冲列表中提取新的缓冲。这常用于进行程序结束时的现场清理工作。
IMAQ Copy Acquired Buffer.vi则可以在任何采集方式的采集过程中,从采集卡的板载内存中复制图像到系统缓冲区,或从驱动分配的系统缓冲区复制图像到用户定义的系统内存中。由于在采集过程中被复制的缓冲区可能已经被覆盖,因此在使用IMAQ Copy Acquired Buffer.vi时要事先通过参数Overwrite Mode选择遇到已经被覆盖的缓冲时函数应如何响应。可选择让函数遇到被重写的缓冲时返回错误提示,获取缓冲区中下一帧新采集到的图像,或者按照默认情况来处理。默认情况下,遇到已经被覆盖的缓冲时,将复制缓冲区中保存的之前采集到的数据。
同样,当程序结束时,需要使用IMAQ Close.vi和IMAQ Dispose关闭图像采集设备并释放程序执行过程中所分配的内存。IMAQ Close.vi执行时会终止所有尚在执行的采集过程。如果不想关闭设备,而只是暂停采集过程,则可以使用IMAQ Stop.vi。此后在需要时,可以再用IMAQ Start.vi重启采集过程。
了解IMAQ图像采集程序开发方法后,就不难写出并理解Sequence、Grab和Ring方式工作的图像采集程序代码。图3-19显示了使用IMAQ高层函数和低层函数实现Sequence图像采集方式的程序代码。程序结构和Snap方式类似,不同之处在于其要采集多帧图像(可以通过Skip Table数组参数设置相邻两帧图像间要跳过的图像帧数),相应地需要为每帧图像分配缓冲。程序结束时使用循环释放所有之前分配的缓冲区。由Sequence采集程序可以看出,IMAQ高层函数实际上是对低层函数的封装。例如代码中IMAQ Sequence.vi就可以看作是对IMAQ Configure List.vi、For循环配置IMAQ Configure Buffer.vi、IMAQ Start.vi和IMAQ Get Buffer.vi的封装。当然在封装过程中还综合考虑了其他因素,因此在实现的细节上略有差异。读者可以通过对比图3-19中的程序代码和IMAQ Sequence.vi的代码,或者研究各个IMAQ函数代码来体会NI封装这些函数的技巧。
图3-19 IMAQ高层和低层函数实现Sequence方式图像采集
图3-20显示了使用IMAQ高层函数和低层函数实现Grab图像采集方式的程序代码。程序在为采集分配好缓冲区后,就不断采集图像帧到缓冲中。当需要某帧图像时,可以将图像从缓冲区中抓取到ImgOut控件中或复制到事先分配的用户缓冲区。使用低层函数实现的Grab采集程序,在系统中为图像采集分配了3个图像帧缓冲ImgBfr0、ImgBfr1和ImgBfr2。一旦IMAQ Start.vi启动采集过程,驱动程序就不断地按照帧缓冲的顺序循环地往其中传输图像帧。此后IMAQ Copy Acquired Buffer.vi在Buffer Number的索引下,把ImgBfr0-2中的图像逐个复制到用户缓冲UsrBfr中。Buffer Number是一个从0开始一直累加的值,当该值超过缓冲区列表的长度3时,又循环从第一个帧缓冲开始编号。例如在本例中,编号为0和编号为3的Buffer Number代表同一图像帧缓冲。
图3-20 IMAQ高层和低层函数实现Grab方式图像采集
虽然Grab采集方式只需要连续获取1帧图像,然而还是建议在系统中为图像采集分配缓冲时分配3帧(或以上)的图像帧缓冲。这可以减少获取帧缓冲中的图像时,因采集过程较快而引起的帧缓冲被覆盖的情况。无论IMAQ高层函数还是低层函数,本质上都是使用索引表的方式管理图像缓冲区。如果为多个图像设置缓冲区,则不仅需要调用IMAQ Configure List.vi配置索引表,还要通过循环调用IMAQ Create和IMAQ Configure Buffer.vi为每帧图像在缓冲区中指定位置,并将列表中的索引与缓冲区进行关联。在配置缓冲区时,应特别注意所配置的缓冲为一次性使用(One-Shot)还是连续使用(Continous)。必要时还要指定图像传至缓冲区前需要忽略的图像帧数。如果不再需要缓冲区,应将所有图像缓冲释放。
图3-21显示了使用IMAQ低层函数实现Ring图像采集方式的程序代码。Ring采集方式的实现相对复杂些,但其对于实时性系统的开发来说却更为可靠。程序先为采集配置了多个图像帧缓冲区列表,并分配了内存空间,此后就开始按顺序向图像帧缓冲区传输图像。当最后一个图像帧缓冲被填满时,又回到第一个图像帧缓冲,如此循环往复,直到任务完成为止。如果需要提取缓冲区中的某一帧图像,可以调用IMAQ Extract Buffer.vi并通过为其指定Buffer Number来索引缓冲中的数据。
图3-21 IMAQ低层函数实现Ring方式图像采集
读者可以在本书所附代码中找到图3-19到图3-21所示的图像采集程序代码,并按照需要稍做修改后使用。在编写这些代码的过程中,除了需要注意正确管理内存缓冲区外,还需要注意对不同采集方式采用不同的图像提取或复制方式。例如,Snap和Sequence方式采集程序使用IMAQ Get Buffer.vi提取缓冲区中所有已经完成采集的图像帧。Grab方式的采集程序则使用IMAQ Copy Acquired Buffer.vi从驱动缓冲区ImgBfr中实时复制图像到用户缓冲区UsrBfr中(注意,需事先分配等量的用户缓冲区)。Ring方式的采集程序则使用IMAQ Extract Buffer.vi暂时隔离某一图像缓冲并提取图像。当然Grab采集方式也可以使用IMAQ Extract Buffer.vi提取图像,Ring方式也可以使用IMAQ Copy Acquired Buffer.vi复制多帧图像到缓冲区进行处理。读者可以自己练习写这两个程序。
以上几种采集程序虽然功能上有所不同,但却都遵循“初始化设备并分配缓冲区→采集并处理图像→关闭设备并释放缓冲区”的开发模式。例如在高层函数实现的Grab采集程序中,一开始调用了IMAQ Grab Setup.vi对采集设备进行初始化。随后在循环中使用IMAQ Grab Acquire.vi不断将采集到的图像复制到应用程序的内存中进行处理,直到完成任务,才关闭设备,释放内存。注意,IMAQ Grab Acquire.vi的Immediate参数决定了函数是立即返回已经采集完成的上一帧图像还是要等待正在采集的新图像帧。默认情况下,Immediate=FALSE,程序将等待正在采集的新图像帧。当处理静止目标时,可以设置Immediate参数为TRUE,立即返回已经采集完成的上一帧图像。
IMAQ支持的模拟相机会输出YUV或YIQ色彩空间的模拟视频,多数图像采集卡对这些模拟视频进行采集时都会将其转换为RGB格式,以便于计算机处理和显示。并行数字相机和Camera Link接口的彩色Bayer相机常会对原始数据进行插值运算,得到完整的RGB数字图像输出。如果相机输出的是未经编码前的原始数据,则可以使用图3-22所示的程序,采集图像帧并对其进行解码。
图3-22从Bayer 相机抓取图像
程序一开始使用IMAQ属性结点读取已经被打开的图像采集设备属性,判断相机是否直接输出未经插值运算的Bayer原始数据。若是,则读取相机文件中的参数,并更新配置前面板上Bayer Decoding Parameter控件的参数;否则,则激活该控件,由用户输入相应参数。在开始连续抓取图像帧前,在缓冲区中分配了两个空间,一个存放未经解码的原始数据,另一个存放解码后的RGB数据。采集开始后,每采集一帧图像的原始数据,就使用IMAQ Bayer to RGB函数将其解码为RGB数据。最后,任务完成后,关闭设备释放缓冲并退出程序。
NI-IMAQdx兼容AIA(Automated Imaging Association,自动成像协会)的GigE标准及IEEE 1394数字相机工业仪器标准(Industrial and Instrumentation specification for Digital Cameras, IIDC)。使用它可以从GigE、IEEE 1394、DirectShow(USB)以及IP(Ethernet)相机的各种类型输出信号中采集图像。NI-IMAQdx实现图像采集程序的基本原理与NI-IMAQ实现方法类似。然而由于它支持的相机类型与NI-IMAQ所支持的相机类型不同,因此图像采集程序也有些细微的差别。图3-23显示了使用NI-IMAQdx高层函数和低层函数实现的Snap方式图像采集程序。
图3-23 IMAQdx高层和低层函数实现Snap方式图像采集
使用高层函数实现的IMAQdx Snap采集程序完全符合打开设备、采集图像、关闭设备并释放内存的易用模式。使用低层函数实现的采集程序在缓冲区的分配和配置方式上与IMAQ略有差异。IMAQ Snap采集程序中用IMAQ Configure List.vi配置缓冲列表,用IMAQ Create为图像帧分配内存空间,此后再通过IMAQ Configure Buffer.vi将图像帧空间与缓冲列表关联,完成整个缓冲区的分配。而IMAQdx Snap采集程序使用IMAQdx Configure Acquisition.vi配置缓冲区,并在采集开始后用IMAQdx Get Image.vi将图像从系统缓冲区复制到IMAQ Create分配的缓冲区中。此外,IMAQdx实现的采集程序中需要调用IMAQdx Stop Acquisition.vi来停止采集,并要在关闭设备前使用IMAQdx Unconfigure Acquisition.vi对IMAQdx Configure Acquisition.vi所做的处理进行反操作。而IMAQ程序中,只要直接使用IMAQ Close.vi关闭设备即可。
与IMAQ不同,IMAQdx只提供了一个IMAQdx Get Image.vi从系统缓冲区中复制图像。它与IMAQ中的IMAQ Copy Acquired Buffer.vi功能上相似,也可以采用3种不同的方式工作:
(1)Buffer Number。按照Buffer Number参数(超过缓冲区长度时,自动从头循环开始)获取指定帧缓冲中的图像。
(2)Next。当要获取的图像帧缓冲被覆盖时,等待并返回缓冲区中下一帧采集完成的图像。
(3)Last:当要获取的图像帧缓冲被覆盖时,获取缓冲区中最近一次采集完成的图像。
IMAQdx Snap程序中使用了Buffer Number工作方式,从参数指定的缓冲区中获取一帧图像。
图3-24显示了使用IMAQdx高层函数和低层函数实现的Sequence方式图像采集程序的代码。除了采集的帧数较多,且需要分配较多帧缓冲之外,本质上它和Snap采集程序没有太大差别。
图3-24 IMAQdx高层和低层函数实现Sequence方式图像采集
图3-25显示了使用IMAQdx高层函数和低层函数实现的Grab方式图像采集程序。注意程序中的IMAQdx Configure Acquisition.vi将图像采集配置为Continuous方式,并为之分配了3帧图像缓冲。IMAQdx Get Image.vi工作在默认的Next方式下,当要获取的图像帧缓冲被覆盖时,vi将等待并返回缓冲区中下一帧采集完成的图像。IMAQdx和IMAQ的Grab采集程序从缓冲区中获取图像的方式本质上没有差别,且都可以看作是Ring采集方式的特例,区别通常仅在图像缓冲区的大小上。
图3-25 IMAQdx高层和低层函数实现Grab方式图像采集
图3-26显示了使用IMAQdx低层函数实现Ring采集方式图像采集程序的代码。程序先按照Number of images参数为图像采集分配帧缓冲和帧存放缓冲区的数量。此后一旦采集启动,则驱动程序就将图像循环不断地传送到缓冲区中。IMAQdx Get Image.vi函数工作在Buffer Number模式下,它按照图像帧缓冲区索引将图像从系统缓冲区复制到用户缓冲区。系统缓冲区与用户缓冲区中可保存的图像帧数量相同,IMAQdx Get Image.vi可以自动对系统帧缓冲中的图像进行循环索引,为了将系统缓冲区中的多帧图像取出并进行分析处理,可以通过Buffer Number与缓冲区中帧缓冲数量的求余结果来索引用户缓冲中的帧缓冲,实现与IMAQdx Get Image.vi循环索引相同的效果。
图3-26 IMAQdx低层函数实现的Ring方式图像采集
除了支持Snap、Sequence、Snap和Ring几种采集方式外,IMAQdx还支持事件驱动的Event采集方式。图3-27给出了一个使用IMAQdx低层函数实现Event采集方式的例子。除了打开图像采集设备、对采集进行配置、开始采集、停止采集、清理现场及关闭设备等常见过程外,程序还注册了Frame Done动态事件。当驱动采集到某一帧图像的完整数据时会产生该事件。此后应用程序就可以利用事件结构捕获该事件,并调用IMAQdx Get Image.vi取出该帧缓冲中的图像。如果在运行过程中规定的时间段内没有捕获到事件,并且发现驱动并未在图像采集过程中,则程序将结束运行。
图3-27 低层函数实现的IMAQdx Event方式图像采集
IMAQdx支持的几种类型的相机(GigE、IEEE 1394、USB和Ethernet相机)并不总输出NI-Vision支持的RGB格式信号。例如,有些USB或IEEE 1394接口的相机回直接把YCbCr422编码方式的视频数据传到缓冲区,部分GigE或Ethernet接口的相机会直接将未经解码的视频数据以网络数据包的格式传送给计算机。在采集时,IMAQdx会自动按照表3-4列出的映射关系对不支持的信号格式进行转换。如果不希望IMAQdx对数据进行自动转换,可以使用IMAQdx Get Image Data.vi直接获取未经解码的原始数据。图3-28给出了以Grab方式采集未解码图像帧数据的例子。除了循环中所使用的图像数据获取函数不同外,该程序与IMAQdx支持的图像数据Grab若要利用各种图像处理算法处理或显示采集到的图像,必须先编写程序对数据进行解码,将其转换为NI-Vision支持的格式。关于相机所输出的原始数据编码格式,通常可以在相机或图像采集卡的使用说明书中找到。
如3.2节所述,IMAQ支持的相机文件(.icd)中存放着与某种型号相机对应的类型参数。它常通过相机接口文件(.iid)与图像采集设备或它的某个端口进行关联,以控制某一型号相机的特性,如相机所输出视频信号的幅度、同步信息等。与相机接口文件和相机文件不同,相机属性参数文件中的属性可以控制相机的某个特定功能,如积分时间、曝光时间、像素时钟等。IMAQ支持的相机属性参数文件以“.txt”形式的文件保存在文件夹C:\Docum ents and Settings\All Users\Documents\National Instruments\NI-IMAQ\Camera Info中。IMAQ支持的相机属性参数可以通过Attribute Name(属性名)、Description(属性描述)、Data Type(数据类型)和Possible Value(可能的值)等字段来表述。图3-29显示了IMAQ支持的型号为Dalsa CL-P1-1024W的相机的属性参数。
图3-28 使用IMAQdx 获取Raw Data
图3-29 Dalsa CL-P1-1024W相机的属性参数
相机的参数和属性可以通过NI-MAX在设计时进行配置。也可以在程序运行时通过程序代码对相机属性参数进行初始化,或者不断根据程序计算结果调整相机的参数。对于保存在相机文件(.icd)中的属性参数,可以使用IMAQ属性结点配置。图3-30给出了一个使用IMAQ属性结点将相机配置为采集偶数场图像数据的例子。
IMAQ则提供了配置控制相机特定功能的属性参数的专门VI。使用这些VI可以在运行时轻松读取或设置相机属性参数,从而改变相机的功能。图3-31显示了读取和设置Dalsa CL-P1-1024W相机积分属性参数及其子属性参数的代码片断。程序取了相同的Integration属性参数及其子属性参数PRIN的值。根据图3-29显示的相机属性参数文件,可以预料所读到的Integration值可能是字符串类型的Total或Controlled。所读到的PRIN子属性参数的值则可能是某一数值类型的值。由于读取相机属性参数的函数只返回字符串,因此需要将其转换为数值类型输出。对相机某个属性参数的子属性参数进行设置时,需要连续运行IMAQ Set Camera Attribute几次,逐级设置数据,直到任务完成为止。有些相机的属性参数需要通过串口进行配置,为此,IMAQ也提供了专门的VI。
图3-30 使用属性结点配置相机参数
图3-31使用IMAQ 配置相机属性参数
由于IMAQdx支持的相机通常都将相机类型参数和属性参数直接保存在相机中,因此IMAQ配置属性参数的方法与IMAQ所用方法略有不同。IMAQdx支持的相机属性参数一般只包括“属性名”和“属性值”两个域,可以直接使用属性结点对这些参数进行读取和设置。应注意的是,IMAQdx中相机的属性参数名表示方法与IMAQ中的不同。完整的属性参数名使用双引号将代表不同层级的关键字隔开,如AcquisitionAttributes︰︰Timeout,也可以简写为Timeout。图3-32给出了IMAQdx配置相机属性参数的例子。
图3-32使用IMAQdx 配置相机属性参数
无论是IMAQ还是IMAQdx,使用属性结点或相机属性参数配置VI所设置的参数,其有效性仅能持续到图像采集会话结束之前。若要彻底更改相机的参数配置,可以使用文件操作函数,更改相机文件中的内容。相机属性参数文件是设置相机属性参数的最佳参考文档,无论是使用VI还是使用属性结点设置相机属性参数,属性名、属性值都必须和文件中的相应字段完全保持一致。
总的来说,IMAQ和IMAQdx提供了从多种相机采集图像的简单易用的函数。其中高层图像采集函数可以满足用户快速开发图像采集程序的需求,低层函则为用户提供了更精确地控制图像采集过程的手段。不仅如此,开发人员还可以利用IMAQ和IMAQdx提供的信号触发控制函数快速构建基于触发信号的图像采集应用。例如,可以使用红外传感器检测生产线上的产品的位置,只在合适的时机采集被检测目标的图像,对其进行检测或进一步控制机械执行机构的相关动作。基于触发信号也可以将多台相机的同步机制和触发结合,完成精准的同步图像采集。