《《学习OpenCV》第5章 图像处理.ppt》由会员分享,可在线阅读,更多相关《《学习OpenCV》第5章 图像处理.ppt(71页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第5章 图像处理本章各小节目录综述平滑处理图像形态学漫水填充算法尺寸调整图像金字塔阈值化练习综述到这里,我们已经掌握了关于图像处理的所有基础知识。我们了解了OpenCV库的结构,也知道了通常用来表示图像的基本数据结构。通过熟悉HighGUI接口,我们可以运行程序并将结果显示在屏幕上。掌握了这些用来控制图像结构的基本方法,我们就可以学习更复杂的图像处理方法了。现在,我们来继续学习高级的处理方法,即把图像以“图像”的方式来处理,而不是由颜色值(或灰度值)组成的数组。在提到“图像处理”时,它的意思是:使用图像结构中所定义的高层处理方法来完成特定任务,这些任务是图形和视觉范畴的任务。平滑处理“平滑处理
2、”也称“模糊处理”(blurring),是一项简单且使用频率很高的图像处理方法。平滑处理的用途有很多,但最常见的是用来减少图像上的噪声或者失真。降低图像分辨率时,平滑处理是很重要的(在本章的“图像金字塔”部分会详细介绍这一点)。目前OpenCV可以提供五种不同的平滑操作方法,所有操作都由cvSmooth函数实现,该函数可以将用户所期望的平滑方式作为参数。void cvSmooth(const CvArr*src,CvArr*dst,int smoothtype=CV_GAUSSIAN,int param1=3,int param2=0,double param3=0,double param4
3、=0);src和dst分别是平滑操作的输入图像和结果,cvSmooth()函数包含4个参数,param1,param2,param3和param4。这些参数的含义取决于smoothtype的值,这些值可能是表5.1中列出的任何一个。(请注意,有些操作不支持in place方式的输入。in place方式意味着输入图像与结果图像是同一个图像。)表表5-1:平滑操作的各种类型平滑平滑类型型名称名称支持支持No输入入类型型输出出类型型简要介要介绍CV_BLUR简单模糊是1,38u,32f8u,32f对每个像素param1param2邻域求和,并做缩放1/(param1 param2)CV_BLUR_
4、NO_SCALE简单无缩放变换的模糊否18u16s(占8u的资源)或32f(占32f的资源大小)对每个像素的param1param2邻域求和CV_MEDIAN中值模糊否1,38u8u对图像进行核大小为parma1param2的中值滤波CV_GAUSSIAN高斯模糊是1,38u,32f8u(占8u的资源)或32f(占32f的资源)对图像进行核大小为param1param2的高斯卷积CV_BILATERAL双边滤波否1,38u8u应用双线性33滤波,颜色sigma=param1,空间sigma=param2图5.1CV_BLUR所例举的simple blur是最简单的一项操作。输出图像的每一个像素
5、是窗口中输入图像对应像素的简单平均值。simple blur支持14个图像通道,可以处理8位图像或者32位的浮点图像。图5-1:简单图像平滑处理:左边为输入图像,右边为结果图像不是所有的模糊操作的输入和结果图像类型都相同,CV_BLUR_NO_SCALE(不缩放比例而进行模糊处理)与simple blur本质上是相同的,但并没有计算其平均值的操作。因此,输入图像和结果图像必须有不同的数值精度,才能保证模糊操作不会导致错误溢出。不缩放比例的simple blur支持8位的输入图像,结果图像的数据类型必须是IPL_DEPTH_16S(CV_16S)或IPL_DEPTH_32S(CV_32S)。同样
6、的操作也可以在32位浮点图像上进行,结果图像也应该是32位浮点类型。简单无缩放变换的模糊不支持in place方式:输入图像与结果图像必须不同。(在8位和16位情况下,很明显不能用in place方式;用32位图像时,也保持这一规定。)用户选择不缩放比例的模糊操作是因为其比缩放比例的模糊操作要快一些。中值滤波器(CV_MEDIAN)Bardyn84将中心要素的正方形邻域内的每个像素值用中间像素值(不是平均像素值)替换,它可以用来处理单个通道、三个通道或者四个通道8位的图像,但不可以in place操作。中值滤波的结果见图5-2。基于平均算法的simple blur对噪声图像特别是有大的孤立点(
7、有时被称为“镜头噪声”)的图像非常敏感,即使有极少数量点存在较大差异也会导致平均值的明显波动,因此中值滤波可以通过选择中间值避免这些点的影响。下一个平滑滤波器是Gaussian filter(CV_GAUSSIAN),虽然它不是最快的,但它是最有用的滤波器。高斯滤波用卷积核与输入图像的每个点进行卷积,最终计算结果之和作为输出图像的像素值。对于高斯模糊(图5-3),前两个参数代表滤波器窗口滤波器窗口的宽度和高度,可选择的第三个参数代表卷积核的sigma值(是最大宽度的四分之一)。如果第?个参数未指定,系统将会根据窗口尺寸通过下面的方程来自动确定高斯核的各个参数。图5-3:对一维像素数组进行高斯模
8、糊参数1:滤波器宽度参数2:滤波器高度如果用户希望高斯核不对称,那么可以引入第四个参数。这样,第三个和第四个参数分别为水平方向和垂直方向的sigma值。如果第三个和第四个参数已经给出,但是前两个参数被设为0,那么窗口的尺寸会根据sigma值自动确定。高斯滤波的OpenCV的实现还为几个常见的核提供了更高的性能优化。具有标准sigma值的33,55和7 7比其他核具有更优的性能。高斯模糊支持单个通道或者三个通道的8位或32位的浮点格式图像,可以进行in place方式操作。高斯模糊的效果见图5-4。OpenCV支持的第五个也是最后一个平滑操作被称作双边滤波(bilateral filtering
9、)Tomasi98,举例见图5-5。双边滤波是“边缘保留滤波”的图像分析方法中的一种。将它与高斯平滑对比后会更容易理解。进行高斯滤波的?是真实在空间内的像素是缓慢变化的,因此临近点的像素变化不会太明显。但是随机?个点就可能形成很大的像素差(也就是说空间噪声点不是相互联系的)。正是?这一点,高斯滤波在保留信号的条件下减少噪声。遗憾的是,这种方法在接近?处就无效了,在那儿你不希望像素与相邻像素相关。因此,高斯滤波会磨平边?。而双边滤波能够提供一种不会将边缘的平滑掉的方法,但作为代价,需要更多?时间。与高斯滤波类似,双边滤波会依据每个像素及其邻域构造一个加权平均值,加权计算包括两个部分,其中第一部分
10、加权方式与高斯平滑中的相同,第二部分也属于高斯加权,但不是基于中心像素点与其他像素点的空间距离之上的加权,而是基于其他像素与中心像素的亮度差值的加权。可以将双边滤波视为高斯平滑,对相似的像素赋予较高的权重,不相似的像素赋予较小的权重。这种滤波的典型?就是使处理过的图像看上去像是一幅源图的水彩画,可用于图像的分割。双边滤波含有两个参数。第一个参数代表空域中使用的高斯核的宽度,和高斯滤波的sigma参数类似。第二个参数代表颜色域内高斯核的宽度。第二个参数越大,表明待滤波的强度(或颜色)范围越大(因此不连续的程度越高,以便保留)。图像形态学OpenCV为进行图像的形态学变换Serra83提供了快速、
11、方便的函数。基本的形态转换是膨胀与腐蚀,它们能实现多种功能:例如消除噪声、分割出独立的图像元素以及在图像中连接相邻的元素。形态学也常被用于寻找图像中的明显的极大值区域或极小值区域以及求出图像的梯度。膨胀和腐蚀膨胀和腐蚀膨胀是指将一些图像(或图像中的一部分区域,称之为A)与核(称之为B)进行卷积。核可以是任何的形状或大小,它拥有一个单独定义出来的参考点(anchor point)。多数情况下,核是一个小的中间带有参考点的实心正方形或圆盘。核可以视为模板或掩码,膨胀是求局部最大值的操作。核B与图像卷积,即计算核B覆盖的区域的像素点最大值,并把这个最大值赋值给参考点指定的像素。这样就会使图像中的高亮
12、区域逐渐增长,如图5-6所示。这样的增长就是“膨胀操作”的初衷。图5-6:形态学膨胀:在核B下取最大像素值腐蚀是膨胀的反操作。腐蚀操作要计算核区域像素的最小值。腐蚀可以通过下面的算法生成一个新的图像:当核B与图像卷积时,计算被B覆盖区域的最小像素值,并把这个值放到参考点上。腐蚀后的图像如图5-7所示。一般来说,膨胀扩展了区域A,而腐蚀缩小了区域A。此图5-7:形态腐蚀:在核B之下取最小像素值外,膨胀可以填补凹洞,腐蚀能够消除细的凸起。当然,准确的效果将取决于核,但当使用凸核时前面的说法一般是对的。在OpenCV,我们利用cvErode()和cvDilate()函数实现上述变换。void cvE
13、rode(IplImage*src,IplImage*dst,IplConvKernel*B=NULL,int iterations=1);void cvDilate(IplImage*src,IplImage*dst,IplConvKernel*B=NULL,int iterations=1);cvErode()和cvDilate()都有源图像和目标图像参数,它们都支持“in-place”操作(源图像和目标图像是同一个图像)。第三个参数是核,默认值为NULL。当为空时,所使用的是参考点位于中心的33核(我们将简单讨论如何构造核)。最后,第四个参数是迭代的次数。如果未将它设置为默认值(1),将
14、在一次函数的调用中执行多次操作。腐蚀操作的结果如图5-8所示,膨胀操作的结果如图5-9所示。腐蚀操作通常是用来消除图像中“斑点”噪声。腐蚀可以将斑点腐蚀掉,且能确保图像内的较大区域依然存在。在试图找到连通分支(即具有相似颜色或强度的像素点的大块的互相分离的区域)时通常使用膨胀操作。因为在大多数情况下一个大区域可能被噪声、阴影等类似的东西分割成多个部分,而一次轻微的膨胀又将使这些部分“融合”在一起。综上所述:当OpenCV执行cvErode()函数时,将某点p的像素值设为与p对应的核覆盖下所有点中的最小值,同样的,对于执行膨胀操作时,将取最小值换为取最大值:大家可能会想,既然之前的算法描述已经能
15、解释清楚,为什么还需要引入一个复杂的公式呢?实际上,有些读者喜欢这样的公式,更重要的是,公式可以阐明一些定性描述表达不清楚的一般性问题。我们能够注意到,如果图像不是二值的,那么膨胀和腐蚀操作起到的作用不是很明显。再看一看图5-8和图5-9,分别展示了对两个图像进行腐蚀和膨胀操作的效果。图5-8:腐蚀的结果或者“最小化”操作,亮的区域被隔离并且缩小 图5-9:膨胀的“最大化”操作:亮的区域得到了扩展和连接自定义核自定义核你不必局限于选择33方形的核。可以创建自定义的IplConvKernel核(即我们之前提到的“核B”)。这样的核由cvCreateStructuringElementEx()函数
16、创建,由cvReleaseStructuringElement()函数释放。IplConvKernel*cvCreateStructuringElementEx(int cols,int rows,int anchor_x,int anchor_y,int shape,int*values=NULL);void cvReleaseStructuringElement(IplConvKernel*element);形态核与卷积核不同,不需要任何的数值填充核。当核在图像上移动时,核的元素只需简单标明应该在哪个范围里计算最大值或最小值。参考点指定核与源图像的位置关系,同时也锁定了计算结果在目标图像中
17、的位置。当构造核时,行与列确定了所构造的矩形大小(矩形内含有结构元素),下两个参数anchor_x和anchor_y,是核的封闭矩形内参考点的横纵坐标(x,y)。第五个参数,形状shape可以取表5-2中所列的值。如果使用CV_SHAPE_CUSTOM,那么使用整数向量value在封闭矩形内定义核的形状。使用光栅扫描法读取向量,使每个元素代表封闭矩形中的不同像素。所有非零值指定在核中对应的各个像素点。如果值为空,通常会构造一个所有值为非空的矩形核。表表5-2:IplConvKernel的形状取值形状形状值含含义CV_SHAPE_RECT核是矩形CV_SHAPE_CROSS核是十字交叉形CV_S
18、HAPE_ELLIPSE核是椭圆形CV_SHAPE_CUSTOM核是用户自定义的值更通用的形态学更通用的形态学在处理布尔图像和图像掩码时,基本的腐蚀和膨胀操作通常是足够的。然而,在处理灰度或彩色图像时,往往需要一些额外的操作。更通用的cvMorphologyEx()函数提供了更多有用的操作。void cvMorphologyEx(const CvArr*src,CvArr*dst,CvArr*temp,IplConvKernel*element,int operation,int iterations=1);除了以往操作中使用过的参数:如src,dst,element和iterations外,
19、cvMorphologyEx()函数增加了两个新的参数。第一个是temp数组,它在一些操作可能会用到(参见表5-3)。使用该数组时,它应与源图像同样大小。第二个参数operation很有趣,它指定形态学操作的方法。表表5-3:cvMorphologyEx()操作选项操作名称操作名称形形态学学是否需要是否需要临时图像像CV_MOP_OPEN开运算否CV_MOP_CLOSE闭运算否CV_MOP_GRADIENT形态梯度总是CV_MOP_TOPHOT“礼帽”in-place情况下(src=dst)需要CV_MOP_BLACKHAT“黑帽”in-place情况下(src=dst)需要开运算与闭运算开运
20、算与闭运算表5-3中的前两个操作开运算和闭运算包含腐蚀和膨胀操作。在开运算的情况下,我们首先将其腐蚀然后再膨胀(图5-10)。开运算通常可以用来统计二值图像中的区域数。若已将显微镜载玻片上观察到的细胞图像作了阈值化处理,可以使用开运算将相邻的细胞分离开来,然后再计算图像中的区域(细胞)数目。在闭图5-10:形态的开运算(向上的孤立点被消除)运算的情况下,我们首先将其膨胀然后再腐蚀(图5-12)。在大多数好的连通区域分析算法中,都会用到闭运算来去除噪声引起区域。对于连通区域分析,通常先采用腐蚀或闭运算来消除纯粹由噪声引起的部分,然后用开运算来连接邻近的区域。(注意,虽然使用开运算或闭运算的结果与
21、使用腐蚀和膨胀的结果类似,但这两个新的操作能更精确地保存源图像连接的区域。)图5-12:形态闭运算的操作(消除低亮度值的孤立点)开运算和闭运算操作几乎都是“保留区域”形式的:最显著的效果是,闭运算消除了低于其邻近点的孤立点,而开运算是消除高于其邻近点的孤立点。开运算的结果如图5-11所示,闭运算的结果如图5-13所示。开运算和闭运算操作几乎都是“面积保持”形式的:最显著的效果是,闭运算消除了低于其邻近点的孤立点,而开运算是消除高于其邻近点的孤立点。开运算的结果如图5-11所示,闭运算的结果如图5-13所示。关于开运算和闭运算,最后一点需要说明的是iterations参数的意思。您可能会认为闭操
22、作执行两次,相当于执行膨胀-腐蚀-膨胀-腐蚀。但事实上,这并不是必要的。真正需要的(并且所能得到的)是膨胀-膨胀-腐蚀-腐蚀这样的过程。通过这种方式,不仅是单一的孤立点会消失,而且邻近的孤离点群也会消失。形态学梯度形态学梯度下一个可用的操作是形态学梯度。在这里我们先给出其公式,然后再解释公式的含义:gradient(src)=dilate(src)erode(src)对二值图像进行这一操作可以将团块(blob)的边缘突出出来。图5-14解释了这一操作,在测试图像上进行操作的效果如图5-15所示。图5-14:形态梯度被应用于灰度图(正如所料,在灰度值变化最剧烈的区域得到的结果数值最大)观察对灰度
23、图像的处理结果,可以获知形态学梯度操作能描述图像亮度变化的剧烈程度;这就是为什么把其称为“形态学梯度”的原因。当我们想突出高亮区域的外围时,通常可使用形态学梯度,这样我们可以把高亮的看成一个整体(或物体的一整部分)。因为从原区域的膨胀中减去了原区域的收缩,所以留下了完整的外围边缘。这与计算梯度有所不同,梯度一般不能获得物体的外围边缘。礼帽和黑帽礼帽和黑帽最后两个操作被称为礼帽(Top Hat)和黑帽变换(Black Hat)Meyer78。这些操作分别用于分离比邻近的点亮或暗的一些斑块。当试图孤立的部分相对于其邻近的部分有亮度变化时,就可以使用这些方法。例如常用与处理有机组织或细胞的显微镜图像
24、。这是两个操作都是基本的操作组合,定义如下:TopHat(src)=src-open(src)BlackHat(src)=close(src)-src可以看出,礼帽操作从A中减去了A的开运算。开运算带来的结果是放大裂缝或局部低亮度区域,因此,从A中减去open(A)可以突出比A周围的区域更明亮的区域,并跟核的大小相关(参见图5-16);相反地,黑帽操作突出比A的周围的区域黑暗的区域(图5-17)。在本章讨论的所有形态操作的结果均可参见图5-18。图5-17:形态学“黑帽”操作的效果(黑色“洞”被分割出)图5-18:所有形态学算子操作的效果汇总漫水填充算法漫水填充(Flood Fill)Heck
25、bert00;Shaw04;Vandevenne04是一个非常有用的功能,它经常被用来标记或分离图像的一部分以便对其进行进一步处理或分析。漫水填充也可以用来从输入图像获取掩码区域,掩码会加速处理过程,或只处理掩码指定的像素点。cvFloodFill函数本身也包含一个可选的掩码参数,用来进一步控制哪些区域将被填充颜色(例如当对同一图像进行多次填充时)。在OpenCV里,漫水填充是填充算法中最通用的方法,也许你看到这里已经将其与典型的计算机绘图程序联系起来。对于两种程序来说,都必须在图像上选择一个种子点,然后把邻近区域所有相似点填充上同样的颜色,不同的是不一定将所有的邻近像素点都被染成同一颜色,漫
26、水填充操作的结果总是某个连续的区域。当邻近像素点位于给定的范围(从loDiff到upDiff)内或在原始seedPoint像素值范围内时,cvFloodFill()函数将为这个点涂上颜色。可选参数mask也可以用来控制漫水法填充。该填充方法的函数原型如下所示:void cvFloodFill(IplImage*img,CvPoint seedPoint,CvScalar newVal,CvScalar loDiff=cvScalarAll(0),CvScalar upDiff=cvScalarAll(0),CvConnectedComp*comp=NULL,int flags=4,CvArr*
27、mask=NULL);img参数代表输入图像,该图像可以是8位或浮点类型的单通道或三通道图像。漫水法填充从点seedPoint开始,newVal是像素点被染色的值。如果一个像素点的值不低于被染色的相邻点减去loDiff且不高于其加上upDiff,那么该像素点就会被染色。如果flags参数包含CV_FLOODFILL_FIXED_RANGE,这时每个像素点都将与种子点而不是相邻点相比较。如果comp不是NULL,那么该CvConnectedComp结构将被设置为被填充区域的统计属性。flags参数(下文会有简短论述)有些复杂,这些参数决定填充的连通性、相关性、是否只填充掩码区域及用来填充的值。我
28、们第一个漫水填充例子见图5-19。这里mask参数所代表的掩码既可以作为cvFloodFill()函数的输入值(此时它控制可以被填充的区域),也可以作为cvFloodFill()函数的输出值(此时它指已经被填充图5-19:漫水填充的效果(上方图像用灰色填充,下方图像用白色填充),从位于两个图像中心旁的黑色圆形区域开始填充;此处hiDiff与loDiff参数均设为7.0的区域)。如果mask非空,那么它必须是一个单通道、8位、像素宽度和高度均比源图像大两倍的图像(这是为了使内部运算更简单快速)。mask图像的像素(x+1,y+1)与源图像的像素(x,y)相对应。注意,cvFloodFill()不
29、会覆盖mask的非0像素点,因此如果不希望mask阻碍填充操作时,将其中元素设为0。源图像img和掩码图像mask均可以用漫水填充来染色。注意:如果漫水填充的掩码不为空,那么要用flags参数的中间比特值(第815位)来填充掩码图像(参考下文)。如果没有设置值flags中间比特值,则取默认值1。如果填充了掩码后显示出来是黑色,不要感到奇怪,因为所设置的值(如果flags的中间值没有被设置)为1,所以如果要显示它,必须需要放大这个掩码图像的数值。下面讲一下flags参数。此参数包含三部分,因为它比较复杂。低8位部分(第07位)可以设为4或8,这个参数控制填充算法的连通性。如果设为4,填充算法只考
30、虑当前像素水平方向和垂直方向的相邻点;如果设为8,除上述相邻点外,还会包含对角线方向的相邻点。高8位部分(第1623位)可以设为CV_FLOODFILL_FIXED_RANGE(如果设置为这个值,则只有当某个相邻点与种子像素之间的差值在指定范围内才填充,否则考虑当前点与其相邻点)或者CV_FLOODFILL_MASK_ONLY(如果设置,函数不填充原始图像,而去填充掩码图像)。很明显,如果设为CV_FLOODFILL_MASK_ONLY,必须输入符合要求的掩码。flags的中间比特(第815位)的值指定填充掩码图像的值。但如果中间比特值为0,则掩码将用1填充。所有flags可以通过OR操作连接
31、起来。例如,如果想用8邻域填充,并填充固定像素值范围,是填充掩码而不是填充源图像,以及设填充值为47,那么输入的参数应该是:flags=8|CV_FLOODFILL_MASK_ONLY|CV_FLOODFILL_FIXED_RANGE|(47total;for(int i=0;iT)?M:0CV_THRESH_BINARY_INVdsti=(srciT)?0:MCV_THRESH_TRUNCdsti=(srciT)?M:srciCV_THRESH_TOZERO_INVdsti=(srciT)?0:srciCV_THRESH_TOZEROdsti=(srciT)?srci:0三个通道求和,然后在
32、值为100处对结果图像进行截断。例例5-2:cvThreshold()函数的用法图5-23:在cvThreshold()中不同阈值类型的操作结果。每个图表的水平虚线代表应用到最上方图的阈值,5种阈值类型的操作结果列于其后void sum_rgb(IplImage*src,IplImage*dst)/Allocate individual image planes.IplImage*r=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);IplImage*g=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);IplIm
33、age*b=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);/Split image onto the color planes.cvSplit(src,r,g,b,NULL);/Temporary storageIplImage*s=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);/Add equally weighted rgb values.cvAddWeighted(r,1./3.,g,1./3.,0.0,s);cvAddWeighted(s,2./3.,b,1./3.,0.0,s);/Truncate
34、 values above 100cvThreshold(s,dst,150,100,CV_THRESH_TRUNC);cvReleaseImage(&r);cvReleaseImage(&g);cvReleaseImage(&b);cvReleaseImage(&s);int main(int argc,char*argv)/Create a named window with the name of the file.cvNamedWindow(Threshold,1);/Load the image from the given file name.IplImage*src=cvLoad
35、Image(E:Picturesportrait.png);IplImage*dst=cvCreateImage(cvGetSize(src),src-depth,1);sum_rgb(src,dst);/Show the image in the named windowcvShowImage(Threshold,dst);/Idle until the user hits the Esc key.while(1)if(cvWaitKey(10)&0 x7f)=27)break;/Clean up and dont be piggiescvDestroyWindow(Threshold);c
36、vReleaseImage(&src);cvReleaseImage(&dst);这里包含几个重要的思想。第一,我们通常不会对8位数组进行加法运算,因为较高的位可能会溢出。取而代之,我们使用加权加法算法(cvAddWeighted())对三个通道求和;然后对结果以100为阈值进行截断处理然后返回。cvThreshold()函数只能处理8位或浮点灰度图像。图标图像必须与源图像的类型一致,或者为8位图像。事实上,cvThreshold()还允许源图像和目标图像是同一图像。如果我们在例5-2中使用了临时浮点图像s,例5-3中有等价的代码。注意,cvAcc()可以将8位整数类型图像累加为浮点图像;然而
37、,cvADD()却不能将整数与浮点数相加。例例5-3:另一种组合不同通道,并阈值化图像的方法IplImage*s=cvCreateImage(cvGetSize(src),IPL_DEPTH_32F,1);cvZero(s);cvAcc(b,s);cvAcc(g,s);cvAcc(r,s);cvThreshold(s,s,200,100,CV_THRESH_TRUNC);cvConvertScale(s,dst,1,0);自适应阈值自适应阈值这是一种改进了的阈值技术,其中阈值本身是一个变量。在OpenCV中,这种方法由函数cvAdaptiveThreshold()Jain86来实现:void
38、cvAdaptiveThreshold(CvArr*src,CvArr*dst,double max_val,int adaptive_method=CV_ADAPTIVE_THRESH_MEAN_C,int threshold_type=CV_THRESH_BINARY,int block_size=3,double param1=5);cvAdaptiveThreshold()有两种不同的自适应阈值方法,可以用参数adaptive_method进行设置。在这两种情况下,自适应阈值T(x,y)在每个像素点都不同。通过计算像素点周围的bb区域的加权平均,然后减去一个常数来得到自适应阈值,b由参
39、数block_size指定,常数由param1指定。如果使用CV_ADAPTIVE_THRESH_MEAN_C方法,那么对区域的所有像素平均加权。如果使用了CV_ADAPTIVE_THRESH_GAUSSIAN_C方法,那么区域中的(x,y)周围的像素根据高斯函数按照它们离中心点的距离进行加权计算。最后,参数threshold_type和表5-5所示的cvThreshold()的参数threshold_type是一样的。针对有很强照明或反射梯度的图像,需要根据梯度进行阈值化时,自适应阈值技术非常有用。此函数只能处理单通道8位图像或浮点图像,它要求源图像和目标图像不能使用同一图像。使用函数cvA
40、daptiveThreshold()和cvThreshold()进行比较的源代码在例5-4中。图5-24显示了对有很强的照明梯度图像的处理结果。图的左下部分显示了使用单一的全局阈值方法cvThreshold()的结果;图的右下部分显示了使用自适应局部阈值cvAdaptiveThreshold()的结果。我们通过自适应阈值得到了整个棋盘格,而在使用单一的阈值时是不能获得。请注意例5-4中代码顶部的使用说明;图5-24所用的参数如下:./adaptThresh 15 1 1 71 15./Data/cal3-L.bmp例例5-4:单一阈值与自适应阈值 图5-24:二值阈值化与自适应二值阈值化。输入
41、图像(上图)使用全局阈值时的二值图像(左下图)和使用自适应阈值时的二值图像(右下图)感谢Kurt Konolidge提供原始图像/Compare thresholding with adaptive thresholding/CALL:/./adaptThreshold Threshold lbinary ladaptivemean/blocksize offset filenameIplImage*Igray=0,*It=0,*Iat;int main(int argc,char*argv)/if(argc!=7)return-1;/7个参数?/Command linedouble thre
42、shold=100;/(double)atof(argv1);/阈值int threshold_type=CV_THRESH_BINARY;/atoi(argv2)?CV_THRESH_BINARY:CV_THRESH_BINARY_INV;/threshold_type阈值类型int adaptive_method=CV_ADAPTIVE_THRESH_MEAN_C;/atoi(argv3)?CV_ADAPTIVE_THRESH_MEAN_C:CV_ADAPTIVE_THRESH_GAUSSIAN_C;/自适应阈值类型int block_size=5;/atoi(argv4);/block_
43、size尺寸大小double offset=2;/(double)atof(argv5);/平移/Read in gray imageif(Igray=cvLoadImage(E:测绘科学与技术SLAMOpenCV学习OpenCV(中文版)随书源码LearningOpenCV_CodeOpenCV_Chessboard.png,CV_LOAD_IMAGE_GRAYSCALE)=0)/argv6 加载图像return-1;/Create the grayscale output imagesIt=cvCreateImage(cvSize(Igray-width,Igray-height),IPL
44、_DEPTH_8U,1);Iat=cvCreateImage(cvSize(Igray-width,Igray-height),IPL_DEPTH_8U,1);/ThresholdcvThreshold(Igray,It,threshold,255,threshold_type);cvAdaptiveThreshold(Igray,Iat,255,adaptive_method,threshold_type,block_size,offset);/PUT UP 2 WINDOWScvNamedWindow(Raw,1);cvNamedWindow(Threshold,1);cvNamedWin
45、dow(Adaptive Threshold,1);/Show the resultscvShowImage(Raw,Igray);cvShowImage(Threshold,It);cvShowImage(Adaptive Threshold,Iat);cvWaitKey(0);/Clean upcvReleaseImage(&Igray);cvReleaseImage(&It);cvReleaseImage(&Iat);cvDestroyWindow(Raw);cvDestroyWindow(Threshold);cvDestroyWindow(Adaptive Threshold);return(0);