再说边缘特征提取sobel算子

来源:互联网 发布:java 堆内存 编辑:程序博客网 时间:2024/06/06 07:37

本文主要讲述以下几个函数的作用:

(1)cvSobel

(2)cvConvertScaleAbs

(3)cvCvtColor


首先,我们来了解一下计算机是如何检测边缘的。以灰度图像为例,它的理论基础是这样的,如果出现一个边缘,那么图像的灰度就会有一定的变化,为了方便假设由黑渐变为白代表一个边界,那么对其灰度分析,在边缘的灰度函数就是一个一次函数y=kx,对其求一阶导数就是其斜率k,就是说边缘的一阶导数是一个常数,而由于非边缘的一阶导数为零,这样通过求一阶导数就能初步判断图像的边缘了。通常是X方向和Y方向的导数,也就是梯度。理论上计算机就是通过这种方式来获得图像的边缘。

    但是,具体应用到图像中你会发现这个导数是求不了的,因为没一个准确的函数让你去求导,而且计算机在求解析解要比求数值解麻烦得多,所以就想到了一种替代的方式来求导数。就是用一个3×3的窗口来对图像进行近似求导。拿对X方向求导为例,某一点的导数为第三行的元素之和减去第一行元素之和,这样就求得了某一点的近似导数。其实也很好理解为什么它就近似代表导数,导数就代表一个变化率,从第一行变为第三行,灰度值相减,当然就是一个变化率了。这就是所谓的Prewitt算子。这样近似X方向导数就求出来了。Y方向导数与X方向导数求法相似,只不过是用第三列元素之和减去第一列元素之和。X方向和Y方向导数有了,那么梯度也就出来了。这样就可以找出一幅图中的边缘了。

   还有一个问题,由于求的是3×3中心点的导数,所以给第二列加了一个权重,它的权重为2,第一列和第三列的权重为1,好了,这就是Sobel算子了。相比Prewitt算子,Sobel的抗噪能力更强。如图所示:


这样,中心点的X方向导数就求出来了。举个例子吧。


X点以Sobel方式求导数ΔX=1×50+2×30+1×50-(1×50+2×30+1×50=0。这样可以看出这个点不是边界。好了,了解了基本理论之后,我们看看OpenCV下的Sobel函数吧。


(1)void cvSobel( const CvArr* src, CvArr* dst, int xorder, intyorder, int aperture_size=3 );

src:输入图像;

dst:输出图像;

xorderx方向上的差分阶数;

yordery方向上的差分阶数;

aperture_size 扩展 Sobel 核的大小(既窗口阶数),必须是 1(注意这是一个3×11×3向量而不是一个方阵), 3, 5 7

   

然后,因为以Sobel方式求完导数后会有负值,还有会大于255的值。而一开始建的Sobel的图像是8位:IPL_DEPTH_8U也就是8位无符号数,所以Sobel建立的图像位数不够,要16位有符号的,也就是 IPL_DEPTH_16S。因此需要建立图像为16位,需要这句sobel= cvCreateImage (cvGetSize(frame) ,IPL_DEPTH_16S,1);这样子运行,才会不报错,但是Sobel图像显示不出来,这是什么原因呢?原来图像显示是以8位无符号显示的,现在是16位有符号,当然显示会出问题了。所以还要将Sobel转为8位无符号。opencv里提供了一个函数,就是cvConvertScaleAbs。


(2)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方向求导是什么效果。


最后讲一下cvCvtColor这个函数,是Opencv里的颜色空间转换函数,可以实现RGB颜色向HSV,HSI等颜色空间的转换,也可以转换为灰度图像。参数CV_RGB2GRAY是RGB到gray,参数 CV_GRAY2RGB是gray到RGB。处理结果是彩色的。

(3)void cvCvtColor( const CvArr* src, CvArr* dst, int code );

src
输入的 8-bit,16-bit或 32-bit单倍精度浮点数影像。
dst
输出的8-bit, 16-bit或 32-bit单倍精度浮点数影像。
code
色彩空间转换的模式,该code来实现不同类型的颜色空间转换。比如:

CV_BGR2GRAY表示转换为灰度图,

CV_BGR2HSV将图片从RGB空间转换为HSV空间。

其中当code选用CV_BGR2GRAY时,dst需要是单通道图片。

当code选用CV_BGR2HSV时,对于8位图,需要将RGB值归一化到0-1之间。
这样得到HSV图中的H范围才是0-360,S和V的范围是0-1。


现在,为了方便大家,我把完整的程序也放上来了。

代码:

#include <cv.h>

#include <highgui.h>
using namespace std;
using namespace cv;
void main()
{
IplImage *frame,*gray,*sobel;
frame=cvLoadImage(“car1.jpg”);//加载图像
gray=cvCreateImage(cvGetSize(frame),frame->depth,1);//注意是8位
//cvSobel要求目标图像必须是IPL_DEPTH_16S
sobel=cvCreateImage(cvGetSize(frame),IPL_DEPTH_16S,1);//注意是16位
cvNamedWindow(“frame”);
cvNamedWindow(“gray”);
cvNamedWindow(“sobel”);
cvCvtColor(frame,gray,CV_BGR2GRAY);//转为灰度
//计算一阶x方向的差分,也可以计算一阶y方向
cvSobel(gray,sobel,1,0,3);//x-1阶导,y-0阶
IplImage *sobel8u=cvCreateImage(cvGetSize(sobel),IPL_DEPTH_8U,1);//注意是8位
//再把格式转回来,用于显示
cvConvertScaleAbs(sobel,sobel8u,1,0);//转换回8位,用于显示
cvShowImage(“frame”,frame);//显示图像
cvShowImage(“gray”,gray);
cvShowImage(“sobel”,sobel8u);

cvWaitKey(0);//等待
cvReleaseImage(&frame);//释放空间(对视频处理很重要,不释放会造成内存泄露)
cvReleaseImage(&gray);
cvReleaseImage(&sobel);
cvDestroyWindow(“frame”);
cvDestroyWindow(“gray”);
cvDestroyWindow(“sobel”);
}

结果:



(完)



原创粉丝点击