边缘检测
注意,边缘检测对噪声比较敏感,需要先用高斯滤波器对图像进行平滑。
Sobel变换和拉普拉斯变换都是高通滤波器。什么是高通滤波器呢?就是保留图像的高频分量(变化剧烈的部分),抑制图像的低频分量(变化缓慢的部分)。而图像变化剧烈的部分,往往反应的就是图像的边沿信息了。
Sobel算子
一个最重要并且最基本的卷积是导数的计算(或者是其近似值),有许多方法可以做到,但是只有少数方法适合于给定情况。
Sobel算子用于边缘检测
在讨论边缘算子之前,首先给出一些术语的定义:
(1)边缘:灰度或结构等信息的突变处,边缘是一个区域的结束,也是另一个区域的开始,利用该特征可以分割图像。
(2)边缘点:图像中具有坐标[x,y],且处在强度显著变化的位置上的点。
(3)边缘段:对应于边缘点坐标[x,y]及其方位 ,边缘的方位可能是梯度角。
cvSobel()
定义:
void cvSobel(
const CvArr* src,
CvArr* dst,
int xorder,
int yorder,
int aperture_size = 3
);
参数:
src 输入图像
dst 输出图像
xorder
x 方向上的差分阶数
yorder
y 方向上的差分阶数
aperture_size
Sobel 核的大小,必须是 1, 3, 5 或 7。
这里,src和dst分别是输入图像和输出图像,xorder和yorder是求导的阶数。通常只可能用到0,1,最多2。值为0表明在这个方向上没有求导①(①无论是xorder还是yorder,都必须非0),
aperture_size参数是方形滤波器的宽(或高)并且应该是奇数。目前,
aperture_size支持1, 3, 5, 7。如果源图像src是8位的,为避免溢出,目标图像的深度必须是IPL_DEPTH_16S。
——因为以Sobel方式求完导数后会有负值,还有会大于255的值而你建的Sobel的图像是 IPL_DEPTH_8U,也就是8位无符号数,所以Sobel建立的图像位数不够,要16位有符号的,也就是 IPL_DEPTH_16S。
程序实例
#include
#include
void main()
{
IplImage *frame,*gray,*sobel;
frame=cvLoadImage("b.jpg");//加载图像
gray=cvCreateImage(cvGetSize(frame),frame->depth,1);
//分配图像空间
sobel=cvCreateImage(cvGetSize(frame),IPL_DEPTH_16S,1);
/*因为以Sobel方式求完导数后会有负值,还有会大于255的值而你建的Sobel的图像是 IPL_DEPTH_8U,也就是8位无符号数,所以Sobel建立的图像位数不够,要16位有符号的,也就是 IPL_DEPTH_16S。*/
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);
//数据转换,IPL_DEPTH_16S变成IPL_DEPTH_8U
cvShowImage("frame",frame);//显示图像
cvShowImage("gray",gray);
cvShowImage("sobel",sobel8u);
cvWaitKey(0);//等待
cvReleaseImage(&frame);
//释放空间(对视频处理很重要,不释放会造成内存泄露)
cvReleaseImage(&gray);
cvReleaseImage(&sobel);
cvDestroyWindow("frame");
cvDestroyWindow("gray");
cvDestroyWindow("sobel");
}
Scharr滤波器——Sobel算子的改进
该函数仅作用于大小为3的内核。该函数的运算与Sobel函数一样快,但结果却更加精确。详见下面的博客:
http://www.tuicool.com/articles/Y3q2Mf
这个滤波器怎么用么?对函数cvSobel( )的参数aperture_size,当它为CV_SCHARR (=-1),对应 3×3 Scharr 滤波器。大家可以在上面的程序的基础上改一下,使用一下这个滤波器。