边缘检测Sobel算子及cvSobel

边缘提取时保留图像灰度变化剧烈的区域,从数学上,最直观的方法是微分,对于数字图像来说就是差分,从信号处理的角度来看,就是用高通滤波器,保留高频信号。以下程序用Sobel算子、Laplace算子、Canny算子实现图像的边缘检测。
注:cvSobel只用于单通道图像变换,如对彩色图像进行cvSobel处理,可分别对每一通道图像进行cvSobel,再转为彩色图像。
===============================================
#include "cv.h"
 #include "cxcore.h"
#include "highgui.h"
 void main()
 {
 IplImage * pImage=NULL;
 IplImage * pImage8uGray=NULL;
IplImage * pImage8uSmooth=NULL;
 IplImage * pImage16uGraySobel=NULL;
 IplImage * pImage8uGraySobelShow=NULL;
 //--------------

IplImage * pImagePlanes[3]={NULL,NULL,NULL};

IplImage * pImage16uColorSobel=NULL;

plImage * pImage8uColorSobelShow=NULL;
//--------------
 IplImage * pImage16uGrayLaplace=NULL;
 IplImage * pImage8uGrayLaplaceShow=NULL;
//--------------
IplImage * pImage8uGrayCanny=NULL;
//==================灰度图像Sobel变换=====================
 pImage=cvLoadImage("lena.jpg",-1);
pImage8uGray=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
pImage8uSmooth=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
pImage8uGraySobelShow=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
//转灰度
cvCvtColor(pImage,pImage8uGray,CV_BGR2GRAY);
//高斯滤波
cvSmooth(pImage8uGray,pImage8uSmooth,CV_GAUSSIAN,3,0,0);
 //cvSobel要求目标图像必须是IPL_DEPTH_16S
 pImage16uGraySobel=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_16S,1);
/计算一阶x方向的差分,也可以计算一阶y方向
cvSobel(pImage8uSmooth,pImage16uGraySobel,0,1,3);
 //再把格式转回来,用于显示
cvConvertScaleAbs(pImage16uGraySobel,pImage8uGraySobelShow,1,0);
 cvNamedWindow("灰度图像Sobel变换",CV_WINDOW_AUTOSIZE);
 cvShowImage("灰度图像Sobel变换",pImage8uGraySobelShow);

 //==================彩色图像Sobel变换=====================
int i;
 for (i=0;i<3;i++)
 {
 pImagePlanes[i]=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
 }
 pImage16uColorSobel=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_16S,1);
 pImage8uColorSobelShow=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,3);
//分成3个单通道
 cvCvtPixToPlane(pImage,pImagePlanes[0],pImagePlanes[1],pImagePlanes[2],NULL);
 for (i=0;i<3;i++)
 {
 cvSobel(pImagePlanes[i],pImage16uColorSobel,0,1,3);
 cvConvertScaleAbs(pImage16uColorSobel,pImagePlanes[i],1,0);
}
 cvCvtPlaneToPix(pImagePlanes[0],pImagePlanes[1],pImagePlanes[2],NULL,pImage8uColorSobelShow);
 cvNamedWindow("彩色图像Sobel变换",CV_WINDOW_AUTOSIZE);
 cvShowImage("彩色图像Sobel变换",pImage8uColorSobelShow);
 
 //==================灰度图像Laplace变换=====================
 pImage16uGrayLaplace=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_16S,1);
 pImage8uGrayLaplaceShow=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
 cvLaplace(pImage8uSmooth,pImage16uGrayLaplace,3);
 cvConvertScaleAbs(pImage16uGrayLaplace,pImage8uGrayLaplaceShow,1,0);
 cvNamedWindow("灰度图像Laplace变换",CV_WINDOW_AUTOSIZE);
 cvShowImage("灰度图像Laplace变换",pImage8uGrayLaplaceShow);

 //==================灰度图像Canny变换=====================
 pImage8uGrayCanny=cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
 cvCanny(pImage8uSmooth,pImage8uGrayCanny,100,200,3);
 cvNamedWindow("灰度图像Canny变换",CV_WINDOW_AUTOSIZE);
cvShowImage("灰度图像Canny变换",pImage8uGrayCanny);

 cvWaitKey(0);
 cvDestroyWindow("灰度图像Sobel变换");
 cvDestroyWindow("彩色图像Sobel变换");
 cvDestroyWindow("灰度图像Laplace变换");
 cvReleaseImage(&pImage);
cvReleaseImage(&pImage8uGray);
 cvReleaseImage(&pImage8uSmooth);
 cvReleaseImage(&pImage16uGraySobel);
 cvReleaseImage(&pImage8uGraySobelShow);
 cvReleaseImage(&pImage16uColorSobel);
 cvReleaseImage(&pImage8uColorSobelShow);
 cvReleaseImage(&pImagePlanes[0]);
 cvReleaseImage(&pImagePlanes[1]);
 cvReleaseImage(&pImagePlanes[2]);
 cvReleaseImage(&pImage16uGrayLaplace);
 cvReleaseImage(&pImage8uGrayLaplaceShow);
 }===============================================
边缘检测Sobel算子及cvSobel_第1张图片
===============================================
Sobel

使用扩展 Sobel 算子计算一阶、二阶、三阶或混合图像差分

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。 除了尺寸为 1, 其它情况下, aperture_size ×aperture_size 可分离内核将用来计算差分。对 aperture_size=1的情况, 使用 3x1 或 1x3 内核 (不进行高斯平滑操作)。这里有一个特殊变量 CV_SCHARR (=-1),对应 3x3 Scharr 滤波器,可以给出比 3x3 Sobel 滤波更精确的结果。Scharr 滤波器系数是:

对 x-方向 以及转置矩阵对 y-方向。

函数 cvSobel 通过对图像用相应的内核进行卷积操作来计算图像差分:

由于Sobel 算子结合了 Gaussian 平滑和微分,所以,其结果或多或少对噪声有一定的鲁棒性。通常情况,函数调用采用如下参数 (xorder=1, yorder=0, aperture_size=3) 或 (xorder=0, yorder=1, aperture_size=3) 来计算一阶 x- 或 y- 方向的图像差分。第一种情况对应:

核。

第二种对应:

或者

核的选则依赖于图像原点的定义 (origin 来自 IplImage 结构的定义)。由于该函数不进行图像尺度变换,所以和输入图像(数组)相比,输出图像(数组)的元素通常具有更大的绝对数值(译者注:即象素的深度)。为防止溢出,当输入图像是 8 位的,要求输出图像是 16 位的。当然可以用函数 cvConvertScale 或 cvConvertScaleAbs 转换为 8 位的。除了 8-比特 图像,函数也接受 32-位 浮点数图像。所有输入和输出图像都必须是单通道的,并且具有相同的图像尺寸或者ROI尺寸。

===============================================

Laplace

计算图像的 Laplacian 变换

void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 );
src
输入图像.
dst
输出图像.
aperture_size
核大小 (与 cvSobel 中定义一样).

函数 cvLaplace 计算输入图像的 Laplacian变换,方法是先用 sobel 算子计算二阶 x- 和 y- 差分,再求和:

dst(x,y) = d2src/dx2 + d2src/dy2

对 aperture_size=1 则给出最快计算结果,相当于对图像采用如下内核做卷积:

类似于 cvSobel 函数,该函数也不作图像的尺度变换,所支持的输入、输出图像类型的组合和cvSobel一致。

===============================================
Canny

void cvCanny( const CvArr* image, CvArr* edges, double threshold1,
double threshold2, int aperture_size=3 );
image 
输入图像. 
edges 
输出的边缘图像 
threshold1 
第一个阈值 
threshold2 
第二个阈值 
aperture_size 
Sobel 算子内核大小 (见 cvSobel). 
函数 cvCanny 采用 CANNY 算法发现输入图像的边缘而且在输出图像中标识这些边缘。threshold1和threshold2 当中的小阈值用来控制边缘连接,大的阈值用来控制强边缘的初始分割。

你可能感兴趣的:(边缘检测Sobel算子及cvSobel)