美文网首页
OpenCV:十四、Sobel边缘检测

OpenCV:十四、Sobel边缘检测

作者: 马洪滔 | 来源:发表于2021-01-15 20:17 被阅读0次

    前言

    在上一章中描述了图像处理边缘,详细描述可点击查看(https://www.jianshu.com/writer#/notebooks/47386368/notes/81791428)

    目标

    本章中,将学习:

    • 卷积应用-图像边缘提取
    • 相关API
    • 代码演示

    卷积应用-图像边缘提取

    • 边缘是什么 - 是像素值发生跃迁的地方,是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要的作用。
    • 如何捕捉/提取边缘 - 对图像求它的一阶导数delta = f(x) - f(x-1),delta越大,说明像素在X方向变化越大,边缘信号越强。


      图像边缘.png
    • Sobel算子是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度;Sobel算子功能集合高斯平滑和微分求导,又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方向和Y方向梯度图像。
    • Sobel算子检测方法对灰度渐变和噪声较多的图像处理效果好,Sobel算子对边缘定位不是很准确,图像的边缘不止一个像素;当对精度要求不是很高时,是一种较为常见的边缘检测方法。算子如下:


      图像梯度.png

      得到了两个新的矩阵,分别反映了每一个点像素在水平方向上的亮度变化情况和在垂直方向上的亮度变化情况,综合考虑这两个方向的变化,我们使用最终图像梯度,反映某个像素的梯度变化情况,为了节省时间,一般使用其绝对值相加替代。

    • Sobel算子求取导数的近似值,但Kernel = 3时不是很准确,OpenCV使用改进版本Scharr函数,算子如下:


      Scharr函数.png

    相关API说明

    void Sobel (  
    InputArray src,//输入图  
     OutputArray dst,//输出图  
     int ddepth,//输出图像的深度  
     int dx,  
     int dy,  
     int ksize=3,  
     double scale=1,  
     double delta=0,  
     int borderType=BORDER_DEFAULT );  
    
    • 第一个参数,InputArray 类型的src,为输入图像,填Mat类型即可。
    • 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
    • 第三个参数,int类型的ddepth,输出图像的深度,支持如下src.depth()和ddepth的组合:
      若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F
      若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
      若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F
      若src.depth() = CV_64F, 取ddepth = -1/CV_64F
    • 第四个参数,int类型dx,x 方向上的差分阶数。
    • 第五个参数,int类型dy,y方向上的差分阶数。
    • 第六个参数,int类型ksize,有默认值3,表示Sobel核的大小;必须取1,3,5或7(奇数)。
    • 第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。
    • 第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
    • 第九个参数, int类型的borderType,边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。

    代码演示

    using namespace cv;
    using namespace std;
    
    int main(int argc, char* argv[])
    {
        //  1、加载图像,可以是BGR或者灰度图像
        Mat src = imread("/hsdf.png");
        if (!src.data) {
            printf("could not load image...\n");
            return -1;
        }
         src = cv.GaussianBlur(src, (3, 3), 0);
             gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY);
    
             grad_x = cv.Sobel(gray, -1, 1, 0, ksize=3);
             grad_y = cv.Sobel(gray, -1, 0, 1, ksize=3);
    
             grad  = cv.addWeighted(grad_x, 0.5, grad_y, 0.5, 0);
             cv.imshow("origin",src);
             cv.imshow("grad",grad);
             cv.waitKey();
         imshow(output_win, dst);
         waitKey(0);
        return 0;
    }
    
    结果图像.png

    首先是高斯模糊去噪.某种意义上说高斯模糊是和sobel相反的过程.高斯模糊平滑了某点像素与周边像素的差异.那为什么还要先高斯去噪呢?
    噪声就是像素的强度相对于真值有个突变。从时域上讲,通过高斯滤波能让一个像素的强度与周围的点相关,就减小了突变的影响;从频域上讲,突变引入了高频分量,而高斯滤波器可以滤除高频分量。
    高斯去噪是为了防止把噪点也检测为边缘.
    然后计算grad_x,grad_y.即对原图做水平方向/垂直方向的sobel卷积核卷积
    最后将两个矩阵叠加,综合考虑水平和垂直方向的像素灰度值变化强度.得到边缘.

    相关文章

      网友评论

          本文标题:OpenCV:十四、Sobel边缘检测

          本文链接:https://www.haomeiwen.com/subject/dfixaktx.html