边缘检测Word文档下载推荐.docx
《边缘检测Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《边缘检测Word文档下载推荐.docx(19页珍藏版)》请在冰点文库上搜索。
由于建筑物图像的特殊性,我们可以发现,处理该类型图像轮廓时,并不需要对梯度方向进行运算,所以程序并没有给出各向同性Sobel算子的处理方法。
由于Sobel算子是滤波算子的形式,用于提取边缘,可以利用快速卷积函数,简单有效,因此应用广泛。
美中不足的是,Sobel算子并没有将图像的主体与背景严格地区分开来,换言之就是Sobel算子没有基于图像灰度进行处理,由于Sobel算子没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。
在观测一幅图像的时候,我们往往首先注意的是图像与背景不同的部分,正是这个部分将主体突出显示,基于该理论,我们可以给出阈值化轮廓提取算法,该算法已在数学上证明当像素点满足正态分布时所求解是最优的。
上面的算子是利用一阶导数的信息,属于梯度算子范畴。
Laplacian算子:
这是二阶微分算子。
其具有各向同性,即与坐标轴方向无关,坐标轴旋转后梯度结果不变。
但是,其对噪声比较敏感,所以,图像一般先经过平滑处理,因为平滑处理也是用模板进行的,所以,通常的分割算法都是把Laplacian算子和平滑算子结合起来生成一个新的模板。
Laplacian算子一般不以其原始形式用于边缘检测,因为其作为一个二阶导数,Laplacian算子对噪声具有无法接受的敏感性;
同时其幅值产生算边缘,这是复杂的分割不希望有的结果;
最后Laplacian算子不能检测边缘的方向;
所以Laplacian在分割中所起的作用包括:
(1)利用它的零交叉性质进行边缘定位;
(2)确定一个像素是在一条边缘暗的一面还是亮的一面;
一般使用的是高斯型拉普拉斯算子(LaplacianofaGaussian,LoG),由于二阶导数是线性运算,利用LoG卷积一幅图像与首先使用高斯型平滑函数卷积改图像,然后计算所得结果的拉普拉斯是一样的。
所以在LoG公式中使用高斯函数的目的就是对图像进行平滑处理,使用Laplacian算子的目的是提供一幅用零交叉确定边缘位置的图像;
图像的平滑处理减少了噪声的影响并且它的主要作用还是抵消由Laplacian算子的二阶导数引起的逐渐增加的噪声影响。
微分算子在图像处理中扮演重要的角色,其算法实现简单,而且边缘检测的效果又较好,因此这些基本的微分算子是学习图像处理过程中的必备方法,下面着重讨论几种常见的微分算子。
1.Sobel
其主要用于边缘检测,在技术上它是以离散型的差分算子,用来运算图像亮度函数的梯度的近似值,缺点是Sobel算子并没有将图像的主题与背景严格地区分开来,换言之就是Sobel算子并没有基于图像灰度进行处理,由于Sobel算子并没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意,算法具体实现很简单,就是3*3的两个不同方向上的模板运算,这里不再写出。
2.Robert算子
根据任一相互垂直方向上的差分都用来估计梯度,Robert算子采用对角方向相邻像素只差
3.Prewitt算子
该算子与Sobel算子类似,只是权值有所变化,但两者实现起来功能还是有差距的,据经验得知Sobel要比Prewitt更能准确检测图像边缘。
4.Laplacian算子
拉普拉斯算子是一种二阶微分算子,若只考虑边缘点的位置而不考虑周围的灰度差时可用该算子进行检测。
对于阶跃状边缘,其二阶导数在边缘点出现零交叉,并且边缘点两旁的像素的二阶导数异号。
5.Canny算子
该算子功能比前面几种都要好,但是它实现起来较为麻烦,Canny算子是一个具有滤波,增强,检测的多阶段的优化算子,在进行处理前,Canny算子先利用高斯平滑滤波器来平滑图像以除去噪声,Canny分割算法采用一阶偏导的有限差分来计算梯度幅值和方向,在处理过程中,Canny算子还将经过一个非极大值抑制的过程,最后Canny算子还采用两个阈值来连接边缘。
下面算法是基于的算法不可能直接运行,只是我把Canny的具体实现步骤写了出来,若需用还要自己写。
该算子具体实现方法:
//anny.cpp:
implementationoftheCannyclass.
//
//////////////////////////////////////////////////////////////////////
#include"
anny.h"
math.h"
//#include"
algorithms.h"
algorithm.h"
stdlib.h"
maths.h"
//usingnamespacestd;
//Construction/Destruction
Canny:
:
Canny(intPicHeight,intPicWidth,double**PicData,doublePicSigma,doublePicRatioLow,doublePicRatioHigh)
{
iHeight=PicHeight;
iWidth=PicWidth;
iData=PicData;
sigma=PicSigma;
dRatioLow=PicRatioLow;
dRatioHigh=PicRatioHigh;
}
~Canny()
voidCanny:
CannyArith(int**iEdgePoint)
inti;
int**iGradX;
//指向x方向导数的指针
int**iGradY;
//指向y方向导数的指针
int**iExtent;
//梯度的幅度
iGradX=newint*[iHeight];
for(i=0;
i&
lt;
iHeight;
i++)
iGradX[i]=newint[iWidth];
iGradY=newint*[iHeight];
iGradY[i]=newint[iWidth];
iExtent=newint*[iHeight];
iExtent[i]=newint[iWidth];
//对原图象进行滤波
GaussionSmooth();
//计算X,Y方向上的方向导数
DirGrad(iGradX,iGradY);
//计算梯度的幅度
GradExtent(iGradX,iGradY,iExtent);
//应用non-maximum抑制
NonMaxSuppress(iExtent,iGradX,iGradY,iEdgePoint);
//应用Hysteresis,找到所有的边界
Hysteresis(iExtent,iEdgePoint);
//释放内存
delete[]*(iGradX+i);
deleteiGradX;
delete[]*(iGradY+i);
deleteiGradY;
delete[]*(iExtent+i);
deleteiExtent;
GaussionSmooth()
inti,j,k;
//循环变量
intiWindowSize;
//记录模板大小的变量
intiHalfLen;
//模板大小的一半
double*pdKernel;
//模板各点的权值
doubledDotMul;
//模板与对应像素点的卷积和
doubledWeightSum;
//模板的权值累加和
double**dTemp;
//记录图像数据的中间变量
//开辟空间
dTemp=newdouble*[iHeight];
i++)
dTemp[i]=newdouble[iWidth];
//获得模板长度和模板的各个权值
MakeGauss(&
amp;
pdKernel,&
iWindowSize);
//得到模板的一半长度
iHalfLen=iWindowSize/2;
//对图像对水方向根据模板进行平滑
{
for(j=0;
j&
iWidth;
j++)
dDotMul=0;
dWeightSum=0;
for(k=(-iHalfLen);
k&
=iHalfLen;
k++)
if((k+j&
gt;
=0)&
&
(k+j&
iWidth))
dDotMul+=iData[i][j+k]*pdKernel[k+iHalfLen];
dWeightSum+=pdKernel[k+iHalfLen];
}
dTemp[i][j]=dDotMul/dWeightSum;
//对图像垂直方向上根据模板的转置进行平滑(注意图像数据是在水平平滑之后进行的)
iHeight))
dDotMul+=dTemp[j+k][i]*pdKernel[k+iHalfLen];
iData[j][i]=dDotMul/dWeightSum;
//空间释放
delete[]pdKernel;
pdKernel=NULL;
delete[]*(dTemp+i);
deletedTemp;
MakeGauss(double**pdKernel,int*iWindowSize)
intnCenter;
//确定高斯模板的一半长度
doubledDistance;
//一维高斯模板各点离中心点的距离
doublePI=3.1415926;
//圆周率
doubledValue;
//中间变量,记录高斯模板各点的权值(未经归一化)
doubledSum=0;
//中间变量,记录高斯模板各点权值的总和
*iWindowSize=int(1+2*int(3*sigma+0.5));
//确定一维高斯模板长度,根据概率论的知识,选取[-3*sigma,3*sigma]以内的数据。
nCenter=(*iWindowSize)/2;
//得到一半长度
*pdKernel=newdouble[*iWindowSize];
//开辟记录各点权值的空间
//利用高斯分布函数(正太分布)确定各点的权值,主要是根据高斯分布离中心点的距离越远,所取的值就越小,这与图像有些
//相似,离中心点越远,对中心点的影响就越小。
(*iWindowSize);
dDistance=double(i-nCenter);
//高斯分布函数求值
dValue=exp((-1/2)*dDistance*dDistance/(sigma*sigma))/(sqrt(2*PI)*sigma);
(*pdKernel)[i]=dValue;
dSum+=dValue;
//归一化(因为要不改变原图像的灰度区域,就必须保证各权值之和为1
(*pdKernel)[i]/=dSum;
DirGrad(int**iGradX,int**iGradY)
inti,j,temp1,temp2;
//水平方向的方向导数(下面都是用min和max对边界值做了相应的处理)
if(iWidth-1&
j+1)
temp1=iWidth-1;
else
temp1=j+1;
if(0&
j-1)
temp2=j-1;
temp2=0;
iGradX[i][j]=int(iData[i][temp1]-iData[i][temp2]);
//垂直方向的方向导数
if(iHeight-1&
temp1=iHeight-1;
iGradY[j][i]=int(iData[temp1][i]-iData[temp2][i]);
GradExtent(int**iGradX,int**iGradY,int**iExtent)
inti,j;
doubleiTemp1,iTemp2;
iTemp1=iGradX[i][j]*iGradX[i][j];
iTemp2=iGradY[i][j]*iGradY[i][j];
iExtent[i][j]=int(sqrt(iTemp1+iTemp2)+0.5);
NonMaxSuppress(int**iExtent,int**iGradX,int**iGradY,int**dUnchRst)
intgx,gy;
//记录像素点X,Y方向的方向导数值
intg1,g2,g3,g4;
//各个领域的梯度值
doubleweight;
//比重
doubledTemp1,dTemp2,dTemp;
//中间变量
//处理边缘值(边缘点不可能是边界点
dUnchRst[i][0]=0;
dUnchRst[i][iWidth-1]=0;
dUnchRst[0][j]=0;
dUnchRst[iHeight-1][j]=0;
//标记有可能是边界点的像素点
for(i=1;
iHeight-1;
for(j=1;
iWidth-1;
//梯度值是0的像素点不可能是边界点
if(iExtent[i][j]==0)
dUnchRst[i][j]=0;
dTemp=iExtent[i][j];
gx=iGradX[i][j];
gy=iGradY[i][j];
//下面都是判断当前像素点的梯度值和其领域像素点的梯度值,如大于就有可能是边界点,如小于就不可能是边界点
if(abs(gy)&
abs(gx))
weight=double(abs(gx)/abs(gy));
g2=iExtent[i-1][j];
g4=iExtent[i+1][j];
if(gx*gy&
0)
g1=iExtent[i-1][j-1];
g3=iExtent[i+1][j+1];
g1=iExtent[i-1][j+1];
g3=iExtent[i+1][j-1];
weight=double(abs(gy)/abs(gx));
g2=iExtent[i][j+1];
g4=iExtent[i][j-1];
g1=iExtent[i+1][j+1];
g3=iExtent[i-1][j-1];
dTemp1=weight*g1+(1-weight)*g2;
dTemp2=weight*g3+(1-weight)*g4;
//当大于的时候就有可能是边界点
if(dTemp&
=dTemp1&
dTemp&
=dTemp2)
dUnchRst[i][j]=128;
dUnchRst[i][j]=0;
}
Hysteresis(int**iExtent,int**iEdgePoint)
intiThreHigh;
intiThreLow;
SetThreshold(iExtent,&
iThreHigh,&
iThreLow,iEdgePoint);
if((iEdgePoint[i][j]==128)&
(iExtent[i][j]&
=iThreHigh))
iEdgePoint[i][j]=255;
TraceEdge(i,j,iThreLow,iEdgePoint,iExtent);
//那些还没有被设置为边界点的象素已经不可能成为边界点
if(iEdgePoint[i][j]!
=255)
//设置为非边界点
iEdgePoint[i][j]=0;
SetThreshold(int**iExtent,int*iThreHigh,int*iThreLow,int**iEdgePoint)
intGradHist[1024];
//统计梯度直方图的数据,梯度最大值不可能超过1024
intiEdgeNum;
//边界点的数量
intiGradMax=0;
//边界点的梯度最大值
intiHighCount;
//根据iRatioHigh小于高阈值像素的个数
//初始化
1024;
GradHist[i]=0;
//梯度直方图统计
if(iEdgePoint[i][j]==128)
GradHist[iExtent[i][j]]++;
iEdgeNum=0;
//找出最大梯度和统计边界点的个数
if(Gr