sobel 使用说明
转自http://www.cnblogs.com/justany/archive/2012/11/23/2782660.html
图像的边缘
图像的边缘从数学上是如何表示的呢?
图像的边缘上,邻近的像素值应当显著地改变了。而在数学上,导数是表示改变快慢的一种方法。梯度值的大变预示着图像中内容的显著变化了。
用更加形象的图像来解释,假设我们有一张一维图形。下图中灰度值的“跃升”表示边缘的存在:
使用一阶微分求导我们可以更加清晰的看到边缘“跃升”的存在(这里显示为高峰值):
由此我们可以得出:边缘可以通过定位梯度值大于邻域的相素的方法找到。
卷积
卷积可以近似地表示求导运算。
那么卷积是什么呢?
卷积是在每一个图像块与某个算子(核)之间进行的运算。
核?!
核就是一个固定大小的数值数组。该数组带有一个锚点 ,一般位于数组中央。
可是这怎么运算啊?
假如你想得到图像的某个特定位置的卷积值,可用下列方法计算:
- 将核的锚点放在该特定位置的像素上,同时,核内的其他值与该像素邻域的各像素重合;
- 将核内各值与相应像素值相乘,并将乘积相加;
- 将所得结果放到与锚点对应的像素上;
- 对图像所有像素重复上述过程。
用公式表示上述过程如下:
在图像边缘的卷积怎么办呢?
计算卷积前,OpenCV通过复制源图像的边界创建虚拟像素,这样边缘的地方也有足够像素计算卷积了。
近似梯度
比如内核为3时。
首先对x方向计算近似导数:
然后对y方向计算近似导数:
然后计算梯度:
当然你也可以写成:
开始求梯度

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h> using namespace cv; int main( int argc, char** argv ){ Mat src, src_gray;
Mat grad;
char* window_name = "求解梯度";
int scale = 1;
int delta = 0;
int ddepth = CV_16S; int c; src = imread( argv[1] ); if( !src.data ){
return -1;
} //高斯模糊
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); //转成灰度图
cvtColor( src, src_gray, CV_RGB2GRAY ); namedWindow( window_name, CV_WINDOW_AUTOSIZE ); Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y; Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x ); Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y ); addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); imshow( window_name, grad ); waitKey(0); return 0;
}

Sobel函数
索贝尔算子(Sobel operator)计算。
- C++: void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize=3, double scale=1, double delta=0, intborderType=BORDER_DEFAULT )
参数
- src – 输入图像。
- dst – 输出图像,与输入图像同样大小,拥有同样个数的通道。
- 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时, 输出图像将和输入图像有相同的深度。输入8位图像则会截取顶端的导数。
- xorder – x方向导数运算参数。
- yorder – y方向导数运算参数。
- ksize – Sobel内核的大小,可以是:1,3,5,7。
- scale – 可选的缩放导数的比例常数。
- delta – 可选的增量常数被叠加到导数中。
- borderType – 用于判断图像边界的模式。
代码注释:
//在x方向求图像近似导数
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); //在y方向求图像近似导数
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
如果我们打印上面两个输出矩阵,可以看到grad_x和grad_y中的元素有正有负。
当然,正方向递增就是正的,正方向递减则是负值。
这很重要,我们可以用来判断梯度方向。
convertScaleAbs函数
线性变换转换输入数组元素成8位无符号整型。
- C++: void convertScaleAbs(InputArray src, OutputArray dst, double alpha=1, double beta=0)
参数
- src – 输入数组。
- dst – 输出数组。
- alpha – 可选缩放比例常数。
- beta – 可选叠加到结果的常数。
对于每个输入数组的元素函数convertScaleAbs 进行三次操作依次是:缩放,得到一个绝对值,转换成无符号8位类型。
对于多通道矩阵,该函数对各通道独立处理。如果输出不是8位,将调用Mat::convertTo 方法并计算结果的绝对值,例如:
Mat_<float> A(30,30);
randu(A, Scalar(-100), Scalar(100));
Mat_<float> B = A*5 + 3;
B = abs(B);
为了能够用图像显示,提供一个直观的图形,我们利用该方法,将-256 — 255的导数值,转成0 — 255的无符号8位类型。
addWeighted函数
计算两个矩阵的加权和。
- C++: void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, intdtype=-1)
参数
- src1 – 第一个输入数组。
- alpha – 第一个数组的加权系数。
- src2 – 第二个输入数组,必须和第一个数组拥有相同的大小和通道。
- beta – 第二个数组的加权系数。
- dst – 输出数组,和第一个数组拥有相同的大小和通道。
- gamma – 对所有和的叠加的常量。
- dtype – 输出数组中的可选的深度,当两个数组具有相同的深度,此系数可设为-1,意义等同于选择与第一个数组相同的深度。
函数addWeighted 两个数组的加权和公式如下:
在多通道情况下,每个通道是独立处理的,该函数可以被替换成一个函数表达式:
dst = src1*alpha + src2*beta + gamma;
利用convertScaleAbs和addWeighted,我们可以对梯度进行一个可以用图像显示的近似表达。
这样我们就可以得到下面的效果:
梯度方向
但有时候边界还不够,我们希望得到图片色块之间的关系,或者研究样本的梯度特征来对机器训练识别物体时候,我们还需要梯度的方向。
二维平面的梯度定义为:

这很好理解,其表明颜色增长的方向与x轴的夹角。
但Sobel算子对于沿x轴和y轴的排列表示的较好,但是对于其他角度表示却不够精确。这时候我们可以使用Scharr滤波器。
Scharr滤波器的内核为:
这样能提供更好的角度信息,现在我们修改原程序,改为使用Scharr滤波器进行计算:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h> using namespace cv; int main( int argc, char** argv ){ Mat src, src_gray;
Mat grad;
char* window_name = "梯度计算";
int scale = 1;
int delta = 0;
int ddepth = CV_16S; int c; src = imread( argv[1] ); if( !src.data ){
return -1;
} GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); cvtColor( src, src_gray, CV_RGB2GRAY ); namedWindow( window_name, CV_WINDOW_AUTOSIZE ); Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y; //改为Scharr滤波器计算x轴导数
Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x ); //改为Scharr滤波器计算y轴导数
Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y ); addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); imshow( window_name, grad ); waitKey(0); return 0;
}

Scharr函数接受参数与Sobel函数相似,这里就不叙述了。
下面我们通过divide函数就能得到一个x/y的矩阵。
对两个输入数组的每个元素执行除操作。
- C++: void divide(InputArray src1, InputArray src2, OutputArray dst, double scale=1, int dtype=-1)
- C++: void divide(double scale, InputArray src2, OutputArray dst, int dtype=-1)
参数
- src1 – 第一个输入数组。
- src2 – 第二个输入数组,必须和第一个数组拥有相同的大小和通道。
- scale – 缩放系数。
- dst – 输出数组,和第二个数组拥有相同的大小和通道。
- dtype – 输出数组中的可选的深度,当两个数组具有相同的深度,此系数可设为-1,意义等同于选择与第一个数组相同的深度。
该函数对两个数组进行除法:
或则只是缩放系数除以一个数组:
这种情况如果src2是0,那么dst也是0。不同的通道是独立处理的。
被山寨的原文
Sobel Derivatives . OpenCV.org
Image Filtering . OpenCV.org
#1楼 adamswater 2013-10-14 21:07
非常有帮助,谢谢!#2楼[楼主] Justany_WhiteSnow 2013-10-14 21:16
@ adamswater
^_^#3楼 cv_ml_张欣男 2015-01-31 16:02
您好,为什么要加一个高斯模糊?GaussianBlur#4楼[楼主] Justany_WhiteSnow 2015-02-04 21:52
#5楼 Maddock 2015-05-07 11:06
不错,程序正确,得到需要效果#6楼 sansejin0321 2016-04-09 09:26
你好,为什么看不到图片呢,可以给我发张吗?大四学生写毕业论文需要谢谢你


About
最新评论
- Re:Javascript图像处理——边缘梯度计算
看不到公式哎 -- sangle - Re:GIST特征描述符使用
正要用gist特征,非常感谢,成功 -- SuperSonicxxx - Re:OpenCV 2.4+ C++ SVM文字识别
博主,有完整的工程分享不,或者字体样本数据? -- 一晌贪欢 - Re:Javascript中this关键字详解
其实就是直接调用函数,该函数内的this为window。 作为对象的方法调用时this指向该对象。 -- Amomentiny - Re:jQuery event(上)
@MachoMan 源代码刚开始看都比较难,看多了就不难了。 -- Justany_WhiteSnow
日历
随笔分类
推荐排行榜
sobel 使用说明的更多相关文章
- Sobel Derivatives
https://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.html ...
- Atitit.项目修改补丁打包工具 使用说明
Atitit.项目修改补丁打包工具 使用说明 1.1. 打包工具已经在群里面.打包工具.bat1 1.2. 使用方法:放在项目主目录下,执行即可1 1.3. 打包工具的原理以及要打包的项目列表1 1. ...
- awk使用说明
原文地址:http://www.cnblogs.com/verrion/p/awk_usage.html Awk使用说明 运维必须掌握的三剑客工具:grep(文件内容过滤器),sed(数据流处理器), ...
- “我爱背单词”beta版发布与使用说明
我爱背单词BETA版本发布 第二轮迭代终于画上圆满句号,我们的“我爱背单词”beta版本已经发布. Beta版本说明 项目名称 我爱背单词 版本 Beta版 团队名称 北京航空航天大学计算机学院 拒 ...
- EasyPR--开发详解(3)高斯模糊、灰度化和Sobel算子
在上篇文章中我们了解了PlateLocate的过程中的所有步骤.在本篇文章中我们对前3个步骤,分别是高斯模糊.灰度化和Sobel算子进行分析. 一.高斯模糊 1.目标 对图像去噪,为边缘检测算法做准备 ...
- Oracle 中 union 和union all 的简单使用说明
1.刚刚工作不久,经常接触oracle,但是对oracle很多东西都不是很熟.今天我们来了解一下union和union all的简单使用说明.Union(union all): 指令的目的是将两个 S ...
- Map工具系列-02-数据迁移工具使用说明
所有cs端工具集成了一个工具面板 -打开(IE) Map工具系列-01-Map代码生成工具说明 Map工具系列-02-数据迁移工具使用说明 Map工具系列-03-代码生成BySQl工具使用说明 Map ...
- Map工具系列-03-代码生成BySQl工具使用说明
所有cs端工具集成了一个工具面板 -打开(IE) Map工具系列-01-Map代码生成工具说明 Map工具系列-02-数据迁移工具使用说明 Map工具系列-03-代码生成BySQl工具使用说明 Map ...
- sobel算子的一些细节
1. 形式 Gy 上下颠倒的 (*A表示卷积图像,忽略先): 看得出来,sobel算子感觉并不统一,特别是方向,我们知道matlab的图像格式是,x轴从左到右,y轴从上到下,原点在左上角. 所以,第二 ...
随机推荐
- 爬虫框架之Scrapy——爬取某招聘信息网站
案例1:爬取内容存储为一个文件 1.建立项目 C:\pythonStudy\ScrapyProject>scrapy startproject tenCent New Scrapy projec ...
- 【转】SQL模糊查询
在进行数据库查询时,有完整查询和模糊查询之分. 一般模糊查询语句如下: SELECT 字段 FROM 表 WHERE 某字段 Like 条件 其中关于条件,SQL提供了四种匹配模式: 1,% :表示任 ...
- 【洛谷】P1357 花园(状压+矩阵快速幂)
题目 传送门:QWQ 分析 因为m很小,考虑把所有状态压成m位二进制数. 那么总状态数小于$ 2^5 $. 如果状态$ i $能转移到$ j $,那么扔进一个矩阵,n次方快速幂一下. 答案是对角线之和 ...
- win10下多版本apache(2.2,2.4)+php(5.3.5,5.5.37,5.6.25,7.0.8)注意点
1.Loaded Configuration File 问题: apache2.2 httpd PHPIniDir D:\php5.3.5\php.ini AddType application/x- ...
- 洛谷:P1087 FBI树 P1030 求先序排列 P1305 新二叉树
至于为啥把这三个题放到一起,大概是因为洛谷的试炼场吧,三道树的水题,首先要理解 先序中序后序遍历方法. fbi树由于数量小,在递归每个区间时,暴力跑一遍区间里的数,看看是否有0和1.至于递归的方法,二 ...
- css实现文本两行或多行文本溢出显示省略号
word-break: break-all; text-overflow: ellipsis; display: -webkit-box; /** 对象作为伸缩盒子模型显示 **/ -webkit-b ...
- SpringBoot 返回json 字符串(jackson 及 fast json)
一.jackson 1.Controller 类加注解@RestController 这个注解相当于@Controller 这个注解加 @ResponseBody 2.springBoot 默认使 ...
- Spring学习之AOP详解
aop使用方式 @Aspect注解 wildcards通配符: * 匹配任意数量的字符 + 匹配指定类及其子类 .. 一般用于匹配任意数的子包或参数 operators运算符 && 与 ...
- 《opencv学习》 之 OTSU算法实现二值化
主要讲解OTSU算法实现图像二值化: 1.统计灰度级图像中每个像素值的个数. 2.计算第一步个数占整个图像的比例. 3.计算每个阈值[0-255]条件下,背景和前景所包含像素值总个数和总概率(就 ...
- 如何使32位Win7支持超过4GB的内存,而不装64位
如何使32位Win7支持超过4GB的内存 让32位系统支持更大的内存超过4G [情况参数:] PC: 联想商用台式机,M4350 RAM: 1600, DDR3 , 2GB OS: Win7 专业版 ...

