opencv——Sobel算子与Scharr算子
目录
- 算子
- 边缘提取与梯度
- 边缘提取
- 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算子相关推荐
- sobel算子,scharr算子,Laplacian算子
1.sobel算子: sobel算子可以计算图像梯度,计算图像梯度的作用是提取边界,一般我们用一个3x3的卷积核去指示sobel算子是如何运算的: 图中左边就是计算水平梯度时的卷积核,简单来说就是右边 ...
- 一文解决Opencv四大经典算子——sobel算子、scharr算子、laplacian算子、canny算子
Opencv四大算子 Sobel算子 Scharr算子 laplacian算子 canny算子 总结 边缘是像素值发生跃迁的位置,是图像的显著特征之一,在图像特征提取,对象检测,模式识别等方面都有重要 ...
- 【opencv学习笔记】018之Sobel算子与Scharr算子
目录 一.前言 二.算子 1.咋理解算子 2.算子定义 三.Sobel算子 1.讲解 2.API 3.代码展示 4.执行结果 四.Scharr算子 1.讲解 2.API 3.代码展示 4.执行结果 一 ...
- 【OpenCV 4开发详解】Scharr算子
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...
- python实现sobel_OpenCV-Python系列之Sobel和Scharr算子
我们再上个教程中留了一个小彩蛋--形态学的梯度问题,通常情况下,它被用于提取图像的轮廓,今天我们来了解图像边缘的另一种方法,它将比形态学梯度更有效,适用范围也更广. Sobel算子 前面的例子,已经接 ...
- 空间滤波 - 锐化处理 - 一阶差分算法(Sobel、Scharr算子)
目录 1. 介绍 2. Sobel 算子 3. Scharr 算子 1. 介绍 空间滤波的另一种用途是图像的锐化,锐化的作用是突出灰度中的过渡区域 图像的模糊在空间域当中可以通过平滑(平均)邻域中的像 ...
- 图像梯度——Sobel算子和Laplacian算子
一.Sobel算子 1.定义 Sobel算子是一种离散的微分算子,结合了高斯平滑和微分求导运算,利用局部拆分寻找边缘,计算所得的是一个梯度的近似值. Sobel算子=|左-右|/|下-上| Schar ...
- OpenCV Sobel检测算子和Scharr检测算子
Sobel边缘检测算法比较简单,实际应用中效率比canny边缘检测效率要高,但是边缘不如Canny检测的准确,但是很多实际应用的场合,sobel边缘却是首选,Sobel算子是高斯平滑与微分操作的结合体 ...
- opencv学习笔记16:梯度运算之scharr算子及其函数使用
前文介绍了sobel算子 opencv学习笔记14:sobel算子及其函数使用 scharr算子理论 系数和sobel不一样,其他一样. scharr函数使用 dst=cv2.Scharr(src,d ...
最新文章
- 初识ES-es与mysql的概念对比
- 二分图之匈牙利算法模版
- Ps 初学者教程,如何使用图层混合模式合成图像?
- PPTP拨号后无法打开网页处理
- linux SCALA 安装及环境配置
- 计算机装系统找不到硬盘,安装系统找不到硬盘怎么办
- 网易考拉布局和css样式
- QQ被盗后被敲诈500元怎么办
- 倪文迪陪你学蓝桥杯2021寒假每日一题:1.25日(2019省赛A组第3题)
- AndroidManifest文件
- win10内存占用率过高怎么办_DNF:WIN10玩DNF卡顿,内存占用过高的解决方法
- 2023-2028年中国燕麦奶行业市场预测与投资规划分析报告
- 今天距离2022年除夕还有多少天?春节放假倒计时在手机便签上提醒
- 数电知识点总结第二章:逻辑代数基础
- mysql 实现日期格式化(date_format)
- java 高内聚低耦合_高内聚低耦合法则实例解析
- Android 高德地图 自己位置的显示与点地图上任意一点的坐标
- python:scipy.optimize.minimize(method=’Nelder-Mead’)
- Registration system
- 成功将log4cpp升级到了vs2005版本,总结下编译时报错及相应的解决方法
热门文章
- docsify安装,docsify搭建,docsify使用教程
- Conflux Studio 安装教学
- 矩阵的投影、线性拟合与最小二乘法
- 在计算机中 无符号书最常用于表示,2012年9月计算机等考《一级MS Office》全真模拟试卷(19)...
- 【开发工具】【memtester】内存测试工具(memtester)的使用
- 数字图像处理 实验二:图像的平滑滤波
- 一卡通系统软件测试,公共交通一卡通互联互通测试平台的研究
- c语言课程设计猜数字游戏报告,C语言课程设计-猜数字游戏报告.doc
- niuke题霸SQ/L篇
- 菜鸟学好 Linux 大绝招