您的位置:首页 > 运维架构

opencv-第六章-图像变换之sobel算子

2015-10-27 11:03 330 查看
opencv-第六章-图像变换
第5章介绍了许多类型的图像处理方法。迄今为止,所介绍的大多数数据操作都用于增强、修改或者“处理”图像,使之成为类似但全新的图像。

本章将关注图像变换(即将一幅图像转变成图像数据)的另一种表现形式。变换最常见的例子就是傅里叶变换,即将图像转换成源图像数据的另一种表示。这类操作的结果仍然保存为opencv图像结构的形式。

卷积

卷积是本章所讨论的很多变换的基础。从抽象的层次说,这个术语意味着我们要对图像的每一个部分进行操作。从这个意义上讲,我们在第5章所看到的许多操作可以被理解成普通卷积的特殊情况。一个特殊卷积所实现的功能是由其卷积核的形式决定的。这个核本质上是一个大小固定、由数值参数构成的数组,数组的参考点通常位于数组的中心。数组的大小称为核支撑。单就技术而言,核支撑实际上仅仅由核数组的非0部分组成。

opencv利用这个函数实现卷积操作。

void cvFilter2D( const CvArr* src, CvArr* dst, const CvMat* kernel, CvPoint anchor=cvPoint(-1,-1));

#define cvConvolve2D cvFilter2D

src

输入图像.

dst

输出图像.

kernel

卷积核, 单通道浮点矩阵. 如果想要应用不同的核于不同的通道,先用 cvSplit 函数分解图像到单个色彩通道上,然后单独处理。

anchor

核的锚点表示一个被滤波的点在核内的位置。 锚点应该处于核内部。缺省值 (-1,-1) 表示锚点在核中心。

函数 cvFilter2D 对图像进行线性滤波,支持 In-place 操作。当核运算部分超出输入图像时,函数从最近邻的图像内部象素差值得到边界外面的象素值。

源图像src和目标图像dst大小应该相同,有些人可能认为考虑到卷积核的额外的长和宽,源图像src应该大于目标图像dst。但是在opencv里源图像src和目标图像dst的大小是可以一样的,因为在默认情况下,在卷积之前,opencv通过复制源图像src的边界创建了虚拟像素,这样以便于目标图像dst边界的像素可以被填充。复制是通过input(-dx,y)=input(0,y),input(w+dx,y)=input(w-1,y)等实现的,此默认行为还有一些替代方法。

卷积边界

对于卷积,一个很自然的问题是如何吃力卷积边界。例如,在使用刚才所讨论的卷积核时,当卷积点在图像边界时会发生什么?许多使用cvFiler2D()的opencv内置函数必须用各种方式来解决这个问题。同样在做卷积时,有必要知道如何有效解决这个问题。

这个解决方法就是使用cvCopyMakeBorder()函数,它可以将特定的图像轻微变大,然后以各种方法自动填充图像边界。

void cvCopyMakeBorder(const CvArr* src, CvArr* dst, CvPoint offset,

int bordertype, CvScalar value= cvScalarAll(0));

offset变量告诉cvCopyMakeBorder将源图像的副本放到目标图像中的位置。典型情况是,如果核为NxN(N为奇数)时,那么边界在每一侧的宽度都应是(N-1)/2,即这副图像比源图像宽或高N-1.在这种情况下,可以把offset设置为cvPoint((N-1)/2,(N-1)/2),使得边界在每一侧都是偶数。

当调用opencv库函数中的卷积功能时,cvCopyMakeBorder函数就会调用。在大多数情况下,边界类型为IPL_BORDER_REPLICATE,但有时并不希望用它,所以在另一种场合,可能用到cvCopyMakeBorder。你可以创建一幅具有比想要得到的边界稍微大一些的图像,无论调用任何常规操作,接下来就可以剪切到对源图像所感兴趣的部分。这样一来,opencv的自动加边就不会影响到所关心的像素。

梯度和sobel导数

通常来说,用来表达微分的最常用的操作时sobel微分算子,sobel算子包含任何阶的微分以及融合偏导。

cvSobel(const CvArr* src, CvArr* dst, int xorder,

int yorder,int aperture_size=3);

这里,src和dst分别是输入图像和输出图像,xorder和yorder是求导的阶数。通常只能是0,1或2.值为0表明在这个方向上没有求导,aperture_size参数是方形滤波器的宽(或高)并且应该是奇数。目前,aperture_size支持1,3,5.7.如果源图像src是8位的,为避免溢出,目标图像的深度必须是IPL_DEPTH_16S。

sobel导数有一个非常好的性质,即可以定义任意大小的核,并且这些核可以用快速迭代方式构造。大核对导数有更好的逼近。因为小核对噪声更敏感。

为了更好地理解以上内容,我们必须认识到一点,即sobel导数并不是真正的导数,因为sobel算子定义于一个离散空间之上。sobel算子真正表示的是多项式拟合,也就是说,x方向上的二阶sobel导数并不是真正的二阶导数。它是对抛物线函数的局部拟合。这说明人们为什么想用较大的核,因为较小的核时在更多像素上计算这种拟合。

scharr滤波器

事实上,在离散网络的场合下有很多方法可以近似地计算出导数。对于小一点的核而言,这种使用于sobel算子近似计算导数的缺点是精度比较低。对于大核,由于在估计时使用了更多的点,所以这个问题并不严重。这种不精确性并不会直接在cvsobel中使用的x和y滤波器中表现出来,因为它们完全沿着x轴和y轴排列。当试图估计图像的方向导数(即,使用y/x滤波器响应的反正切得到的图像梯度的方向)时,难度就出现了。

scharr滤波器通sobel滤波器一样快,但是准确率更高,所以当你使用3x3滤波器实现图像度量的时候应该使用scharr滤波器。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: