• OpenCV-C++ Sobel算子使用


    Sobel算子

    Sobel算子主要用于边缘检测;

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

    sobel算子:

    • 是离散微分算子,用来计算图像灰度的近似梯度
    • sobel算子功能集合高斯平滑和微分求导;
    • 又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像x方法与y方向梯度图像;

    那么最终的图像梯度:

    [G = sqrt{G_x^2+G_y^2} ]

    可以近似为:

    [G = |G_x| + |G_y| ]

    改进的版本Scharr算子:

    当内核大小为3时,以上Sobel可能产生比较明显的误差(毕竟,Sobel算子只是求取了导数的近似值),为了解决这一问题,OpenCV提供了Scharr函数,但该函数仅作用域大小为3的内核;计算速度与Sobel函数一样快,但结果更加精确,不怕干扰,其内核为:

    图像边缘提取

    使用Sobel算子提取图像边缘,包含以下四个步骤:

    1. 对图像进行高斯模糊;
    2. 将图像转换到灰度空间;
    3. 利用Sobel算子或者Scharr算子计算图像梯度;
    4. 利用提取的梯度,调整图像灰度值,提取图像边缘;

    Sobel算子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 );
    
    • src表示输入的灰度图像
    • dst表示输出的梯度;
    • ddepth表示输出梯度的数据类型,必须大于输入的图像数据类型,关系如下图所示:

    • dx=1, dy=0表示对x方向计算梯度;
    • dx=0, dy=1表示对y方向计算梯度;

    Scharr算子的使用方式:

    void Scharr( InputArray src, OutputArray dst, int ddepth,
                int dx, int dy, double scale = 1, double delta = 0,
                int borderType = BORDER_DEFAULT );
    
    • 参数与Sobel算子基本一致;
    • 但是不需要设置核的大小,因为Scharr默认就是3;

    完成代码如下:

    #include <iostream>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    /**
     * 边缘处理
    */
    
    int main(){
        // 读取图像
        Mat src = imread("/home/chen/dataset/lena.jpg");
        if (src.empty()){
            cout << "could not load image." << endl;
            return -1;
        }
        namedWindow("src", WINDOW_AUTOSIZE);
        imshow("src", src); 
    
        // 1. 高斯模糊
        Mat srcBlur;
        GaussianBlur(src, srcBlur, Size(3, 3), 0, 0);
    
        // 2. 转灰度
        Mat srcGray;
        cvtColor(srcBlur, srcGray, COLOR_BGR2GRAY);
    
        // 3. 求方向梯度
        Mat gradX, gradY;
        Sobel(srcGray, gradX, CV_16S, 1, 0, 3);
        Sobel(srcGray, gradY, CV_16S, 0, 1, 3);
        // Scharr(srcGray, gradX, CV_16S, 1, 0);
        // Scharr(srcGray, gradY, CV_16S, 0, 1);
        convertScaleAbs(gradX, gradX);  // calculates absolute values, and converts the result to 8-bit.
        convertScaleAbs(gradY, gradY);
        namedWindow("gradY", WINDOW_AUTOSIZE);
        imshow("gradX", gradX);
        namedWindow("gradY", WINDOW_AUTOSIZE);
        imshow("gradY", gradY);
    
        printf("type: %d, %d", gradX.type(), gradY.type());
    
        // 4. 图像混合
        Mat dst;
        addWeighted(gradX, 0.5, gradY, 0.5, 0, dst);
        namedWindow("dst", WINDOW_AUTOSIZE);
        imshow("dst", dst);
    
        // 4.1 
        Mat gradXY = Mat(gradX.size(), gradX.type());
        for (int row = 0; row < gradX.rows; row++){
            for (int col = 0; col < gradX.cols; col++){
                int gX = gradX.at<uchar>(row, col);
                int gY = gradY.at<uchar>(row, col);
                gradXY.at<uchar>(row, col) = saturate_cast<uchar>(gX + gY);
            }
        }
        namedWindow("gradXY", WINDOW_AUTOSIZE);
        imshow("gradXY", gradXY);
      
        waitKey(0);
        return 0;
    }
    
    • 使用Sobel的结果

    • 使用Scharr算子的结果

  • 相关阅读:
    SpringCloud Alibaba整合Sentinel
    Jmter入门教程
    惊!!!笔记本外接显示器,显示器界面不能充满全屏
    js-使用attr()方法
    关于JS的assign() 方法
    《转》webpack+vue+vueRouter模块化构建完整项目实例超详细步骤(附截图、代码、入门篇)
    元素水平垂直居中的四种方式(别人文章)
    关于截取字符串substr和substring两者的区别
    JavaScript三种弹出框(alert,confirm和prompt)用法举例
    ::before和::after伪元素的用法
  • 原文地址:https://www.cnblogs.com/chenzhen0530/p/14660498.html
Copyright © 2020-2023  润新知