【OpenCV】边缘检测:梯度,sobel算子的理解
2017-09-27 22:23
525 查看
在这一讲中我们来学习一下opencv中最基本的边缘检测的知识,首先我们来介绍一下图像梯度
1.图像梯度
可以把图像看成二维离散函数,图像梯度其实就是这个二维离散函数的求导:
图像梯度:
计算这个向量的大小为:
近似为:
梯度的方向角为:
可能上面的数学表达式大家觉得还是过于抽象,那么我们将图片看成是二维的离散函数,那么图像的梯度其实就是这个二维离散函数的求导(偏导数)
图像梯度: G(x,y) = dx i + dy j;
dx(i,j) = I(i+1,j) - I(i,j);
dy(i,j) = I(i,j+1) - I(i,j);
其中,I是图像像素的值(如:RGB值),(i,j)为像素的坐标。
图像梯度一般也可以用中值差分:
dx(i,j) = [I(i+1,j) - I(i-1,j)]/2;
dy(i,j) = [I(i,j+1) - I(i,j-1)]/2;
图像边缘一般都是通过对图像进行梯度运算来实现的。
图像梯度的最重要性质是,梯度的方向在图像灰度最大变化率上,它恰好可以反映出图像边缘上的灰度变化
上面说的是简单的梯度定义,其实还有更多更复杂的梯度公式。
2.边缘检测
关于边缘的细节知识,请参考博主 http://blog.csdn.net/xiaowei_cqu/article/details/7829481
下面让我们来看一下边缘检测中常用的一些算子:
sobel算子边缘检测算法
索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量
Sobel卷积因子为:
具体计算如下:
Gx = (-1)*f(x-1, y-1) + 0*f(x,y-1) + 1*f(x+1,y-1)
+(-2)*f(x-1,y) + 0*f(x,y)+2*f(x+1,y)
+(-1)*f(x-1,y+1) + 0*f(x,y+1) + 1*f(x+1,y+1)
= [f(x+1,y-1)+2*f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+2*f(x-1,y)+f(x-1,y+1)]
Gy =1* f(x-1, y-1) + 2*f(x,y-1)+ 1*f(x+1,y-1)
+0*f(x-1,y) 0*f(x,y) + 0*f(x+1,y)
+(-1)*f(x-1,y+1) + (-2)*f(x,y+1) + (-1)*f(x+1, y+1)
= [f(x-1,y-1) + 2f(x,y-1) + f(x+1,y-1)]-[f(x-1, y+1) + 2*f(x,y+1)+f(x+1,y+1)]
其中f(a,b), 表示图像(a,b)点的灰度值;
Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。
其实在边缘检测中还会用到很多算子,如普利维特算子(Prewitt operate);[b]罗伯茨交叉边缘检测(Roberts Cross operator);拉普拉斯算子等等。[/b]
2.opencv中Sobel算子实现边缘检测效果图
先上效果图:
当然,opencv中其实上面的代码完全可以用
这个函数来代替,相应的参数大家可以去百度,在这就不一一介绍了,本文主要针对sobel算子的检测原理来进行说明。
代码如下
[cpp] view
plain copy
#include "cv.h"
#include "highgui.h"
#include "math.h"
#include "stdio.h"
#include "malloc.h"
IplImage *image; //声明IplImage指针
int height, width;
CvScalar s;
int sobel_y[9] = { 1, 2, 1, 0, 0, 0, -1, -2, -1 }; //y方向sobel算子
int sobel_x[9] = { 1, 0, -1, 2, 0, -2, 1, 0, -1 }; //x方向sobel算子
void sobel()
{
int i, j, k;
int grayx = 0, grayy = 0, gray;
int *data;
int a[9];
data = (int *)malloc(height*width*sizeof(int));
for (i = 0; i<height; i++)
{
for (j = 0; j<width; j++)
{
s = cvGet2D(image, i, j);
gray = (int)s.val[0];
data[i*width + j] = gray;
}
}
for (i = 1; i<height - 1; i++)
{
for (j = 1; j<width - 1; j++)
{
grayx = 0;
grayy = 0;
s = cvGet2D(image, i, j);
a[0] = data[width*(i - 1) + j - 1];
a[1] = data[width*(i - 1) + j];
a[2] = data[width*(i - 1) + j + 1];
a[3] = data[width*i + j - 1];
a[4] = data[width*i + j];
a[5] = data[width*i + j + 1];
a[6] = data[width*(i + 1) + j - 1];
a[7] = data[width*(i + 1) + j];
a[8] = data[width*(i + 1) + j + 1];
for (k = 0; k<9; k++)
grayy += a[k] * sobel_y[k];
for (k = 0; k<9; k++)
grayx += a[k] * sobel_x[k];
s.val[0] = (abs(grayx) + abs(grayy));//此处需要取绝对值
cvSet2D(image, i, j, s);
}
}
free(data);
}
int main(int argc, char** argv)
{
image = cvLoadImage("image1.jpg", 0);
IplImage* image1 = cvLoadImage("image1.jpg", 1);
height = image->height;
width = image->width;
sobel();
cvNamedWindow("Image", 1);//创建窗口
cvNamedWindow("Sobel", 1);//创建窗口
cvShowImage("Image", image1);//显示图像
cvShowImage("Sobel", image);//显示图像
cvWaitKey(0); //等待按键
cvDestroyWindow("Image");//销毁窗口
cvReleaseImage(&image); //释放图像
return 0;
}
参考文章:
http://blog.csdn.net/xiaowei_cqu/article/details/7829481
1.图像梯度
可以把图像看成二维离散函数,图像梯度其实就是这个二维离散函数的求导:
图像梯度:
梯度算子 Gradient operators
函数f(x,y)在(x,y)处的梯度为一个向量:计算这个向量的大小为:
近似为:
梯度的方向角为:
可能上面的数学表达式大家觉得还是过于抽象,那么我们将图片看成是二维的离散函数,那么图像的梯度其实就是这个二维离散函数的求导(偏导数)
图像梯度: G(x,y) = dx i + dy j;
dx(i,j) = I(i+1,j) - I(i,j);
dy(i,j) = I(i,j+1) - I(i,j);
其中,I是图像像素的值(如:RGB值),(i,j)为像素的坐标。
图像梯度一般也可以用中值差分:
dx(i,j) = [I(i+1,j) - I(i-1,j)]/2;
dy(i,j) = [I(i,j+1) - I(i,j-1)]/2;
图像边缘一般都是通过对图像进行梯度运算来实现的。
图像梯度的最重要性质是,梯度的方向在图像灰度最大变化率上,它恰好可以反映出图像边缘上的灰度变化
上面说的是简单的梯度定义,其实还有更多更复杂的梯度公式。
2.边缘检测
关于边缘的细节知识,请参考博主 http://blog.csdn.net/xiaowei_cqu/article/details/7829481
下面让我们来看一下边缘检测中常用的一些算子:
sobel算子边缘检测算法
索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量
Sobel卷积因子为:
具体计算如下:
Gx = (-1)*f(x-1, y-1) + 0*f(x,y-1) + 1*f(x+1,y-1)
+(-2)*f(x-1,y) + 0*f(x,y)+2*f(x+1,y)
+(-1)*f(x-1,y+1) + 0*f(x,y+1) + 1*f(x+1,y+1)
= [f(x+1,y-1)+2*f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+2*f(x-1,y)+f(x-1,y+1)]
Gy =1* f(x-1, y-1) + 2*f(x,y-1)+ 1*f(x+1,y-1)
+0*f(x-1,y) 0*f(x,y) + 0*f(x+1,y)
+(-1)*f(x-1,y+1) + (-2)*f(x,y+1) + (-1)*f(x+1, y+1)
= [f(x-1,y-1) + 2f(x,y-1) + f(x+1,y-1)]-[f(x-1, y+1) + 2*f(x,y+1)+f(x+1,y+1)]
其中f(a,b), 表示图像(a,b)点的灰度值;
Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。
其实在边缘检测中还会用到很多算子,如普利维特算子(Prewitt operate);[b]罗伯茨交叉边缘检测(Roberts Cross operator);拉普拉斯算子等等。[/b]
2.opencv中Sobel算子实现边缘检测效果图
先上效果图:
当然,opencv中其实上面的代码完全可以用
void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 );
这个函数来代替,相应的参数大家可以去百度,在这就不一一介绍了,本文主要针对sobel算子的检测原理来进行说明。
代码如下
[cpp] view
plain copy
#include "cv.h"
#include "highgui.h"
#include "math.h"
#include "stdio.h"
#include "malloc.h"
IplImage *image; //声明IplImage指针
int height, width;
CvScalar s;
int sobel_y[9] = { 1, 2, 1, 0, 0, 0, -1, -2, -1 }; //y方向sobel算子
int sobel_x[9] = { 1, 0, -1, 2, 0, -2, 1, 0, -1 }; //x方向sobel算子
void sobel()
{
int i, j, k;
int grayx = 0, grayy = 0, gray;
int *data;
int a[9];
data = (int *)malloc(height*width*sizeof(int));
for (i = 0; i<height; i++)
{
for (j = 0; j<width; j++)
{
s = cvGet2D(image, i, j);
gray = (int)s.val[0];
data[i*width + j] = gray;
}
}
for (i = 1; i<height - 1; i++)
{
for (j = 1; j<width - 1; j++)
{
grayx = 0;
grayy = 0;
s = cvGet2D(image, i, j);
a[0] = data[width*(i - 1) + j - 1];
a[1] = data[width*(i - 1) + j];
a[2] = data[width*(i - 1) + j + 1];
a[3] = data[width*i + j - 1];
a[4] = data[width*i + j];
a[5] = data[width*i + j + 1];
a[6] = data[width*(i + 1) + j - 1];
a[7] = data[width*(i + 1) + j];
a[8] = data[width*(i + 1) + j + 1];
for (k = 0; k<9; k++)
grayy += a[k] * sobel_y[k];
for (k = 0; k<9; k++)
grayx += a[k] * sobel_x[k];
s.val[0] = (abs(grayx) + abs(grayy));//此处需要取绝对值
cvSet2D(image, i, j, s);
}
}
free(data);
}
int main(int argc, char** argv)
{
image = cvLoadImage("image1.jpg", 0);
IplImage* image1 = cvLoadImage("image1.jpg", 1);
height = image->height;
width = image->width;
sobel();
cvNamedWindow("Image", 1);//创建窗口
cvNamedWindow("Sobel", 1);//创建窗口
cvShowImage("Image", image1);//显示图像
cvShowImage("Sobel", image);//显示图像
cvWaitKey(0); //等待按键
cvDestroyWindow("Image");//销毁窗口
cvReleaseImage(&image); //释放图像
return 0;
}
参考文章:
http://blog.csdn.net/xiaowei_cqu/article/details/7829481
相关文章推荐
- 【OpenCV】边缘检测:梯度,sobel算子的理解
- opencv学习笔记(二十一) Sobel算子边缘检测
- OpenCV2马拉松第16圈——边缘检测(形态学梯度)
- OpenCV学习笔记(13)OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
- 【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
- vim+python+OpenCV学习七 : Sobel算子、Laplacian算子和Canny边缘检测
- OpenCVForUnity边缘检测(梯度)与滤波
- 【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
- 基于OpenCv的边缘检测(Sobel算子)
- 【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
- opencv中的开运算,闭运算,形态学梯度,顶帽和黑帽,Canny算子,Sobel算子,Laplace算子,Scharr滤波器 简易理解。
- 【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
- 【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
- 【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑合辑
- 【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
- OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
- opencv----边缘检测:canny算子、sobel算子、laplace算子、scharr滤波器
- opencv 图像处理 形态学操作 腐蚀 膨胀 开闭运算 阈值二值化 图像卷积 图像金字塔 Sobel算子 Laplacian 算子 candy边缘检测 霍夫变换 直方图
- opencv(十三)--边缘检测和梯度
- 【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑