0032-使用OpenCV对图像作边缘检测(Canny、Sobel、Laplace)

边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。 这些包括(i)深度上的不连续、(ii)表面方向不连续、(iii)物质属性变化和(iv)场景照明变化。 边缘检测是图像处理和计算机视觉中,尤其是特征提取中的一个研究领域。图像边缘检测大幅度地减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。

OpenCV提供了相关函数来实现各种边缘检测算子,具体的各种边缘检测的算子的算法原理请大家自行百度,下面分别介绍并给出示例代码。

一、Canny边缘检测算子
OpenCV提供了Canny函数来实现Canny边缘检测算子,函数原型如下
C++: void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false )
参数意义如下
image:输入图像,其类型要求只能是8位的
edges:边缘输出,其类型要求是单通道的8位图像,和输入图像有相同的大小。
threshold1:第一个滞后性阈值。
threshold2:第二个滞后性阈值。
apertureSize:使用Sobel算子的孔径大小,有默认值为3。
L2gradient:是否使用 L_2 norm  =\sqrt{(dI/dx)^2 + (dI/dy)^2来计算图像的梯度幅值,默认值为false,表示不使用L_2 norm来计算梯度幅值,此时使用L_1 norm来计算梯度幅值。
补充说明:两个滞后性阈值中较小的那个用来确定边缘连接,较大的那个用来初始化强边缘的检测,详细原理可参见链接:http://en.wikipedia.org/wiki/Canny_edge_detector
使用Canny函数进行边缘检测的代码如下
代码中用到的图像下载链接:https://pan.baidu.com/s/1hs8ImVU 密码:irnd

图像处理开发资料、图像处理开发需求、图像处理接私活挣零花钱,可以搜索公众号"qxsf321",并关注!

//opencv版本:OpenCV3.0
//VS版本:VS2013
//Author:qxsf321.net

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>

#include <iostream>

using namespace cv;
using namespace std;

int main()
{
        //载入原始图    
        Mat src = imread("20.jpg");  
        Mat src_1 = imread("20.jpg", 0);
        Mat gray = imread("20.jpg", 0);

        imshow("原图", src);

        //----------------------------------------------------------------------------------  
        //  一、最简单的canny用法,拿到原图后直接用。  
        //----------------------------------------------------------------------------------  
        Canny(src_1, src_1, 100, 150, 3);
        imshow("简单用法的Canny边缘检测结果", src_1);

        //----------------------------------------------------------------------------------  
        //  二、高阶的canny用法,转成灰度图,降噪,用canny,最后将得到的边缘作为掩码,拷贝原图到效果图上,得到彩色的边缘图  
        //----------------------------------------------------------------------------------  
        Mat dst, edge;

        // 【1】创建与src同类型和大小的矩阵(dst)  
        dst.create(gray.size(), gray.type());

        // 【2】先用使用 3x3内核来降噪  
        blur(gray, edge, Size(3, 3));

        // 【3】运行Canny算子  
        Canny(edge, edge, 100, 150, 3);

        imshow("高阶用法的Canny边缘检测结果", edge);

        //【4】将g_dstImage内的所有元素设置为0   
        dst = Scalar::all(0);

        //【5】使用Canny算子输出的边缘图g_cannyDetectedEdges作为掩码,来将原图g_srcImage拷到目标图g_dstImage中  
        src.copyTo(dst, edge);

        //【6】显示效果图   
        imshow("高阶用法的合成图", dst);

        waitKey(0);

        return 0;
}

代码运行截果如下图所示


二、Sobel算子
OpecnCV提供了Sobel函数来计算图像的一阶,二阶,三阶导数,使用的算子是扩展了的Sobel算子。
函数原型如下
C++: 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:目标图像的深度,支持的深度如下:
    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
    当 ddepth = -1时,目标图像和源图像的深度一样,当深度是8位时,程序会对数作截断处理。
dx:x方向的求导阶数
dy:y方向的求导阶数
ksize:扩展Sobel算子的大小,可以的取值为1,3,5,7,值得注意的是,当ksize=CV_SCHARR (-1)时,使用3×3的Scharr 滤波器进行计算,这样精度更高。Scharr在x方向和y方向上的核算子矩阵为:

Scharr函数的原型如下
C++: void Scharr(InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale=1, double delta=0, int borderType=BORDER_DEFAULT )
这里就不对Scharr的参数多做介绍了,也不单独给Scharr的使用示例,因为它就是Sobel算子的一个特例,和Sobel算子的使用上,除了没有ksize这个参数外,其它都一样。
scale:可选的导数计算比例因子,默认不使用比例因子。
borderType:边界处理方法,具体的详见帖子https://blog.csdn.net/lehuoziyuan/article/details/84101788
值得注意的是:Sobel算子在计算中进行了高斯平滑和差分运算,这样或多或少对噪声有消除作用。可以设置(xorder = 1, yorder = 0, ksize = 3)或(xorder = 0, yorder = 1, ksize = 3)来计算在x或y方向上的一阶导数。
一阶导数的核算子如下

二阶导数的核算子如下



使用Sobel函数计算图像边缘的代码如下

图像处理开发资料、图像处理开发需求、图像处理接私活挣零花钱,可以搜索公众号"qxsf321",并关注!
代码中用到的图像下载链接:https://pan.baidu.com/s/1gfAggZh 密码:dnol

//opencv版本:OpenCV3.0
//VS版本:VS2013
//Author:qxsf321.net

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>

#include <iostream>

using namespace cv;
using namespace std;

//-----------------------------------【头文件包含部分】---------------------------------------  
//            描述:包含程序所依赖的头文件  
//----------------------------------------------------------------------------------------------  
#include <opencv2/opencv.hpp>  
#include<opencv2/highgui/highgui.hpp>  
#include<opencv2/imgproc/imgproc.hpp>  

//-----------------------------------【命名空间声明部分】---------------------------------------  
//            描述:包含程序所使用的命名空间  
//-----------------------------------------------------------------------------------------------  
using namespace cv;  
//-----------------------------------【main( )函数】--------------------------------------------  
//            描述:控制台应用程序的入口函数,我们的程序从这里开始  
//-----------------------------------------------------------------------------------------------  
int main( )  
{  
    //【0】创建 grad_x 和 grad_y 矩阵  
    Mat grad_x, grad_y;  
    Mat abs_grad_x, abs_grad_y,dst;  

    //【1】载入原始图    
    Mat src = imread("21.jpg");  

    //【2】显示原始图   
    imshow("【原始图】sobel边缘检测", src);   

    //【3】求 X方向梯度  
    Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT );  
    convertScaleAbs( grad_x, abs_grad_x );  
    imshow("【效果图】 X方向Sobel", abs_grad_x);   

    //【4】求Y方向梯度  
    Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT );  
    convertScaleAbs( grad_y, abs_grad_y );  
    imshow("【效果图】Y方向Sobel", abs_grad_y);   

    //【5】合并梯度(近似)  
    addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst );  
    imshow("【效果图】整体方向Sobel", dst);   

    waitKey(0);   
    return 0;   
}

运行结果如下图所示:



三、Laplace算子
OpecnCV提供了Laplacian函数来计算图像的拉普拉斯运算
函数原型如下
C++: void Laplacian(InputArray src, OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType=BORDER_DEFAULT )
参数意义如下:
src:源图像
dst:目标图像,和源图像的大小和通道数一样。
ddepth:目标图像深度。
ksize:核算子的大小,用计算二阶导数时使用。
delta:可选的delta值,结果进行存储前的附加值、
borderType:边界处理方法,具体的详见帖子https://blog.csdn.net/lehuoziyuan/article/details/84101788
这个函数实际上就是把使用Sobel在x方向和y方向算子计算出的二阶层数进行合成,从而得到自己的计算结果。
使用Laplacian函数计算图像边缘的代码如下

图像处理开发资料、图像处理开发需求、图像处理接私活挣零花钱,可以搜索公众号"qxsf321",并关注!
代码中用到的图像下载链接:https://pan.baidu.com/s/1slJptsL 密码:tiki

//opencv版本:OpenCV3.0
//VS版本:VS2013
//Author:qxsf321.net

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>

#include <iostream>

using namespace cv;
using namespace std;

//-----------------------------------【头文件包含部分】---------------------------------------  
//            描述:包含程序所依赖的头文件  
//----------------------------------------------------------------------------------------------  
#include <opencv2/opencv.hpp>  
#include<opencv2/highgui/highgui.hpp>  
#include<opencv2/imgproc/imgproc.hpp>  

//-----------------------------------【命名空间声明部分】---------------------------------------  
//            描述:包含程序所使用的命名空间  
//-----------------------------------------------------------------------------------------------  
using namespace cv;


//-----------------------------------【main( )函数】--------------------------------------------  
//            描述:控制台应用程序的入口函数,我们的程序从这里开始  
//-----------------------------------------------------------------------------------------------  
int main()
{
        //【0】变量的定义  
        Mat src, src_gray, dst, abs_dst;

        //【1】载入原始图    
        src = imread("22.jpg");  

        //【2】显示原始图   
        imshow("【原始图】图像Laplace变换", src);

        //【3】使用高斯滤波消除噪声  
        GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);

        //【4】转换为灰度图  
        cvtColor(src, src_gray, CV_RGB2GRAY);

        //【5】使用Laplace函数  
        Laplacian(src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);

        //【6】计算绝对值,并将结果转换成8位  
        convertScaleAbs(dst, abs_dst);

        //【7】显示效果图  
        imshow("【效果图】图像Laplace变换", abs_dst);

        waitKey(0);

        return 0;
}

运行结果如下图所示:


 

猜你喜欢

转载自blog.csdn.net/lehuoziyuan/article/details/84136050