一、边缘检测原理边缘Edge是指图像中局部灰度值强度发生显著变化的区域通常存在于目标与目标之间目标与背景之间区域与区域之间不同颜色或纹理之间图像强度变化的两种典型形式阶跃变化Step Edge图像灰度在某一点两侧发生突变即像素值突然从一个灰度跳到另一个灰度。屋顶变化Roof Edge/线条变化图像灰度突然升高保持一小段距离后又下降回原值。前向差分Forward Difference计算梯度当前像素与左侧像素的差值 → 近似水平变化率改进后中心差分二、Sobel算子边缘检测/* 用途用于计算图像的一阶或高阶梯度通过Sobel卷积算子检测图像在 x方向或y方向的灰度变化从而提取边缘信息 */ void cv::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决定 ddepth输出图像的数据类型深度 dxx方向求导阶数 dyy方向求导阶数 ksizeSobel算子核大小必须为1、3、5、7等奇数 scale缩放系数对计算结果进行比例放大或缩小 delta偏移量在结果中额外加上的值 borderType像素外推法选择标志 */三、Scharr算子边缘检测/* 用途用于计算图像在x方向或y方向的梯度是Sobel算子的增强版本。 在使用3×3核时Scharr算子相比Sobel具有更高的精度和更好的旋转对称性 能更准确地检测图像边缘细节与灰度变化*/ void cv::Scharr( InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale 1, double delta 0, int borderType BORDER_DEFAULT ); /* src输入图像 dst输出图像与输入图像具有相同的尺寸数据类型由ddepth决定 ddepth输出图像的数据类型深度 dxx方向求导阶数 dyy方向求导阶数 scale缩放系数对计算结果进行比例放大或缩小 delta偏移量在结果中额外加上的值 borderType像素外推法选择标志 */四、两种算子的生成/* 用途用于生成图像导数运算所需的一维卷积核x方向与y方向 这些卷积核通常用于Sobel、Scharr等梯度计算 或与sepFilter2D配合实现自定义微分滤波。 通过该函数可灵活构造一阶导数、二阶导数等算子 常用于边缘检测、梯度分析、特征提取以及高性能可分离卷积计算 */ void cv::getDerivKernels( OutputArray kx, OutputArray ky, int dx, int dy, int ksize, bool normalize false, int ktype CV_32F ); /* kx行滤波器系数的输出矩阵尺寸为ksize * 1 ky列滤波器系数的输出矩阵尺寸为ksize * 1 dxX方向导数的阶次 dyy方向导数的阶次 ksize滤波器的大小可以选择的参数为FILTER_SCHARR135或7 normalize是否对滤波器系数进行归一化的标志默认值为false表示不进行系数归一化 ktype滤波器系数类型可以选择CV_32F或CV_64F默认参数为CV_32F */五、示例代码QString imgPath QApplication::applicationDirPath() /Images; cv::String s_imgPath imgPath.toLocal8Bit().data(); Mat img imread(s_imgPath /equalLena.jpg, IMREAD_ANYCOLOR); if (img.empty()) { qDebug() 图片加载失败, 请确认图像文件名称是否正确; return; } Mat resultX, resultY, resultXY; /*X方向一阶边缘*/ Sobel(img, resultX, CV_16S, 1, 0, 3); convertScaleAbs(resultX, resultX);/*求取绝对值*/ /*Y方向一阶边缘*/ Sobel(img, resultY, CV_16S, 0, 1, 3); convertScaleAbs(resultY, resultY); /*整幅图像的一阶边缘*/ resultXY resultX resultY; imshow(resultX, resultX); imshow(resultY, resultY); imshow(resultXY, resultXY); waitKey(0); /*X方向一阶边缘*/ Scharr(img, resultX, CV_16S, 1, 0); convertScaleAbs(resultX, resultX);/*求取绝对值*/ /*Y方向一阶边缘*/ Scharr(img, resultY, CV_16S, 0, 1); convertScaleAbs(resultY, resultY);/*求取绝对值*/ resultXY resultX resultY; imshow(resultX, resultX); imshow(resultY, resultY); imshow(resultXY, resultXY); waitKey(0); /*生成边缘检测器*/ Mat sobel_x1, sobel_y1;/*存放分离的sobel算子*/ Mat scharr_x, scharr_y;/*存放分离的scharr算子*/ Mat sobelX1, scharrX;/*存放最终算子*/ getDerivKernels(sobel_x1, sobel_y1, 1, 0, 3); sobel_x1 sobel_x1.reshape(CV_8U, 1); sobelX1 sobel_y1 * sobel_x1;/*计算滤波器*/ getDerivKernels(scharr_x, scharr_y, 1, 0, FILTER_SCHARR); scharr_x scharr_x.reshape(CV_8U, 1); scharrX scharr_y * scharr_x;/*计算滤波器*/ cout X sobel: endl sobelX1 endl; cout X scharr: endl scharrX endl; waitKey(0); destroyAllWindows();六、Laplacian算子边缘检测1、Laplacian算子Laplacian算子是一种基于二阶导数的边缘检测算法主要用于识别图像中的快速亮度变化即边缘。由于它直接与图像的二阶导数相关因此能够有效地找到边缘位置但对噪声比较敏感。Sobel和Scharr边缘检测算法存在的问题分别计算两个方向边缘边缘与方向相关性较大Laplacian算子方向无关容易受到噪声的影响3 * 3的Laplacian算子​​​​​​​2、Laplacian边缘检测函数/* 用途用于计算图像的二阶导数Laplacian算子通过检测灰度变化的“变化率” 强调图像中灰度突变的位置从而突出边缘信息。 与Sobel一阶导数相比Laplacian对边缘方向不敏感 能同时检测各个方向的边缘但对噪声也更敏感 */ void cv::Laplacian( InputArray src, OutputArray dst, int ddepth, int ksize 1, double scale 1, double delta 0, int borderType BORDER_DEFAULT ); /* src输入原图像可以是灰度图像和彩色图像 dst输出图像与输入图像src具有相同的尺寸和通道数 ddepth输出图像的数据类型深度根据输入图像的数据类型不同拥有不同的取值范围 ksize滤波器的大小必须为正奇数 scale对导数计算结果进行缩放的缩放因子默认系数为1不进行缩放 delta偏值在计算结果中加上偏值 borderType像素外推法选择标志 */七、Canny算子边缘检测1、Canny边缘检测原理介绍Canny边缘检测的主要步骤1 使用高斯滤波平滑图像在进行边缘检测之前首先需要对原始图像进行平滑处理。因为图像在采集、传输过程中不可避免会引入噪声而边缘检测本质上依赖于灰度变化率导数这种运算会对噪声非常敏感甚至会把噪声误判为边缘。常用高斯滤波平滑图像滤波器​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​2 计算图像中每个像素的梯度方向和幅度在平滑后的图像上计算每个像素点的灰度变化情况。通常通过Sobel算子分别计算水平方向和垂直方向的变化量得到两个梯度分量 Ix 和 Iy​。然后将这两个分量合成为梯度方向 θ表示变化发生的方向用于确定边缘的走向梯度幅值 G表示灰度变化的强度用来判断该点是否可能是边缘3 应用非极大值抑制算法边缘检测带来的杂散响应在上一步中得到的边缘通常是比较“粗”的带状结构而不是理想的单像素边缘。因此需要进一步细化。非极大值抑制的核心思想是沿着梯度方向只保留局部最大的那个像素点其余的全部抑制为0。也就是说如果某个像素点不是该方向上的“最高点”就认为它不是最真实的边缘位置。经过这一步处理后边缘会从“宽线条”变成“细线条”更加精确。4 应用双阈值法划分强边缘和弱边缘经过非极大值抑制后图像中仍然存在一些不确定的边缘需要进一步筛选。Canny算法采用双阈值策略而不是简单的单阈值。具体做法是设置一个高阈值和一个低阈值梯度值高于高阈值的像素 → 明确的强边缘梯度值介于两者之间 → 可能的弱边缘梯度值低于低阈值 → 直接认为不是边缘这种方法的优势在于既能保留明显边缘又不会因为阈值过高导致边缘断裂。5 消除孤立的弱边缘边缘连接 / 滞后处理在弱边缘中既包含真实边缘只是强度较低也包含噪声。为了区分它们Canny引入“边缘连接”策略。具体规则是如果一个弱边缘像素与强边缘相连8邻域连接则认为它属于真实边缘 → 保留如果一个弱边缘像素是孤立的没有连接到强边缘 → 认为是噪声 → 删除通过这一步可以有效去除孤立噪声点同时保证边缘的连续性。2、Canny算法函数/* 用途用于进行高质量边缘检测通过一整套优化流程高斯滤波、梯度计算、 非极大值抑制、双阈值筛选和边缘连接提取图像中的清晰边缘。 相比Sobel、Laplacian等基础算子Canny能够有效抑制噪声、 保留真实边缘并去除伪边缘 */ void cv::Canny( InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize 3, bool L2gradient false ); /* image输入图像必须是CV_8U单通道或者三通道图像 edges输出图像与输入图像具有相同尺寸的单通道图像且数据类型为CV_8U threshold1第一个滞后阈值低阈值----弱边缘判定 threshold2第二个滞后阈值高阈值----强边缘判定 apertureSizeSobel算子的直径 L2gradient计算图像梯度幅值的标志是否使用更精确的梯度计算方式 */八、示例代码QString imgPath QApplication::applicationDirPath() /Images; cv::String s_imgPath imgPath.toLocal8Bit().data(); Mat img imread(s_imgPath /equalLena.jpg, IMREAD_ANYCOLOR); if (img.empty()) { qDebug() 图片加载失败, 请确认图像文件名称是否正确; return; } Mat result, result_g, result_G; /*未滤波提取边缘*/ Laplacian(img, result, CV_16S, 3, 1, 0); convertScaleAbs(result, result); /*滤波后提取Laplacian边缘*/ GaussianBlur(img, result_g, Size(3, 3), 5, 0); Laplacian(result_g, result_G, CV_16S, 3, 1, 0); convertScaleAbs(result_G, result_G); imshow(result, result); imshow(result_G, result_G); waitKey(0); Mat resultHigh, resultLow, resultG; /*大阈值检测图像边缘*/ Canny(img, resultHigh, 100, 200, 3); /*小阈值检测图像边缘*/ Canny(img, resultLow, 20, 40, 3); /*高斯模糊后检测图像边缘*/ GaussianBlur(img, resultG, Size(3, 3), 5); Canny(resultG, resultG, 100, 200, 3); imshow(resultHigh, resultHigh); imshow(resultLow, resultLow); imshow(resultG, resultG); waitKey(0); destroyAllWindows();九、四种边缘检测算子对比表对比维度Sobel算子Scharr算子Laplacian算子Canny算子算子类型一阶梯度一阶梯度优化版二阶导数多阶段算法数学本质一阶偏导近似改进的一阶偏导二阶偏导散度梯度 优化流程是否有方向性有x/y有x/y无有梯度方向核心公式梯度 ∇f梯度 ∇f更精确∇²f多步骤非单一公式卷积核大小3×3 / 5×5固定3×33×3常用不固定组合抗噪声能力中等带平滑中等优于Sobel差极敏感强高斯滤波边缘定位精度中等高高但不稳定很高边缘连续性一般一般较差易断裂很好是否产生双边缘可能可能容易产生基本不会对细节敏感度中高很高含噪声高受阈值控制计算复杂度低低低较高实时性强强强一般典型问题方向误差基本无明显问题噪声放大参数敏感是否需要预处理可选可选必须平滑内置高斯是否需要后处理可选可选可选已包含OpenCV函数Sobel()Scharr()Laplacian()Canny()精度优先Canny Scharr Sobel Laplacian速度优先Sobel ≈ Scharr ≈ Laplacian Canny稳定性Canny Scharr Sobel Laplacian