博客
关于我
Sobel算子边缘检测原理及实现
阅读量:798 次
发布时间:2023-04-15

本文共 3934 字,大约阅读时间需要 13 分钟。

Sobel算子:边缘检测的精确选择

1. 算子概述

Sobel算子是一种广泛应用于图像处理领域的边缘检测算子。它通过计算图像在水平和垂直方向上的梯度,能够有效地提取图像的边缘信息。与Prewitt算子和Roberts算子相比,Sobel算子的特点是其对像素位置的加权处理,能够在保持精度的同时,提高边缘检测的准确性。

2. 优点分析

Sobel算子的主要优势体现在以下几个方面:

  • 边缘定位准确:Sobel算子能够较为精确地定位图像的边缘,尤其在处理灰度渐变和噪声较多的图像时表现突出。
  • 计算简便:相比于其他边缘检测算子,Sobel算子的计算过程较为简单,且可以分别计算水平和垂直方向的边缘。
  • 可分离性:Sobel算子的边缘检测过程具有很强的可分离性,可以通过先平滑后差分的方式实现,从而提高了计算效率。

3. 工作原理

3.1 平滑算子

Sobel算子的平滑过程采用了非归一化的高斯平滑原理。具体来说,平滑算子的系数来源于二项式展开式的系数。对于窗口大小为3的情况,平滑算子的系数为:[ [1, 1] ]而对于更大的窗口大小,平滑算子的系数可以通过将二项式系数进行扩展得到。例如,窗口大小为5时,平滑算子的系数为:[ [1, 3, 3, 1] ]

3.2 差分算子

差分算子是通过对平滑算子进行后向差分得到的。例如,窗口大小为5时,差分算子的系数为:[ [1, 2, 0, -2, -1] ]差分算子的作用是从平滑算子中提取出边缘的变化信息。

3.3 边缘检测流程

Sobel算子的边缘检测流程可以分为两个主要步骤:

  • 水平方向平滑:使用平滑算子对图像进行水平方向的平滑处理。
  • 垂直方向差分:对平滑后的图像进行垂直方向的差分操作,从而得到垂直方向的边缘信息。
  • 水平方向差分:对平滑后的图像进行水平方向的差分操作,从而得到水平方向的边缘信息。
  • 通过上述流程,Sobel算子能够分别计算出图像的水平和垂直边缘信息。

    4. 代码实现

    4.1 平滑算子和差分算子的构建

    int factorial(int n) {    int fac = 1;    if (n == 0) return fac;    for (int i = 1; i <= n; ++i) {        fac *= i;    }    return fac;}cv::Mat getSobelSmooth(int wsize) {    int n = wsize - 1;    cv::Mat smoothKernel = cv::Mat::zeros(cv::Size(wsize, 1), CV_32FC1);    for (int k = 0; k <= n; ++k) {        float *ptr = smoothKernel.ptr
    (0); ptr[k] = factorial(n) / (factorial(k) * factorial(n - k)); } return smoothKernel;}cv::Mat getSobeldiff(int wsize) { cv::Mat diffKernel = cv::Mat::zeros(cv::Size(wsize, 1), CV_32FC1); cv::Mat smoothKernel = getSobelSmooth(wsize - 1); for (int k = 0; k < wsize; ++k) { if (k == 0) { diffKernel.at
    (0, k) = 1; } else if (k == wsize - 1) { diffKernel.at
    (0, k) = -1; } else { diffKernel.at
    (0, k) = smoothKernel.at
    (0, k) - smoothKernel.at
    (0, k - 1); } } return diffKernel;}

    4.2 可分离卷积实现

    void sepConv2D_Y_X(cv::Mat &src, cv::Mat &dst, cv::Mat &kernel_Y, cv::Mat &kernel_X, int ddepth, cv::Point anchor = cv::Point(-1, -1), int delta = 0, int borderType = cv::BORDER_DEFAULT) {    cv::Mat temp = conv2D(src, temp, kernel_Y, ddepth, anchor, delta, borderType);    conv2D(temp, dst, kernel_X, ddepth, anchor, delta, borderType);}void sepConv2D_X_Y(cv::Mat &src, cv::Mat &dst, cv::Mat &kernel_X, cv::Mat &kernel_Y, int ddepth, cv::Point anchor = cv::Point(-1, -1), int delta = 0, int borderType = cv::BORDER_DEFAULT) {    cv::Mat temp = conv2D(src, temp, kernel_X, ddepth, anchor, delta, borderType);    conv2D(temp, dst, kernel_Y, ddepth, anchor, delta, borderType);}

    4.3 边缘检测主函数

    void Sobel(cv::Mat &src, cv::Mat &dst_X, cv::Mat &dst_Y, cv::Mat &dst, int wsize, int ddepth) {    cv::Mat smoothKernel = getSobelSmooth(wsize);    cv::Mat diffKernel = getSobeldiff(wsize);        sepConv2D_Y_X(src, dst_X, smoothKernel, diffKernel, ddepth);    sepConv2D_X_Y(src, dst_Y, smoothKernel, diffKernel, ddepth);        cv::abs(dst_X, dst_X);    cv::abs(dst_Y, dst_Y);    cv::convertScaleAbs(dst, dst);}

    4.4 使用示例

    int main() {    cv::Mat src = cv::imread("I:\\Learning-and-Practice\\2019Change\\Image process algorithm\\Img\\Fig1025(a)(building_original).tif");    if (src.empty()) {        return -1;    }    if (src.channels() > 1) {        cv::cvtColor(src, src, CV_RGB2GRAY);    }        int wsize = 3;    cv::Mat SobelDiff, SobelSmooth;    Sobel(src, dst_Y, dst_X, dst, wsize, CV_32FC1);        cv::namedWindow("src", CV_WINDOW_NORMAL);    imshow("src", src);        cv::namedWindow("水平边缘", CV_WINDOW_NORMAL);    imshow("水平边缘", dst_Y);        cv::namedWindow("垂直边缘", CV_WINDOW_NORMAL);    imshow("垂直边缘", dst_X);        cv::namedWindow("边缘强度", CV_WINDOW_NORMAL);    imshow("边缘强度", dst);        cv::namedWindow("边缘强度取反-铅笔素描", CV_WINDOW_NORMAL);    imshow("边缘强度取反-铅笔素描", 255 - dst);        cv::waitKey(0);    return 0;}

    5. 效果展示

    5.1 原图和边缘检测结果

    通过对比原图和边缘检测结果,可以清晰地看到Sobel算子捕捉到的边缘信息。图像的水平和垂直方向的边缘都被准确地提取出来,显示出图像的轮廓和细节。

    5.2 铅笔素描效果

    将边缘检测结果取反后,可以得到一种类似铅笔素描的效果。这种效果特别适用于手绘风格的图像处理,能够突出图像的轮廓和主要细节。

    6. 参考文献

    • 《OpenCV算法精解》--- 张平

    转载地址:http://ggrfk.baihongyu.com/

    你可能感兴趣的文章
    MTCNN 人脸检测
    查看>>
    MyEcplise中SpringBoot怎样定制启动banner?
    查看>>
    MyPython
    查看>>
    MTD技术介绍
    查看>>
    MySQL
    查看>>
    MySQL
    查看>>
    mysql
    查看>>
    MTK Android 如何获取系统权限
    查看>>
    MySQL - 4种基本索引、聚簇索引和非聚索引、索引失效情况、SQL 优化
    查看>>
    MySQL - ERROR 1406
    查看>>
    mysql - 视图
    查看>>
    MySQL - 解读MySQL事务与锁机制
    查看>>
    MTTR、MTBF、MTTF的大白话理解
    查看>>
    mt_rand
    查看>>
    mysql -存储过程
    查看>>
    mysql /*! 50100 ... */ 条件编译
    查看>>
    mudbox卸载/完美解决安装失败/如何彻底卸载清除干净mudbox各种残留注册表和文件的方法...
    查看>>
    mysql 1264_关于mysql 出现 1264 Out of range value for column 错误的解决办法
    查看>>
    mysql 1593_Linux高可用(HA)之MySQL主从复制中出现1593错误码的低级错误
    查看>>
    mysql 5.6 修改端口_mysql5.6.24怎么修改端口号
    查看>>