OpenCV图像处理编程研究
2013-06-23李中健黄士飞西北工业大学自动化学院陕西西安709中国人民解放军978部队上海00436
晁 越,李中健,黄士飞(.西北工业大学 自动化学院,陕西 西安 709;.中国人民解放军978部队 上海00436)
OpenCV的全称是:Open Source Computer Vision Library。是Intel公司支持的开源计算机视觉库。它轻量级而且高效——由一系列C函数和少量C++类构成,实现了图像处理和计算机视觉方面的很多通用算法。由于OpenCV的源代码是完全开放的,而且源代码的编写简洁而又高效,特别是其中大部分的函数都已经过汇编最优化,以使之能高效而充分地利用英特尔系列处理芯片的设计体系,所以近年来在国外的图像处理相关领域中被广泛地使用,成为一种流行的图像处理软件。
1 OpenCV常用的数据结构
OpenCV设计了一些基础的数据类型和一些帮助数据类型,在运用OpenCV函数库进行编程的过程中,常常会需要用到这些结构类型,只有真正了解这些结构才能够很好地利用OpenCV函数库来解决问题。我们在此仅介绍IplImage进行介绍。通常情况下,使用DIB格式来处理图像,而OpenCV库则是使用 “IplImage”结构体来创造和处理图像。由于OpenCV主要针对的是计算机视觉方面的处理,因此在函数库中,最重要的结构体就是IplImage结构。IplImage结构来源于inter的另外一个函数库IPL,该函数库主要是针对图像处理。使用这种格式的优点是可以比DIB格式表示更多的图像性质,而且可以很方便地存取图像中的像素值,IplImage结构的具体定义如下[1]:
width和height这两个变量很重要,其次是depth和nchannals。depth变量的值取自ipl.h中定义的一组数据,但与在矩阵中看到的对应变量不同。因为在图像中,我们往往将深度和通道数分开处理,而在矩阵中,我们往往同时表示它们。可用的深度值如表1所示(通道数nChannels可取的值是1,2,3或4)。
表1 OpenCV图像类型Tab.1 Image types of OpenCV
2 OpenCV常用体系和常用函数
OpenCV1.0版本,包含以下5个部分:
1)CxCore:一些基本函数(各种数据类型的基本类型的基本运算等)。
2)CV:图像处理和计算机视觉功能(图像处理、结构分析、运动分析、物体跟踪、模式识别、摄像机定标)。
3)CvAux:一些实验性的函数。
4)HighGUI:用户交互部分(GUI,图像视频I/O、系统调用函数)。
5)CvCam:linux版本中已经抛弃,windows版本中将directx支持加入HighGUI后,CVCam将彻底去掉。
下面介绍一下OpenCV中常用的3种函数:
1)LoadImage():图像载入函数
语 法:IplImage*cvLoadImage(const char*filename,int iscolor=1);
参数类型说明
Filename const char*待载入图像的名称,包括图像的扩展名
Iscolor int辅助参数项,可选正数、负数、零。正数表示强制作为三通道(彩色)图像载入,零表示该图像作为单通道(灰度)图像,负数表示载入图像的通道数由图像文件自身决定
返回值:IplImage结构指针
2)NamedWindow():窗口定义函数
语 法:int cvNamedWindow (const char*name,unsigned long flags);
参数类型说明
Name const char*窗口名
Flags unsigned long窗口属性指标值,可以选择CV_WINDOW_AUTOSIZE
1和0两种值。CV_WINDOW_AUTOSIZE表示窗口尺寸与原始尺寸相同,0表示以固定的尺寸显示图像
说明:cvNamedWindow创建一个放置图像和rtackbar的窗口。被创建的窗口可以通过他们的名字被引用。如果已经存在这个名字的窗口,这个函数将不做任何事情。
返回值:无。
3)WaitKey():按钮等待函数
语法:int cvWaitKey(int delay=0);
参数类型说明
Delay int等待按键。如果delay<=0,那么无限等待;否则等待delay毫秒这返回
说明:在程序循环中,有时候由于程序一直处于计算中,导致窗口无法重绘(比如读出视频中的所有帧并显示),可以加入cvWaitKey函数,使程序等待几毫秒,让窗口完成重绘在执行其他操作。
3 Vincent算法的基本思想和实现
早期的分水岭算法的效率较低,Vincent[3]提出的改进分水岭算法使处理效率大大提高,使得分水岭算法为越来越多的学者所重视。
Vincent分水岭算法处理过程:
1)排序过程,按图像各像素的灰度值进行升序排列;
2)浸没过程,对每一层的阈值进行宽度优先搜索,通过queue结构(FIFO)完成;
下面对该算法的处理过程进行详细的描述[4]:
1)排序过程
对指针进行操作,确定图像精确的灰度级频率分布。使得每个像素都可以被直接定位到排序数组中的唯一单元。
n,图像的像素数目;
hmin,最低的灰度级别;
hmax,最高的灰度级别。
这种排序技术只需要2n步 “查找和处理”操作,(hmaxhmin-1)步“赋值”操作以得到累积频率分布。所以,排序所需要的时间和所占用的内存几乎可以忽略不计。从而,能够直接从排序数组(元素为指向图像像素的指针)中读取给定层高的某层像素,用于下一步的浸没操作。
2)浸没过程
一旦,对图像的像素排序完毕,就开始进行浸没聚水盆的操作。假定,现在已经浸没到高度为h的某层。每个被找到聚水盆(例如,每个聚水盆的相应最小值的点的高度都低于或等于h)被赋予一个唯一的标识。由于已经有了像素的排序数组,所以我们可以直接读取h+1层的像素,并给赋给它们具体的值,这一过程称为“MASK”。作为当前像素邻居、已经被标识的像素被放进queue里。从这些像素开始,queue可以将标识好的聚水盆扩展,并递归浸没过程,直至所有的像素都被处理。
4 OpenCV中分水岭分割实现
OpenCV函数库中分水岭源代码是在Vincent分水岭算法的基础上进行的改进。它首先计算灰度图像[5]的梯度;这对山谷或没有纹理的盆地(亮度是低的点)的形成有效,也对山头或图像中有主导线段的山脉(山脊对应的边缘)的形成有效。然后开始从用户指定点(或算法得到点)开始持续“灌注”盆地直到这些区域连在一起。基于这样产生的标记就可以把区域合并到一起,合并后的区域又通过聚集的方式进行分割,好像图像被“填充”起来一样。通过这种方式,与指示点相连的盆地就为指示点“所拥有”。最终能把图像分割成相应的标记区域。
更确切地说,该分水岭算法允许用户(或算法)来标记目标的某个部分为目标,或背景的某个部分为背景。用户或算法可以通过画一条简单的线,有效地告知分水岭算法把这些点像这样的组合起来。接着分水岭算法通过允许在梯度图像中和片段连接的标识区域“拥有”边沿定义的山谷来分割图像。
分水岭算法的函数定义如下[6]:
void cvWatershed(const CvArr*image,CvArr*markers);
这里image是一个8位 (三通道)的彩色图像,而markers是单通道整型(IPL_DEPTH_32S),具有相同维数(x,y)。除非用户(或算法)用正整数标记属于同一部分的区域,markers的值都是0。
5 仿真结果
如图2所示,左边的青椒被标记为1,中间的青椒被标记为2,上边的青椒被标记为3,右边的被标记为4,背景被标记为5。程序通过对每个标记给定一个正整数,并把未标记的区域记为-1,从而告知分水岭用户标记的边缘,并在此基础上进行分水岭分割,然后用随机生成的颜色填充分割后的区域,得到最终的结果如图3。
图2 分割前标记图Fig.2 Marked original image
图3 分割结果图Fig.3 Watershed segmentation image
6 结束语
由于时间的限制,本文仅在了解OpenCV初级使用的基础上,对数字图像进行了分割处理,并未达到自适应的效果。希望在研究生阶段能深入了解OpenCV的特性,更好的掌握OpenCV的使用,通过该软件提高对数字图像的处理技术;并尝试通过移植OpenCV在DSP平台上实现图像处理功能。
图1 原图像Fig.1 Original image
[1]陈胜勇,刘盛.基于OpenCV的计算机视觉技术实现[M].北京:科学出版社,2008.
[2]Gary Bradski and Adrian Kaebler.Learning OpenCV(影印版)[M].南京:东南大学出版社,2009.
[3]陈天华.数字图像处理[M].北京:清华大学出版社,2007.
[4]景晓军.图像处理技术及应用[M].北京:国防工业出版社,2005.
[5]刘瑞祯,于仕琪.OpenCV教程基础篇[M].北京:北京航空航天大学出版社,2007.
[6]章毓晋.图像分割[M].北京:科学出版社,2001.