OpenCV(十五)边缘检测1 -- Sobel算子(一阶微分算子,X、Y方向边缘检测)

2023-10-27

目录

一、边缘检测基础理论

1、作用:

2、分类

1、基于搜索

 2、基于零穿越

3、算子比较

二、Sobel算子基础理论

1、作用

2、原理及推导

3、更详细推导

4、Sobel函数

 二、实战

1、对x方向微分

2、对y方向微分

3、线性混合

总代码

其他应用

参考资料


一、边缘检测基础理论

1、作用:

图像边缘检测大幅度地减少了数据量,并且剔除了不相关的信息保留了图像重要的结构属性

        边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的标识数字图像中亮度变化明显的点图像属性中的显著变化通常反映了属性的重要事件和变化。边缘的表现形式如下图所示:

纵轴:灰度值 横轴:位置信息

图像边缘检测大幅度地减少了数据量,并且剔除了不相关的信息保留了图像重要的结构属性。有许多方法用于边缘检测,它们的绝大部分可以划分为两类∶基于搜索基于零穿越

2、分类

基于搜索:利用一阶导数最大值检测边缘

基于零穿越:利用二阶导数为0检测边缘

1、基于搜索

基于搜索:通过寻找图像一阶导数中的最大值检测边界,然后利用计算结果估计边缘的局部方向通常采用梯度的方向,并利用此方向找到局部梯度模的最大值,代表算法是Sobel算子Scharr算子

原理:边缘附近的像素值会有明显突变,即变化最大,也就是一阶导数最大。那么找到最大的一阶导数也就找到了像素变化最大的点,即边缘点。

 2、基于零穿越

基于零穿越:通过寻找二阶导数零穿越寻找边界,代表算法是Laplace算子

原理:在一阶导数的基础上再求一次导,那么此时零点就是变化最大的点,即边缘点。

3、算子比较

其中,Canny算子永远的神!(最优边缘检测)

二、Sobel算子基础理论

1、作用

Sobel算子:用于边缘检测离散微分算子。(一阶)(结合了高斯平滑微分

1、边缘检测: Gx 用于检测纵向边缘, Gy 用于检测横向边缘.

2、计算法线: Gx 用于计算法线的横向偏移, Gy 用于计算法线的纵向偏移.

        Sobel边缘检测算法比较简单,实际应用中效率比canny边缘检测效率要,但是边缘不如Canny检测的准确,但是很多实际应用的场合,sobel边缘却是首选Sobel算子是高斯平滑与微分操作的结合体,所以其抗噪声能力很强,用途较多尤其是效率要求较高,而对细纹理不太关心的时候

注:需要x方向图像就对y求微分,需要y方向图像就对x求微分,两者颠倒
对x方向求导,得到的是y方向的边缘;
对y方向求导,得到的是x方向的边缘。

2、原理及推导

因为图像是二维的,所以需要在两个方向求导

垂直方向的边缘在水平方向梯度(偏导数)幅值较大

水平方向的边缘在垂直方向梯度(偏导数)幅值较大

Sobel算子刚好能描述这个图像变化

过程:

先分别求x和y方向sobel算子,再取绝对值转换成uint8),然后线性混合。(如图)

梯度公式

对于图像而言,它是离散的,所以h的最小值只能是1了,那么这意味着,图像中某个像素位置的梯度(以x方向为例)等于它左右两个像素点的像素之差除以2。

可以看出:后 - 前 

所以:

 

 综上求出:

例:假设有一行像素是这样分布的:
123 155 173
那么,像素值为155的像素位置x方向的梯度为(173 - 123)/2 = 25

Schar算子能够弥补Sobel内核为3时的误差:(更佳的3*3滤波器Scahrr ()函数)

3、更详细推导

 Prewitt算子:x方向和y方向卷积核分别为:

                         

sobel算子:在此基础上加了一些权值,结合了高斯平滑微分求导。

Sebel算子x方向和y方向的卷积核分别为:

求出了水平方向和竖直方向的梯度GxGy之后
近似的梯度就可以用下面的方法算出来: 

 

4、Sobel函数

void Sobel (InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize=3, 
            double scale=1, double delta=0, int borderType=BORDER_DEFAULT );  

函数参数解释:

InputArray src:输入的原图像,Mat类型

OutputArray dst:输出的边缘检测结果图像,Mat型,大小与原图像相同。

int ddepth:输出图像的深度,针对不同的输入图像,输出目标图像有不同的深度,具体组合如下:

- 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F

- 若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F

- 若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F

- 若src.depth() = CV_64F, 取ddepth = -1/CV_64F

注:ddepth =-1时,代表输出图像与输入图像相同的深度。

int dx:int类型dx,x 方向上的差分阶数,1或0

int dy:int类型dy,y 方向上的差分阶数,1或0

其中,dx=1,dy=0,表示计算X方向的导数,检测出的是垂直方向上的边缘;dx=0,dy=1,表示计算Y方向的导数,检测出的是水平方向上的边缘。

int ksize:为进行边缘检测时的模板大小为ksize*ksize,取值为1、3、5和7,其中默认值为3。特殊情况:ksize=1时,采用的模板为3*1或1*3。

当ksize=3时,Sobel内核可能产生比较明显的误差,此时,可以使用 Scharr 函数,该函数仅作用于大小为3的内核。具有跟sobel一样的速度,但结果更精确,其内核为:

C++:

Sobel(gray, grad_x, CV_16S, 1,                0,           3);
    //                      x方向差分阶数    y方向差分阶数   核大小

 python:

x = cv.Sobel(img, cv.CV_16S, 1,     0)
y = cv.Sobel(img, cv.CV_16S, 0,     1)
#                 深度      x方向阶数 y方向阶数

 二、实战

首先欣赏下原图及灰度图:

src = imread("Resource/test12.jpg");
    imshow("原图", src);
    cvtColor(src, gray, COLOR_RGB2GRAY);   //转变为灰度图
    imshow("灰度图", src);

1、对x方向微分

对x方向微分,得到的是y方向的边缘。 

//对x方向微分
    Sobel(gray, grad_x, CV_16S, 1,                      0,                      3);   
    //                          x方向差分阶数           y方向差分阶数           核大小
    convertScaleAbs(grad_x, abs_grad_x);     //可将任意类型的数据转化为CV_8UC1
    imshow("【边缘图x】", abs_grad_x); 
    //边缘与梯度方向垂直,所以输出的边缘是和我们所计算的某一方向的梯度是垂直的

2、对y方向微分

对y方向微分,得到的是x方向的边缘。  

//对y方向微分
    Sobel(gray, grad_y, CV_16S, 0,                      1,                      3);
    //                         x方向差分阶数           y方向差分阶数           核大小
    convertScaleAbs(grad_y, abs_grad_y);     //可将任意类型的数据转化为CV_8UC1
    imshow("边缘图y", abs_grad_y);

3、线性混合

//图像的线性混合
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
    imshow("线性混合", dst);

总代码

C++:

//Sobel算子(微分)
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;

int main()
{
    Mat src, dst, gray, grad_x, grad_y, abs_grad_x, abs_grad_y;
    src = imread("Resource/test12.jpg");
    imshow("原图", src);
    cvtColor(src, gray, COLOR_RGB2GRAY);   //转变为灰度图
    imshow("灰度图", gray);

    //对x方向微分
    Sobel(gray, grad_x, CV_16S, 1,                      0,                      3);   
    //                                          x方向差分阶数   y方向差分阶数   核大小
    convertScaleAbs(grad_x, abs_grad_x);     //可将任意类型的数据转化为CV_8UC1
    imshow("边缘图x", abs_grad_x); 
    //边缘与梯度方向垂直,所以输出的边缘是和我们所计算的某一方向的梯度是垂直的

    //对y方向微分
    Sobel(gray, grad_y, CV_16S, 0,                      1,                      3);
    //                                          x方向差分阶数   y方向差分阶数   核大小
    convertScaleAbs(grad_y, abs_grad_y);     //可将任意类型的数据转化为CV_8UC1
    imshow("边缘图y", abs_grad_y);

    //图像的线性混合
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
    imshow("线性混合", dst);
   
    waitKey(0);
}

python:

# 边缘检测(Sobel、Laplace、Canny)
import cv2 as cv


# Sobel一阶微分算子
def Sobel():
    # 1、对X和Y方向求微分
    x = cv.Sobel(img, cv.CV_16S, 1,     0)
    y = cv.Sobel(img, cv.CV_16S, 0,     1)
    #                 深度      x方向阶数 y方向阶数

    # 2、取绝对值
    absX = cv.convertScaleAbs(x)  # 转回uint8
    absY = cv.convertScaleAbs(y)

    # 3、线性混合
    dst = cv.addWeighted(absX, 0.5, absY, 0.5, 0)
    #                          比例       比例  常数

    # 4、显示
    cv.imshow("absX", absX)
    cv.imshow("absY", absY)
    cv.imshow("dst", dst)


if __name__ == '__main__':
    # 读取图片
    img = cv.imread("Resource/test5.jpg")
    cv.imshow("img", img)

    Sobel()         #Sobel一阶微分算子

    cv.waitKey(0)

其他应用

x方向梯度使竖直的黑条特征变得明显):

 

参考资料

https://blog.csdn.net/weixin_44586473/article/details/93229385?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162895010516780271586263%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162895010516780271586263&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-93229385.ecpm_v1_rank_v29&utm_term=sobel&spm=1018.2226.3001.4187

https://www.baidu.com/link?url=14oBZycvBio7eVQbSDl-XWg_eyg92lbbpOCNxZu5g-rxq39fby3yvmI-_OYGULcmmQ0SuvMyGJU0dBPCZBeEYKHPi_pldWGT23zLbLry6DG&wd=&eqid=efae8130000106120000000561187322

https://www.bilibili.com/video/BV1Fo4y1d7JL?p=34&spm_id_from=pageDriver

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenCV(十五)边缘检测1 -- Sobel算子(一阶微分算子,X、Y方向边缘检测) 的相关文章

随机推荐

  • linux编译安装kvm、qemu

    kvm作为主流虚拟化产品 其实它的用户层使用的是qemu 所以要安装使用kvm 一般需要安装kvm kmod以及qemu两部分 安装kvm kmod 1 首先下载kvm kmod源码并解压 2 进入源码目录 3 configure kern
  • Spring Web MVC框架(五) 文件上传

    Spring同样支持文件上传功能 不过该功能默认未开启 因为可能有些开发者可能希望自己处理文件上传过程 Spring的文件上传功能在org springframework web multipart包下 有两个MultipartResolv
  • gitLab清理大文件_包括历史记录中的大文件

    文章目录 gitLab清理大文件 包括历史记录中的大文件 前言 查看仓库大小 解除保护分支 操作 gitLab清理大文件 包括历史记录中的大文件 项目中经常有不小心提交的大文件 这个就是清理方法 后面发现了更好的方法 使用bfg快速清理gi
  • 02.01 服务器开机报错

    Dell PowerEdge T320服务器 开机显示 Fatal Errort all channells have been disabled due to DIMMS falled the memory 原因 内存自检失败 可能是太久
  • yolo算法的优缺点分析_【精选推荐】基于深度学习的单阶段目标检测算法研究综述...

    DOI 10 12132 ISSN 1673 5048 2019 0100 引用格式 刘俊明 孟卫华 基于深度学习的单阶段目标检测算法研究综述 J 航空兵器 2020 27 3 44 53 Liu Junming Meng Weihua R
  • 【Python深度学习】RNN循环神经网络结构讲解及序列回归问题实战(图文解释 附源码)

    需要全部代码请点赞关注收藏后评论区留言私信 循环神经网络 循环神经网络 Recurrent Neural Network RNN 是用于对序列的非线性特征进行学习的深度神经网络 循环神经网络的输入是有前后关联关系的序列 循环神经网络可以用来
  • Spring Cache常用注解

    EnableCaching 开启缓存注解功能 Cacheable 在方法执行前spring先查看缓存中是否有数据 如果有数据 则直接返回缓存数据 若没有数据 调用方法并将方法返回值放到缓存中 CachePut 将方法的返回值放到缓存中 Ca
  • JS 实现 AES 加解密(十六进制)

    引入 aes min js js文件 aes min js Javascript文档类资源 CSDN下载js文件 aes min js更多下载资源 学习资料请访问CSDN下载频道 https download csdn net downlo
  • Python中用户管理(用户的登陆、用户的增删改查)

    一 用户登陆 题目要求 1 系统里面有多个用户 用户的信息目前保存在列表里面 users root westos passwd 123 456 2 用户登陆 判断用户登陆是否成功 1 判断用户是否存在 2 如果存在 1 判断用户密码是否正确
  • C: GNU regex library (regex.h)正则表达式调用示例

    GNU regex是GNU提供的跨平台的POSIX 正则表达式库 C语言 我也是最近才接触这个相对于C Java实现来说非常简陋 勉强够用的正则表达式库 不算GNU提供的扩展函数 POSIX标准的regex库总共就4个函数regcomp r
  • 第一章 数据结构绪论

    一 数据结构的基本概念 数据结构的三要素 逻辑结构 定义 存储结构 数据的运算 基本运算 增删改查 二 算法和算法评价 时间复杂度 时间复杂度的关键 就是想办法求出次数
  • 在虚拟机中安装Linux系统CentOS7详细教程

    虚拟机 VMware Workstation Linux CentOS 7 x86 64 DVD 1708 iso镜像文件 下载 虚拟机所在电脑系统 windows 安装步骤 安装VMware Workstation虚拟机 略 下载Linu
  • swiper 滚回第一个数据_数据库发展史(上)

    数据库技术是信息技术领域的核心技术之一 几乎所有的信息系统都需要使用数据库系统来组织 存储 操纵和管理业务数据 数据库领域也是现代计算机学科的重要分支和研究方向 目前 在数据库领域已经产生了四位图灵奖得主 他们在数据库理论和实践领域均有突出
  • DocArray x Weaviate

    Weaviate 作为 DocArray 中的 Document Store 可以使得 Document 在云端的处理和检索更加迅速 DocArray Weaviate 大起底 DocArray Data structure for uns
  • Jetpack App Startup——SDK自动初始化,告别Init

    一个项目在开发过程中 常常都伴随着很多sdk的依赖 大部分的sdk在使用时都需要在应用启动时进行初始化才能正常工作 所以在集成sdk时通常需要做如下操作 在Application的onCreate内调用对应sdk的初始化方法 目的是 保证在
  • invokeMethod的介绍

    QMetaObject invokeMethod 的介绍 在Qt框架中 QMetaObject类提供了一些反射机制可以实现类似于Java反射机制的功能 其中一个函数就是QMetaObject invokeMethod 它可以通过字符串调用对
  • 分布式锁(zookeeper)与接口幂等性实现

    背景 随着数据量的增大 用户的增多 系统的并发访问越来越大 传统的单机已经满足不了需求 分布式系统成为一种必然的趋势 分布式系统错综复杂 今天 我们着重对分布式系统的互斥性与幂等性进行分析与解决 互斥性 互斥性问题也就是共享资源的抢占问题
  • 尤雨溪谈Vue.js :缔造自由与真我

    尤雨溪 Evan You 前端框架Vue js 作者 独立开源开发者 现居美国新泽西 曾就职于 Google Creative Labs 和 Meteor Development Group 由于工作中大量接触开源的 JavaScript
  • 文件或目录损坏无法读取

    删除文件无法删除也没有任何提示 用cmd命令删除提示该目录不为空 执行SVN update提示文件或目录损坏无法读取 解决办法 右键D盘 属性 工具 修复 立即重启并修复 解决问题
  • OpenCV(十五)边缘检测1 -- Sobel算子(一阶微分算子,X、Y方向边缘检测)

    目录 一 边缘检测基础理论 1 作用 2 分类 1 基于搜索 2 基于零穿越 3 算子比较 二 Sobel算子基础理论 1 作用 2 原理及推导 3 更详细推导 4 Sobel函数 二 实战 1 对x方向微分 2 对y方向微分 3 线性混合