【小白】Open-CV 学习笔记 - 7.1 基于OpenCV的边缘检测 (canny算子、 sobel算子、 Laplacian算子、scharr滤波器)

1.基于OpenCV的边缘检测

1.1一般的步骤

  1. 滤波:边缘检测算法主要是基于图像强度的一阶和二阶导数,但是导数对于噪声很敏感,因此需要采用滤波器来改善与噪声有关的边缘检测器的性能
  2. 增强:增强边缘的基础是确定图像各点邻域强度的变化值。增强算法可以将灰度点邻域强度值有显著变化的点凸显出来
  3. 检测:邻域中有很多的点的梯度值较大,但是在特定的应用中,这些点并不是要找的边缘点,需要取舍

1.2 Canny算子

评价标准

  • 低错误率:标识出尽可能多的实际边缘,同时尽可能地减少噪声产生的误报。
  • 高定位性:标识出的边缘要与图像中的实际边缘尽可能接近
  • 最小响应:图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘

canny边缘检测的步骤

(1)消除噪声
高斯平滑滤波卷积降噪(size = 5)
在这里插入图片描述

(2)计算梯度幅值和方向
在这里插入图片描述
(3)非极大值抑制
排除非边缘像素,仅仅保留一些细线条
(4)滞后阈值

  1. 若某一像素位置的幅值超过高阈值,该像素被保留为边缘像素
  2. 若某一像素位置的幅值小于低阈值,该像素被排除
  3. 若某一像素位置的幅值在两个阈值之间,该像素仅仅在连接一个高于高阈值的像素时被保留

canny边缘检测:Canny()函数

void Canny(InputArray image, OutputArray edges, double threshold,
	double threshold2,int apertureSize = 3,bool L2gradient = false)
  • 第三个参数:double 类型的threshold1,第一个滞后性阈值
  • 第四个参数:double类型的threshold2,第二个滞后性阈值
  • 第五个参数:int类型的apertureSize,表示应用Sobel算子的孔径大小,默认值为3
  • 第六个参数:bool类型的L2gradient,一个计算图像梯度幅值的标识,默认值false
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

//main()函数
//应用程序入口
int main()
{
    Mat src = imread("1.jpg");
    Mat src1 = src.clone();

    //显示原始图
    imshow("【原始图】Canny边缘检测", src);
    //转化为灰度图,减噪,然后用canny得到的边缘作为掩码,拷贝原图到效果图,得到彩色的边缘图
    Mat dst, edge, gray;

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

    //将原图像转换为灰度图像
    cvtColor(src1, gray, COLOR_BGR2GRAY);

    //使用3×3内核降噪
    blur(gray, edge, Size(3, 3));

    //使用canny算子
    Canny(edge, edge, 3, 9, 3);

    imshow("【效果图】Canny边缘检测1", edge);
    //将dstImage内所有元素为0
    dst = Scalar::all(0);

    //使用Canny算子输出的边缘图,g_cannyDetectedEdges作为掩码,来将原图g_srcImage拷贝到目标图g_dstImage中
    src1.copyTo(dst, edge);
    imshow("【效果图】Canny边缘检测2", dst);
    waitKey(0);
    return 0;
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.3 sobel算子

Sobel算子是一个主要用于边缘检测的离散微分算子(discrete differentiation operator),它结合高斯平滑和微分求导。用来计算图像灰度函数的近似函数

1.3.1 sobel算子的计算过程
在这里插入图片描述
1.3.2 使用sobel算子:Sobel()函数

函数原型

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)

在这里插入图片描述
1.3.3 综合示例

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

//main() 函数
int main()
{
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y, dst;
    //载入图像
    Mat src = imread("1.jpg");

    //显示原始图
    imshow("【原始图】sobel边缘检测", src);
    //求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);

    //求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);

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

    waitKey(0);
    return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.4 Laplacian算子

Laplacian算子是n维欧几里得空间中的一个二阶微分算子。定义为梯度grad的散度div。定义如下:

  1. ff 的拉普拉斯算子也是笛卡尔坐标系中的所有非混合二阶偏导数求和
  2. 作为一个二阶微分算子,拉普拉斯算子把C函数映射到C函数,对于k≥2k≥2,定义一个算子ΔΔ:C®→C®C®→C®
    二阶导数可以用来进行检测边缘,因为图像是“二维”的,需要在两个方向上进行求导。
    Laplacian算子定义:
    在这里插入图片描述
    1.4.1 Laplacian()函数
void Laplacian(InputArray src, OutputArray dst,int ddepth ,int ksize = 1,double scale = 1,
	double delta = 0,intborderType = BORDER_DEFAULT)
  • double 类型的scale,计算拉普拉斯值的时候可选的比例因子,默认值为1
  • double 类型的delta,表示在结果存入目标图之前可选的delta值,默认值为0

在这里插入图片描述
1.4.2 Laplacian算子的使用

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

//main()函数

int main()
{
    //变量定义
    Mat src, src_gray, dst, abs_dst;
    //载入原始图
    src = imread("1.jpg");

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

    //使用高斯滤波消除噪声
    GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
    //转换为灰度图
    cvtColor(src, src_gray, COLOR_RGB2GRAY);
    //使用Laplace函数
    Laplacian(src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);
    //计算绝对值
    convertScaleAbs(dst, abs_dst);
    //显示效果图
    imshow("【效果图】图像Laplace变换", abs_dst);
    waitKey(0);
    return 0;
}

在这里插入图片描述
在这里插入图片描述

1.5 scharr滤波器

1.5.1 计算图像差分:Scharr()函数

函数原型

void Scharr(InputArray src, OutputArray dst,int ddepth ,
		int dx, int dy,double scale = 1,double delta = 0,int)
  • int 类型的dx, x方向的差分阶数
    i- nt 类型的dy,y方向的差分阶数

1.5.2 示例程序

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

//main()函数

int main()
{
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y, dst;

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

    imshow("【原始图】Scharr滤波器", src);

    //求x方向的梯度
    Scharr(src, grad_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(grad_x, abs_grad_x);
    imshow("【效果图】X方向Scharr", abs_grad_x);
    //求y方向的梯度
    Scharr(src, grad_y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(grad_y, abs_grad_y);
    imshow("【效果图】Y方向Scharr", abs_grad_y);

    //合并梯度
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);

    //显示效果图
    imshow("【效果图】合并梯度后Scharr", dst);
    waitKey(0);
    return 0;
}

在这里插入图片描述

1.6综合示例

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

//全局变量声明部分

//原图,和目标图

Mat g_srcImage, g_srcGrayImage, g_dstImage;

//Canny边缘检测相关的变量
Mat g_cannyDetectedEdges;
int g_cannyLowThreshold = 1; // TrackBar 位置参数

// Sobel 边缘检测相关变量
Mat g_sobelGradient_X, g_sobelGradient_Y;
Mat g_sobelAbsGradient_X, g_sobelAbsGradient_Y;
int g_sobelKernelSize = 1;  // TrackBar 位置参数

//Scharr滤波器相关参数
Mat g_scharrGradient_x, g_scharrGradient_Y;
Mat g_scharrAbsGradient_x, g_scharrAbsGradient_Y;

//全局函数声明

static void on_Canny(int, void *);  //Canny边缘检测窗口滚动条的回调函数
static void on_Sobel(int, void *);  //Sobel边缘检测窗口滚动条的回调函数
void Scharr();  //封住了Scharr边缘检测的相关的代码函数

//main()函数

int main()
{
    //改变颜色
    system("color 2F");

    //载入原图
    g_srcImage = imread("1.jpg");

    if (!g_srcImage.data)
    {
        printf("读取文件错误~!\n");
        return false;
    }
    //显示原始图
    namedWindow("【原始图】");
    imshow("【原始图】", g_srcImage);

    //创建与src同类型和大小的矩阵dst
    g_dstImage.create(g_srcImage.size(), g_srcImage.type());

    //将原图像转换为灰度图像
    cvtColor(g_srcImage, g_srcGrayImage, COLOR_BGR2GRAY);

    //创建显示窗口
    namedWindow("【效果图】Canny边缘检测", WINDOW_AUTOSIZE);
    namedWindow("【效果图】Sobel边缘检测", WINDOW_AUTOSIZE);

    //创建tracker
    createTrackbar("参数值:", "【效果图】Canny边缘检测", &g_cannyLowThreshold, 120, on_Canny);
    createTrackbar("参数值:", "【效果图】Sobel边缘检测", &g_sobelKernelSize, 3, on_Sobel);
    //调用回调函数
    on_Canny(0, 0);
    on_Sobel(0, 0);

    //调用封装的Scharr边缘检测代码的函数
    Scharr();

    while ((char)waitKey(1) != 'q') {}
    return 0;
}

// on_Canny函数
void on_Canny(int, void *)
{
    //先使用3×3的内核进行降噪
    blur(g_srcGrayImage, g_cannyDetectedEdges, Size(3, 3));

    //运行Canny算子
    Canny(g_cannyDetectedEdges, g_cannyDetectedEdges, g_cannyLowThreshold, g_cannyLowThreshold * 3, 3);
    //设置为0
    g_dstImage = Scalar::all(0);
    //使用Canny算子输出的边缘图g_cannyDetectedEdge作为掩码,将原图g_srcImage拷贝到g_dstImage中
    g_srcImage.copyTo(g_dstImage, g_cannyDetectedEdges);

    //显示效果图
    imshow("【效果图】Canny边缘检测", g_dstImage);
}
//on_Sobel()函数
void on_Sobel(int, void *)
{
    Sobel(g_srcImage, g_sobelGradient_X, CV_16S, 1, 0, (2 * g_sobelKernelSize + 1), 1, BORDER_DEFAULT);
    convertScaleAbs(g_sobelGradient_X, g_sobelAbsGradient_X);

    //求Y方向的梯度
    Sobel(g_srcImage, g_sobelGradient_Y, CV_16S, 0, 1, (2 * g_sobelKernelSize + 1), 1, BORDER_DEFAULT);
    convertScaleAbs(g_sobelGradient_Y, g_sobelAbsGradient_Y);
    //合并梯度
    addWeighted(g_sobelAbsGradient_X, 0.5, g_sobelAbsGradient_Y, 0.5, 0, g_dstImage);

    //显示效果
    imshow("【效果图】Sobel边缘检测", g_dstImage);

}

//Scharr()函数
void Scharr()
{
    //求x方向的梯度
    Scharr(g_srcImage, g_scharrGradient_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(g_scharrGradient_x, g_scharrAbsGradient_x);

    //求y方向的梯度
    Scharr(g_srcImage, g_scharrGradient_Y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(g_scharrGradient_Y, g_scharrAbsGradient_Y);
    //合并梯度
    addWeighted(g_scharrAbsGradient_x, 0.5, g_scharrAbsGradient_Y, 0.5, 0, g_dstImage);
    imshow("【效果图】Scharr滤波器", g_dstImage);
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


作者:绝尘花遗落
来源:CSDN
原文:https://blog.csdn.net/huayunhualuo/article/details/81478037
版权声明:本文为博主原创文章,转载请附上博文链接!

发布了34 篇原创文章 · 获赞 8 · 访问量 1882

猜你喜欢

转载自blog.csdn.net/weixin_43583163/article/details/97303430
今日推荐