图像处理、分析与机器视觉
上QQ阅读APP看书,第一时间看更新

4.1 内存中的图像

一个程序及其运行时的数据在内存中通常由二进制代码区、数据区、堆和栈区构成,如图4-2所示。其中栈区用于存储函数参数和常规变量,由编译器在编译时分配空间,且由操作系统自动管理。而存放于堆中的数据则可在运行时由程序动态分配和释放。操作系统为栈区预留的空间相对于堆来说要小得多(Windows一般为2MB),并且它是一块连续的内存区域,若申请的空间超过栈的剩余空间,就会产生溢出问题。堆是向高地址扩展的数据结构,并且是不连续的内存区域,因此从其中获得的空间不仅灵活,而且也比较大。由于图像处理过程中一般都要处理大量数据,因此一般都在内存的堆区为图像处理分配空间。

图4-2 内存中的程序

NI Vision使用IMAQ Create VI为图像处理在内存的堆区申请空间。当调用该函数时,NI Vision会先在内存堆上创建一个保存图像名和边界等属性信息的数据结构,但并不立刻为像素数据分配空间。只有等到图像尺寸改变时,才会自动根据实际情况为像素数据分配所需要的空间。图像尺寸改变通常在图像文件读取、图像采集开始或图像被重新采样时发生。IMAQ Create VI在内存的堆区域为图像像素数据分配空间后,会返回指向图像数据结构的引用。使用这一引用,就可以访问堆上的图像数据。若图像处理代码会改变堆上的图像数据,一般需要在堆上重新分配空间,复制图像数据。图像处理完成后,由IMAQ Dispose函数释放在堆上为图像处理分配的空间。

NI Vision在内存堆区为图像处理分配的图像数据结构中,除了图像属性信息外就是编码后的像素数据。这些像素数据将按照图4-3所示的方式进行组织。由图4-3可以看出,NI Vision基于原有像素,为图像增加了边界(Image Border)、左对齐(Left Alignment)和右对齐(Right Alignment)。而图像在内存中的线宽等于图像水平分辨率、图像左右边界以及图像左右对齐宽度之和。很多图像处理算法都基于相邻区域内像素值的某种关系来进行计算,但是图像边沿的像素却只占邻域的一半,要正常使用邻域处理算法,必须为这些边沿的像素补齐另外一半的邻域像素值。为图像添加边界,正是为了确保涉及图像边沿的邻域处理算法可正常运行。

图4-3 NI Vision在系统内存中组织图像数据的方式

图像边界的设置涉及边界的尺寸和图像边界范围内像素值的大小。图像边界的尺寸一般应大于或等于算法所使用的最大邻域算子行数或列数的一半向下取整,这样就可以确保算法正常运行。例如,如果算法使用5×5的邻域算子,则图像边界就应至少包含两个像素;如果图像的边界包含3个像素,则可以适应7×7以内大小的算子。默认情况下,NI Vision会自动在内存中为图像分配大小为3个像素的边界,以支持大小为7×7以下的算子。

边界范围内像素值的设置可使用以下3种方法中的一种:置0法(border clear)、复制法(border copy)或镜像法(border mirror)。置0法将边界区域内的所有像素值均统一设置为0,复制法将图像边沿的像素值复制到边界区域中,而镜像法则沿着图像边沿取图像中镜像位置的像素值。图4-4分别显示了使用这3种方法设置图像边界像素值的效果,其中灰色区域为图像边界。

图4-4 图像边界中像素值的设置方法

使用何种方法设置图像边界像素值,视机器视觉应用所使用的算法而定。例如,如果应用需要基于像素灰度检测图像中的边缘,就不能使用置0法。这是因为如果将边界区域内的像素置为0,图像4个边沿处灰度就会产生迅速变化,从而为应用引入错误结果。这种情况下最好使用复制法或镜像法填充边界像素以获取较为准确的计算结果。NI Vision中多数使用邻域算子的函数会自动在内存中为图像分配并填充边界,这些函数所采用的边界填充方法也不尽相同,如表4-1所示。例如,灰度低通滤波函数、N阶滤波函数和边缘检测函数均使用镜像法,二值形态学函数、灰度形态学函数和图像分割函数均使用复制法,相关函数、圆形查找函数、去除边框函数、斑点移除函数、细化和标签函数则使用置0法。注意,图像边界只在内存中进行图像处理时存在,并不会被保存至图像文件中。

表4-1 使用邻域算子的NI Vision函数自动设置边界区域像素值的方法

左右对齐可确保图像首个像素在系统内存中实现32B对齐,即首像素在内存中的地址所指向数据位置是32B的整数倍。由于CPU从内存中读取字节时并非逐字节读取,而是以2B、4B、8B、16B或32B成串读取,因此左右对齐可以将图像处理的速度几乎提高30%。在内存中,如果水平方向上每行像素所占字节数是32B的整倍数,就不再需要左右对齐,此时内存中图像的线宽就等于图像水平分辨率与图像边界之和。

内存中的像素数据按顺序从上到下、从左到右进行存放。但是如果用多个字节表示一个像素的灰度或颜色,还应注意字节在内存中的存放顺序。字节在内存中的存放顺序与操作系统有关,Windows使用从低到高的顺序在内存中存放字节(Little-Endian、Intel),UNIX等系统则采用由高到低的顺序存放字节(Big-Endian、Motorola),因此像16位的灰度图像或32位的彩色图像,每个像素在内存中的存放顺序可能随平台的不同各异。例如,某彩色像素0xA8B9C0D1在Windows平台上将以D1 C0 B9 A8的顺序在内存中存放,而如果在UNIX平台上,则可能以A8 B9 C0 D1的顺序存放,如图4-5所示。虽然NI Vision的VI和操作系统封装了这些细节,但是工程人员在开发过程中应时刻清楚这些基本概念。

图4-5 图像边界中像素值的设置方法

需要再次说明的是,NI Vision仅直接支持表3-3所示的几种图像类型。这意味着无论是经采集还是文件将图像数据传输至NI Vision VI所分配的内存中时,都必须将NI Vision不支持的图像类型转换为它支持的几种图像类型之一。图像采集时,这个转换由图像采集软件自动完成(图4-6);而由文件中读入数据时,转换由文件读取VI完成(详见第5章)。限定所支持的图像类型并不意味着NI Vision对图像进行处理的能力降低。相反,通过转换图像类型间接支持其他图像类型的方式,不仅不会损失图像信息,还可以规范各种算法的接口,并极大地降低算法设计的复杂性。

图4-6 图像采集软件对图像类型的转换

综上所述,由NI Vision软件加载至内存中的图像是一份添加了边界和左右对齐且已经转换为NI Vision可支持类型的图像数据副本。