• 『OpenCV3』滤波器边缘检测


    一、原理简介

    边缘检测原理 - Sobel, Laplace, Canny算子

    X方向Sobel算子

    -1 -2 -1
    0 0 0
    1 2 1

    Y方向Sobel算子

    -1 0 1
    -2 0 2
    -1 0 1

    Laplace算子

    1 1 1
    1 -8 1
    1 1 1

    Canny 边缘检测算子

    高斯滤波器平滑图像

    一阶差分偏导计算梯度值和方向

    对梯度值不是极大值的地方进行抑制

    用双阈值连接图上的联通点

    通俗说一下,
    1.用高斯滤波主要是去掉图像上的噪声。
    2.计算一阶差分,OpenCV 源码中也是用 sobel 算子来算的。
    3.算出来的梯度值,把不是极值的点,全部置0,去掉了大部分弱的边缘。所以图像边缘会变细。
    4.双阈值 t1, t2, 是这样的,t1 <= t2
    大于 t2 的点肯定是边缘
    小于 t1 的点肯定不是边缘
    在 t1, t2 之间的点,通过已确定的边缘点,发起8领域方向的搜索(广搜),图中可达的是边缘,不可达的点不是边缘。
    最后得出 canny 边缘图。

    二、代码演示

    有关函数 convertScaleAbs,文档解释如下,不过这里不使用其放缩功能

    1、Sobel 边缘检测算子

    由于需要指定横向纵向,所以分两步进行,最后组合即可,

    	cv::Mat image = cv::imread("test.jpg");
    	cv::imshow("原图", image);
    	cv::Mat gray;
    	cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
    
    	cv::Mat contours;	
            cv::Mat sobelX, sobelY;
    	cv::Sobel(
    		image,
    		sobelX,
    		CV_16S,  // 图像depth,输入8U,输出16S防止外溢
    		1, 0,   // xorder, yorder
    		3,		// 内核尺寸
    		1, 1	// 输出结果乘alpha加beta
    	);
    	cv::convertScaleAbs(sobelX, sobelX);
    	cv::imshow("Sobel_X", sobelX);
    	cv::Sobel(
    		image,
    		sobelY,
    		CV_8U,
    		0, 1,
    		3,
    		1, 1
    	);
    	cv::convertScaleAbs(sobelY, sobelY);
    	cv::imshow("Sobel_Y", sobelY);
    	cv::addWeighted(sobelX, 0.5, sobelY, 0.5, 0, contours);
    	cv::imshow("Sobel", contours);    
    

     XY单方向输出如下,

    两这合并如下,

    2、Laplace 边缘检测算子

    	// cv::Mat image = cv::imread("skin.jfif");
    	cv::Mat image = cv::imread("test.jpg");
    	cv::imshow("原图", image);
    	cv::Mat gray;
    	cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
    
    	cv::Mat contours;
            cv::GaussianBlur(gray, gray, cv::Size(5, 5), 1.5);
    	cv::Laplacian(
    		gray,
    		contours,
    		CV_16S,
    		3,  // 内核尺寸
    		1, 0 // 放缩因子
    	);
    	
    	cv::convertScaleAbs(contours, contours);
    	cv::imshow("Laplacian", contours);
    

    3、Canny 边缘检测算子

    	// cv::Mat image = cv::imread("skin.jfif");
    	cv::Mat image = cv::imread("test.jpg");
    	cv::imshow("原图", image);
    	cv::Mat gray;
    	cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
    
    	cv::Mat contours;
    	cv::GaussianBlur(gray, gray, cv::Size(5, 5), 1.5);
    	cv::Canny(
    		gray,
    		contours,
    		10,  // 低阈值
    		150   // 高阈值
    	);
    	cv::imshow("Canny", contours);
    

    高低阈值参数的设定对于检测效果影响很大,一般来说低阈值检测出十分琐碎的边缘,且设置的越低检测出来的越多,而高阈值这决定了保留多少边缘,对于上图,我们将高阈值下调至50查看一下效果,会发现保留细节数目增加了

    附录、函数总览

    void edge() {
    	// cv::Mat image = cv::imread("skin.jfif");
    	cv::Mat image = cv::imread("test.jpg");
    	cv::imshow("原图", image);
    	cv::Mat gray;
    	cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
    
    	cv::Mat contours;
    	cv::GaussianBlur(gray, gray, cv::Size(5, 5), 1.5);
    	cv::Canny(
    		gray,
    		contours,
    		10,  // 低阈值
    		150   // 高阈值
    	);
    	cv::imshow("Canny", contours);
    
    	cv::Laplacian(
    		gray,
    		contours,
    		CV_16S,
    		3,  // 内核尺寸
    		1
    	);
    	cv::Mat abs_dst;
    	cv::convertScaleAbs(contours, contours);
    	cv::imshow("Laplacian", contours);
    
    	cv::Mat sobelX, sobelY;
    	cv::Sobel(
    		image,
    		sobelX,
    		CV_16S,  // 图像depth,输入8U,输出16S防止外溢
    		1, 0,   // xorder, yorder
    		3,		// 内核尺寸
    		1, 1	// 输出结果乘alpha加beta
    	);
    	cv::convertScaleAbs(sobelX, sobelX);
    	cv::imshow("Sobel_X", sobelX);
    	cv::Sobel(
    		image,
    		sobelY,
    		CV_8U,
    		0, 1,
    		3,
    		1, 1
    	);
    	cv::convertScaleAbs(sobelY, sobelY);
    	cv::imshow("Sobel_Y", sobelY);
    	cv::addWeighted(sobelX, 0.5, sobelY, 0.5, 0, contours);
    	cv::imshow("Sobel", contours);
    }
    
  • 相关阅读:
    给文章生成二维码
    用HTML5 Canvas做一个画图板
    失败多少次不要紧,人们只会记住你成功的那一次
    关于读大学的意义
    卸载Anaconda
    Anaconda基本命令
    plt.imshow()
    matplotlib不显示图片
    在Anaconda环境下使用Jupyter Notebook
    join()
  • 原文地址:https://www.cnblogs.com/hellcat/p/9891656.html
Copyright © 2020-2023  润新知