搜档网
当前位置:搜档网 › 基于OpenCV的图像轮廓提取方法的实现毕业论文

基于OpenCV的图像轮廓提取方法的实现毕业论文

基于OpenCV的图像轮廓提取的实现

【摘要】OpenCV是近几年来推出的一个开源的、免费的计算机视觉库.OpenCV的目标是构建一个简单易用的计算机视觉框架,利用它所包含的函数帮助开发人员方便快捷地实现图像处理和视频处理。而图像的轮廓是图像的一种基本特征,携带着一幅图像大部分的信息,经常被应用到较高层次的图像应用中。它在图像分离,图像识别和图像压缩等领域有很广泛的应用,也是图像处理的基础。本文首先阐述了OpenCV的特点和结构,然后采用一系列的可行性算法来获取图像特征参数并通过各种算子(Sobel算子,Laplace算子,Canny算子)对图像的灰度进行分析,调节,用实现对图像的边缘检测和轮廓提取。

【关键词】OpenCV 图像轮廓提取

The realization of the image contour extraction based on OpenCV

【Abstract】OpenCV is launched an open source in recent years.Free computer vision library. OpenCV's goal is to build a simple and easy to use computer vision framework, function to help developers use it contains quick and easy to realize image processing and video processing.And the outline of the image is a basic feature of image, carrying an image, most of the information is often applied to the higher level of the image application.It in image separation, image recognition and image compression, and other fields have a wide range of applications, is also the basis of image processing.At first, this paper expounds the characteristics and structure of OpenCV, then a series of the feasibility of the algorithm is used to obtain image feature parameters and through a variety of operator (Sobel operator, Laplace operator, Canny operator) analysis of image gray level, adjustment, use of image edge detection and contour extraction.

【Key words】OpenCV Image Contour extraction

目录

1引言 (1)

1.1 课题背景 (1)

1.2 研究的目的及意义 (1)

1.3 可行性分析 (2)

2 开发工具及轮廓提取概述 (3)

2.1 OpenCV (3)

2.1.1 OpenCV简介 (3)

2.1.2 OpenCV安装及环境搭建 (3)

2.2 边缘检测........................................................................................ 错误!未定义书签。

2.2.1 边缘检测 (4)

2.2.2 边缘检测原理 (5)

2.2.3 边缘检测算子 (5)

2.3 轮廓提取 (9)

2.3.1轮廓提取目的 (9)

2.3.2 轮廓提取内容 (9)

3 需求分析 (10)

3.1 系统功能分析 (10)

3.2 系统流程图 (10)

4 总体设计 (11)

4.1 系统功能要求及说明和实现方法 (11)

4.2 系统功能模块 (11)

5 详细设计与实现....................................................................................... 错误!未定义书签。

5.1 图片提取........................................................................................ 错误!未定义书签。

5.2 图像边缘检测 (15)

5.3 图像轮廓提取.............................................................................. 错误!未定义书签。8

6 程序界面................................................................................................... 错误!未定义书签。总结与展望.. (23)

参考文献 (23)

致谢 (26)

1引言

1.1 课题背景

图像处理在应用及科研方面已经是一个占据相当重要地位的方向,在人们的生活中也有很广泛的应用,图像表示直观且信息丰富,是声音和文字所不能及的。在图像处理方面很多软件公司和科研机构都研究了关于图像处理的软件。而OpenCV在计算机视觉的开发和图像处理中扮演着重要的角色。它为计算机视觉应用开发提供了灵活、功能强大的开发接口,使其成为计算机视觉专业人员所依赖的重要开发工具。它就被广泛用在许多应用领域、产品和研究成果中。

1.2 研究目的及意义

图像处理,就是对图像信息进行加工来满足人的视觉心理或应用需求的行为。视觉是人类从大自然中获取信息的最主要的手段。据资料统计,人类获取信息时,视觉信息约占60%,听觉信息约占20%,其他的如味觉信息、触觉信息等约占20%。可以知道视觉信息对人类的重要性,然后图像就是人类获取视觉信息的主要造径。

随着科学技术的发展和人民生活水平的提高,摄像机的出现和数字图像处理技术的发展,在如今的数字化时代中,越来越引起人们的广泛关注,数字图像处理已经成为必备的基础知识。近年来由于计算机技术的蓬勃发展,图像处理技术也得到了空前的发展和应用。目前,图像处理技术已经广泛应用于工业、军事、医学、交通、农业、天气预报、银行、超市、重要部门的监控报警系统、可视电话、网络传输等等领域,就连人们日常生活中的自拍和游戏也和图像处理有密切的关系。

本文主要是对计算机视觉系统的应用,图像轮廓提取技术进行研究。实现表面缺陷的自动检测图像,灰度等级自动分选排序,提高图像的价值有一个非常重要的作用。而影响检测整体水平的重要方面之一是缺陷图像的处理过程,而本文研究的重点图像轮廓提取技术是图像分割、目标区域识别区域实践提取等图像分析处理领域的基础是非常重要的。用非接触式,精度高,能够提供全面的分析识别方法来替代人工视觉,解决图像表面的模式识别和测量问题,是图像加工行业面临的一大难题,也是值得我们长期探讨的科研课题。

1.3 可行性分析

技术上的可行性:系统开发采用C++语言进行程序设计,运用OpenCV强大的数字图像处理技术,在Windows平台上设计图像边缘检测和图像轮廓提取的图像处理系统,使用VS2012的开发环境,利用QT的界面管理,给系统提供了高性能的保障。保障了代码的质量,对代码模块有了清晰的管,和对后期代码的修改和扩展提供了很好的支持。综上所述,本系统的设计与开发在技术上都是满足的。

经济上的可行性:随着计算机的超速发展,计算机如今已是处于高配置,低价格的时代,而本系统的开发,其应用在游戏,教育,文艺,工业等多个领域有着重要的意义。本系统的运行可以代替人工进行很多繁琐重复的工作,节省物力人力和很多资源,大大提高了生产效率。所以在经济上是可行的[1]。

运行上的可行性:本系统作为一个小型的图像轮廓提取系统,所需资源无论是从硬件方面还是软件方面都能够满足条件,所以在运行上也是可行的。

2开发工具及轮廓提取概述

2.1 OpenCV

2.1.1 程序流程图

OpenCV 全称 Open Source Computer Vision Library,是由Inter公司资助的开源计算机视觉库,它是用C/C++语言编写的,可以实现图像处理和计算机视觉中的很多算法,可以运行在Linux/Windows/Mac等操作系统上。由于OpenCV的源代码是完全开源的,并且编写高效又简洁,很多函数都已经汇编最优化。所以近些年来在国内外的图像处理和相关领域中被广泛的使用,成为了一种流行的图像处理软件。

主要应用领域有:1.人机互动 2.物体识别 3.图象分割 4.人脸识别 5.动作识别 6.运动跟踪7.机器人等。

2.1.2 OpenCV安装及环境搭建

首先把OpenCV正确的配置到VS开发环境中。设置预先编译的头文件的路径与动态链接库的路径[2]。

第一步:安装OpenCV和环境变量配置

计算机-> 属性-> 高级系统设置->环境变量

加入名为OPENCV的变量,值为F:\opencv\build(这里是自己OpenCV安装路径),在Path变量后追加;%OPENCV%\x86\vc11\bin(X86是32位系统,X64是64位系统,vc11是vc2012,vc12是2013)。

第二步:在VS2012中新建项目

建好工程后,视图->属性管理器,右键Debug,添加新项目属性表,新建名为OpenCVx86.Debug.prop的项目属性表(区分Release的)。

双击新建好的OpenCVx86.Debug.props属性表,找到常规 -> VC++目录 -> 包含目录下拉后点开编辑,添加如下几项

F:\opencv\build\include

F:\opencv\build\include\opencv

F:\opencv\build\include\opencv2

确定后,点开库目录,编辑,追加如下2项:

F:\opencv\build\x86\vc11\lib

F:\opencv\build\x86\vc11\staticlib

确定后,返回VC++目录,找到链接器 -> 输入 -> 附加依赖项。

第三步:测试是否配置成功

将自己所要显示的图片放到工程下,新建源文件输入以下代码,运行,若看到显示图片就说明配置成功了!

如果以后有其他新建项目用到OpenCV,只需要在属性管理器页面导入以上创建的项目属性表即可!

2.2 边缘检测

2.2.1 边缘检测

计算机处理图像有两个目的:第一个是产生更加能够让人观察和识别的图像,第二个是更加能够让计算机自动识别和理解图像[3]。总之,最终的目的先对大量的图像携带的信息进行分解,通过处理分解出来的最基本的基元从而来处理图像。而边缘检测是计算机视觉和图像处理中的基本问题,边缘检测的目的则是标识图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的变化。这些包括(i)深度上的不连续、(ii)表面方向不连续、(iii)物质属性变化和(iv)场景照明变化。边缘检测是图像处理和计算机视觉中,尤其是特征提取中的一个研究领域。

图像的边缘是图像最基本的特征。图像边缘指的是周围像素灰度有阶级跳跃的变化或者屋顶变换的像素的集合。边缘的种类有两种,我们通常把它们记作:阶跃性边缘(两边的灰度值有显著的不同)和屋顶状边缘(存在于灰度值从增加到减少的变化转折点),那么怎么分辨图像的边缘呢?图像的边缘其实就是存在在物体与物体,物体与图像背景之间,这些都是我们能用眼睛看见的,可以从宏观上这么说。其实基元与基元之间都存在着边缘,这些是微观方面的说话。所以这都是图像要分割,分离的最基本的特征,我们通过寻找边缘就能分离图像。

边缘的种类有两种,我们通常把它们记作:阶跃性边缘(两边的灰度值有显著的不同)和屋顶状边缘(存在于灰度值从增加到减少的变化转折点)。下面是几种类型边缘的截面图。

图2-1理想跃阶式 图2-2斜降式 图2-3斜升式

图2-4 脉冲式 图2-5屋顶式

2.2.2 边缘检测原理

通过前面的介绍我们也大概的了解到边缘检测的基本概念,我们把边缘定义为图像中灰度发生急剧变化的局域。那么边缘检测的原理就能很好的理解,就是用某些已存在的算法来解决我们所要表达的问题,更官方一点的话说就是用算法提取图像和背景之间的交界线,从而来实现边缘分离和提取[4]。

边缘检测算子其实也就是解决问题的算法,这种算法自然有很多,早期的经典算法有边缘算子法,模拟匹配法,门限法等方法。近些年来随着人工智能的方法,越来越多的人开始关注,于是又涌现了很多新的边缘检测算法,其中最为人多议论的有小波变换和小波包的边缘检测法、基于形态学和神经网络的边缘检测法。

我们可以来初步了解一下计算机是怎样检测图像边缘的。就以灰度图像为例,它的理论基础是,如果有一个边缘,那么图像的灰度就肯定会发生变化(为了方便假设由黑渐变为白代表一个边界),这时我们可以对其灰度分析,边缘的灰度函数就是一个标准一次函数y=kx+b ,我们对其求一阶导数后结果就是它斜率k ,也就是说边缘的一阶导数是一个常数,而我们又知道由于非边缘的一阶导数为零,这样通过求一阶导数就能初步判断图像的边缘了[5]。下面先来介绍下经典的几种算法。

(1)Roberts 算子

这里介绍一个名词梯度,我们把梯度定义为一个向量(Δf ),Δf 指出了灰度变化最快的方向和变化量。用公式可以表示为

),( Δf y f x f αααα= (2.1)

其中我们可以从以前学过的数学知道它的梯度大小为

2)(2)(

y f x f f αααα+=? (2.2)

梯度的角度θ为

????? ??=x f y f αααα θ (2.3) 而这个Roberts 算子其实就是对图像的Δx (水平方向)和Δy (垂直方向)来趋近梯度算子。

))1,(),(),,1(),((----=?y x f y x f y x f y x f f (2.4)

我们就能得出Roberts 算子的表达式为

2))1,()),1((2))1,1(),((),(+-++++-=y x f y x f y x f y x f y x g (2.5)

(2)Sobel 算子

上面介绍了计算机通过y=kx+b 求导数识别图像边缘的,但是在具体图像中我们会发现是求不了导数的,因为没有准确的函数公式让我们来求导数,所以厉害的研究人员就想到了用另一种方式来替换原来的方式求导数。用一个3×3的二维矩阵窗口对原来图像进行近似求导。这里拿对x 方向求导为例,如下图2-6,我们定义b2的导数Ko 为第三列的元素(a3,b3,c3)之和减去第一列元素(a1,b1,c1)之和,这样就求得了b2的近似导数。我们知道导数其实就是代表一个变化率,从第一列到第三列,灰度值相减,当然就是一个变化率了。当然Y 方向导数与X 方向导数求法相似,就是用第三行元素之和减去第一行元素之和。这样一来X 方向和Y 方向导数有了,那么梯度我们也就知道了。 如果这个时候我们给每一列都加一个权重,分别为1,2,1。这就是Sobel 算子了。再举一例,如图2-7中,求χ是不是边缘点,我们有公式得Δχ= (10*1+20*2+30*1)-(30*1+20*2+10*1)=0。由此可知χ不是边缘点。图2-8和图2-9中的Gx 和Gy 分别为Sobel 算子中水平方向和垂直方向的梯度。

??????????c3 c2 1b3 b2 1a3 a2 1c b a ??

????????10 20 300 030 20 10χ I *1 2 10 0 01- 2- 1- Gy

I * 1 0 1-2 0 2-1 0 1-??????????+++=??????????+++=Gx 图2-6 矩阵1 图2-7 矩阵x 图2-8水平方向梯度 图2-9 垂直方向梯度

(3)Laplace 算子

上面介绍的两个算子都是一阶差分算子,而Laplace 算子是二阶差分算子。我们可以想象为对一个函数的二次求导。我们可以想象一下,如果图像中有噪声(图像在传输过程中的通道传输误差等因素会造成图像上出现一些随机的、离散的、孤立的像素点,就是

图像噪声),噪声在一阶导数处也会取得极大值从而被当作边缘。如果采用二阶导数,这是函数的极大值点就为0了,我们就可以认为这个点就是图像的边缘点了。如下图2-10为原函数,图2-11为一阶导数,图2-12为二阶导数。

图2-10 原函数 图2-11 一阶导数 图2-12 二阶导数

但是Laplace 算子会放大噪声,所以我们要采用了LOG 算子,就是Laplace 算子,

先对图像进行高斯模糊,抑制噪声,再求二阶导数,二阶导数为0的地方就是图像的边缘。

(4)canny 算子

我从一些博客和资料中了解到了canny 的原理。我们知道图像边缘检测要满足两个条件,一是能有效的抑制噪声;二是能精确的确定边缘的位置。然后根据对信噪比和定位的乘积来进行度量,得到优化的算子,这其实就是Canny 边缘检测算子。类似于Laplace 边缘检测方法,先平滑后求导数[6]。

我们来了解一下canny 的步骤。

1.消除噪声;

在这一步中,其实就是用高斯平滑滤波器卷积降低噪声。也就是一个固定值的内核。如下图2-13所示。

????????????????=2 4 5 4 24 9 12 9 45 12 15 12 54 9 12 9 4 2 4 5 4 21391k

图2-13 5核高斯内核

2.用一阶偏导的有限差分来计算梯度的幅值和方向;

这一步类似于Sobel 算子的求X,Y 方向上的梯度。

F ’’(x)

F(x) F ’(x)

I *1 2 10 0 01- 2- 1- Gy I * 1 0 1-2 0 2-1 0 1-??

????????+++=??????????+++=Gx

图2-14 水平和垂直方向上的卷积

然后使用下列公式,求得梯度的幅度G 和方向θ(一般为0°,45°,90°,135°)。

)x tan(a y2

2G Gy rc G Gx G =+=θ (2.6)

3.对梯度幅值进行非极大值抑制; 经过上面的步骤,得到梯度并不能确定边缘,因此我们应该保留局部梯度最大的点,而抑制非极大值。如果图像梯度幅值矩阵中的元素值越大,说明图像中该点的梯度值越大,但这不不能说明该点就是边缘。在Canny 算子里面,非极大值抑制是图像边缘检测的最重要的步骤,它的任务就是寻找像素点局部最大值,将非极大值点所对应的灰度值置为0,这样做就能删除一大部分的非边缘的点[7]。

图2-15 非极大值抑制图

我从一篇博客上了解到了非极大值抑制的工作原理。由上图2-15可知,要进行非极大值抑制,以图中c 像素点为例,我们首先要知道像素点c 的灰度值是否在它的8值邻域中最大。图中红色的线方向我们认为是c 像素点的方向,我们就可以认为它局部的最大值是分布在这条线红色的线上的,而梯度方向的交点d1和d2这两个像素点的值也可能是局部最大值。综上可知,我们比较c 像素点和这两像素点的灰度就可以判断c 像素点的灰度值是否在它的8值邻域中最大。如果c 像素点灰度值最小,c 像素点不是局部最大灰度值,那么我们就可以认定c 像素点不是边缘[8]。

g1 g2 θ d1 θ C g3 d2 g4

4.用双阈值算法检测和连接边缘。

这一步,Canny 采用了滞后阈值,滞后阈值需要两个阈值,一般有三种情况作为判定是否为边缘点,第一如果某个像素点位置的幅值高于高阈值,,则该像素被保留为边缘像素点。第二如果某个像素点的位置的幅值低于低阈值,则该像素点不是边缘像素点,移除。如果某个像素点的位置在高阈值和低阈值之间,则该像素点只在被连接到高于高阈值的像素点时才被保留。

好吧,我们来看看OpenCV中canny算法。我们还是看看实现函数和其参数。

void Canny(

InputArray image,//输入图像,即源图像

OutputArray edges,//输出边缘图像,需要和源图像一样的尺寸和类型

double threshold1,//第一个滞后性阈值

double threshold2,//第而个滞后性阈值

int apertureSize=3,//表示应用Sobel算子的孔径大小,其有默认值3

bool L2gradient=false);//计算图像梯度幅值的标识,默认值为false

2.3 轮廓提取

2.3.1 轮廓提取目的

为什么要对图像进行处理呢,在现实生活中其实都都能多例子,比如为了让自拍照变得漂亮,为了更清新的看见图片内容,将很多照片的部分拼凑起来变成更好有价值的图像等等。前面已经介绍,利用计算机对图像进行处理,其目的就是得到更适合人观察和识别的图像或者由计算机自动识别和理解的图像[9]。提取图像的基本特征和属性,用于计算机分析后就能得出自己想要的图像,图像的轮廓作为图像的基本特征,经常被应用到较高层次的图像应用中去。本论文研究的图像轮廓提取其实就是实现上述目的的重要的基础。

2.3.2 轮廓提取内容

图像轮廓携带着图像大部分信息,而轮廓存在于图像不规则的结构和不稳定的像素点,当然也有的存在于信号的突变处。这些轮廓就是我们在图像边缘检测时重要的条件和因数,所以我们需要对图像进行边缘检测从而提取出图像的轮廓出来。这些方法或者说是算法都是我们前面说研究过的。有时我们要把自己感兴趣的东西从目标图像中提取出来,一般用到的方法是通过颜色或纹理提取出目标图像的前景图,如果这是我们要对前景图进行分析然后把目标提取出来,这里用到的方法就是提取目标的轮廓[10]。

3需求分析

3.1 系统功能分析

本文主要是研究的图像的边缘处理技术(边缘检测和轮廓提取)的一些算法。前面我们介绍了很多经典的图像边缘检测的方法,它们是构造对像素点灰度阶跃变化明显的微分算子(Sobel 算子等)。

这种检测速度是非常喜人的,但是我们得到的图像结果一般都是断断续续的,不怎么完整的结构信息。

可它们的优势在于它们对噪声非常的敏感,一般这类算法都要对愿图像进行平滑操作,然后在进行边缘检测,这样一来就能够检测出真正的图像边缘了。在边缘检测技术中比较靠谱的方法就是线性滤波器,这其实就是Laplace 算子。它能很好的解决频域最优化和空域最优化之间的矛盾,这类算子的优点在于,利用零点检测中具有各向同性的特点,保证了边缘的封闭性。这样处理的图像会更加符合人眼对图像的视觉效果。我希望利用所学的知识,在VS+QT 的环境中来实现它们,进一步的理解它们,能使最后得到的图像有很好的效果

3.2 系统流程图

图3-1 系统流程图 开始 打 开 文 件 选取图像 图像 处理

保存 目标图像

4总体设计

4.1 系统功能要求及说明和实现方法

这一部分是介绍系统的实现过程,叙述系统的整体框架。对系统有一个全面的认识,将它的功能和实现方法有全面的了解。

在功能上,我们主要有几个要求,第一整体风格要大方一致,结构要清晰合理,实行模块化管理,界面要清晰,要使用户一眼就能明白,方面用户操作。第二要做到开发的代码简洁,便于管理,便于修改,便于扩充。第三,有完善的数据的输入和输出,容错性好,不会因为用户的某个操作造成程序的崩溃,提示多,每一步的操作都很简单明了,都能提醒用户及时改正[11]。

实现方法,我采用的是QT5.0+vs2012+OpenCV3.0的框架,选择QT我看好的是QT5.0是一个跨平台的C++图形用户界面应用程序框架,相比原来qt5.0提升了兼容性,更加兼容OpenCV图像处理和渲染。然而QT Create的出现也方便了我对代码的编写,很多一键式的操作,给用户带来了很多便利。使用QT也就不言而喻了。

本系统主要由MyClass类和MyClass.ui类组成。在QT中有QMainWindow提供一个有菜单条、例如工具条和一个状态条的主应用程序窗口,而正是我们需要的。很直观的想法是以QMainWindow作为父类派生出MyClass类。在MyClass类中,我们实现了对图像的提取,图像格式的转换,图像的处理,图像的保存,按键监听,信号槽和界面退出等操作[12]。当然也是连接MyClass.ui界面类的。

在实现过程中,完成了对MyClass类中,对各个函数的调试和修改,对代码的注释,对帮助提示框的修改。按钮与实现功能事件一一对应,最后对程序进行打包。

4.2 系统功能模块

本系统结构分为四个模块,如图4-1所示。分别为:

文件模块:对图片文件的打开,显示在界面,图片大小的自适应,图片格式转换,保存模块:对处理后的图片文件格式转换,保存。

边缘检测模块:运用前章节所介绍的各种算子,进行图片边缘检测。

轮廓提取模块:对图像轮廓提取。

图像轮廓处理系统

图片提取保存图片边缘检测轮廓提取

图4-1 系统模块图

下面图4.2每个子模块功能图。

图4-2 图片提取功能模块图

图4-3各轮廓提取功能模块图

5详细设计

5.1 图片提取

这个模块首先是利用QT Create 创建了一个名为MyClass.ui 界面类,在类中添加了一个按钮PushButton 。然后利用QT 中的信号/槽关联一个事件函数OpenImageClicked(),在该函数中实现对图片的提取。下面为实现代码。

QString fileName = QFileDialog::getOpenFileName(this,tr("Open Image"), ".",tr("Image Files (*.png *.jpg *.bmp)")); qDebug()<<"filenames:"<label->setText(fileName);

originalimg = image.clone(); //复制克隆原图片

图片提取 读取图片 路径 转换图片格式 显示图片在UI 上

轮廓提取 读取UI 上的图片 二值化处理 轮廓提取

灰度处理 轮廓标记

qimg = MyClass::Mat2QImage(image); //转换图片格式Mat->Qimage

display(qimg); //显示图片在UI上来的label上

if(image.data) //根据图片的读取情况判断按钮的显示状态 {

ui->pushButton->setEnabled(true);

ui->pushButton_2->setEnabled(true);

}

5.2 图片边缘检测

(1)Sobel边缘算子

我们来了解一下Sobel算子在OpenCV中的实现吧。在OpenCV中,用Sobel这个函数来实现的。

void Sobel (

InputArray src,//输入图像

OutputArray dst,//输出图像

int ddepth,//输出图像的深度

int dx,//x 方向上的差分阶数

int dy,//y 方向上的差分阶数

int ksize=3,//表示Sobel核的大小(如同上面看见的矩阵),默认值为3

double scale=1,//计算导数值时可选的缩放因子,默认值为1(没有应用缩放) double delta=0,//表示在结果存入目标图像之前可选的delta值,默认值为0 int borderType=BORDER_DEFAULT );//边界模式,默认值为BORDER_DEFAULT

在这一个模块中,我依然沿用了UI-MyClass 信号/槽的模式,将UI中的Sobel检测按钮与MyClass类中的SobelImageClicked()函数相关联。然后实现Sobel边缘检测。代码如下。

void MyClass::SobelImage(int ,void *)//Sobel实现函数

{

if(!image.empty())

{

//原图,原图的灰度版,目标图

Mat g_srcImage, g_srcGrayImage,g_dstImage;

//Sobel边缘检测相关变量

Mat g_sobelGradient_X, g_sobelGradient_Y;

Mat g_sobelAbsGradient_X, g_sobelAbsGradient_Y;

int g_sobelKernelSize=1;//TrackBar位置参数

g_srcImage =image;//显示原始图

namedWindow( "Sobel边缘检测", WINDOW_AUTOSIZE ); //显示处理后的新窗口

Sobel(g_srcImage,g_sobelGradient_X,CV_16S, 1, 0, (2*g_sobelKernelSize+1), 1, 1, BORDER_DEFAULT ); // 求 X方向梯度

convertScaleAbs( g_sobelGradient_X, g_sobelAbsGradient_X );//计算绝对值,并将结果转换成8位

Sobel(g_srcImage,g_sobelGradient_Y,CV_16S, 0, 1, (2*g_sobelKernelSize+1), 1, 1, BORDER_DEFAULT ); // 求Y方向梯度

convertScaleAbs( g_sobelGradient_Y, g_sobelAbsGradient_Y );//计算绝对值,并将结果转换成8位

addWeighted( g_sobelAbsGradient_X, 0.5, g_sobelAbsGradient_Y, 0.5, 0, g_dstImage ); // 合并X和Y方向的梯度

imshow("Sobel边缘检测", g_dstImage); //显示效果图

}

else

{

QMessageBox::information(this, tr("ERROR!"),

tr("please click picture!").arg(""));//弹出错误提示框 } }

看完代码和注释后,我们大概知道了Sobel的实现过程,下面我们来看看测试结果吧。

图5-1 sobel边缘检测效果图

(2)Laplace边缘算子

现在我们来看看Laplace在OpenCV中是怎样实现的。

void Laplacian(

InputArray src,//输入图像

OutputArray dst,//输出图像

int ddepth,//输出图像的深度

int ksize=3,//表示Sobel核的大小(如同上面看见的矩阵),默认值为3

double scale=1,//计算导数值时可选的缩放因子,默认值为1(没有应用缩放) double delta=0,//表示在结果存入目标图像之前可选的delta值,默认值为0 int borderType=BORDER_DEFAULT );//边界模式,默认值为BORDER_DEFAULT

我们可以看到在这个Laplacian函数中和Sobel参数基本相同。下面我们来看看效果怎么样。如图5-2。

图5-2 Laplace边缘检测效果图

(3)Canny边缘算子

这个模块的实现也是用的上面的模式,简单明了的实现了Canny边缘算子的功能。在OpenCV中,Canny的参数与Laplace算子的参数差不多,我们来看看实现函数和其参数。

void Canny(

InputArray image,//输入图像,即源图像

OutputArray edges,//输出边缘图像,需要和源图像一样的尺寸和类型

double threshold1,//第一个滞后性阈值

double threshold2,//第而个滞后性阈值

int apertureSize=3,//表示应用Sobel算子的孔径大小,其有默认值3

bool L2gradient=false);//计算图像梯度幅值的标识,默认值为false

下面是实现代码:

void MyClass::CannyImage(int,void *)

{

if(!image.empty())

{

Mat g_srcImage, g_srcGrayImage,g_dstImage;

Mat g_cannyDetectedEdges; //canny算子的原图,二值图,目标图的声明。

int g_cannyLowThreshold=20;//canny检测处理的值,我自己设置检测程度。

g_srcImage =image;//获得UI上的图片

namedWindow( "Canny边缘检测", WINDOW_AUTOSIZE);//创建边缘检测处理后的新窗口

g_dstImage.create( g_srcImage.size(), g_srcImage.type() ); //创建与原始图像同类型和大小的矩阵(dst)

cvtColor( g_srcImage, g_srcGrayImage, CV_BGR2GRAY ); // 将原图像转换为灰度图像

blur( g_srcGrayImage, g_cannyDetectedEdges, Size(3,3) ); //使用 3x3内核来降噪

Canny(g_cannyDetectedEdges,g_cannyDetectedEdges,g_cannyLowThreshold, g_cannyLowThreshold*3, 3 );//使用canny算子处理

g_dstImage = Scalar::all(0);

g_srcImage.copyTo( g_dstImage, g_cannyDetectedEdges); //复制处理后的图像到目标图像中

imshow( "Canny边缘检测", g_dstImage ); //显示目标图像

}

else

{

QMessageBox::information(this, tr("ERROR!"),

tr("please click picture!").arg(""));//弹出帮助提示框

}

}

下面是原图和目标图的对比效果:

图5-3 Canny边缘检测效果图

5.3 图像轮廓提取

图像轮廓到底是什么?有的说轮廓就是一系列的点,也有的说就是图像中的一条曲线。我们可以根据不同的表现方法来定义不同的图像轮廓,就像同多种边缘算法都能检测出图像的边缘。我了解到在OpenCV中一般是用序列来存储轮廓信息.序列中的每个元素是就是图像曲线的一个位置反映.只要简单把轮廓想象为使用CvSeq表示的一系列的点就可以了。

在OpenCV中,我们用FindContours()函数进行轮廓提取,如下图5-4,是轮廓提取后的效果图,可以看到在图中我们设定为C为内轮廓,H为外轮廓,两种轮廓,在不同的算子实现方法中,就分别表示轮廓的外边界和内边界。在OpenCV中我们把得到的轮廓用轮廓树来表达,从而把包含关系编码到树结构中.这个图的轮廓树在根节点的轮廓叫c0,孔h00和h01是它的字子节点.这些轮廓中直接包含轮廓称为他们的子节点,以此类推.不同的

轮廓树的方式,代表不同的轮廓存储方式。

相关主题