边缘检测
边缘检测
简介
-
边缘检测是一种图像处理技术,用于识别对象的边界(边缘)或图像中的区域
-
图像的边缘指的是图像中像素灰度值突然发生变化的区域
-
图像的边缘有可能是由高像素值变为低像素值,也有可能是由低像素值变成高像素值,因此通过计算得到的边缘信息会有正数值和负数值。为了在图像中同时表示出这两种边缘信息,需要将计算的结果求取绝对值。OpenCV提供了
converScaleAbs()
函数用于计算矩阵中所有数据的绝对值
converScaleAbs(src, dst)
- 另外,由于求取边缘的结果可能会有负数,不在原始图像的CV_8U的数据类型内,因此滤波后的图像数据类型不要用 “-1” ,而应该改为CV_16S
以下所有代码均用此图作为示例
Sobel算子
简介
- Sobel算子通过寻找图像一阶导数中的最大值来检测边界,然后利用计算结果估计边缘的局部方向,通常采用梯度的方向,并利用此方向找到局部梯度模的最大值
- Sobel算子在实际应用中效率比Canny算法要高,但是边缘不如Canny检测的准确,但是很多实际应用的场合,Sobel算子却是首选
- Sobel算子是高斯平滑与微分操作的结合体,所以抗噪声能力很强,用途较多,尤其是效率要求较高,而对细纹理不太关心的时候
实现
以下是 OpenCV 4 应用Sobel边缘检测的语法
Sobel(src, dst, ddepth, dx, dy, ksize)
-
src:待提取边缘的图像
-
dst:输出图像,与输入图像具有相同的尺寸和通道数,数据类型由第三个参数 ddepth 控制
-
ddepth:输出图像的数据类型(深度),根据输入图像数据类型的不同拥有不同的取值范围,具体如下表
输入图像数据类型 输出图像可选数据类型 CV_8U -1 / CV_16S / CV_32F / CV_64F CV_16U / CV_16S -1 / CV_32F / CV_64F CV_12F -1 / CV_32F / CV_64F CV_64F -1 / CV_64F - 当赋值为-1时,输出图像的数据类型自动选择
-
dx:X方向的差分阶数。如果dx = 1和dy = 0,我们提取X方向的边缘信息
-
dy:Y方向的差分阶数。如果两者dx = 1和dy = 1,我们提取两个方向也就是整幅图像的边缘信息
-
ksize:Sobel算子的尺寸,必须是1、3、5或7,默认为3
补:任意一个方向的差分阶数都需要小于算子的尺寸。特殊情况是,当ksize = 1时,任意一个方向的阶数都需要小于3。在一般情况下,当差分阶数的最大值为1时,算子尺寸选3;当差分阶数的最大值为2时,算子尺寸选5;当差分阶数最大值为3时,算子尺寸选7
注,由于提取边缘信息时有可能出现负数,因此不要使用CV_8U类型的输出图像
示例代码如下:
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { // 读取图像,黑白图像边缘检测结果较为明显 Mat img = imread("/home/kslas/OpenCV/edge.jpg", IMREAD_ANYCOLOR); if (img.empty()) { cout << "Could not read the image" << endl; return -1; } // X方向一阶边缘 Mat resultX; Sobel(img, resultX, CV_16S, 2, 0, 1); convertScaleAbs(resultX, resultX); // Y方向一阶边缘 Mat resultY; Sobel(img, resultY, CV_16S, 0, 1, 3); convertScaleAbs(resultY, resultY); // 整幅图像的一阶边缘 Mat resultXY = resultX + resultY; // 显示图像 imshow("resultX", resultX); imshow("resultY", resultY); imshow("resultXY", resultXY); waitKey(0); destroyAllWindows(); return 0; }
运行结果:
Laplacian算子
简介
- Laplacian算子通过寻找图像二阶导数零穿越来寻找边界
- Laplacian算子具有各方向同性的特点,能够对任意方向的边缘进行提取,具有无方向性的优点
- Laplacian算子是一种二阶导数算子,对噪声比较敏感,因此常需要配合高斯滤波一起使用
实现
以下是 OpenCV 4 应用Laplacian边缘检测的语法
Laplacian(src, dst, ddepth, ksize)
- scr:输入原始图像,可以是灰度图像或彩色图像
- dst:输出图像,与输入图像具有相同的尺寸和通道数
- ddepth:同上
- ksize:滤波器的大小,必须为正奇数
注,由于提取边缘信息时有可能出现负数,因此不要使用CV_8U类型的输出图像,否则会使得图像边缘提取不准确
示例代码如下:
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { // 读取图像,黑白图像边缘检测结果较为明显 Mat img = imread("/home/kslas/OpenCV/edge.jpg", IMREAD_ANYCOLOR); if (img.empty()) { cout << "Could not read the image" << endl; return -1; } // 未进行滤波提取Laplacian边缘 Mat result; Laplacian(img, result, CV_16S, 3); convertScaleAbs(result, result); // 滤波后提取Laplacian边缘 Mat result_g, result_G; GaussianBlur(img ,result_g, Size(3, 3), 5, 0); // 高斯滤波 Laplacian(result_g, result_G, CV_16S, 3); convertScaleAbs(result_G, result_G); // 显示图像 imshow("result", result); imshow("result_G", result_G); waitKey(0); destroyAllWindows(); return 0; }
运行结果:
Canny算法
简介
-
Canny算法是目前最优越的边缘检测算法之一
-
Canny算法不容易受到噪声的影响,能够识别图像中的弱边缘和强边缘,并结合强弱边缘的位置关系,综合给出图像整体的边缘信息
-
该方法的检测过程可分为以下5个步骤:
- 使用高斯滤波平滑图像
- 计算图像中每个像素的梯度方向和幅值
- 应用非极大值抑制算法消除边缘检测带来的杂散相应
- 应用双阈值法划分强边缘和弱边缘
- 消除孤立的弱边缘
实现
OpenCV 4 提供了Canny()
函数用于实现Canny算法检测图像中的边缘
Canny(image, edges, threshold1, threshold2, apertureSize, L2gradient)
- image:输入图像,必须是CV_8U的单通道或者三通道图像
- edges:输出图像,与输入图像具有相同尺寸的单通道图像,且数据类型为CV_8U
- threshold1:第一个滞后阈值
- threshold2:第二个滞后阈值
- apertureSize:Sobel算子的直径,默认为3
- L2gradient:计算图像梯度幅度方法的标志,默认为false
补1:在一般情况下,较大阈值与较小阈值的比值在 2 : 1 到 3 : 1 之间
补2:较高的阈值会降低噪声信息对图像提取边缘结果的影响,但同时也会减少结果中的边缘信息
补3:高斯模糊在边缘纹理较多的区域能减少边缘检测的结果,但对纹理较少的区域影响较小
示例代码:
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { // 读取图像,黑白图像边缘检测结果较为明显 Mat img = imread("/home/kslas/OpenCV/edge.jpg", IMREAD_ANYCOLOR); if (img.empty()) { cout << "Could not read the image" << endl; return -1; } // 高阈值检测图像边缘 Mat resultHigh; Canny(img, resultHigh, 100, 200, 3); // 低阈值检测图像边缘 Mat resultLow; Canny(img, resultLow, 20, 40, 3); // 高斯模糊后检测图像边缘 Mat resultG, resultGC; GaussianBlur(img, resultG, Size(3, 3), 5); Canny(resultG, resultGC, 100, 200, 3); // 显示图像 imshow("resultHigh", resultHigh); imshow("resultLow", resultLow); imshow("resultG", resultGC); waitKey(0); destroyAllWindows(); return 0; }
运行结果:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!