opencv(10)图像变换之边缘检测
1.sobel算子
sobel算子利用多项式计算导数的近似值,其计算公式和3*3模版如下,sobel算子结合了一些滤波的效果,对噪声有一定的鲁棒性。
opencv提供了进行sobel算子的函数,函数如下:
void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 );
src :输入图像. 单通道,8位或者浮点
dst: 输出图像. 单通道,如果是8位图像,为了防止溢出,输出必须是IPL_DEPTH_16S类型
xorder: x 方向上的差分阶数
yorder : y 方向上的差分阶数 可以是0 1 2
aperture_size :扩展 Sobel 核的大小,必须是 1, 3, 5 或 7。 除了尺寸为 1, 其它情况下, aperture_size ×aperture_size 可分离内核将用来计算差分。对 aperture_size=1的情况, 使用 3x1 或 1x3 内核 (不进行高斯平滑操作)。这里有一个特殊变量 CV_SCHARR (=-1),对应 3x3 Scharr 滤波器,可以给出比 3x3 Sobel 滤波更精确的结果。
sobel算子使用大核计算到导数更加的逼近,小核对噪声更加敏感,当计算X,Y方向的梯度的时候,精确度还可以,但是使用Y/X计算图像梯度方向的时候,精度就很差,尤其是小核的时候。所以opencv提供了scharr滤波器来解决这个问题,计算梯度的准确率会比sobel 3*3的效果好。
2.拉普拉斯算子
拉普拉斯算子的是对拉普拉斯函数的离散模拟,函数形式如下,opencv中利用二次sobel算子来实现,先利用sobel算子计算X Y方向的差分,然后再求和。
opencv中的实现函数:
void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 );参数和cvsobel函数类似。注意的拉普莱斯中对过零问题做了处理,将二阶差分为0 ,一阶差分算子响应低的边缘点滤除掉。3.CANNY算子void cvCanny( const CvArr* image, CvArr* edges, double threshold1,double threshold2, int aperture_size=3 );canny的步骤如下step1:用高斯滤波器平滑图象;step2:用一阶偏导的有限差分来计算梯度的幅值和方向;step3:对梯度幅值进行非极大值抑制;
step4:用双阈值算法检测和连接边缘。image:canny只接受单通道图像double threshold1,double threshold2为canny算子中采用的两个最大阈值和最小阈值,一个像素的梯度大于最大阈值被认定为边缘,如果小于最小阈值则被抛弃,如果介于二者之间,主要当期与高于上限阈值的连接时才会被认定为接受。也可以采用自适应的阈值算法,可以参考:自适应阈值算法aperture:计算一阶偏导的时候opencv采用sobel算子,这个参数为sobel的内核大小。默认为3*3
测试代码:
1: IplImage *Image1;
2: Image1 = cvLoadImage("7.jpg");
3: IplImage *ImageGray = cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,1);
4: IplImage *SobelDstImg= cvCreateImage(cvGetSize(Image1),IPL_DEPTH_16S,1);
5: IplImage *ImageGray2 = cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,1);
6: cvCvtColor(Image1,ImageGray,CV_BGR2GRAY);
7:
8: cvNamedWindow("src");
9: cvShowImage("src",ImageGray);
10:
11: cvSobel(ImageGray,SobelDstImg,1,1,3 );
12: cvConvertScaleAbs(SobelDstImg,ImageGray2);
13:
14: cvNamedWindow("sobel");
15: cvShowImage("sobel",ImageGray2);
16:
17: cvLaplace(ImageGray,SobelDstImg,3);
18: cvConvertScaleAbs(SobelDstImg,ImageGray2);
19:
20: cvNamedWindow("Laplace");
21: cvShowImage("Laplace",ImageGray2);
22:
23: cvCanny(ImageGray,ImageGray2,50,100,3);
24:
25: cvNamedWindow("Canny");
26: cvShowImage("Canny",ImageGray2);
27:
28: cvCanny(ImageGray,ImageGray2,100,150,3);
29:
30: cvNamedWindow("Canny2");
31: cvShowImage("Canny2",ImageGray2);
32:
33: cvWaitKey();
测试图像:
sobel检测效果没有canny好,拉普拉斯产生了双边缘,canny不同的阈值得到的结果也有很大的差别。