我对sobel算子的理解
转自:http://blog.csdn.net/yanmy2012/article/details/8110316
索贝尔算子(Sobeloperator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量
Sobel卷积因子为:

该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像灰度值,其公式如下:

具体计算如下:
图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:

通常,为了提高效率使用不开平方的近似值:

然后可用以下公式计算梯度方向:

若图像为:

则使用近似公式的计算的结果为:

Sobel算子另一种形式是各向同性Sobel(Isotropic Sobel)算子,也有两个,一个是检测水平边沿的,另一个是检测垂直边沿的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。将Sobel算子矩阵中的所有2改为根号2,就能得到各向同性Sobel的矩阵。
由于Sobel算子是滤波算子的形式,用于提取边缘,可以利用快速卷积函数, 简单有效,因此应用广泛。美中不足的是,Sobel算子并没有将图像的主体与背景严格地区分开来,即Sobel算子没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。
参考:http://homepages.inf.ed.ac.uk/rbf/HIPR2/sobel.htm
http://blog.csdn.NET/tianhai110/article/details/5663756
除此之外:由于基础核具有关于0,0,0所在的中轴正负对称,所以通过对基础核的旋转,和图像做卷积,可以获得灰度图的边缘图,同时消去旋转角方向+180°上的边缘,迭代多个方向即可消去多个方向的边缘,但是为消去的边缘会加倍。
基础核:
0°
|
-1 |
0 |
1 |
|
-2 |
0 |
2 |
|
-1 |
0 |
1 |
旋转后的核(顺时针为正)
45°
|
-2 |
-1 |
0 |
|
-1 |
0 |
1 |
|
0 |
1 |
2 |
90°
|
-1 |
-2 |
-1 |
|
0 |
0 |
0 |
|
1 |
2 |
1 |
135°
|
0 |
-1 |
-2 |
|
1 |
0 |
-1 |
|
2 |
1 |
0 |
180°
|
1 |
0 |
-1 |
|
2 |
0 |
-2 |
|
1 |
0 |
-1 |
225°
|
2 |
1 |
0 |
|
1 |
0 |
-1 |
|
0 |
-1 |
-2 |
270°
|
1 |
2 |
1 |
|
0 |
0 |
0 |
|
-1 |
-2 |
-1 |
原图:

结果图如下,按0°,45°,90°,135°,180°,225°,270°排序







代码如下:
#include "cv.h"
#include "cxmisc.h"
#include "highgui.h"
#include <vector>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <ctype.h>
#pragma comment(lib, "G:\\OpenCV-2.1.0\\vc2008\\lib\\cxcore210d.lib")
#pragma comment(lib, "G:\\OpenCV-2.1.0\\vc2008\\lib\\cv210d.lib")
#pragma comment(lib, "G:\\OpenCV-2.1.0\\vc2008\\lib\\highgui210d.lib")
//对不同深度图片和较大的图片进行放缩,以至于可以在显示器上完全显示
void ShowConvertImage(char name[200],IplImage* Image)
{
cvNamedWindow(name,1);
char savename[350];
sprintf(savename,"%s.jpg",name);
cvSaveImage(savename,Image);
if(Image->width<1280)
{
if(Image->depth!=IPL_DEPTH_8U)
{
IplImage* NormalizeImage=NULL;
NormalizeImage=cvCreateImage(cvGetSize(Image),IPL_DEPTH_8U,1);
cvConvertScale(Image,NormalizeImage,1,0);//将图转为0-256,用于图片显示,
cvShowImage(name,NormalizeImage);
cvReleaseImage(&NormalizeImage);
}
else
{
cvShowImage(name,Image);
}
}
else
{
IplImage* ImageResize=cvCreateImage(cvSize(1280,Image->height/(Image->width/1280)),Image->depth ,Image->nChannels);
cvResize(Image,ImageResize,1);
if(ImageResize->depth!=IPL_DEPTH_8U)
{
IplImage* NormalizeImage=NULL;
NormalizeImage=cvCreateImage(cvGetSize(ImageResize),IPL_DEPTH_8U,1);
cvConvertScale(Image,NormalizeImage,1,0);//将图转为0-256,用于图片显示,
cvShowImage(name,NormalizeImage);
cvReleaseImage(&NormalizeImage);
}
else
{
cvShowImage(name,ImageResize);
}
cvReleaseImage(&ImageResize);
}
}
//对较大的图片缩放,不然显示器分辨率不支持,只能部分显示,具体见http://blog.csdn.net/yanmy2012/article/details/8110516
int MaxImageWidth=2650;
float Scale=1;
int MinPicWidth=640;
int MinPicHeight=428*MinPicWidth/640;
int Maxradius_self=68*MinPicWidth/640;
int Minradius_self=50*MinPicWidth/640;
int Radius_dist=20*MinPicWidth/640;
int MaxPicWidth=MinPicWidth*Scale;
int MaxPicHeight=MinPicHeight*Scale;
void main()
{
IplImage * pictemp=NULL;
IplImage * pic=NULL;
char *imgpath="12.jpg";
pictemp=cvLoadImage(imgpath,-1);///获取图片,原色获取
//pictemp=cvLoadImage("IMG_02071.jpg",-1);///获取图片,原色获取
/////////////////改变图片的像素大小
if(pic!=NULL)
{
cvReleaseImage(&pic);
}
if(pictemp->width>MaxImageWidth)
{
pic=cvCreateImage(cvSize(MaxPicWidth,MaxPicHeight),pictemp->depth ,3);
cvResize(pictemp,pic,CV_INTER_AREA );
}
else
{
pic=cvCloneImage(pictemp);
}
ShowConvertImage("pic",pic);
cvReleaseImage(&pictemp);
IplImage * Gray_pic=cvCreateImage(cvGetSize(pic),pic->depth ,1);
cvCvtColor(pic,Gray_pic, CV_BGR2GRAY ); //////将Image变成灰度图片保存在gray中
cvCanny(Gray_pic,Gray_pic,50,150,3);
IplImage * Result_pic=cvCreateImage(cvGetSize(pic),IPL_DEPTH_16S ,1);
// IplImage * Result_pic=cvCreateImage(cvGetSize(pic),IPL_DEPTH_8U ,1);
CvMat *kernel=cvCreateMat(3,3,CV_32FC1);
///卷积核的初始化
////90度模板卷积核
{
cvSetReal2D(kernel,0,0, 1); cvSetReal2D(kernel,0,1, 2); cvSetReal2D(kernel,0,2, 1);
cvSetReal2D(kernel,1,0, 0); cvSetReal2D(kernel,1,1, 0); cvSetReal2D(kernel,1,2, 0);
cvSetReal2D(kernel,2,0,-1); cvSetReal2D(kernel,2,1,-2); cvSetReal2D(kernel,2,2,-1);
}
////////////进行卷积核计算
cvFilter2D(Gray_pic,Result_pic,kernel,cvPoint(1,1));
ShowConvertImage("卷积结果90°",Result_pic);
////225度模板卷积核
{
cvSetReal2D(kernel,0,0, 2); cvSetReal2D(kernel,0,1, 1); cvSetReal2D(kernel,0,2, 0);
cvSetReal2D(kernel,1,0, 1); cvSetReal2D(kernel,1,1, 0); cvSetReal2D(kernel,1,2,-1);
cvSetReal2D(kernel,2,0, 0); cvSetReal2D(kernel,2,1,-1); cvSetReal2D(kernel,2,2,-2);
}
////////////进行卷积核计算
cvFilter2D(Gray_pic,Result_pic,kernel,cvPoint(1,1));
ShowConvertImage("卷积结果225°",Result_pic);
////180度模板卷积核
{
cvSetReal2D(kernel,0,0, 1); cvSetReal2D(kernel,0,1, 0); cvSetReal2D(kernel,0,2,-1);
cvSetReal2D(kernel,1,0, 2); cvSetReal2D(kernel,1,1, 0); cvSetReal2D(kernel,1,2,-2);
cvSetReal2D(kernel,2,0, 1); cvSetReal2D(kernel,2,1, 0); cvSetReal2D(kernel,2,2,-1);
}
////////////进行卷积核计算
cvFilter2D(Gray_pic,Result_pic,kernel,cvPoint(1,1));
ShowConvertImage("卷积结果180°",Result_pic);
////135度模板卷积核
{
cvSetReal2D(kernel,0,0, 0); cvSetReal2D(kernel,0,1,-1); cvSetReal2D(kernel,0,2,-2);
cvSetReal2D(kernel,1,0, 1); cvSetReal2D(kernel,1,1, 0); cvSetReal2D(kernel,1,2,-1);
cvSetReal2D(kernel,2,0, 2); cvSetReal2D(kernel,2,1, 1); cvSetReal2D(kernel,2,2, 0);
}
////////////进行卷积核计算
cvFilter2D(Gray_pic,Result_pic,kernel,cvPoint(1,1));
ShowConvertImage("卷积结果135°",Result_pic);
//90度模板卷积核
{
cvSetReal2D(kernel,0,0,-1); cvSetReal2D(kernel,0,1,-2); cvSetReal2D(kernel,0,2,-1);
cvSetReal2D(kernel,1,0, 0); cvSetReal2D(kernel,1,1, 0); cvSetReal2D(kernel,1,2, 0);
cvSetReal2D(kernel,2,0, 1); cvSetReal2D(kernel,2,1, 2); cvSetReal2D(kernel,2,2, 1);
}
////////////进行卷积核计算
cvFilter2D(Gray_pic,Result_pic,kernel,cvPoint(1,1));
ShowConvertImage("卷积结果90°",Result_pic);
////45度模板卷积核
{
cvSetReal2D(kernel,0,0,-2); cvSetReal2D(kernel,0,1,-1); cvSetReal2D(kernel,0,2, 0);
cvSetReal2D(kernel,1,0,-1); cvSetReal2D(kernel,1,1, 0); cvSetReal2D(kernel,1,2, 1);
cvSetReal2D(kernel,2,0, 0); cvSetReal2D(kernel,2,1, 1); cvSetReal2D(kernel,2,2, 2);
}
////////////进行卷积核计算
cvFilter2D(Gray_pic,Result_pic,kernel,cvPoint(1,1));
ShowConvertImage("卷积结果45°",Result_pic);
////0度模板卷积核
{
cvSetReal2D(kernel,0,0,-1); cvSetReal2D(kernel,0,1, 0); cvSetReal2D(kernel,0,2, 1);
cvSetReal2D(kernel,1,0,-2); cvSetReal2D(kernel,1,1, 0); cvSetReal2D(kernel,1,2, 2);
cvSetReal2D(kernel,2,0,-1); cvSetReal2D(kernel,2,1, 0); cvSetReal2D(kernel,2,2, 1);
}
////////////进行卷积核计算
cvFilter2D(Gray_pic,Result_pic,kernel,cvPoint(1,1));
ShowConvertImage("卷积结果0°",Result_pic);
//315度模板卷积核
{
cvSetReal2D(kernel,0,0, 0); cvSetReal2D(kernel,0,1, 1); cvSetReal2D(kernel,0,2, 2);
cvSetReal2D(kernel,1,0,-1); cvSetReal2D(kernel,1,1, 0); cvSetReal2D(kernel,1,2, 1);
cvSetReal2D(kernel,2,0,-2); cvSetReal2D(kernel,2,1,-1); cvSetReal2D(kernel,2,2, 0);
}
////////////进行卷积核计算
cvFilter2D(Gray_pic,Result_pic,kernel,cvPoint(-1,-1));
ShowConvertImage("卷积结果315",Result_pic);
cvSobel(Gray_pic,Result_pic,0,1,3);
ShowConvertImage("Sobel结果X=0,Y=1",Result_pic);
cvSobel(Gray_pic,Result_pic,0,2,3);
ShowConvertImage("Sobel结果X=0,Y=2",Result_pic);
cvSobel(Gray_pic,Result_pic,1,0,3);
ShowConvertImage("Sobel结果X=1,Y=0",Result_pic);
cvSobel(Gray_pic,Result_pic,1,1,3);
ShowConvertImage("Sobel结果X=1,Y=1",Result_pic);
cvSobel(Gray_pic,Result_pic,1,2,3);
ShowConvertImage("Sobel结果X=1,Y=2",Result_pic);
cvSobel(Gray_pic,Result_pic,2,0,3);
ShowConvertImage("Sobel结果X=2,Y=0",Result_pic);
cvSobel(Gray_pic,Result_pic,2,1,3);
ShowConvertImage("Sobel结果X=2,Y=1",Result_pic);
cvSobel(Gray_pic,Result_pic,2,2,3);
ShowConvertImage("Sobel结果X=2,Y=2",Result_pic);
cvWaitKey(0);
cvReleaseImage(&Result_pic);
cvReleaseImage(&Gray_pic);
cvReleaseImage(&pic);
cvReleaseMat(&kernel);
}
我对sobel算子的理解的更多相关文章
- 彻底理解数字图像处理中的卷积-以Sobel算子为例
彻底理解数字图像处理中的卷积-以Sobel算子为例 作者:FreeBlues 修订记录 2016.08.04 初稿完成 概述 卷积在信号处理领域有极其广泛的应用, 也有严格的物理和数学定义. 本文只讨 ...
- EasyPR--开发详解(3)高斯模糊、灰度化和Sobel算子
在上篇文章中我们了解了PlateLocate的过程中的所有步骤.在本篇文章中我们对前3个步骤,分别是高斯模糊.灰度化和Sobel算子进行分析. 一.高斯模糊 1.目标 对图像去噪,为边缘检测算法做准备 ...
- sobel算子
#1,个人理解 网上查了很多资料,都说sobel算子是用来检测边缘的,分别给了两个方向上的卷积核,然后说明做法,就说这就是sobel算子.对于我个人来说,还有很多不明白的地方,所以理清下思路. #2, ...
- 【OpenCV新手教程之十二】OpenCV边缘检測:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/25560901 作者:毛星云(浅墨) ...
- 对于Sobel算子的学习
本来想说很多目前对于 Sobel 算子的认识,但最终还是觉得对于其掌握程度太低,没有一个系统的理解,远不足以写博客,但为了12月不至于零输出,还是决定把自己学习过程中找到的相关资料进行分享. 等到一月 ...
- [OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
http://blog.csdn.net/poem_qianmo/article/details/25560901 本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog ...
- 学习 opencv---(11)OpenC 边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器
本篇文章中,我们将一起学习OpenCV中边缘检测的各种算子和滤波器——Canny算子,Sobel算子,Laplace算子以及Scharr滤波器.文章中包含了五个浅墨为大家准备的详细注释的博文配套源代码 ...
- 边缘检测sobel算子
sobel算子 - sophia_hxw - 博客园http://www.cnblogs.com/sophia-hxw/p/6088035.html #1,个人理解 网上查了很多资料,都说sobel算 ...
- sobel算子的一些细节
1. 形式 Gy 上下颠倒的 (*A表示卷积图像,忽略先): 看得出来,sobel算子感觉并不统一,特别是方向,我们知道matlab的图像格式是,x轴从左到右,y轴从上到下,原点在左上角. 所以,第二 ...
随机推荐
- Python学习总结之三 -- 优雅的字符串
优雅的字符串 前言 记得我在Python学习总结第一篇中有提到字符串,那个可以算是先打个招呼吧,因为没有提到任何关于字符串的处理方法.今天,给大家详细讲解一下Python中字符串的使用方法,如有不当或 ...
- iOS项目 -- 模仿花椒直播做的第三层设计完整版
由于是获取第三方的数据,开发的时候,把数据结构分为:闭环数据,和开环数据. 开环数据是网络的第三方数据,自己不能控制的了. 闭环数据是自己的数据,可以进行各式各样的设计. 这是闭环数据的数据库关键字设 ...
- linux find 根据条件查找文件
版权为个人所有,欢迎转载如转载请说明出处.(东北大亨) http://www.cnblogs.com/northeastTycoon/p/5513231.html 1. 实现说明 按照某一个时间点查找 ...
- 开源监控系统Prometheus介绍
前言 Prometheus是CNCF的一个开源项目,Google BorgMon监控系统的开源版本,是一个系统和服务的监控系统.周期性采集metrics指标,匹配规则和展示结果,以及触发某些条件的告警 ...
- 九度OJ 1016:火星A+B (进制转换)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:4913 解决:1334 题目描述: 读入两个不超过25位的火星正整数A和B,计算A+B.需要注意的是:在火星上,整数不是单一进制的, ...
- 使用Retrofit发送POST请求提交JSON数据
Retrofit官网:https://square.github.io/retrofit/ 示例如下 HttpService.java import okhttp3.RequestBody; impo ...
- JavaScript演示如何访问Search字段
<!DOCTYPE html> <html> <body> <h3>演示如何访问Search字段</h3> <input type=& ...
- Nginx + Tomcat 应用证书启用 SSL
第一部分 简述 - 附:相关概念 1 Nginx 是什么? - 2 Tomcat 是什么? - 3 SSL 是什么? Secure Sockets Layer,现在应该叫"TLS" ...
- 【tensorflow】tensorflow学习记录——安装、第一个程序篇
机器学习,人工智能往后肯定是一个趋势,现阶段有必要研究一两个人工智能的工具,以免自己技术落伍,其中tensorflow就是一个很不错的项目,有谷歌开发后开源,下面开始学习安装和使用 安装篇: 很不幸, ...
- 插头dp小结
插头dp: \(A:\)插头dp是什么? \(B:\)一种基于连通性状态压缩的动态规划问题 \(A:\)请问有什么应用呢? \(B:\)各种网格覆盖问题,范围允许状压解决,常用于计算方案数与联通块权值 ...