Sobel 算子是一个离散的一阶微分算子,用来计算图像灰度函数的近似梯度。

在空间域上Sobel算子很容易实现,执行速度快,对部分噪声具有平滑作用,还能够提供较为精确的边缘方向信息,缺点是边缘定位精度不够高。边缘是指一个物体与另一个物体的分界处,一般边缘内外处都会有灰度值上的差异,Sobel算子就是通过像素点空间邻域内上下,左右相邻点的灰度加权运算,求取物体边缘。


经典Sobel的卷积因子为:



对于待检测边缘的图像I,分别在水平(X)方向和垂直方向(Y)方向求导,方法是分别图像I与卷积核Gx和Gy进行卷积,公式表述如下:

                                                                  

之后对求得的水平和垂直方向的梯度图像上的每一点执行:


    

或更为简单粗暴的:

   

G即为Sobel求得的梯度图像。


以下是C++实现:

#include "core/core.hpp"  
#include "highgui/highgui.hpp"  
#include "imgproc/imgproc.hpp"  
#include "iostream"

using namespace std; 
using namespace cv;  

int main(int argc,char *argv[])  
{
	Mat image=imread(argv[1],0);
	Mat imageX=Mat::zeros(image.size(),CV_16SC1);
	Mat imageY=Mat::zeros(image.size(),CV_16SC1);	
	Mat imageXY=Mat::zeros(image.size(),CV_16SC1);	
	Mat imageX8UC;
	Mat imageY8UC;
	Mat imageXY8UC;
	if(!image.data)
	{
		return -1;
	}
	GaussianBlur(image,image,Size(3,3),0); //高斯滤波消除噪点
	uchar *P=image.data;
	uchar *PX=imageX.data;
	uchar *PY=imageY.data;
	int step=image.step;
	int stepXY=imageX.step;
	for(int i=1;i<image.rows-1;i++)
	{
		for(int j=1;j<image.cols-1;j++)
		{
			//通过指针遍历图像上每一个像素
			PX[i*imageX.step+j*(stepXY/step)]=abs(P[(i-1)*step+j+1]+P[i*step+j+1]*2+P[(i+1)*step+j+1]-P[(i-1)*step+j-1]-P[i*step+j-1]*2-P[(i+1)*step+j-1]);
			PY[i*imageX.step+j*(stepXY/step)]=abs(P[(i+1)*step+j-1]+P[(i+1)*step+j]*2+P[(i+1)*step+j+1]-P[(i-1)*step+j-1]-P[(i-1)*step+j]*2-P[(i-1)*step+j+1]);
		}
	}
	addWeighted(imageX,0.5,imageY,0.5,0,imageXY);//融合X、Y方向	
	convertScaleAbs(imageX,imageX8UC);
	convertScaleAbs(imageY,imageY8UC);
	convertScaleAbs(imageXY,imageXY8UC);   //转换为8bit图像

	Mat imageSobel;
	Sobel(image,imageSobel,CV_8UC1,1,1); //Opencv的Sobel函数

	imshow("Source Image",image);
	imshow("X Direction",imageX8UC);
	imshow("Y Direction",imageY8UC);
	imshow("XY Direction",imageXY8UC);
	imshow("Opencv Soble",imageSobel);
	waitKey();	
	return 0;
}

原始的Lena美女;



X方向梯度:



Y方向梯度:



X、Y方向梯度融合效果:



Opencv Sobel函数效果:



posted on 2016-08-22 22:39  未雨愁眸  阅读(1260)  评论(0编辑  收藏  举报