目录

  • 算子
    • 边缘提取与梯度
    • 边缘提取
  • Sobel算子
    • 原理
    • API
    • 代码展示
      • 结果
    • 优化代码
      • 结果
  • Scharr算子
    • 代码
    • 结果

算子

  • 狭义的算子实际上是指从一个函数空间到另一个函数空间(或它自身)的映射。

  • 广义的算子的定义只要把上面的空间推广到一般空间,可以是向量空间,赋范向量空间,内积空间,或更进一步,Banach空间,Hilbert空间都可以。算子还可分为有界的与无界的,线性的与非线性的等等类别。

边缘提取与梯度


如上图,在画圈处有明显的像素值变化,这就是图像中的边缘


上图,是图像像素的变化图
圆圈处就是和源图像对应的点。可以看出,这里的变化率是最大的
变化率也称梯度
谈及变化率,我们就要想到导数
如下图

边缘提取

边缘是什么 – 像素值发生跃迁的地方
是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要的作用。

如何捕捉/提取边缘 – 对图像求它的一阶导数

  delta =  f(x) – f(x-1)

delta越大,说明像素在X方向变化越大,边缘信号越强

在opencv中,我们只需要使用Sobel算子就可以提取边缘,不用再使用求导操作

Sobel算子

原理

Sobel算子又叫索贝尔算子,是计算机视觉领域的一种重要处理方法。

主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。

Sobel算子是把图像中每个像素的上下左右四领域的灰度值加权差,在边缘处达到极值从而检测边缘。

Sobel算子所采用的算法是先进行加权平均,然后进行微分运算,算子的计算方法如下:

对于一个二元函数f(x,y)来说,x有三个取值,y有三个取值,那我们就可以构造一个3×3的矩阵,矩阵的中心点为(x,y),向上向左为减一,向右向下为加一。我们用矩阵来表示一下上面的式子:
由此,我们设计两个核,一个是x方向上的,一个是y方向上的,设计的两个核是3×3的矩阵,分别是:


所以,如果对于一个图像I,我们能通过这两个核分别计算该图像X方向和Y方向的梯度:

我们也能根据两个方向的梯度计算总的梯度:

第二个式子是第一个式子的近似计算,这是由于CPU乘除的开销远大于加减
所以会这么用

Sobel算子对噪声比较敏感,在使用前建议高斯模糊去噪再使用Sobel算子进行边缘提取

API

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
);
  • (1)InputArray类型的src ,输入图像。

  • (2)OutputArray类型的dst ,输出图像,图像的大小、通道数和输入图像相同。

  • (3)int类型的ddepth,输出图像深度,请参阅@ref filter_depth“组合”;如果是8位输入图像,则会导致导数截断。
    计算sobel的时候有负,一边黑一边白就变成500多了。如果我们的depth是-1,输入图像是CV_8U的灰度图像,输出也是CV_8U。那么超过255的就会被截断,与实际数值不吻合。所以输出图像的位数要比输入高,比如输入CV_8U,输出就要用CV_16S

  • (4)int类型的dx,导数x的阶数。

  • (5)int类型的dy,导数y的阶数。

  • (6)int类型的ksize,扩展Sobel内核的大小;它必须是1、3、5或7。

  • (7)double类型的scale,计算派生值的可选比例因子;默认情况下,不应用缩放(有关详细信息,请参见cv::getDerivKernels。

  • (8)double类型的delta,在将筛选的像素存储到dst中之前添加到这些像素的可选值。说的有点专业了其实就是给所选的像素值添加一个值delta。

  • (9)int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT。

我们还用了一个很简单的函数,用于计算绝对值

void convertScaleAbs( InputArray src, OutputArray dst, double alpha= 1,                       double belt= 0,
);

我们这个函数只需要设置前两个参数,这个函数可以计算图像src的像素绝对值,输出到图像dst。

代码展示

#include<iostream>
#include<opencv2/opencv.hpp>using namespace std;
using namespace cv;int main()
{Mat src, gx, gy, dst;src = imread("C:/Users/86176/Pictures/pics/lena(1).tiff");if (!src.data){cout << "could not load image !";return -1;}imshow("【输入图像】", src);Mat tmp,gray;GaussianBlur(src, tmp, Size(3,3), 0, 0);cvtColor(tmp, gray, CV_BGR2GRAY);Sobel(gray, gx, CV_16S, 1, 0,3);Sobel(gray, gy, CV_16S, 0, 1,3);convertScaleAbs(gx, gx);convertScaleAbs(gy, gy);//若不用绝对值,那么产出的图像就会缺失很多细节addWeighted(gx, 0.5, gy, 0.5, 0, dst);imshow("【输出图像】", dst);waitKey(0);return 0;
}

结果

优化代码

我们在上述代码使用的是加权相加,并非是绝对值相加
我们现在来优化代码

#include<iostream>
#include<opencv2/opencv.hpp>using namespace std;
using namespace cv;int main()
{Mat src, gx, gy, dst;src = imread("C:/Users/86176/Pictures/pics/lena(1).tiff");if (!src.data){cout << "could not load image !";return -1;}imshow("【输入图像】", src);Mat tmp,gray;GaussianBlur(src, tmp, Size(3,3), 0, 0);cvtColor(tmp, gray, CV_BGR2GRAY);Sobel(gray, gx, CV_16S, 1, 0);Sobel(gray, gy, CV_16S, 0, 1);convertScaleAbs(gx, gx);convertScaleAbs(gy, gy);//若不用绝对值,那么产出的图像就会缺失很多细节//addWeighted(gx, 0.5, gy, 0.5, 0, dst);dst = Mat(gx.size(), gx.type());//printf("type : %d\n", gx.type()); //这里能看到gx的type是0,即CV_8U,所以下面指针类型都是ucharint width = dst.cols;int height = dst.rows;for (int row = 0; row < height; row++){for (int col = 0; col < width; col++){   //每个取号绝对值的像素值都相加int xg = gx.at<uchar>(row, col);int yg = gy.at<uchar>(row, col);int xy = xg + yg;dst.at<uchar>(row, col) = saturate_cast<uchar>(xy);//指定像素值在0~255,防止被截断}}imshow("【输出图像】", dst);waitKey(0);return 0;
}

结果


可以看到,细节比上面加权相加多了很多

加权相加的结果如下

如果我们直接使用加权相加,丢失了一些细节,那么我们后续的处理可能会差的更远。所谓差之毫厘,谬以千里。
所以我们需要了解图像处理的本质。

Scharr算子

我们之前聊到梯度,即周围像素差值的变化率,要了解这个概念,我们就需要求导。

导数是对于连续函数来说的,图像差值不是连续的函数,所以这种方式,其实只是一个近似解。

这种近似解,对于上面的来说又不是特别的精确,所以,在opencv中,采用更加精确的Scharr算子:

代码

#include<iostream>
#include<opencv2/opencv.hpp>using namespace std;
using namespace cv;int main()
{Mat src, gx, gy, dst;src = imread("C:/Users/86176/Pictures/pics/lena(1).tiff");if (!src.data){cout << "could not load image !";return -1;}imshow("【输入图像】", src);Mat tmp,gray;GaussianBlur(src, tmp, Size(3,3), 0, 0);cvtColor(tmp, gray, CV_BGR2GRAY);Scharr(gray, gx, CV_16S, 1, 0);Scharr(gray, gy, CV_16S, 0, 1);//Sobel(gray, gx, CV_16S, 1, 0);//Sobel(gray, gy, CV_16S, 0, 1);convertScaleAbs(gx, gx);convertScaleAbs(gy, gy);//若不用绝对值,那么产出的图像就会缺失很多细节//addWeighted(gx, 0.5, gy, 0.5, 0, dst);dst = Mat(gx.size(), gx.type());//printf("type : %d\n", gx.type()); //这里能看到gx的type是0,即CV_8U,所以下面指针类型都是ucharint width = dst.cols;int height = dst.rows;for (int row = 0; row < height; row++){for (int col = 0; col < width; col++){ //每个取号绝对值的像素值都相加int xg = gx.at<uchar>(row, col);int yg = gy.at<uchar>(row, col);int xy = xg + yg;dst.at<uchar>(row, col) = saturate_cast<uchar>(xy);//指定像素值在0~255,防止被截断}}imshow("【输出图像】", dst);waitKey(0);return 0;
}

结果


相较于Sobel,Scharr对图像的边缘有了更大的加强
即,Scharr对抗噪声的干扰强于Sobel

opencv——Sobel算子与Scharr算子相关推荐

  1. sobel算子,scharr算子,Laplacian算子

    1.sobel算子: sobel算子可以计算图像梯度,计算图像梯度的作用是提取边界,一般我们用一个3x3的卷积核去指示sobel算子是如何运算的: 图中左边就是计算水平梯度时的卷积核,简单来说就是右边 ...

  2. 一文解决Opencv四大经典算子——sobel算子、scharr算子、laplacian算子、canny算子

    Opencv四大算子 Sobel算子 Scharr算子 laplacian算子 canny算子 总结 边缘是像素值发生跃迁的位置,是图像的显著特征之一,在图像特征提取,对象检测,模式识别等方面都有重要 ...

  3. 【opencv学习笔记】018之Sobel算子与Scharr算子

    目录 一.前言 二.算子 1.咋理解算子 2.算子定义 三.Sobel算子 1.讲解 2.API 3.代码展示 4.执行结果 四.Scharr算子 1.讲解 2.API 3.代码展示 4.执行结果 一 ...

  4. 【OpenCV 4开发详解】Scharr算子

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  5. python实现sobel_OpenCV-Python系列之Sobel和Scharr算子

    我们再上个教程中留了一个小彩蛋--形态学的梯度问题,通常情况下,它被用于提取图像的轮廓,今天我们来了解图像边缘的另一种方法,它将比形态学梯度更有效,适用范围也更广. Sobel算子 前面的例子,已经接 ...

  6. 空间滤波 - 锐化处理 - 一阶差分算法(Sobel、Scharr算子)

    目录 1. 介绍 2. Sobel 算子 3. Scharr 算子 1. 介绍 空间滤波的另一种用途是图像的锐化,锐化的作用是突出灰度中的过渡区域 图像的模糊在空间域当中可以通过平滑(平均)邻域中的像 ...

  7. 图像梯度——Sobel算子和Laplacian算子

    一.Sobel算子 1.定义 Sobel算子是一种离散的微分算子,结合了高斯平滑和微分求导运算,利用局部拆分寻找边缘,计算所得的是一个梯度的近似值. Sobel算子=|左-右|/|下-上| Schar ...

  8. OpenCV Sobel检测算子和Scharr检测算子

    Sobel边缘检测算法比较简单,实际应用中效率比canny边缘检测效率要高,但是边缘不如Canny检测的准确,但是很多实际应用的场合,sobel边缘却是首选,Sobel算子是高斯平滑与微分操作的结合体 ...

  9. opencv学习笔记16:梯度运算之scharr算子及其函数使用

    前文介绍了sobel算子 opencv学习笔记14:sobel算子及其函数使用 scharr算子理论 系数和sobel不一样,其他一样. scharr函数使用 dst=cv2.Scharr(src,d ...

最新文章

  1. iOS-常用的自定义控件
  2. Eclipes的使用小技巧
  3. Qt Style Sheets(qt样式表)
  4. iPhone或让国内运营商划地为牢
  5. MIP 官方发布 v1稳定版本
  6. HTML5游戏引擎Egret发布2.0版 开发工具亦获更新
  7. Fix一个随机出现的键盘弹出的issue后的思考(ReactNative)
  8. LeetCode 153 寻找旋转排序数组中的最小值
  9. java当前路径_java获取当前路径的几种方法
  10. I/O: 阻塞非阻塞I/O 同步异步I/O
  11. 多易教育大数据课程学费调整通知
  12. 【学习笔记】从eXeScope到汇编与反汇编、加壳与脱壳的理解
  13. 如何构建Birt报表应用程序?
  14. redis 安装以及redis desktop manger 连接
  15. VCS建立仿真生成DVE波形
  16. Python 基于Rawpy 索尼A73 RAW文件转为JPG功能实现
  17. 虚幻四C++ 添加角色动画
  18. 从创建服务器到搭建一台内网穿透服务器
  19. EtherCAT,PowerLink和Ethernet/IP三种协议的比较
  20. VHDL设计一个同步置数、异步清零的D触发器

热门文章

  1. OPJ2.1基本算法之枚举1815:画家问题
  2. Flowable入门系列文章62 - 异步延续
  3. kubernetes-nvidia-plugin设计解读
  4. php判断某年是不是闰年,PHP怎么判断一年是否为闰年?
  5. zigbee人员定位技术系统组成及自身特点
  6. 如何做一个职业的程序员-《麦肯锡方法》读书笔记
  7. 运营一款电视盒子需要注意什么?
  8. MemTest内存软件测试介绍说明-2
  9. 单片机入门基础篇(一):Keil基本操作
  10. 入行3D建模有什么职业可以选择?自学能学会3dsmax吗?