博客
关于我
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/

    你可能感兴趣的文章
    Mysql-事务阻塞
    查看>>
    Mysql-存储引擎
    查看>>
    mysql-开启慢查询&所有操作记录日志
    查看>>
    MySQL-数据目录
    查看>>
    MySQL-数据页的结构
    查看>>
    MySQL-架构篇
    查看>>
    MySQL-索引的分类(聚簇索引、二级索引、联合索引)
    查看>>
    Mysql-触发器及创建触发器失败原因
    查看>>
    MySQL-连接
    查看>>
    mysql-递归查询(二)
    查看>>
    MySQL5.1安装
    查看>>
    mysql5.5和5.6版本间的坑
    查看>>
    mysql5.5最简安装教程
    查看>>
    mysql5.6 TIME,DATETIME,TIMESTAMP
    查看>>
    mysql5.6.21重置数据库的root密码
    查看>>
    Mysql5.6主从复制-基于binlog
    查看>>
    MySQL5.6忘记root密码(win平台)
    查看>>
    MySQL5.6的Linux安装shell脚本之二进制安装(一)
    查看>>
    MySQL5.6的zip包安装教程
    查看>>
    mysql5.7 for windows_MySQL 5.7 for Windows 解压缩版配置安装
    查看>>