• opencv基础篇 ——(七)边缘检测和图像锐化


            锐化和边缘检测是图像处理中常用的两种技术,它们可以用来增强图像的特征以及检测图像中的边缘

    锐化: 锐化是一种增强图像中细节和边缘的技术,它使图像中的过渡区域更加明显,从而提高图像的清晰度和对比度。常见的锐化方法包括拉普拉斯算子和高斯滤波器等。

    边缘检测: 边缘检测是一种寻找图像中突变区域的技术,它可以帮助我们找到图像中不同区域之间的边界。常见的边缘检测算法包括 Sobel、Canny 和 Scharr 等。

    拉普拉斯算子laplacian 

            cv::laplacian 是 OpenCV 库中用于计算图像拉普拉斯算子(Laplacian operator)的函数,常用于边缘检测和图像锐化。拉普拉斯算子是一个二阶微分算子,可以捕捉图像中灰度值的快速变化,即边缘和细节变化。

    函数声明:

    1. void cv::laplacian(
    2. InputArray src,
    3. OutputArray dst,
    4. int ddepth,
    5. int ksize = 1,
    6. double scale = 1,
    7. double delta = 0,
    8. int borderType = BORDER_DEFAULT);

    参数说明:

    • InputArray src: 输入图像,可以是单通道 8-bit、16-bit 或 32-bit 浮点型图像,或者是多通道图像(在这种情况下,每个通道分别计算拉普拉斯响应,然后组合成输出图像)。

    • OutputArray dst: 输出图像,存储计算得到的拉普拉斯响应。数据类型取决于 ddepth 参数。

    • int ddepth: 输出图像的数据深度。可以选择如下值:

      • -1:表示与输入图像 src 同样的深度。
      • CV_8UCV_16UCV_16SCV_32F 或 CV_64F:指定输出图像的具体数据类型。
    • int ksize: 拉普拉斯滤波器的大小,必须为奇数且大于等于 1。较大的 ksize 可以平滑噪声,但可能会降低边缘定位的精度;较小的 ksize 对噪声敏感,但能更好地保留边缘细节。

    • double scale: 用于调整拉普拉斯响应的尺度因子。计算出的拉普拉斯值乘以 scale 后再存储到输出图像中。默认值为 1

    • double delta: 加到拉普拉斯响应上的偏置值。通常用于避免由于计算导致的负值或值过小的问题,有助于保持结果的动态范围。默认值为 0

    • int borderType: 边界填充类型,定义了如何处理图像边缘以外的像素。可选值包括:

      • BORDER_CONSTANT: 使用指定的 borderValue 填充边缘。
      • BORDER_REPLICATE: 复制边缘像素值。
      • BORDER_REFLECT: 反射边缘像素。
      • BORDER_WRAP: 包裹边缘像素。
      • 其他边界模式,具体参见 OpenCV 文档。

      默认值为 BORDER_DEFAULT,相当于 BORDER_REFLECT_101,即边缘像素以一种类似镜面反射的方式扩展。

    工作原理与应用:

    cv::laplacian 函数计算输入图像 src 上的拉普拉斯算子响应。拉普拉斯算子本质上是对图像在二维空间上进行二次微分,其数学表达式为:

    其中,( f(x, y) ) 表示图像在坐标 ( (x, y) )处的灰度值。通过计算图像在水平和垂直方向上的二阶导数之和,拉普拉斯算子能够检测到灰度值的过零点(zero-crossings),这些点通常对应图像中的边缘位置。

    在实际计算过程中,cv::laplacian 函数使用一个离散化的模板(卷积核)来近似拉普拉斯算子。模板的大小由 ksize 参数指定,常见的如 3x35x5 等。模板内的系数构成一个类似于: 

    的对角线权重分布,中心像素与周围像素的差异被放大,从而凸显边缘。

    应用示例:

    1. // 读取输入图像
    2. cv::Mat src = cv::imread("input_image.png", cv::IMREAD_GRAYSCALE);
    3. // 计算拉普拉斯响应,输出图像为 CV_8U 类型
    4. cv::Mat laplacianImage;
    5. cv::Laplacian(src, laplacianImage, CV_8U, 3);
    6. // 将拉普拉斯响应进行阈值处理以获得边缘图像
    7. cv::threshold(laplacianImage, laplacianImage, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    8. // 显示结果
    9. cv::imshow("Original Image", src);
    10. cv::imshow("Laplacian Edges", laplacianImage);
    11. cv::waitKey();

    边缘检测算法Canny 

      cv::Canny 是 OpenCV 库中用于实现 Canny 边缘检测算法的函数。Canny 边缘检测是一种广泛应用的边缘检测方法,因其能够提供高质量、单像素宽且无断点的边缘,同时具备较好的抗噪性能而闻名。

    函数声明:

    1. void cv::Canny(
    2. InputArray image,
    3. OutputArray edges,
    4. double threshold1,
    5. double threshold2,
    6. int apertureSize = 3,
    7. bool L2gradient = false);

    参数说明:

    • InputArray image: 输入图像,通常为单通道 8-bit 或浮点型灰度图像。为了得到最佳结果,建议先对彩色图像进行灰度化处理。

    • OutputArray edges: 输出边缘图像,与输入图像 image 同样大小,存储类型为 8-bit 单通道图像,其中边缘像素值为非零值(通常为 255),非边缘像素值为零。

    • double threshold1: 较低阈值。任何边缘强度高于此阈值的像素被认为是潜在边缘。

    • double threshold2: 较高阈值。只有那些连接到至少一个高于较高阈值的边缘像素的潜在边缘才会最终被保留为真正的边缘。

    • int apertureSize: Sobel 导数计算时使用的卷积核大小,一般取值为 3 或 5。较大的值可以提供更精确的边缘方向估计,但计算成本更高。

    • bool L2gradient: 是否使用 L2 范数(欧几里得范数)来计算图像梯度。默认值为 false,表示使用 L1 范数(绝对值和)。

    工作原理与应用:

    Canny 边缘检测算法通常包含以下四个步骤:

    1. 高斯滤波: 首先对输入图像进行高斯平滑,以减少噪声对边缘检测的影响。这一步通常使用高斯核进行卷积操作。

    2. 梯度计算: 计算平滑后的图像在水平和垂直方向上的一阶导数(梯度)。OpenCV 使用 Sobel 算子或者 Scharr 算子(如果指定了 L2gradient=true)来完成这一任务。计算得到的梯度包括幅值(表示边缘强度)和方向。

    3. 非极大值抑制: 在梯度方向上对每个像素进行局部比较,如果该像素的梯度幅值不是其梯度方向上邻域内的最大值(即非极大值),则将其梯度幅值置零,以消除边缘检测过程中产生的虚假响应。

    4. 双阈值检测: 应用两个阈值(threshold1 和 threshold2)来确定最终的边缘。所有梯度幅值高于较高阈值的像素被认为是边缘像素;对于幅值介于高低阈值之间的像素,如果它们与已确定的边缘像素(即幅值超过较高阈值的像素)相连,则也被认为是边缘像素。低于较低阈值的像素被舍弃。

    应用示例:

    1. // 读取输入图像并转换为灰度
    2. cv::Mat src = cv::imread("input_image.png", cv::IMREAD_GRAYSCALE);
    3. // 设置 Canny 边缘检测参数
    4. double lowThreshold = 100.0;
    5. double highThreshold = 200.0;
    6. // 执行 Canny 边缘检测
    7. cv::Mat edges;
    8. cv::Canny(src, edges, lowThreshold, highThreshold, 3);
    9. // 显示结果
    10. cv::imshow("Original Image", src);
    11. cv::imshow("Canny Edges", edges);
    12. cv::waitKey();

    索贝尔算子 Sobel

            Sobel 算子是一种常用的边缘检测算子,通过计算图像在特定方向上的一阶或二阶导数来检测图像中的边缘。

    函数声明:

    1. void cv::Sobel(
    2. InputArray src,
    3. OutputArray dst,
    4. int ddepth,
    5. int dx,
    6. int dy,
    7. int ksize = 3,
    8. double scale = 1,
    9. double delta = 0,
    10. int borderType = BORDER_DEFAULT);

    参数说明:

    • InputArray src: 输入图像,通常为单通道 8-bit 或浮点型灰度图像。为了得到最佳结果,建议先对彩色图像进行灰度化处理。

    • OutputArray dst: 输出图像,存储计算得到的 Sobel 算子响应。数据类型取决于 ddepth 参数。

    • int ddepth: 输出图像的数据深度。可以选择如下值:

      • -1:表示与输入图像 src 同样的深度。
      • CV_8UCV_16UCV_16SCV_32F 或 CV_64F:指定输出图像的具体数据类型。
    • int dx 和 int dy: 分别表示在 x 轴和 y 轴方向上的微分阶数。通常 dx 和 dy 取值为 1(表示一阶导数),用于计算图像在水平和垂直方向上的边缘。若两者均为 0,则 cv::Sobel 函数相当于进行图像平滑处理。也可以取值为 2(表示二阶导数),用于计算图像的拉普拉斯响应(边缘强度)。

    • int ksize: Sobel 核函数的大小,必须为奇数且大于等于 1。常见的取值有 357 等。较大的 ksize 可以平滑噪声,但可能会降低边缘定位的精度;较小的 ksize 对噪声敏感,但能更好地保留边缘细节。

    • double scale: 用于调整 Sobel 响应的尺度因子。计算出的 Sobel 值乘以 scale 后再存储到输出图像中。默认值为 1

    • double delta: 加到 Sobel 响应上的偏置值。通常用于避免由于计算导致的负值或值过小的问题,有助于保持结果的动态范围。默认值为 0

    • int borderType: 边界填充类型,定义了如何处理图像边缘以外的像素。可选值包括:

      • BORDER_CONSTANT: 使用指定的 borderValue 填充边缘。
      • BORDER_REPLICATE: 复制边缘像素值。
      • BORDER_REFLECT: 反射边缘像素。
      • BORDER_WRAP: 包裹边缘像素。
      • 其他边界模式,具体参见 OpenCV 文档。

      默认值为 BORDER_DEFAULT,相当于 BORDER_REFLECT_101,即边缘像素以一种类似镜面反射的方式扩展。

    工作原理与应用:

    cv::Sobel 函数计算输入图像 src 上的 Sobel 算子响应。Sobel 算子本质上是一种离散化的微分算子,用于估计图像在特定方向上的导数。对于一阶导数,Sobel 算子的核函数在 x 轴和 y 轴方向上分别为:

    1. -1 0 1
    2. -2 0 2
    3. -1 0 1

    1. -1 -2 -1
    2. 0 0 0
    3. 1 2 1

    计算得到的响应可以反映图像在相应方向上灰度值的变化情况,即边缘信息。当 dx 和 dy 为 1 时,cv::Sobel 函数返回图像在 x 轴和 y 轴方向上的梯度;当两者均为 2 时,返回图像的拉普拉斯响应,即边缘强度。

    在实际应用中,cv::Sobel 函数通常用于计算图像在 x 轴和 y 轴方向上的梯度幅值和方向,进而用于边缘检测、图像分析和计算机视觉任务。计算得到的 Sobel 响应可以进一步通过阈值处理、非极大值抑制等步骤提取出图像的边缘。

    应用示例:

    1. // 读取输入图像并转换为灰度
    2. cv::Mat src = cv::imread("input_image.png", cv::IMREAD_GRAYSCALE);
    3. // 计算 Sobel 响应在 x 轴和 y 轴方向上的响应
    4. cv::Mat sobelX, sobelY;
    5. cv::Sobel(src, sobelX, CV_32F, 1, 0, 3);
    6. cv::Sobel(src, sobelY, CV_32F, 0, 1, 3);
    7. // 计算梯度幅值和方向
    8. cv::Mat gradientMag, gradientAngle;
    9. cv::cartToPolar(sobelX, sobelY, gradientMag, gradientAngle, true);
    10. // 应用阈值处理提取边缘
    11. double edgeThresh = 50.0;
    12. cv::Mat edges;
    13. cv::threshold(gradientMag, edges, edgeThresh, 255, cv::THRESH_BINARY);
    14. // 显示结果
    15. cv::imshow("Original Image", src);
    16. cv::imshow("Sobel Edges", edges);
    17. cv::waitKey();

    Scharr算子

            Scharr 算子是一种专门设计用于图像边缘检测的微分算子,它是 Sobel 算子的一种改进版本,特别是在处理较小的内核尺寸(如 3x3)时,Scharr 算子能提供更高的精度。

    函数声明:

    1. void cv::Scharr(
    2. InputArray src,
    3. OutputArray dst,
    4. int ddepth,
    5. int dx,
    6. int dy,
    7. double scale = 1,
    8. double delta = 0,
    9. int borderType = BORDER_DEFAULT);

    参数说明:

    • InputArray src: 输入图像,通常为单通道 8-bit 或浮点型灰度图像。为了得到最佳结果,建议先对彩色图像进行灰度化处理。

    • OutputArray dst: 输出图像,存储计算得到的 Scharr 算子响应。数据类型取决于 ddepth 参数。

    • int ddepth: 输出图像的数据深度。可以选择如下值:

      • -1:表示与输入图像 src 同样的深度。
      • CV_8UCV_16UCV_16SCV_32F 或 CV_64F:指定输出图像的具体数据类型。
    • int dx 和 int dy: 分别表示在 x 轴和 y 轴方向上的微分阶数。通常 dx 和 dy 取值为 1(表示一阶导数),用于计算图像在水平和垂直方向上的边缘。若两者均为 0,则 cv::Scharr 函数相当于进行图像平滑处理。

    • double scale: 用于调整 Scharr 响应的尺度因子。计算出的 Scharr 值乘以 scale 后再存储到输出图像中。默认值为 1

    • double delta: 加到 Scharr 响应上的偏置值。通常用于避免由于计算导致的负值或值过小的问题,有助于保持结果的动态范围。默认值为 0

    • int borderType: 边界填充类型,定义了如何处理图像边缘以外的像素。可选值包括:

      • BORDER_CONSTANT: 使用指定的 borderValue 填充边缘。
      • BORDER_REPLICATE: 复制边缘像素值。
      • BORDER_REFLECT: 反射边缘像素。
      • BORDER_WRAP: 包裹边缘像素。
      • 其他边界模式,具体参见 OpenCV 文档。

      默认值为 BORDER_DEFAULT,相当于 BORDER_REFLECT_101,即边缘像素以一种类似镜面反射的方式扩展。

    工作原理与应用:

    cv::Scharr 函数计算输入图像 src 上的 Scharr 算子响应。Scharr 算子是一种精确的一阶微分算子,其核函数在设计时考虑了像素间的距离权重,使得在小内核尺寸(如 3x3)下也能更精确地逼近图像的一阶导数。对于一阶导数,Scharr 算子的核函数在 x 轴和 y 轴方向上分别为:

    1. 3 10 3
    2. 0 0 0
    3. -3 -10 -3

    1. -3 0 3
    2. -10 0 10
    3. -3 0 3

    相比于传统的 Sobel 算子,Scharr 算子的权重分配更接近于理论上的精确一阶导数计算,尤其是在接近图像边缘的像素处,这使得它在相同内核尺寸下能提供更精确的边缘检测结果。

    在实际应用中,cv::Scharr 函数通常用于计算图像在 x 轴或 y 轴方向上的梯度幅值和方向,进而用于边缘检测、图像分析和计算机视觉任务。计算得到的 Scharr 响应可以进一步通过阈值处理、非极大值抑制等步骤提取出图像的边缘。

    应用示例:

    1. // 读取输入图像并转换为灰度
    2. cv::Mat src = cv::imread("input_image.png", cv::IMREAD_GRAYSCALE);
    3. // 计算 Scharr 响应在 x 轴和 y 轴方向上的响应
    4. cv::Mat scharrX, scharrY;
    5. cv::Scharr(src, scharrX, CV_32F, 1, 0);
    6. cv::Scharr(src, scharrY, CV_32F, 0, 1);
    7. // 计算梯度幅值和方向
    8. cv::Mat gradientMag, gradientAngle;
    9. cv::cartToPolar(scharrX, scharrY, gradientMag, gradientAngle, true);
    10. // 应用阈值处理提取边缘
    11. double edgeThresh = 50.0;
    12. cv::Mat edges;
    13. cv::threshold(gradientMag, edges, edgeThresh, 255, cv::THRESH_BINARY);
    14. // 显示结果
    15. cv::imshow("Original Image", src);
    16. cv::imshow("Scharr Edges", edges);
    17. cv::waitKey();

    spatialGradient 算子

            cv::spatialGradient 是 OpenCV 库中用于计算图像的局部空间梯度(即 x 和 y 方向的一阶导数)的函数。该函数返回一个包含两个元素的 std::vector,分别表示图像在 x 轴和 y 轴方向上的梯度响应。

    1. std::vector cv::spatialGradient(
    2. InputArray src,
    3. OutputArray dx,
    4. OutputArray dy,
    5. int ksize = 3,
    6. int borderType = BORDER_DEFAULT);

    参数说明:

    • InputArray src: 输入图像,通常为单通道 8-bit 或浮点型灰度图像。为了得到最佳结果,建议先对彩色图像进行灰度化处理。

    • OutputArray dx 和 OutputArray dy: 可选的输出参数,分别用于存储图像在 x 轴和 y 轴方向上的梯度响应。如果不提供这两个参数,函数将返回一个包含两个元素的 std::vector 结果。

    • int ksize: 梯度计算所使用的卷积核大小,必须为奇数且大于等于 1。常见的取值有 357 等。较大的 ksize 可以平滑噪声,但可能会降低边缘定位的精度;较小的 ksize 对噪声敏感,但能更好地保留边缘细节。

    • int borderType: 边界填充类型,定义了如何处理图像边缘以外的像素。可选值包括:

      • BORDER_CONSTANT: 使用指定的 borderValue 填充边缘。
      • BORDER_REPLICATE: 复制边缘像素值。
      • BORDER_REFLECT: 反射边缘像素。
      • BORDER_WRAP: 包裹边缘像素。
      • 其他边界模式,具体参见 OpenCV 文档。

      默认值为 BORDER_DEFAULT,相当于 BORDER_REFLECT_101,即边缘像素以一种类似镜面反射的方式扩展。

    工作原理与应用:

    cv::spatialGradient 函数计算输入图像 src 上的局部空间梯度,即在 x 轴和 y 轴方向上的一阶导数。函数内部可能使用 Sobel 算子、Scharr 算子或其他适当的微分算子来计算梯度。计算得到的梯度响应反映了图像在相应方向上灰度值的变化情况,即边缘信息。

    在实际应用中,cv::spatialGradient 函数通常用于计算图像在 x 轴和 y 轴方向上的梯度幅值和方向,进而用于边缘检测、图像分析和计算机视觉任务。计算得到的梯度响应可以进一步通过阈值处理、非极大值抑制等步骤提取出图像的边缘。

    应用示例:

    1. // 读取输入图像并转换为灰度
    2. cv::Mat src = cv::imread("input_image.png", cv::IMREAD_GRAYSCALE);
    3. // 计算图像的 x 和 y 方向梯度
    4. cv::Mat dx, dy;
    5. cv::spatialGradient(src, dx, dy, 3);
    6. cv::Mat fdx, fdy;
    7. dx.convertTo(fdx, CV_32F);
    8. dy.convertTo(fdy, CV_32F);
    9. // 计算梯度幅值和方向
    10. cv::Mat gradientMag, gradientAngle;
    11. cv::cartToPolar(fdx, fdy, gradientMag, gradientAngle, true);
    12. // 应用阈值处理提取边缘
    13. double edgeThresh = 50.0;
    14. cv::Mat edges;
    15. cv::threshold(gradientMag, edges, edgeThresh, 255, cv::THRESH_BINARY);
    16. // 显示结果
    17. cv::imshow("Original Image", src);
    18. cv::imshow("Spatial Gradient Edges", edges);
    19. cv::waitKey();

    效果展示

    laplacian、canny算子效果

    sobel、scharr算子效果

    spatialGradient 算子

  • 相关阅读:
    52.【Java 数据结构——线性表】
    二.STM32F030C8T6 MCU开发之 NVIC中断配置
    什么是SDN?用一篇文章彻底讲明白 SDN 软件定义网络是什么!
    (AtCoder Beginner Contest 321)(退背包,二叉树)
    【7-创建商城系统的子模块并将修改后的信息使用Git提交到Gitee上】
    ZCMU--1431: Epic Game(C语言)
    VS编程技巧——写好枚举后自动补全switch
    只要15分钟,轻松get费用报销系统
    LiveCharts.Wpf 的使用
    ALevel生物vs普高生物的区别
  • 原文地址:https://blog.csdn.net/fengqiao1999/article/details/137925235