Sobel算子是一阶导数的边缘检测算子,在算法实现过程中,通过3×3模板作为核与图像中的每个像素点做卷积和运算,然后选取合适的阈值提取边缘。
采用3×3邻域可以避免在像素之间内插点上计算梯度。Sobel算子也是一种梯度幅值,即:其中的偏导数Sx和Sy可用卷积模板来实现。其模板如下:
Sx = (Z1 + 2*Z2 + Z3)-(Z7 + 2*Z8 + Z9);
Sy = (Z1 + 2*Z4 + Z7)-(Z3 + 2*Z6 + Z9);
Sobel算子算法的优点是计算简单,速度快。但是由于只采用了2个方向的模板,只能检测水平和垂直方向的边缘,因此这种算法对于纹理较为复杂的图像,其边缘检测效果就不是很理想。
代码如下:
#include
#include
void main()
{
IplImage *frame,*gray,*sobel;
frame=cvLoadImage("car.bmp");//加载图像
gray=cvCreateImage(cvGetSize(frame),frame->depth,1);//分配图像空间
sobel=cvCreateImage(cvGetSize(frame),frame->depth,1);
cvCvtColor(frame,gray,CV_BGR2GRAY);//转为灰度
cvSobel(gray,sobel,1,0,3);
cvNamedWindow("frame");
cvNamedWindow("gray");
cvNamedWindow("sobel");
cvShowImage("frame",frame);//显示图像
cvShowImage("gray",gray);
cvShowImage("sobel",sobel);
cvWaitKey(0);//等待
cvReleaseImage(&frame);//释放空间(对视频处理很重要,不释放会构成内存败露)
cvReleaseImage(&gray);
cvReleaseImage(&sobel);
cvDestroyWindow("frame");
cvDestroyWindow("gray");
cvDestroyWindow("sobel");
}
运行之后没有发现语法错误,其实仔细看还是有问题的。因为以Sobel方式求完导数后会有负值,还有会大于255的值而你建的Sobel的图像是 IPL_DEPTH_8U,也就是8位无符号数,所以Sobel建立的图像位数不够,要16位有符号的,也就是 IPL_DEPTH_16S。改为sobel=cvCreateImage(cvGetSize(frame),IPL_DEPTH_16S,1);运行之后,发现不报错了,但是Sobel图像显示不出来,这是什么原因呢?原来图像显示是以8位无符号显示的,现在是16位有符号,当然显示会出问题了。所以还要将Sobel转为8位无符号。
OpenCv里有cvConvertScaleAbs( const CvArr* src, CvArr* dst, double scale=1, double shift=0 );
src:源图像;dst:目标图像;scale:转化前乘的系数;shift转化前加的系数。
这样新建一个无符号图像再转换就可以实现了。
IplImage *sobel8u=cvCreateImage(cvGetSize(sobel),IPL_DEPTH_8U,1);
再在显示图像前加上cvConvertScaleAbs(sobel,sobel8u,1,0);这样就可以看到cvSobel的效果了。可以看X方向或Y 方向求导是什么效果。修改后的程序如下:
#include
#include
void main()
{
IplImage *frame,*gray,*sobel;
frame=cvLoadImage("car.jpg");//加载图像
gray=cvCreateImage(cvGetSize(frame),frame->depth,1);//分配图像空间
sobel=cvCreateImage(cvGetSize(frame),IPL_DEPTH_16S,1);
cvNamedWindow("frame");
cvNamedWindow("gray");
cvNamedWindow("sobel");
cvCvtColor(frame,gray,CV_BGR2GRAY);//转为灰度
cvSobel(gray,sobel,1,0,3);
IplImage *sobel8u=cvCreateImage(cvGetSize(sobel),IPL_DEPTH_8U,1);
cvConvertScaleAbs(sobel,sobel8u,1,0);
cvShowImage("frame",frame);//显示图像
cvShowImage("gray",gray);
cvShowImage("sobel",sobel8u);
cvWaitKey(0);//等待
cvReleaseImage(&frame);//释放空间(对视频处理很重要,不释放会造成内存泄露)
cvReleaseImage(&gray);
cvReleaseImage(&sobel);
cvDestroyWindow("frame");
cvDestroyWindow("gray");
cvDestroyWindow("sobel");
}
实验结果如下:
原图
16S的Sobel图(什么都没有)
Sobel边缘图