OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV用C++语言编写,它的主要接口也是C++语言,但是依然保留了大量的C语言接口。该库也有大量的Python, Java and MATLAB/OCTAVE (版本2.5)的接口。这些语言的API接口函数可以通过在线文档获得。如今也提供对于C#,Ch, Ruby的支持。
OpenCV于1999年由Intel建立,如今由Willow Garage提供支持。OpenCV是一个基于BSD许可[1] (开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。 最新版本是3.3 ,2017年8月3日发布。
OpenCV 拥有包括 500 多个C函数的跨平台的中、高层 API。它不依赖于其它的外部库——尽管也可以使用某些外部库。OpenCV 为Intel® Integrated Performance Primitives (IPP) 提供了透明接口。 这意味着如果有为特定处理器优化的 IPP 库, OpenCV 将在运行时自动加载这些库。
VC++是微软公司开发的一个集成开发环境,具有多方面强大的功能,可以利用其开发许多领域的实用软件,数字图像处理也是其主要功能之但纯用VC++处理图像难度很大,仅图像的读入和显示就需要很大的代码量,并要求开发人员必须对图像的内部结构认识清晰且能熟练使用C+t语言。而对于初次使用VC++处理图像的人员来说要做到这些方面确实有一定的难度。OPENCV提供了许多数字图像处理的函数,如果能和VC++结合使用将会在很大程度上降低工作难度,减少工作量。本文以灰度图像的目标提取为例说明OPENCV和VC++结合处理图像的能力。
环境配量
在VC++中使用OPENCV函数,首先要将OPENCV函数库嵌入到VC++中。目前OPENCV最典型的版本为1.0和2.0,VC++版本有6.0,2005和2008,若要使用OPENCV2.0则必须使用VC++2005或VC++2008,因为目前OPENCV2.0在VC++6.0中还没有成功案例。本文以OPENCV1.0和VC++6.0作为开发环境。将OPENCV1.0函数库嵌入到VC++6.0的方法很多资料上都有详细的阐述,这里就不做介绍了。
目标提取
目标提取的任务是从单幅图像或序列图像中将感兴趣的目标与背最分割开来,用于后续的处理。感兴趣目标的有效提取对于目标分类、身份识别和行为理解等中高层次的任务非常重要,因为后续的处理过程通常只考虑图像中对应于感兴趣区域的像素,并将极大的促进视频编码、检索、人机交互、运动捕捉等课题的研究目标提取技术最常见的处理过程如图1所示:
导入图像
对一幅图像进行处理之前,首先要读取图像的相关数据,为了观察算法的实现效果,还需清楚地看到处理后的图像结果,这就需要读入和显示图像。假若只用VC++,需要开发人员对图像的结构及VC++知识有个深刻的理解,代码量大,运算复杂,这就让很多初学者望而却步,然而在VC++环境下借助OPENCV函数库,可以方便的读入和显示图片。代码如下:
Ip1Image*img=cvLoadImage(“E: \hua.bmp”,-1) ;
cvNamedWindow(“win1”,0) ;
cvShowImage(“win1”,img) ;
cvWai tKey (0) ;
第一句功能为读入图像,需要注意的是表示路径的反斜杠必须为“\”,因为字符串中“\”为转义字符,代表一个“”,参数“-1”表示以原有颜色通道显示图像(还可以选择别的值,在这里就不加说明了); 第二句功能为建立一个名字为“win1“ 的窗口,“0”表示窗 口 大小由系统自动给定; 第三句功能是将图像在“win1” 窗口中显示; 第四句功能为延迟窗口显示时间,按回车键窗口会关闭,假若没有第四局,图像会闪一下消失,用户观察不到具体的图像。
去除背景
读入图像后,需要做的第一步就是去除背景。去除背景就是在一幅图像中,把目标从背景中分离出来,以便于进一步处理[2]。去除背最是目标提取的一个重要环节,背最是否去除干净以及目标图像保留信息的完整性直接决定著下一步任务能否正常完成。去除背最方法根据算法的不同可分为阚值法、边界探测法和匹配法等[3],其中阔值法的使用最为普遍。众多资料介绍了多种图像阈值分割算法。OPENCV提供了固定阚值分割函数cvThreshold和自适应阚值函数cvAdaptiveThreshold,函数cvThreshold对单通道数组应用固定阈值操作,该函数的典型应用是对灰度图像进行固定阈值操作得到二值图像,cvAdaptiveThreshold原则上为自适应阚值算法提供的函数,然而经过测试,此函数的确切功能是获得物体边缘,而非二值化函数,这应该是OPENCV不完善的地方之一。
在众多的阚值法分割图像算法中,大津法OSTU (又叫最大类间方差法) 是阚值分割的经典算法。大津法利用阚值threld将图像分为前景和背景,前最点数占图像比例为n1,平均灰度为o1,背景点数占图像比例为n2,平均灰度为m2,图像总的平均灰度为=n1*如1+n2*m2,前景和背景像素方差公式为n1*(m1-m)2+n2*(m-m2)2,将m的值带入上式即得最终方差公式n1*n2*(m1-m2)*(m1-m2),当方差值最大时,说明此时的阚值threld最合适.OSTU算法的核心代码如下:
for(k=0; k《256; k++)
{
n1+=ihist[k];
if(!nl)
cont inue ;
n2=n-n 1;
if(n2==0)
break ;
csum+=k*ihist[k];
m1=csum/n1;
m2=(sum-csum)/n2;
sb=n1*n2*(m1-m2)*(m1-m2) ;
if (sb》fmax)
{
fmax=sb;
threld=k;
}
}
}
经过OSTU算法找出最佳阚值后,将小于阚值的像素设为0,大于阚值的像素设为256,这样图像被设置为黑白两色(白背景黑目标)。代码如下:
for(i=0; i《height; i++)
{
for(j=0; j《width; j++)
{
for(k=0; k《channels; k++)
if(data[i*step+j*channels+k]》threld)
data [i *s t ep+j*c hanne 1s +k]=256 ;
else
data[i*step+j*channels+k]=0;
}
}
}
其中,“height“为图像宽,“width为图像高,“ channe 1s”为图像通道,“data[i*step+j*channels+k]” 为像素数值,threld为OSTU算法得出的阈值。
因为图像可能有不同程度的噪波,因此图像进行这样的处理后可能不需要灵活采取各种方法处理噪波的会达到完全处理掉背景的目的,此时,遗留痕迹,如腐蚀和膨胀,OPENCV分别提供了对应的函数Erode()和Dilate()。
二值化图像
通过以上过程得到黑白两色图像,对于深色背景浅色目标得到黑背景白目标,对于浅色背景深色目标得到白背景黑目标。由于控制器在处理图像时对于白色检测对象辨别度较好,故应将目标设为白色,就是说,假若得到白背景黑目标,需要对其进行反色处理。利用OPENCV在VC++环境中对图像进行反色处理的代码为:
i++)
for(i=0; i《height;
for(j=0; j《width; j++)
for(k=0; k《channels; k++)
Data[ i*s t ep+j*channe ls + k]=255-data[ i*s t ep+j*c hanne ls + k] ;
以上的黑白图像为灰度图像,即像素值为0到255,而二值化图像像素不是0 (黑色) 就是1(白色),有时候为了计算简单需将黑白灰度图像转换为二值图像,OPENCV提供了cvThreshold函数对图像进行二值化。同样,
假若得到的二值图像是白背景黑目标,需要将其反色处理。
提取目标
通过以上过程已经得到了白色目标。如果需要显示目标轮廓,OPENCV提供了对应的函数cvFindContours.以下如图2和图3为相关试验结果:
由上可知,在VC++环境下进行数字图像处理时,若借助于OPENCV函数以上方法仅适合库,可以在很大程度上降低工作难度。而通过实验可知,于简单背景图像的目标提取,对于复杂背景,仅仅使用OSTU法去除背景还不能达到非常满意的效果,在这方面,还需要进行进一步的研究。
评论
查看更多