介绍最简单的梯度的方法。

     检测边缘:以灰度图像为例,它的理论基础是这样的:如果出现一个边缘,那么图像的灰度就会有一定的变化。

     为了方便假设由黑渐变为白代表一个边界,那么对其灰度分析,在边缘的灰度函数就是一个一次函数y=kx,对其求一阶导数就是其斜率k,就是说边缘的一阶导数是一个常数,而由于非边缘的一阶导数为零,这样通过求一阶导数就能初步判断图像的边缘了。通常是X方向和Y方向的导数,也就是梯度。计算机就是通过这种方式来获得图像的边缘。


     但是,具体应用到图像中你会发现这个导数是不现实的,因为没一个准确的函数让你去求导,而且计算机在求解析解要比求数值解麻烦得多,所以就想到了一种替代的方式来求导数。就是用一个3×3的窗口来对图像进行近似求导。以X方向求导为例,某一点的导数为第三列的元素之和减去第一列元素之和,这样就求得了某一点的近似导数。导数就代表一个变化率,从第一列变为第三列,灰度值相减,当然就是一个变化率了。这就是所谓的Prewitt算子。这样近似X方向导数就求出来了。Y方向导数与X方向导数求法相似,只不过是用第三行元素之和减去第一行元素之和。X方向和Y方向导数有了,那么梯度也就出来了。这样就可以找出一幅图中的边缘了。

由于求的是3×3中心点的导数,所以给第二列加了一个权重,它的权重为2,第一列和第三列的权重为1,好了,这就是Sobel算子了。相比Prewitt算子,Sobel的抗噪能力更强。如图所示:


Sobel算子(cvSobel)边缘检测_差分

这样,中心点的Y方向导数就求出来了。

举个例子吧。


Sobel算子(cvSobel)边缘检测_权重_02

X点以Sobel方式求导数ΔX=1×50+2×30+1×50-(1×50+2×30+1×50)=0。这样可以看出这个点不是边界。

OpenCv下的Sobel函数:

    void  cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, intaperture_size=3 );

    src:输入图像;

    dst:输出图像;

    xorder:x方向上的差分阶数;

    yorder:y方向上的差分阶数;

   aperture_size扩展Sobel核的大小(既窗口阶数),必须是1(注意这是一个3×1或1×3向量而不是一个方阵),3, 5 或7。