当前位置: 首页 > news >正文

OpenCV 卷积 Robert算子,Laplance算子,Sobel算子,Canny边缘检测原理

提取边缘原理

OpenCV 提取边缘的原理主要依赖于图像的梯度变化。边缘是图像中灰度值发生显著变化的区域,通常对应于物体的边界。在图像特征提权,对象检测,模式识别都有重要作用。判断灰度值发生显著变化通常通过计算图像的梯度来实现。梯度是图像灰度值变化的速率或方向,即垂直方向和水平方向的一阶导数,delta = f(x)-f(x-1),delta越大,说明像素在x方向变化越大,边缘信号越强,说明是极有可能是边界。

在这里插入图片描述

如何得到梯度值呢? 使用卷积操作

Robert算子的基本原理

Robert算子是一种基于图像梯度的边缘检测算法,其主要原理是通过计算图像中每个像素的局部灰度变化来识别图像的边缘。它是边缘检测算法中的一种经典方法,广泛应用于图像处理领域。

梯度计算

  • Robert算子通过计算图像中灰度值的局部变化来估计梯度。边缘通常表示为灰度值的突变,因此,边缘检测算法的核心是计算图像中灰度变化的大小和方向。

  • Robert算子使用两个简单的卷积核(或掩模)来计算图像在水平和垂直方向上的梯度。这两个卷积核分别是:

    在这里插入图片描述

卷积操作

  • 卷积是图像处理中用于计算图像局部特征的操作。在Robert算子中,我们将上述卷积核与图像进行卷积,计算每个像素的局部梯度。
  • 对于每个图像像素,将卷积核与像素及其邻域的灰度值进行乘法和求和,得到水平和垂直方向上的梯度分量。

梯度幅值

  • 计算图像中每个像素的梯度幅值,以获取边缘强度。梯度幅值表示灰度变化的强度,计算公式为:

  • G = G x 2 + G y 2 G = \sqrt{G_x^2 + G_y^2} G=Gx2+Gy2

  • 其中,Gx和 Gy 分别是水平和垂直方向上的梯度分量。幅值高的地方通常表示图像的边缘。

边缘检测

  • 根据梯度幅值进行边缘检测。通常会应用一个阈值,将幅值高于阈值的像素标记为边缘像素,从而得到二值化的边缘图像。

示例代码

int main()
{// 读取图像Mat image = imread("C:\\Users\\Marxist\\Pictures\\coco\\wanxi1.png", IMREAD_GRAYSCALE);if (image.empty()) {cout << "Could not open or find the image" << endl;return -1;}// 定义Robert算子的卷积核Mat kernel_x = (Mat_<float>(2, 2) << 1, 0, 0, -1);Mat kernel_y = (Mat_<float>(2, 2) << 0, 1, -1, 0);// 应用Robert算子Mat grad_x, grad_y;filter2D(image, grad_x, CV_32F, kernel_x);filter2D(image, grad_y, CV_32F, kernel_y);// 计算梯度幅值Mat grad_magnitude;magnitude(grad_x, grad_y, grad_magnitude);// 将结果转换为8位图像Mat grad_magnitude_8u;grad_magnitude.convertTo(grad_magnitude_8u, CV_8U);// 显示结果imshow("Original Image", image);imshow("Robert Gradient Magnitude", grad_magnitude_8u);waitKey(0);return 0;
}

效果如图:图像的边缘线条就被勾勒出来了

在这里插入图片描述

Sobel算子的基本原理

Sobel算子是一种常用的边缘检测算子,它通过计算图像在水平和垂直方向上的梯度来检测图像中的边缘。在OpenCV中,提供了Sobel函数轻松实现Sobel算子的应用。

Sobel算子使用两个卷积核来计算图像的水平和垂直梯度:

水平梯度核(Gx):
[ − 1 0 1 − 2 0 2 − 1 0 1 ] \begin {bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix} 121000121
垂直梯度核(Gy):
[ − 1 − 2 − 1 0 0 0 1 2 1 ] \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix} 101202101
代码实现:

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main()
{// 读取图像并转换为灰度图像Mat image = imread("C:\\Users\\Marxist\\Pictures\\coco\\example.jpg");if (image.empty()) {cout << "Could not open or find the image" << endl;return -1;}Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);// 使用Sobel算子计算水平和垂直方向的梯度Mat grad_x, grad_y;Mat abs_grad_x, abs_grad_y;// Sobel函数参数解释:// 第一个参数:输入图像// 第二个参数:输出图像// 第三个参数:图像深度,通常使用CV_16S以避免梯度计算溢出 因为值很有可能超过8位// 第四个参数:x方向上的导数阶数// 第五个参数:y方向上的导数阶数// 第六个参数:内核大小(一般为3)Sobel(gray, grad_x, CV_16S, 1, 0, 3);Sobel(gray, grad_y, CV_16S, 0, 1, 3);// 将梯度转换为绝对值,然后转换回8位convertScaleAbs(grad_x, abs_grad_x);convertScaleAbs(grad_y, abs_grad_y);// 计算梯度的总和Mat grad;addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);// 显示结果imshow("Original Image", image);imshow("Gray Image", gray);imshow("Sobel - Grad X", abs_grad_x);imshow("Sobel - Grad Y", abs_grad_y);imshow("Sobel - Combined Gradient", grad);waitKey(0);return 0;
}

效果如图:明显强过Robert算子

在这里插入图片描述

拉普拉斯算子的基本原理

拉普拉斯算子(Laplacian operator)是一种用于图像处理和边缘检测的二阶导数算子。它通过计算图像中像素的二阶导数来检测边缘,特别适用于检测图像中的快速变化区域。拉普拉斯算子具有方向无关性,即它在所有方向上都计算图像的变化,因此能够检测出所有方向的边缘。

拉普拉斯算子基于二阶导数,主要用于检测图像中灰度值的变化。对于二维函数 ( f(x, y) )(图像中的灰度值),拉普拉斯算子定义为:
∇ 2 f = ∂ 2 f ∂ x 2 + ∂ 2 f ∂ y 2 \nabla^2 f = \frac{\partial^2 f}{\partial x^2} + \frac{\partial^2 f}{\partial y^2} 2f=x22f+y22f
在图像处理中,离散的拉普拉斯算子通常使用卷积核来实现。这些卷积核近似于计算二阶导数。常用的卷积核包括:

  • 4-邻域:
    [ 0 1 0 1 − 4 1 0 1 0 ] \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{bmatrix} 010141010

  • 8-邻域:
    [ 1 1 1 1 − 8 1 1 1 1 ] \begin{bmatrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\ 1 & 1 & 1 \end{bmatrix} 111181111

使用这些卷积核对图像进行卷积运算,可以得到图像的二阶导数,从而检测出图像中的边缘。

拉普拉斯算子的特点

  1. 方向无关性:拉普拉斯算子计算的是图像在所有方向上的变化,因此能够检测出所有方向的边缘。
  2. 增强边缘:由于计算的是二阶导数,拉普拉斯算子对图像中的边缘增强效果明显,能够突出快速变化的区域。
  3. 敏感性拉普拉斯算子对噪声敏感,因此在应用拉普拉斯算子之前,通常需要对图像进行平滑处理(例如高斯模糊)以减少噪声。

代码实现

OpenCV提供了Laplacian函数,可以方便地对图像应用拉普拉斯算子。

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main()
{// 读取图像并转换为灰度图像Mat image = imread("C:\\Users\\Marxist\\Pictures\\coco\\example.jpg");if (image.empty()) {cout << "Could not open or find the image" << endl;return -1;}Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);// 使用高斯模糊平滑图像以减少噪声Mat blurred;GaussianBlur(gray, blurred, Size(3, 3), 0);// 使用拉普拉斯算子检测边缘Mat laplacian;Laplacian(blurred, laplacian, CV_16S, 3);Mat abs_laplacian;convertScaleAbs(laplacian, abs_laplacian);// 显示结果imshow("Original Image", image);imshow("Gray Image", gray);imshow("Laplacian Edge Detection", abs_laplacian);waitKey(0);return 0;
}

效果如图

在这里插入图片描述

Canny边缘检测原理

Canny边缘检测是一种多级边缘检测算法,由John F. Canny在1986年开发。它在边缘检测中广泛应用,因为它能够显著提高图像中的边缘检测精度,同时降低噪声的影响。Canny边缘检测算法包括五个主要步骤:高斯滤波、计算梯度、非极大值抑制、双阈值检测和边缘连接

1.高斯滤波

为了减少图像中的噪声,首先对图像进行高斯滤波。高斯滤波是一种平滑滤波器,它通过卷积运算来减弱图像中的噪声,而不会显著影响边缘。

2.计算梯度

使用Sobel算子计算图像的梯度。Sobel算子计算图像在水平方向(Gx)和垂直方向(Gy)上的一阶导数。通过这两个梯度,可以计算梯度幅值和方向

3.非极大值抑制

非极大值抑制用于细化边缘,即抑制非边缘的像素。对于每个像素点,检查其在梯度方向上的邻域,并保留局部极大值点。具体来说,如果一个像素点的梯度幅值大于其梯度方向上的两个相邻像素点的梯度幅值,则保留该点,否则将其抑制。

4.双阈值检测

双阈值检测使用两个阈值(高阈值和低阈值)来区分强边缘、弱边缘和非边缘:

  • 强边缘:梯度幅值大于高阈值的像素点。
  • 弱边缘:梯度幅值介于高阈值和低阈值之间的像素点。
  • 非边缘:梯度幅值小于低阈值的像素点。

5.边缘连接

通过连接强边缘和相邻的弱边缘来形成连续的边缘。如果一个弱边缘像素与强边缘像素连接,则将其视为边缘的一部分,否则将其抑制。

示例代码

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main()
{// 读取图像并转换为灰度图像Mat image = imread("C:\\Users\\Marxist\\Pictures\\coco\\example.jpg");if (image.empty()) {cout << "Could not open or find the image" << endl;return -1;}Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);// 高斯滤波以减少噪声Mat blurred;GaussianBlur(gray, blurred, Size(5, 5), 1.5);// 应用Canny边缘检测Mat edges;Canny(blurred, edges, 50, 100);//推荐低阈值 和高阈值 1:2 或者1:3  ,如果发现图像线条丢失严重,建议减低高阈值,得到更多线条。// 显示结果imshow("Original Image", image);imshow("Gray Image", gray);imshow("Canny Edge Detection", edges);waitKey(0);return 0;
}

Canny函数原型

void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false);

参数说明:

  1. image:输入图像。通常是一个单通道的灰度图像。输入图像的类型应为 CV_8U
  2. edges:输出图像。该图像将包含检测到的边缘。输出图像的类型为 CV_8U
  3. threshold1:第一个阈值,用于边缘连接的低阈值。任何小于此值的梯度强度将被认为不是边缘。
  4. threshold2:第二个阈值,用于边缘连接的高阈值。任何大于此值的梯度强度将被认为是强边缘。
  5. apertureSize:Sobel算子的孔径大小,用于计算图像梯度。默认值为3,常见取值有3、5、7。
  6. L2gradient:布尔值,用于指定是否使用更精确的L2范数(即欧几里得距离)来计算图像梯度幅值。如果为false,则使用L1范数(即曼哈顿距离)。默认值为false。

效果如图:
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【DVWA靶场】Web安全之(布尔值/延时型)SQL盲注(超详细教程)
  • Android RSA 加解密
  • stm32F1xx时钟配置分析总结
  • linux快速入门-学习笔记
  • Adobe“加速”创意人士开启设计新篇章
  • MongoDB教程(二十二):MongoDB固定集合
  • [k8s源码]8.deltaFIFO
  • Vue Router基础
  • BSV区块链在人工智能时代的数字化转型中的角色
  • 【快速实践 OpenCV morphology】形态学操作:腐蚀、膨胀、开运算、闭运算
  • 无人机飞行姿态俯仰、横滚、偏航、油门详解
  • vite+react+ts+Rust来进行前后端web开发(hello world)
  • 后端返回一个图片链接,前端如何实现下载功能?
  • 零基础入门:创建一个简单的Python爬虫管理系统
  • 杰发科技AC7840——SENT数据解析及软件Sent发送的实现
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • Git学习与使用心得(1)—— 初始化
  • TCP拥塞控制
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • 那些年我们用过的显示性能指标
  • 一份游戏开发学习路线
  • Java性能优化之JVM GC(垃圾回收机制)
  • PostgreSQL之连接数修改
  • 浅谈sql中的in与not in,exists与not exists的区别
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • # 数仓建模:如何构建主题宽表模型?
  • #LLM入门|Prompt#3.3_存储_Memory
  • #Z0458. 树的中心2
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (¥1011)-(一千零一拾一元整)输出
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (6)STL算法之转换
  • (zhuan) 一些RL的文献(及笔记)
  • (八)Spring源码解析:Spring MVC
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (四)模仿学习-完成后台管理页面查询
  • (转)ABI是什么
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (转)Sql Server 保留几位小数的两种做法
  • (转载)Linux网络编程入门
  • **python多态
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .DFS.
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .Net mvc总结
  • @Conditional注解详解
  • @Not - Empty-Null-Blank