1,边缘处理
图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波。我们知道微分运算是求信号的变化率,具有加强高频分量的作用。
在空域运算中来说,对图像的锐化就是计算微分。由于数字图像的离散信号,微分运算就变成计算差分或梯度。
图像处理中有多种边缘检测(梯度)算子,常用的包括普通一阶差分,Robert算子(交叉差分),Sobel算子等等,是基于寻找梯度强度。拉普拉斯算子(二阶差分)是基于过零点检测。通过计算梯度,设置阀值,得到边缘图像。
2,Canny边缘检测算法简介
Canny边缘检测算子是一种多级检测算法。1986年由John F. Canny提出,同时提出了边缘检测的三大准则:
(1) 低错误率的边缘检测:检测算法应该精确地找到图像中的尽可能多的边缘,尽可能的减少漏检和误检。
(2) 最优定位:检测的边缘点应该精确地定位于边缘的中心。
(3)图像中的任意边缘应该只被标记一次,同时图像噪声不应产生伪边缘。
为了满足这些要求,Canny使用了变分法。Canny检测器中的最优函数使用四个指数项的和来描述,它可以由高斯函数的一阶导数来近似。
3,Canny边缘检测算法的处理流程
(1)灰度转换:
该部分是按照Canny算法通常处理的图像为灰度图,如果获取的彩色图像,那首先就得进行灰度化。以RGB格式的彩图为例,通常灰度化采用的公式是:
Gray=0.299R+0.587G+0.114B
在OpenCV中也提供相关的API(cvtColor)
源代码:
///第一步:灰度化
2 IplImage * ColorImage=cvLoadImage("c:\\photo.bmp",1);
3 if (ColorImage==NULL)
4 {
5 printf("image read error");
6 return 0;
7 }
8 cvNamedWindow("Sourceimg",0);
9 cvShowImage("Sourceimg",ColorImage); //
10 IplImage * OpenCvGrayImage;
11 OpenCvGrayImage=cvCreateImage(cvGetSize(ColorImage),ColorImage->depth,1);
12 float data1,data2,data3;
13 for (int i=0;i<ColorImage->height;i++)
14 {
15 for (int j=0;j<ColorImage->width;j++)
16 {
17 data1=(uchar)(ColorImage->imageData[i*ColorImage->widthStep+j*3+0]);
18 data2=(uchar)(ColorImage->imageData[i*ColorImage->widthStep+j*3+1]);
19 data3=(uchar)(ColorImage->imageData[i*ColorImage->widthStep+j*3+2]);
20 OpenCvGrayImage->imageData[i*OpenCvGrayImage->widthStep+j]=(uchar)(0.07*data1 + 0.71*data2 + 0.21*data3);
21 }
22 }
23 cvNamedWindow("GrayImage",0);
24 cvShowImage("GrayImage",OpenCvGrayImage); //显示灰度图
25 cvWaitKey(0);
26 cvDestroyWindow("GrayImage");
(2) 使用高斯滤波器,以平滑图像,滤除噪声(高斯模糊):
了尽可能减少噪声对边缘检测结果的影响,所以必须滤除噪声以防止由噪声引起的错误检测。为了平滑图像,使用高斯滤波器与图像进行卷积,该步骤将平滑图像,以减少边缘检测器上明显的噪声影响。大小为(2k+1)x(2k+1)的高斯滤波器核的生成方程式由下式给出:
下面是一个sigma = 1.4,尺寸为3x3的高斯卷积核的例子(需要注意归一化):
若图像中一个3x3的窗口为A,要滤波的像素点为e,则经过高斯滤波之后,像素点e的亮度值为:
其中*为卷积符号,sum表示矩阵中所有元素相加求和。重要的是需要理解,高斯卷积核大小的选择将影响Canny检测器的性能。尺寸越大,检测器对噪声的敏感度越低,但是边缘检测的定位误差也将略有增加。一般5x5是一个比较不错的trade off。
源代码:
///第二步:高斯滤波
///
double nSigma=0.2;
int nWindowSize=1+2*ceil(3*nSigma);//通过sigma得到窗口大小
int nCenter=nWindowSize/2;
int nWidth=OpenCvGrayImage->width;
int nHeight=OpenCvGrayImage->height;
IplImage * pCanny;
pCanny=cvCreateImage(cvGetSize(ColorImage),ColorImage->depth,1);
//生成二维滤波核
double *pKernel_2=new double[nWindowSize*nWindowSize];
double d_sum=0.0;
for(int i=0;i<nWindowSize;i++)
{
for (int j=0;j<nWindowSize;j++)
{
double n_Disx=i-nCenter;//水平方向距离中心像素距离
double n_Disy=j-nCenter;
pKernel_2[j*nWindowSize+i]=exp(-0.5*(n_Disx*n_Disx+n_Disy*n_Disy)/(nSigma*nSigma))/(2.0*3.1415926)*nSigma*nSigma;
d_sum=d_sum+pKernel_2[j*nWindowSize+i];
}
}
for(int i=0;i<nWindowSize;i++)//归一化处理
{
for (int j=0;j<nWindowSize;j++)
{
pKernel_2[j*nWindo