• opencv计算图像梯度:Sobel、Scharr、Laplacian详解


    opencv计算图像梯度:Sobel、Scharr、Laplacian、Canny详解

    1.边界填充

    函数:

    void cv::copyMakeBorder	(InputArray 	src,
                             OutputArray 	dst,
                             int 	top,  
                             int 	bottom,
                             int 	left,
                             int 	right,
                             int 	borderType, //填充类型
                             const Scalar & value = Scalar() //填充颜色 
    )		
    Python:
    cv.copyMakeBorder(	src, top, bottom, left, right, borderType[, dst[, value]]	) ->	dst
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    填充类型:

    • BORDER_CONSTANT:用固定值填充图像
    • BORDER_REPLICATE:原始边界最边缘的行或列被复制到额外的边界。

    使用如下:

    RNG rng(12345);
    int top, bottom, left, right;
    int borderType = BORDER_CONSTANT;
    // Initialize arguments for the filter
    top = (int) (0.05*src.rows); bottom = top;
    left = (int) (0.05*src.cols); right = left;
    
    Scalar value( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) );
    copyMakeBorder( src, dst, top, bottom, left, right, borderType, value );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    2. Sobel算子

    边缘检测原理如下图所示:
    在这里插入图片描述
    数学原理:
    在这里插入图片描述
    函数:

    void cv::Sobel	(InputArray 	src,
                     OutputArray 	dst,
                     int 	ddepth,  
                     int 	dx,    //x方向
                     int 	dy,    //y方向
                     int 	ksize = 3, //核大小
                     double 	scale = 1,
                     double 	delta = 0,
                     int 	borderType = BORDER_DEFAULT 
    )		
    Python:
    cv.Sobel(	src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]	) ->	dst
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    变换函数:

    void cv::convertScaleAbs( InputArray 	src,
                              OutputArray 	dst,
                              double 	alpha = 1,  //对比度
                              double 	beta = 0  //亮度
    )		
    Python:
    cv.convertScaleAbs(	src[, dst[, alpha[, beta]]]	) ->	dst
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    变换原理:
    在这里插入图片描述
    求梯度:

    cvtColor(src, src_gray, COLOR_BGR2GRAY);
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;
    Sobel(src_gray, grad_x, ddepth, 1, 0, ksize, scale, delta, BORDER_DEFAULT);
    Sobel(src_gray, grad_y, ddepth, 0, 1, ksize, scale, delta, BORDER_DEFAULT);
    // converting back to CV_8U
    convertScaleAbs(grad_x, abs_grad_x);
    convertScaleAbs(grad_y, abs_grad_y);
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    3. Scharr算子

    函数接口:

    void cv::Scharr	(InputArray 	src,
                     OutputArray 	dst,
                     int 	ddepth,
                     int 	dx,
                     int 	dy,
                     double 	scale = 1,
                     double 	delta = 0,
                     int 	borderType = BORDER_DEFAULT 
    )		
    Python:
    cv.Scharr(	src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]]	) ->	dst
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    当核的大小为3时,上面所示的Sobel核可能产生明显的不准确性(毕竟,Sobel只是导数的近似值)。OpenCV通过使用Scharr()函数解决了大小为3的内核的不准确性问题。这与标准Sobel函数一样快,但更准确。它实现了以下内核:
    在这里插入图片描述
    求梯度时,与Sobel算子实现代码相同,下边给出边缘检测应用:

    Mat dx,dy;
    Scharr(blurImage,dx,CV_16S,1,0);
    Scharr(blurImage,dy,CV_16S,0,1);
    Canny( dx,dy, edge2, edgeThreshScharr, edgeThreshScharr*3 );
    cedge = Scalar::all(0);
    image.copyTo(cedge, edge2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4. Laplacian算子

    图形化数学原理:
    在这里插入图片描述

    void cv::Laplacian(	InputArray 	src,
                        OutputArray 	dst,
                        int 	ddepth,
                        int 	ksize = 1,
                        double 	scale = 1,
                        double 	delta = 0,
                        int 	borderType = BORDER_DEFAULT 
    )		
    Python:
    cv.Laplacian(	src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]]	) ->	dst
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    求梯度实现:

    cvtColor( src, src_gray, COLOR_BGR2GRAY ); // Convert the image to grayscale
    Mat abs_dst;
    Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );
    // converting back to CV_8U
    convertScaleAbs( dst, abs_dst );
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    5.Canny

    边缘检测算法步骤:

    • 先经过高斯平滑,目的是去噪声

    • 寻找图像强度梯度

    • 非极大值抑制
      上一步算出来的边缘可能比较粗糙,假设边缘是一条很细的线的话,上面处理完的结果你可以理解为得到一条比较粗的线条,所谓非极大值抑制,就是要在局部像素点中找到变换最剧烈的一个点,这样就得到了更细的边缘.

    • 双阈值检测和连接边缘

    void Canny(cv::InputArray src, 
                cv::OutputArray dst,
                double threshold1,  //梯度小于minVal的像素点弃用,不视为边缘
                double threshold2,  //梯度大于maxVal的像素点保留,视为边缘
                int aperture_size=3   
              );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    详细参考:
    https://blog.csdn.net/Vermont_/article/details/108471205
    https://blog.csdn.net/xddwz/article/details/111585648

    #include 
    #include 
    #include 
    #include 
    #include 
     
    using namespace std;
    using namespace cv;
    int main() {
        Mat srcImage, grayImage;
        srcImage = imread("/Users/dwz/Desktop/cpp/1.jpg");
        Mat srcImage1 = srcImage.clone();
        cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
        Mat dstImage, edge;
     
        blur(grayImage, grayImage, Size(3,3));
        Canny(grayImage, edge, 150, 100, 3);
     
        dstImage.create(srcImage1.size(), srcImage1.type());
        dstImage = Scalar::all(0);
        srcImage1.copyTo(dstImage, edge);
        imwrite("canny.jpg", dstImage);
     
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    6.总结

    • 研究这个算子是想将其放在特征匹配前,通过对原始图像求出梯度,分析梯度图像的灰度信息特征来进行特征提取,发现加入梯度求解后算法耗时增加,二维卷积确实引进了不少耗时,竟然要高于同样尺寸大小的模板匹配
    • 梯度算子对于提取图像中的关键特征具有重要作用,是作为轮廓提取的重要步骤
    • 通常情况下,二维算子的效果要强于一维算子效果。
  • 相关阅读:
    微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍
    [工业互联-8]:PLD编程快速概览、PLD五种编程语言与七款常见的PLC编程软件
    STL-queue的使用及其模拟实现
    C语言详解系列——关于调试那些事
    Eavesdropping(窃听机制)在机器学习中的用法
    基于单片机的脉搏测量仪毕业设计
    博客网页制作基础大二dw作业 web课程设计网页制作 个人网页设计与实现 我的个人博客网页开发
    【使用jquery编写第一个油猴(tempermonkey)脚本】
    人工智能将彻底改变营销行业的4种方式
    JUC并发编程与源码分析笔记02-线程基础知识复习
  • 原文地址:https://blog.csdn.net/yohnyang/article/details/127688747