一、综述
本节我们将来探讨关于图像处理方面的诸多技术和应用。在学完了第一个常用的工具包之后,学习这一节将更加轻松。废话不多说,切入正题。
二、平滑处理和图像形态学
1、滤波器
"平滑处理“或者也称为”模糊处理“,英文名为blurring。对于平滑处理,我们先来介绍一个重要的函数,所有的操作都由这个函数来实现。
void cvSmooth
{
const CvArr* src,
CvArr* dst,
intsmoothtype=CV_GAUSSIAN,
int param1 = 3,
int param2 = 0,
double param3 = 0,
double param4 = 0
};
如你所见,src和dst都是平滑处理的输入和输出图像。smoothtype共有5种类型,包括:CV_BLUR,CV_BLUR_NO_SCALE,CV_MEDIAN_CV_GAUSSIAN,CV_BILATERAL。下面我们挑几个介绍。
中值滤波器(CV_MEDIAN):它是一种非线性数字滤波器,经常用于去除图像或者其他信号中的杂讯。中值滤波是图像处理中的一个常用步骤,它对于斑点噪声(speckle noise)和椒盐噪音(salt-and-pepper
noise)来说尤其有用,以后我们将会介绍着两种噪声。
高斯滤波(CV_GAUSSIAN):用卷积核与输入图像的每个点进行卷积,将最终计算结果之和作为输出图像的像素值。对于高斯模糊,前2个参数代表滤波器窗口的宽度和高度可选择第三个参数来代表高斯卷积核的sigma值(其是最大宽度的四分之一)。高斯函数是单值函数,另外其宽度决定了平滑程度。
双边滤波(CV_BILATERAL):双边滤波的最大优点便是其可以做到边缘保存。进行高斯滤波的通常原因是真实图像在空间内的像素是缓慢变化的,因此临近点的像素变化不会很明显。但是随机的两个点就可能形成很大的像素差,这就是说空间上噪声点不是相互联系的。但是这种方法在接近边缘处就无效了。因此,高斯滤波会磨破边缘,而双边滤波器能够提供一种不会将边缘的平滑掉的方法,不过因此也需要更多的时间。至于应用上,这种滤波的效果大体上讲便是使画面更像一幅水彩画,也可以用于图像分割。
2、膨胀和腐蚀
膨胀是将一些图像,即为下列示例中的A部分和核B部分进行卷积。核可以是任意大小或形状,它拥有一个单独定义的参考点(anchor point)。而腐蚀是膨胀的反操作。在OpenCV中,我们用void
cvErode(IplImage* src, IplImage* dst, IplConvKernel* B = NULL,int iterations = 1);
和void cvDilate(IplImage* src, IplImage* dst, IplConvKernel* B = NULL,int iterations = 1);。
3、自定义核
通过cvCreateStrcturingElementEx函数我们可以创建自定义的IplConvKernel核。IplConvKernel的形状取值:CV_SHAPE_RECT,CV_SHAPE_CROSS,
CV_SHAPE_ELLIPSE, CV_SHAPE_CUSTOM。
4、形态学
下面我们再来介绍一个新的函数。
voidcvMorphologyEx(const CvArr* src, CvArr* dst, CvArr* temp, IplConvKernel*element, int operation, int iterations = 1)。该函数新加了2个参数,一个是temp数组一个是operation,后者用来指定形态学的操作方法。主要有:CV_MOP_OPEN,
CV_MOP_CLOSE, CV_MOP_GRADIENT, CV_MOP_TOPHAT,CV_MOP_BLASKHAT。
5、开运算和闭运算
在开运算的情况下,我们首先将其腐蚀然后膨胀。开运算通常可以用来统计二值图像中的区域数。在闭运算的情况下,我们首先将其膨胀然后腐蚀。闭运算消除了低于其邻近点的孤立点,而开运算则消除了高于其邻近点的孤立点。
6、形态学梯度
形态学梯度用来描述图像亮度变化的剧烈程度。以下是其的公式:gradient( src) = dilate (src )- erode (src)
7、礼帽和黑帽
TopHat (src) =src – open (src)
BlackHat (src) =close (src) – src
三、漫水填充
1.漫水填充的介绍
漫水填充的英文名是Flood Fill,它用来标记或者分离图像的一部分以便对其进行进一步的处理或分析。
2.函数分析
voidcvFloodFill(IplImage* img, CvPoint seedPoint, CvScalar newVal, CvScalar loDiff= cvScalarAll(0), CvScalar upDiff = cvScalarAll(0),CvConnectedComp*
comp =NULL, int flaags = 4, CvArr* mask = NULL); newVal是像素点被染色的值,如果一个像素点的值不低于被染色的相邻点减去loDiff且不高于其加上upDiff,那么这个像素点就会被染色。如果flags参数包含CV_FLOODFILL_FIXED_RANGE,这时每个像素点都将与种子点而不是相邻点比较。mask参数所代表的掩码既可以作为cvFloodFill()函数的输入值,也可以作为输出值。如果其非空,那么它必须是一个单通道、8位、像素宽度和高度均比原图像大两个像素的图像。
四、尺寸及图像金字塔
1.尺寸的调整
我们常用cvResize()函数来放大或缩小图像。该函数可以将原图像精确转换为目标图像的尺寸。cvResize()中有3种插值方式:CV_INTER_NN,
CV_INTER_LINEAR,CV_INTER_AREA,CV_INTER_CUBIC。
2.图像金字塔
图像金字塔是一个图像集合,集合中的所有图像都源于同一个原始图像,而且是通过对原始图像连续采样获得,直到达到某个终止条件才停止采样。我们常用的有高斯金字塔和拉普拉斯金字塔,分别为向下采样图像和从底层向上采样重建一个图像。
最常用的用途便是用金字塔来进行图像分割,先建立一个图像金字塔,然后建立起父与子的关系,通过这种方式,快速初始分割可以先在金字塔高层的低分辨率图像上完成,然后逐层对分割加以优化。OpenCV中用一下函数来进行此算法。
voidcvPyrSegmentation( IplImage* src, IplImage* dst, CvMemStorage* storage, CvSeq**comp, int level, double threshold1, double threshold2);关于src和dst,特别需要注意的一点是,由于图像金字塔各层的长和宽都必须是整数,所以要求起始图像的长和宽都能被2整除,并且能被2整除的次数不能少于金字塔的总层数。例如,对于5曾的金字塔,长度为48是满足要求的,因为48=2*2*2*2*3。
CvMemStorage*storage = cvCreateMemStorage()可以用来分配存储区域。
五、阈值化
1.介绍
阈值化的基本思想是将给定的一个数组,根据数组中的每个元素的值是否低于或高于阈值而进行的相关处理。
2、具体函数
doublecvThreshold(CvArr* src, CvArr* dst, double threshold, double max_value, intthreshold_type);其中的阈值的类型为:CV_THRESH_BINARY,
CV_THRESH_BINARY_INV, CV_THRESH_TRUNC,CV_THRESH_TOZERO_INV, CV_THRESH_TOZERO。
3.阈值化
最好不要对8位数组进行加法运算,因为在较高的位可能会溢出。不过可以使用加权加法算法(cvAddWeighted())对三个通道求和。cvThreshold()函数只能处理8位或浮点灰度图像。目标图像必须与源图像的类型是一致,或者为8位图像。事实上,cvThreshold()还允许源图像和目标图像是同一图像。
4.自适应阈值
针对有很强照明或反射梯度的图像,需要根据梯度进行阈值化时,自适应阈值技术非常有用。这种方法由以下函数实现:
void cvAdaptiveThreshold(CvArr* src, CvArr* dst, double max_val, intadaptive_method = CV_ADAPTIVE_THRESH_MEAN_C, int threshold_type
=CV_THRESH_BINARY, int block_size =3, double param1 = 5);