Matlab图像锐化处理及边缘检测
本章要点:
图像边缘锐化的基本方法 微分运算 梯度锐化 边缘检测
6.1 图像边缘锐化的基本方法
物体的边缘是以图像局部特性不连续性的形式出现。本质上边缘常意味着一个区域的终结和另一个区域的开始。图像边缘信息在图像分析和人的视觉中都是十分重要的,是图像识别中提取图像特征的一个重要特性。图像的边缘有方向和幅度两个特性。通常,延边缘走向的像素变化平缓,而垂直于边缘走向的像素变化剧烈。边缘的描述包含以下几个方面:
(1) 边缘点——它两边像素的灰度值有显著的不同。边缘点也存在于这样一对邻点之间即一个在较亮的区域内部,另一个在外部。
(2)边缘法线方向——在某点灰度变化最剧烈的方向,与边缘方向垂直。 (3)边缘方向——与边缘法线方向垂直,是目标边界的切线方向。 (4)边缘位置——边缘所在的坐标位置。
(5)边缘强度——沿边缘法线方向图像局部的变化强度的量度。
粗略地区分边缘种类可以有两种,其一是阶跃状边缘,它两边像素的灰度值有显著的不同,其二是屋顶状边缘,它位于灰度值从增加到减少的变化转折点。这些变化分别对应景物
.
中不同的物理状态。边缘是图像上灰度变化比较剧烈的地方,如果一个像素落在图像中某一个物体的边界上,那么它的邻域将成为一个灰度级的变化带。对这种变化最有用的两个特征是灰度的变化率和方向,在灰度变化突变处进行微分,将产生高值。经典的边缘提取方法是考虑图像的每个像素在某个领域内的变化,利用边缘邻近一阶或二阶方向导数变化规律,来检测边缘。图像灰度值的显著变化可以用一阶差分替代一阶微分的梯度来表示,它们分别以梯度向量的幅度和方向来表示。因此图像中陡峭边缘的梯度值将是很大的;那些灰度变化平缓的地方,梯度值是比较小的;而那些灰度值相同的地方,梯度值将为零。图像经过梯度运算能灵敏地检测出边界线,这种微分边缘检测算子运算简单易行,但有方向性。
利用计算机进行图像锐化处理有两个目的,一是与柔化处理相反,增强图像边缘,使模糊的图像变得更加清晰起来,颜色变得鲜明突出,图像的质量有所改善,产生更适合人观察和识别的图像,本章的梯度锐化就是介绍这方面的内容。二是希望经过锐化处理后,目标物体的边缘鲜明,以便于计算机提取目标物体的边界、对图像进行分割、目标区域识别、区域形状提取等,为图像理解和分析打下基础,目前它已成为机器视觉研究领域最活跃的课题之一,在工程应用中占有十分重要的地位,本章的边缘检测算子就是介绍这方面的内容。
与图像平滑处理相对应,图像锐化也可以分为空间域图像锐化法和空间频率域图像锐化法两大类型。空间频率域图像锐化的方法将在第九章介绍,本章介绍边缘增强及边缘检测的方法,基于空间域处理,为分割及目标物体特征提取打下基础。
6.2 微分运算
边缘是由相邻域灰度级不同像素点构成的,若想增强边缘,就应该突出相邻点间灰度级的变化。如下图所示,不难发现原图中左边暗,右边亮,中间存在着一条明显的边界。
0 0 1 255 255 255 255
1 1 1 254 253 254 254
.
0 0 0 255 255 253 253 1 1 0 254 254 254 254
注意:由于计算机显示屏幕的坐标原点在视窗的左上角,显示屏幕的坐标系如图
6-1所示。
(0,0) x
f(x,y) y
图6-1 显示屏幕的坐标系
为了与f ( x,y)表示法相一致,图像f(i,j)中的i代表列,j代表行。如果用右列减去左列,即每一个像素的值为:
G ( i, j ) = f ( i , j )- f ( i-1, j ) 结果如下: 0 1 254 0 0 0 0 0 253 -1 1 0 0 0 255 0 -2 0 0 - 1 254 0 0 0
可以看出,第3列比其他列的灰度值高很多,在边界附近,灰度值有明显的跳变,人眼观察时,就能发现一条很明显的亮边;在灰度相近的区域内,这么做的结果使得该点的灰度值接近于0,区域都很暗。
这样,G ( i, j ) = f ( i , j )- f ( i-1, j )就起到了垂直边沿检测的作用。 如对于上面那幅图像转置,得到如下图像数据:
0 1 0 1 0 1 0 1
.
1 1 0 0
255 254 255 254 255 255 255
该边缘是水平方向的,这时如果还用左列减去右列就得不到边界数据,必须是下一行减去上一行,即每一个像素的值为:
253 255 254
254 253 254 254 253 254
G ( i, j ) = - f ( i, j-1 ) + f ( i , j ),图像上得到一条很明显的亮边。
这就是一种边沿检测器,它在数学上的涵义是一种基于梯度的滤波器,又称边沿算子,梯度是有方向的,和边沿的方向总是正交(垂直)的。
图像灰度的变化情况可以用灰度分布的梯度来反映。图像处理中最常用的微分方法是求梯度。对于图像f(i,j), 它在点(i,j)处的梯度是一个矢量,定义为:
fi (6-1)
g[f(i,j)]fj其方向导数在边缘法线方向上取得局部最大值。怎样求f(i,j)梯度的局部最大值和方向呢?我们知道f(i,j) 沿方向r的梯度为:
ffifjficosfjsin (6-2) rirjrfrf 的最大值条件是r =0
即:fisinfjcos=0 (6-3) 梯度是向量,各向同性。梯度方向对应于f(i,j)最大变化率方向上,即
tan1fj/fi
.
梯度最大值 G=f=rmaxfifj (6-4)
22为了减少计算量而用G=fifj (6-5)
梯度幅度比例于邻像素的灰度级,在灰度陡变区域,梯度值大,在灰度相似区,梯度值小,在灰度级为常数区,梯度为零。因此,微分运算应用在图像上,可使图像的轮廓清晰。
本节介绍的微分运算有: 纵向微分运算;
横向微分运算; 双方向一次微分运算。
6.2.1 纵向微分运算
1.理论基础
对灰度图像在纵方向进行微分实现了将图像向左平移一个像素,再用原图像减去平移后图像。相减的结果反映了原图像亮度变化率的大小。原图像中像素值保持不变的区域,相减的结果为零,即像素为黑;原图像中像素灰度值变化剧烈的区域,相减后得到较大的变化率,对应的像素很亮,而且像素灰度值差别越大,则得到的像素就越亮,所以图像的垂直边缘得到增强。
本程序对灰度图像f在纵方向或横方向进行微分,在数字处理中,微分用差分表近似,并按下式求得:
G ( i, j ) = f ( i , j )- f ( i-1, j-1 ) (6-6) 该算法用如下卷积核:
000 110 000 .
2.实现步骤
(1)取得原图的数据区指针。
(2)开辟一块内存缓冲区,并初始化为255。
(3)每个像素依次循环,新图像缓冲区中的当前像素的灰度值等于原图中当前像素的灰度值与其左方的像素的灰度值之差的绝对值。 (4)将缓冲区中的图像复制回原图数据区。 3.程序代码
/************************************************************** *函数名称:ZongXiang() *函数类型:void *功能:对图像进行纵向微分 **************************************************************/ void WeiFenDib::ZongXiang() {
LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight ();
LPBYTE temp=new BYTE [wide*height]; //开辟图像一缓冲区 memset(temp,255,wide*height); for(int j=1;j //当前像素的灰度值等于其和左方像素灰度值之差的绝对值 temp[wide*j+i]=abs(p_data[wide*j+i]-p_data[wide*j+(i-1)]); //将缓冲区中的图像复制回原图数据区 memcpy(p_data, temp,wide*height); //删除缓冲区 delete temp; } 4.效果对比图 (a)原图 (b)纵向微分运算 图6-2纵向微分运算 6.2.2 横向微分运算 1.理论基础 该算法的数学表达式为: G ( i, j ) = f ( i , j ) - f ( i , j-1 )+ (6-7) 该算法用如下卷积核: 010010 0002。实现步骤 . (1)取得原图的数据区指针。 (2)开辟一块内存缓冲区,并初始化为255。 (3)每个像素依次循环,新图像缓冲区中的当前像素的灰度值等于原图中当前像素的灰度值与其上方的像素的灰度值之差的绝对值。 (4)将缓冲区中的图像复制回原图数据区。 3.程序代码 /************************************************************** *函数名称:HengXiang() *函数类型:void *功能:对图像进行横向微分 **************************************************************/ void WeiFenDib::HengXiang() { LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE temp=new BYTE [wide*height]; //开辟图像一缓冲区 memset(temp,255,wide*height); for(int j=1;j . temp[wide*j+i]=abs(p_data[wide*j+i]-p_data[wide*(j-1)+i]); //将缓冲区中的图像复制回原图数据区 memcpy(p_data, temp,wide*height); //删除缓冲区 delete temp; } 4.效果对比图 图6-3 横向微分运算 6.2.3 双方向一次微分运算 1.理论基础 对灰度图像f在纵方向和横方向两个方向进行微分。该算法是同时增强水平和垂直方向的边缘。该算法的数学表达式为: G(i,j)=sqrt{[f(i,j)-f(i,j-1)]*[f(i,j)-f(i,j-1)]+[f(i,j)-f(i-1,j)]* [f(i,j)-f(i-1,j)]} (6-8) 对于含小数的G ( i , j )可四舍五入。 该算法用如下卷积核: . 010010 000000110 000 水平(i方向) 垂直(j方向) 使用水平方向卷积核得出像素值为m,使用垂直方向卷积核得出像素值为n,该像素边界强度为:sqrt[(m×m)+(n×n)]。该算法是同时增强水平和垂直方向的边缘。 2.实现步骤 (1)取得原图的数据区指针。 (2)开辟一块内存缓冲区,并初始化为255。 (3)每个像素依次循环,原图中当前像素的灰度值与其左方的像素的灰度值之差 的绝对值的平方,再加上当前像素的灰度值与其上方的像素的灰度值之差的绝对值的平方,所得的平方根即为新图像当前像素的灰度值。 (4)缓冲区中的图像复制回原图数据区。 3.程序代码 /************************************************************** *函数名称:ShuangXiang() *函数类型:void *功能:对图像进行双向一次微分 **************************************************************/ void WeiFenDib::ShuangXiang() { LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE temp=new BYTE [wide*height]; //开辟图像一缓冲区 . memset(temp,255,wide*height); for(int j=1;j temp[wide*j+i]=(int)sqrt((p_data[wide*j+i]-p_data[wide*j+(i-1)])*(p_data[wide*j+i] -p_data[wide*j+(i-1)])+(p_data[wide*j+i]-p_data[wide*(j-1)+i]) *(p_data[wide*j+i]-p_data[wide*(j-1)+i])); //将缓冲区中的图像复制回原图数据区 memcpy(p_data, temp,wide*height); //删除缓冲区 delete temp; } 4.处理结果 (a)原图 (b)纵向微分运算 (c) 横向微分运算 (d) 双方向一次微分运算 图6-4 微分运算 6.3梯度锐化 . 图像平滑往往使图像中的边界、轮廓变得模糊,为了减少这类不利效果的影响,这就需要利用图像鋭化技术,使边缘变得清晰。经过平滑的图像变得模糊的根本原因是图像受到了平均或积分运算,因此可以对其进行逆运算(如微分运算),就可以使图像变得清晰。 图像处理中最常用的微分方法是求梯度。对于图像f(i,j), 它在点(i,j)处的梯度是一个矢量,定义为: G[f(i,j)]的梯度为: G[f(i,j)]=[ ( f2 1/2f2 )+( )] (6-9) ji 对离散图像而言,可用差分法近似上述公式,得到: G[f(i,j)]={[ f(i,j) - f(i-1,j)]2+ [ f(i,j) - f(i,j-1)]2 }1/2 (6-10) 这正是双方向一次微分运算。为了便于编程和提高运算,在某些场合可进一步简化为: G[f(i,j)]=| f(i,j)- f(i-1,j)|+| f(i,j)- f(i,j-1)| (6-11) 利用差分运算时,图像的第一行和第一列的像素的梯度无法求得,一般用后一行或后一列的梯度值近似代替。微分运算可用来求信号的变化率,因而具有加强高频分量的作用,从上一节效果图上可知仅仅微分处理后的图像非常暗,不适用。如果将前面介绍的各种微分运算应用在图像上,既要求图像的轮廓清晰,又要求保持目标物体的内部灰度不变,这就是图像梯度锐化的目的。 梯度锐化常用的方法有: 直接以梯度值代替; 辅以门限判断; 给边缘规定一个特定的灰度级; 给背景规定灰度级; 根据梯度二值化图像. 6.3.1 直接以梯度值代替 利用双方向一次微分运算,算出梯度后让梯度值等于该点的灰度值。 . 即f(i,j)= G[f(i,j)]。 G[f(i,j)]={[ f(i,j) - f(i-1,j)]2+ [ f(i,j) - f(i,j-1)]2 }1/2 或G[f(i,j)]=| f(i,j)- f(i-1,j)|+| f(i,j)- f(i,j-1)| 这种方法直截了当。但在均匀的区域,因梯度值G[f(i,j)]很小,会表现出图像很暗的特性,这在某些场合是不适宜的。就像在前面看到的微分效果一样,除了黑色的背景,几乎看不出什么边界,所以在这里我们就不作介绍了。 6.3.2辅以门限判断 1理论基础 门限判断梯度锐化的公式如下: G[f(i,j)]={[ f(i,j) - f(i-1,j)]2+ [ f(i,j) - f(i,j-1)]2 }1/2 G[f(i,j)]+100; G[f(i,j)]≥T g(i,j)= f(i,j); 其它 (6-12) 该方法基本上不破坏图像的背景,又可增强边缘。这是因为G[f(i,j)]表示的是两个像素点之间灰度差的大小,也就是梯度的大小。对于图像而言,物体和物体之间,背景和背景之间的梯度变化一般很小,灰度变化较大的地方一般集中在图像的边缘上,也就是物体和背景交接的地方,当设定一个合适的阈值T,G[f(i,j)]大于T就认为该像素点处于图像的边缘,对结果加100,以使边缘变亮,而对于G[f(i,j)]不大于T就认为像素点是同类像素(同是物体或同是背景)。这样既增亮了物体的边界,同时又保留了图像背景原来的状态。 2. 实现步骤 (1)获得原图像的首地址,及图像的宽和高; . (2)开辟一块内存缓冲区,并初始化为255; (3)计算图像的像素的梯度,将结果保存在内存缓冲区; (4)比较像素的梯度是否大于30,是则将梯度值加100,不是则将该像素点的灰度值恢复,如果梯度加100大于255,将其置为255; (5)将内存中的数据复制到图像数据区。 3. 编程代码 /*************************************************************** *函数名称:Menxianruihua() *函数类型:void *功能:对图像进行门限梯度锐化 ***************************************************************/ void TiDuRuiHuaDib::Menxianruihua() { LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE p_temp=new BYTE [wide*height]; //开辟图像一缓冲区 memset(p_temp,255,wide*height); //初始化为255 int temp; for(int j=1;j { //根据双向一次微分公式计算当前像素的灰度值 temp=(int)sqrt((p_data[wide*j+i]-p_data[wide*j+(i-1)])*(p_data[wide*j +i] -p_data[wide*j+(i-1)])+(p_data[wide*j+i]-p_data[wide*(j-1)+i]) *(p_data[wide*j+i]-p_data[wide*(j-1)+i])); if (temp>=30) if((temp+100)>255) { p_temp[wide*j+i]=255; } if (temp<30) } //将缓冲区中的图像复制回原图数据区 memcpy(p_data,p_temp,wide*height); //删除缓冲区 delete p_temp; p_temp[wide*j+i]=p_data[wide*j+i]; else p_temp[wide*j+i]=temp+100; . } 4.处理效果图 (a) 原图 (b)辅以门限判断效果图 图6-5辅以门限判断效果图 6.3.3 给边缘规定一个特定的灰度级 1理论基础 G[f(i,j)]={[ f(i,j) - f(i-1,j)]2+ [ f(i,j) - f(i,j-1)]2 }1/2 La; G[f(i,j)]≥T g(i,j)= f(i,j); 其它 (6-13) La为一指定的灰度值。这种处理实际上是门限锐化的一种特殊形式,它将边界的灰度值统一化,这样可以使边界更加清晰明显。该方法基本上不破坏图像的背景,又可找到边缘,并根据需要增强边缘。 2实现步骤 (1)获得原图像的首地址,及图像的高和宽。 (2)开辟一块内存缓冲区,并初始化为255。 . (3)计算图像的像素的梯度,将结果保存在内存缓冲区。 (4)比较像素的梯度是否大于30,是则将灰度值置为255,否则恢复该像素原来的 灰度值。 (5)将内存中的数据复制到图像数据区。 3. 编程代码 /*************************************************************** *函数名称:GuDingRuiHua() *函数类型:void *功能:给边缘规定一个特定的灰度级。 ***************************************************************/ void TiDuRuiHuaDib::GuDingRuiHua() { LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE p_temp=new BYTE [wide*height]; //开辟图像一缓冲区 memset(p_temp,255,wide*height); //初始化为255 int temp; for(int j=1;j //根据双向一次微分公式计算当前像素的灰度值 temp=(int)sqrt((p_data[wide*j+i]-p_data[wide*j+(i-1)])*(p_data[wide*j+i] -p_data[wide*j+(i-1)])+(p_data[wide*j+i]-p_data[wide*(j-1)+i]) *(p_data[wide*j+i]-p_data[wide*(j-1)+i])); if (temp>30) { p_temp[wide*j+i]=255; } //将缓冲区中的图像复制回原图数据区 } 4.效果对比图 memcpy(p_data,p_temp,wide*height); //删除缓冲区 delete p_temp; } else p_temp[wide*j+i]=p_data[wide*j+i]; . (a)原图 (b)给边缘规定一个特定的灰度级 图6-6给边缘规定一个特定的灰度级 6.3.4给背景规定灰度级 G[f(i,j)]; G[f(i,j)]≥T g(i,j)= Lb; 其它 (6-14) Lb为一对背景指定的灰度值。这种处理的原理和上一节介绍的给边缘规定一个特定的灰度级的原理是一样的,只不过这种处理将图像的背景灰度值统一化了,因此在这里不重复介绍了。 6.3.5 根据梯度二值化图像 1理论基础 对阶跃边缘,在边缘点其一阶导数取极值。由此,我们对数字图像f(i,j)的每个像素取它的梯度值G(i,j),适当取门限T作如下判断:若G(i,j)>T则(i,j)点为阶跃状边缘点,G(i,j)称为梯度算子的边缘图像。 La; G[f(i,j)]≥T g(i,j)= . Lb; 其它 (6-15) La 和 Lb 的意义同上。 梯度是向量,各向同性。梯度方向对应于F(i,j)最大变化率方向上,即 Q=arctan[ f(i,j)f(i,j) /] (6-16) ji梯度幅度比例于邻像素的灰度级,在灰度陡变区域,梯度值大,在灰度相似区,梯度值小,在灰度级为常数区,梯度为零。这样处理可以使图像锐化的结果更加清晰,把图像中我们关心的部分突出出来,去除了我们不感兴趣的部分。 2实现步骤 (1)获得原图像的首地址,及图像的高和宽; (2)开辟一块内存缓冲区,并初始化为255; (3)计算图像的像素的梯度; (4)将结果保存在内存缓冲区比较像素的梯度是否大于30,是则将灰度值置为255,否则将该像素的灰度值置位0; (5)将内存中的数据复制到原图像的数据区。 3. 编程代码 /*************************************************************** *函数名称:Erzhirihua() *函数类型:void *功能: 根据梯度二值化图像。 ***************************************************************/ void TiDuRuiHuaDib::Erzhirihua() . { LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE p_temp=new BYTE [wide*height]; //开辟图像一缓冲区 memset(p_temp,255,wide*height); //初始化为255 int temp; for(int j=1;j //根据双向一次微分公式计算当前像素的灰度值 temp=(int)sqrt((p_data[wide*j+i]-p_data[wide*j+(i-1)]) *(p_data[wide*j+i]-p_data[wide*j+(i-1)])+(p_data[wide*j+i] -p_data[wide*(j-1)+i])*(p_data[wide*j+i]-p_data[wide*(j-1)+i])); if (temp>30) { p_temp[wide*j+i]=255; } else } p_temp[wide*j+i]=0; . } //将缓冲区中的图像复制回原图数据区 memcpy(p_data,p_temp,wide*height); //删除缓冲区 delete p_temp; 4.处理效果图 (a) 原图 (b)根据梯度二值化效果图 图6-7根据梯度二值化 6.4边缘检测 图像边缘对图像识别和计算机分析十分有用。边缘能勾划出目标物体,使观察者一目了然;边缘蕴含了丰富的内在信息(如方向,阶跃性质、形状等),是图像识别中抽取图像特征的重要属性。从本质上说,图像边缘是图像局部特性不连续性(灰度突变、颜色突变等)的反映,它标志着一个区域的终结和另一个区域的开始。 边缘提取首先检出图像局部特性的不连续性,然后在将这些不连续的边缘像素连成完备的边界。边缘的特性是沿边缘走向的像素变化平缓,而垂直与边缘方向的像素变化剧烈。所以,从这个意义上说,提取边缘的算法就是检出符合边缘特性的边缘像素的数学算子。 边缘检测算子检查每个像素的邻域并对灰度变化率进行量化,通常也包括方向的确定。有若干种方法可以使用,其中大多数是基于方向导数模板求卷积的方法。边缘模板用于沿着 . 不同的方向检测边缘的四个模板。如下给出了大小为3×3的边缘模板,它们能够在0º、45º、90º 和135º四个方向上检测边缘,将所有的边缘模板逐一作用于图像中的每一个像素,产生最大输出值的边缘模板为候选模板,其方向表示了该点处边缘的方向,如果所有方向上的边缘模板接近于零,则在该像素点处没有边缘;如果所有方向上的边缘模板输出值都近似相等,则该像素点处没有可靠的边缘方向。 -101101 1011110 00111111100101 101 110011 (a)0º模板 (b)90º模板 (c)45º模板 (d)135º模板 对于灰度图像f,对以像素f(i,j)为中心的3×3区域施加不同的3×3加权屏蔽窗口,每个3×3窗口称为算子,是一个3×3的整数矩阵,处理时用卷积的方法,即将算子覆盖的区域按相应位置的像素值乘以算子中相应的系数再相加,其结果即为此窗口的相关值,求最大值作为中心点像素的灰度值。 由于我们常常无法事先确定轮廓的取向,因而挑选用于轮廓增强的微分算子时,必须选择那些不具备空间方向性的和具有旋转不变的线形微分算子。最基本的一类边缘检测算子是微分算子类。包括:梯度算子,Robert梯度算子、Sobel算子、Prewitt边缘检测算子、 Krisch边缘检测算子、Laplacian算子等。除了Laplacian算子,其他的算子基于的是一阶方向导数在边缘处取最大值这一变化规律。Robert采用的是对角方向相邻的两个像素之差。从图像处理的实际效果来看,用Robert梯度检测边缘较好。Sobel算子有一定噪声抑制能力,在检测阶跃边缘时得到的边缘宽度至少为二像素,它不依赖于边缘方向的二阶微分算子,是一个标量而不是向量,具有旋转不变即各向同性的性质,在图像处理中经常被用来提取图像的边缘。Laplacian算子基于的是二阶导数的零交叉。微分算子类边缘检测方法的 . 效果类似于空间域的高通滤波,有增强高频分量的作用。因而,这类算子对噪声是敏感的。对于有噪声的图像,LoG算子对图像先进行高斯滤波,然后应用Laplacian算子来提高边缘提取的能力。当然也可以不先滤除噪声,而是对处理的结果进行统计检测来获得边缘。 本节介绍的算子有: Roberts边缘检测算子; Sobel边缘检测算子; Prewitt边缘检测算子; Krisch边缘检测; LoG_Laplacian高斯-拉普拉斯算子。 6.4.1 Roberts边缘检测算子 1 理论基础 Roberts边缘算子采用的是对角方向相邻的两个像素之差。从图像处理的实际效果来看,边缘定位准,对噪声敏感。Roberts边缘检测算子是一种利用局部差分算子寻找边缘的算子,它由下式给出: Roberts算子:G[i,j]=|f[i,j]-f[i+1,j+1]|+|f[i+1,j]-f[i,j+1]|; (6-17) G[i,j]=[(f[i,j]-f[i+1,j+1]) 2+(f[i+1,j]-f[i,j+1]) 2] 1/2; (6-18) 其中G[i,j]表示处理后(i,j)点的灰度值,f[i,j]表示处理前该点的灰度值。 其中f(i,j)是具有整数像素坐标的输入图像,平方根运算使该处理类似于在人类视觉系统中发生的过程。 该算法的算子如下: 0110 1001 . 2 实现步骤 (1)取得原图的数据区指针。 (2)开辟一个和原图相同大小的图像缓冲区,并设定新图像初值为全白(255)。 (3)每个像素依次循环,用Roberts边缘检测算子分别计算图像中各点灰度值,对它们平方之和,再开方。 (4)将缓冲区中的数据复制到原图数据区。 3 编程实现 /*************************************************************** *函数名称:Robert() *函数类型:void *功能:用罗伯特算子对图像进行边缘检测。 ***************************************************************/ void BianYuanJianCeDib::Robert() { LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 int i,j; //循环变量 int pixel[4]; //Robert算子 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE temp=new BYTE[wide*height]; //新图像缓冲区 . //设定新图像初值为255 memset(temp,255, wide*height); //由于使用2*2的模板,为防止越界,所以不处理最下边和最右边的两列像素 for(j=0;j pixel[0]=p_data[j*wide+i]; pixel[1]=p_data[j*wide+i+1]; pixel[2]=p_data[(j+1)*wide+i]; pixel[3]=p_data[(j+1)*wide+i+1]; //处理当前像素 temp[j*wide+i]=(int)sqrt((pixel[0]-pixel[3])*(pixel[0]-pixel[3]) +(pixel[1]-pixel[2])*(pixel[1]-pixel[2])); } //将缓冲区中的数据复制到原图数据区 memcpy(p_data, temp,wide*height); //删除缓冲区 delete temp; } 4.效果对比图 . 图6-8 Roberts边缘检测效果图 6.4.2 Sobel边缘检测算子 1理论基础 (1)卷积 卷积可以简单的看成加权求和的过程。卷积时使用的权用一个很小的矩阵来表示,矩阵的大小是奇数,而且与使用的区域的大小相同。这种权矩阵叫做卷积核,区域中的每个像素分别与卷积核中的每个元素相乘,所有乘积之和即区域中心像素的新值。比如,对于一个3×3的区域P与卷积核K卷积后,区域P的中心像素p5表示如下: p5=p1*k1+ p2*k2+ …p8*k8+ p9*k9 其中 p1 p2 p3 k1 k2 k3 p= p4 p5 p6 k = k4 k5 k6 p7 p8 p9 k7 k8 k9 . 卷积核中各元素叫卷积系数。卷积核中卷积系数的大小、方向及排列次序决定了卷积的图像处理效果。大多数常用的卷积核都是3×3的,所有卷积核的行、列都是奇数。进行卷积时会遇到一些较复杂的问题,首先是图像边界的问题。当在图像上逐个移动卷积核时,只要卷积核移到了图像边界,即卷积核悬挂在图像边界上时,就会出现计算上的问题。这时在原图像上就不能完整找到与卷积核中卷积系数相对应的九个(对3×3卷积核)图像像素。解决这一问题的两个简单方法是:或者忽略图像边界数据,或者在图像的四周复制图像的边界数据。 (2)Sobel边缘检测算子 Sobel边缘检测算子是先做成加权平均,再微分,然后求梯度。以下两个卷积核形成了Sobel边缘检测算子,图中的每个点都用这两个核做卷积,其中一个对垂直边缘影响最大,而另一个对水平边缘影响最大。边缘检测算子的中心与中心像素相对应,进行卷积运算。两个卷积核的最大值作为该点的输出位。运算结果是一幅边缘幅度图像。在边沿检测中,sobel算子对于像素的位置的影响做了加权,加权平均边宽 2像素,因此效果更好。 . 1210 00211101202 101水平边缘Sobel算子 垂直边缘Sobel算子 即: f(i-1,j-1) f(i,j-1) f(i+1,j-1) f(i-1,j) f(i,j) f(i+1,j) f(i-1,j+1) f(i,j+1) f(i+1,j+1) △G i= f(i-1,j+1) + 2f(i,j+1) + f(i+1,j+1)- f(i-1,j-1) - 2f(i,j-1) - f(i+1,j-1); △G j= f(i-1,j-1) + 2f(i-1,j) + f(i-1,j+1)- f(i+1,j-1) - 2f(i+1,j) - f(i+1,j+1); G[f(i,j)]=| △G i |+|△G j |; 有时为了检测特定方向上的边缘,也采用特殊的方向算子,如检测450或1350边缘的Sobel方向算子 012101 021021101 012检测450 Sobel方向算子 检测1350 Sobel方向算子 2 实现步骤 (1)取得原图的数据区指针。 . (2)开辟两个和原图相同大小的图像缓冲区,将原图复制到两个缓冲区。 (3)分别设置Sobel算子的两个模板,调用Templat()模板函数分别对两个缓冲区中的图像进行卷积计算。 (4)两个缓存图像每个像素依次循环,取两个缓存中各个像素灰度值较大者。 (5)将缓冲区中的图像复制到原图数据区。 2 编程实现 (1)卷积 /************************************************************** *函数名称:Templat(BYTE *m_pdata, int wide, int height, int tempH, int tempW, int tempMX, int tempMY, float *fpArray, float fCoef) *函数类型:void *参数:BYTE* m_pdata:指向原DIB图像指针 * int wide:原图像宽度 * int height:原图像高度 * int tempH:模板高度 * int tempW:模板宽度 * int tempMX:模板的中心元素X坐标( void BianYuanJianCeDib::Templat(BYTE *m_pdata, int wide, int height, int tempH, int tempW, int tempMX, int tempMY, float *fpArray, float fCoef) { int i,j,k,l; //循环变量 BYTE* temp=new BYTE[wide*height]; //新图像缓冲区 //初始化新图像为原始图像 memcpy( temp,m_pdata,wide*height); float fResult; //像素值计算结果 fResult=fResult+m_pdata[(j-tempMY+k)*wide+(i-tempMX+l)]*fpArray[k*tempfor(j=tempMY;j for(k=0;k //乘上系数 fResult*=fCoef; //取绝对值 fResult=(float)fabs(fResult); //判断是否超过255 . if(fResult>255) //若超过255,直接赋值为255 temp[j*wide+i]=255; } else //未超过255,赋值为计算结果 temp[j*wide+i]=(int)(fResult+0.5); memcpy(m_pdata, temp,wide*height); //复制处理后的图像 } (2)Sobel水平与垂直边缘检测边缘检测 /*************************************************************** *函数名称:Sobel() *函数类型:void *功能:用索伯尔算子对图像进行水平与垂直边缘检测。 **************************************************************/ void BianYuanJianCeDib::Sobel() { LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 int i,j; //循环变量 int tempH; //模板高度 delete temp; int tempW; //模板宽度 float tempC; //模板系数 int tempMY; //模板中心元素Y坐标 int tempMX; //模板中心元素X坐标 float Template[9]; //模板数组 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE temp1=new BYTE[wide*height]; LPBYTE temp2=new BYTE[wide*height]; //拷贝原图像到缓存图像 memcpy( temp1,p_data,wide*height); memcpy( temp2,p_data,wide*height); //设置Sobel模板参数 tempW=3; tempH=3; tempC=1.0; tempMY=1; tempMX=1; Template[0]=-1.0; Template[1]=-2.0; Template[2]=-1.0; Template[3]=0.0; . //新图像缓冲区 //新图像缓冲区 . ; Template[4]=0.0; Template[5]=0.0; Template[6]=1.0; Template[7]=2.0; Template[8]=1.0; //调用Templat()函数 Templat( temp1,wide,height,tempH,tempW,tempMX,tempMY,Template,tempC) //设置Sobel模板参数 Template[0]=-1.0; Template[1]=0.0; ; //求两幅缓存图像的最大值 for(j=0;j . for(i=0;i temp1[j*wide+i]= temp2[j*wide+i]; //将缓存中的图像复制到原图数据区 } 4 处理效果 图6-9 Sobel边缘检测 memcpy(p_data, temp1,wide*height); //删除缓冲区 delete temp1; delete temp2; 6.4.3 Prewitt边缘检测算子 1 理论基础 以下两个卷积核形成了Prewitt边缘检测算子。同使用Sobel算子的方法一样,图像中的每个点都用这两个核进行卷积,取最大值作为输出。Prewitt边缘检测算子也产生一幅边 . 缘强度图像。Prewitt边缘检测算子为: -111 00 0111 2 实现步骤 (1)取得原图的数据区指针。 101101 101(2)开辟两个和原图相同大小的图像缓冲区,将原图复制到两个缓冲区。 (3)分别设置Prewitt算子的两个模板,调用Templat()模板函数分别对两个缓冲区中的图像进行卷积计算。 (4)两个缓存图像每个像素依次循环,取两个缓存中各个像素灰度值较大者。 (5)将缓冲区中的图像复制到原图数据区。 3 程序代码 /*************************************************************** *函数名称:PreWitt() *函数类型:void *功能:用普瑞维特算子对图像进行边缘检测。 **************************************************************/ void BianYuanJianCeDib::PreWitt() { LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 int i,j; //循环变量 int tempH; //模板高度 int tempW; //模板宽度 float tempC; //模板系数 int tempMY; //模板中心元素Y坐标 int tempMX; //模板中心元素X坐标 float Template[9]; //模板数组 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE temp1=new BYTE[wide*height]; LPBYTE temp2=new BYTE[wide*height]; //拷贝原图像到缓存图像 memcpy( temp1,p_data,wide*height); memcpy( temp2,p_data,wide*height); //设置Prewitt模板1参数 tempW=3; tempH=3; tempC=1.0; tempMY=1; tempMX=1; Template[0]=-1.0; Template[1]=-1.0; Template[2]=-1.0; Template[3]=0.0; . //新图像缓冲区 //新图像缓冲区 . Template[4]=0.0; Template[5]=0.0; Template[6]=1.0; Template[7]=1.0; Template[8]=1.0; //调用Templat()函数 Templat( temp1,wide,height,tempH,tempW,tempMX,tempMY,Template,tempC ); //设置Prewitt模板2参数 Template[0]=1.0; Template[1]=0.0; Template[2]=-1.0; Template[3]=1.0; Template[4]=0.0; Template[5]=-1.0; Template[6]=1.0; Template[7]=0.0; Template[8]=-1.0; //调用Templat()函数 Templat( temp2,wide,height,tempH,tempW,tempMX,tempMY,Template,tempC); //求两幅缓存图像的最大值 for(j=0;j for(i=0;i temp1[j*wide+i]= temp2[j*wide+i]; memcpy(p_data, temp1,wide*height); //复制处理后的图像 delete temp1; delete temp2; } 4 处理效果 图6-10 Prewitt边缘检测 6.4.4 Krisch边缘检测 1 理论基础 以下8个卷积核组成了Kirsch边缘检测算子。图像中的每个点都用8个掩模进行卷积,每个掩模都对某个特定边缘方向作出最大响应,所有8个方向中的最大值作为边缘幅度图像输出。最大响应掩模的序号构成了边缘方向的编码。Kirsch边缘检测算子为: . 55-3555303 30 5333333-333-333303 5 03555355 2 实现步骤 1) 取得原图的数据区指针。 -335-333305 30 5533535535335503 5 035333332) 开辟两个和原图相同大小的图像缓冲区,将原图复制到两个缓冲区。 3) 分别设置Kirsch算子的模板1和模板2,调用Templat()模板函数分别对两个缓 冲区中的图像进行卷积计算。求出两幅缓存图像中每个像素的较大灰度值存放在缓存图像1中,并将缓存图像1拷贝到缓存图像2中。 4) 同第三步,以此类推,分别设置Kirsch算子的模板3、模板4、模板5、模板6、 模板7和模板8,每次计算后,求出两幅缓存图像中灰度值较大者存放在缓存图像1中。 5) 最后将得到的结果缓存图像1复制到原图。 3 编程实现 /*************************************************************** *函数名称:Krisch() *函数类型:void *功能:用克瑞斯算子对图像边缘检测。 **************************************************************/ void BianYuanJianCeDib::Krisch() LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 int i,j; //循环变量 int tempH; //模板高度 int tempW; //模板宽度 float tempC; //模板系数 int tempMY; //模板中心元素Y坐标 int tempMX; //模板中心元素X坐标 float Template[9]; //模板数组 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE temp1=new BYTE[wide*height]; LPBYTE temp2=new BYTE[wide*height]; //拷贝原图像到缓存图像 memcpy( temp1,p_data,wide*height); memcpy( temp2,p_data,wide*height); //设置Kirsch模板1参数 tempW=3; tempH=3; tempC=0.5; tempMY=1; . //新图像缓冲区 //新图像缓冲区 { . tempMX=1; Template[0]=5.0; Template[1]=5.0; Template[2]=5.0; Template[3]=-3.0; Template[4]=0.0; Template[5]=-3.0; Template[6]=-3.0; Template[7]=-3.0; Template[8]=-3.0; //调用Templat()函数 Templat( temp1,wide,height,tempH,tempW,tempMX,tempMY,Template,tempC); //设置Kirsch模板2参数 Template[0]=-3.0; Template[1]=5.0; Template[2]=5.0; Template[3]=-3.0; Template[4]=0.0; Template[5]=5.0; Template[6]=-3.0; Template[7]=-3.0; Template[8]=-3.0; . //调用Templat()函数 Templat(temp2,wide,height,tempH,tempW,tempMX,tempMY,Template,tempC); //求两幅缓存图像的最大值 for(j=0;j temp1[j*wide+i]= temp2[j*wide+i]; //拷贝原图像到缓存图像2中 memcpy( temp2,p_data,wide*height); //设置Kirsch模板3参数 Template[0]=-3.0; Template[1]=-3.0; Template[2]=5.0; Template[3]=-3.0; Template[4]=0.0; Template[5]=5.0; Template[6]=-3.0; Template[7]=-3.0; Template[8]=5.0; //调用Templat()函数 Templat( temp2,wide,height,tempH,tempW,tempMX,tempMY,Template,te mpC); //求两幅缓存图像的最大值 . for(j=0;j temp1[j*wide+i]= temp2[j*wide+i]; //拷贝原图像到缓存图像2中 memcpy( temp2,p_data,wide*height); //设置Kirsch模板4参数 Template[0]=-3.0; Template[1]=-3.0; mpC); //求两幅缓存图像的最大值 for(j=0;j Templat( temp2,wide,height,tempH,tempW,tempMX,tempMY,Template,te . temp1[j*wide+i]= temp2[j*wide+i]; //拷贝原图像到缓存图像2中 memcpy( temp2,p_data,wide*height); //设置Kirsch模板5参数 Template[0]=-3.0; Template[1]=-3.0; Template[2]=-3.0; Template[3]=-3.0; Template[4]=0.0; Template[5]=-3.0; Template[6]=5.0; Template[7]=5.0; Template[8]=5.0; //调用Templat()函数 pC); //拷贝原图像到缓存图像2中 Templat( temp2,wide,height,tempH,tempW,tempMX,tempMY,Template,tem memcpy( temp2,p_data,wide*height); //求两幅缓存图像的最大值 for(j=0;j . temp1[j*wide+i]= temp2[j*wide+i]; //拷贝原图像到缓存图像2中 memcpy( temp2,p_data,wide*height); //设置Kirsch模板6参数 Template[0]=-3.0; Template[1]=-3.0; Template[2]=-3.0; Template[3]=5.0; Template[4]=0.0; Template[5]=-3.0; Template[6]=5.0; Template[7]=5.0; Template[8]=-3.0; //调用Templat()函数 Templat( temp2,wide,height,tempH,tempW,tempMX,tempMY,Template,te mpC); //求两幅缓存图像的最大值 for(j=0;j temp1[j*wide+i]= temp2[j*wide+i]; //拷贝原图像到缓存图像2中 memcpy( temp2,p_data,wide*height); . //设置Kirsch模板7参数 Template[0]=5.0; Template[1]=-3.0; Templat( temp2,wide,height,tempH,tempW,tempMX,tempMY,Template,tempC); //求两幅缓存图像的最大值 for(j=0;j temp1[j*wide+i]= temp2[j*wide+i]; Template[2]=-3.0; Template[3]=5.0; Template[4]=0.0; Template[5]=-3.0; Template[6]=5.0; Template[7]=-3.0; Template[8]=-3.0; //调用Templat()函数 //拷贝原图像到缓存图像2中 memcpy( temp2,p_data,wide*height); //设置Kirsch模板8参数 Template[0]=5.0; Template[1]=5.0; . Template[2]=-3.0; Template[3]=5.0; Template[4]=0.0; Template[5]=-3.0; Template[6]=-3.0; Template[7]=-3.0; Template[8]=-3.0; //调用Templat()函数 Templat( temp2,wide,height,tempH,tempW,tempMX,tempMY,Template,tempC); //求两幅缓存图像的最大值 for(j=0;j temp1[j*wide+i]= temp2[j*wide+i]; memcpy(p_data, temp1,wide*height); //复制处理后的图像 delete temp1; delete temp2; } 4 处理效果 . 图6-11 Krisch边缘检测 6.5 高斯-拉普拉斯算子 1 理论基础 因为图像边缘有大的灰度变化,所以图像的一阶偏导数在边缘处有局部最大值或最小值,则二阶偏导数在边缘处会通过零点(由正到负或由负到正)。 考虑坐标旋转变换,设旋转前坐标为(x,y),旋转后为(x,y),则有: x=xcos-ysin y=xsin-ycos ,,,,,,ffxfyffcossin (6-19) ,,,xyxyxxxffxfyffsincos (6-20) ,,,xyyyxyy容易看出,虽然 2ff,不是各向同性的,但是它们的平方和是各向同性的。 xy222ffff即, (6-21) ,xyxy2f2f定义Laplacian算子为f=2 2xy2 . 拉普拉斯算子是各向同性(isotropic)的微分算子。 2f(i,j)f(i,j)14[f(i,j1)f(i,j1)f(i1,j)f(i1,j)](6-22) 因此,Laplacian算子是线性二次微分算子,与梯度算子一样,具有旋转不变性,从而满足不同走向的图像边界的锐化要求。 对阶跃状边缘,二阶导数在边缘点出现零交叉,即边缘点两旁二阶导函数取异号,据此,对数字图像{f(i,j)}的每个像素,Laplacian算子取它关于x轴方向和y轴方向的二阶差分之和。 G(i,j)=2f(i,j) (6-23) 这是一个与边缘方向无关的边缘检测算子。若2f(i,j)在(i,j)点发生零交叉,则(i,j)为阶跃边缘点。 对屋顶状边缘,在边缘点的二阶导数取极小值。据此,对数字图像{f(i,j)}的每个像素取它的关于x方向和y方向的二阶差分之和的相反数,即Laplacian算子的相反数: G(i,j)= -2f(i,j) - f(i+1,j) - f(i-1,j) - f(i,j+1) -f(i,j-1)+ 4f(i,j),G(i,j)称作边缘图像。 由于我们关心的是边缘点位置而不是其周围的实际灰度差,因此,一般都选择与方向无关的边缘检测算子。用拉普拉斯算子检测边缘就是估算拉普拉斯算子的输出,找出它的零点位置。 离散情况下,有几种不同的模板计算形式: 2 xf(i,j)+ y2f(i,j)= f(i+1,j)+ f(i-1,j)+ f(i,j+1)+ f(i,j-1)-4f(i,j) 010111121或181或242 (6-24) 2141010111121 拉普拉斯算子 由于拉普拉斯算子是一个二阶导数,它将在边缘处产生一个陡峭的零交叉。由于噪声点对边沿检测有一定影响,所以高斯拉普拉斯算子是效果较好的边沿检测器。他把高斯平滑 . 滤波器和拉普拉斯锐化滤波器结合了起来,先平滑掉噪声,再进行边沿检测,所以效果更好。通常的高斯拉普拉斯算子是一个5×5的模板: 244440804824880402444244 42高斯-拉普拉斯算子 2 实现步骤 1) 取得原图的数据区指针。 2) 开辟一个和原图相同大小的图像缓冲区,将原图复制到缓冲区。 3) 设置Iirsch模板1参数,调用Templat()函数对缓存图像进行卷积计算。 4) 将计算结果复制回原图。 3 编程实现 /*************************************************************** *函数名称:Guasslaplacian() *函数类型:void *功能:用高斯拉普拉斯算子对图像边缘检测。 ***************************************************************/ void BianYuanJianCeDib::Guasslaplacian() { LPBYTE p_data; //原图数据区指针 int wide,height; //原图长、宽 int tempH; //模板高度 int tempW; //模板宽度 float tempC; //模板系数 int tempMY; //模板中心元素Y坐标 int tempMX; //模板中心元素X坐标 float Template[25]; //模板数组 p_data=this->GetData (); wide=this->GetWidth (); height=this->GetHeight (); LPBYTE temp1=new BYTE[wide*height]; LPBYTE temp2=new BYTE[wide*height]; //拷贝原图像到缓存图像 memcpy( temp1,p_data,wide*height); memcpy( temp2,p_data,wide*height); //设置Guasslaplacian模板参数 tempW=5; tempH=5; tempC=0.25; tempMY=4; tempMX=4; Template[0]=-2.0; Template[1]=-4.0; Template[2]=-4.0; . //新图像缓冲区 //新图像缓冲区 . Template[3]=-4.0; Template[4]=-2.0; Template[5]=-4.0; Template[6]=0.0; Template[7]=8.0; Template[8]=0.0; Template[9]=-4.0; Template[10]=-4.0; Template[11]=8.0; Template[12]=24.0; Template[13]=8.0; Template[14]=-4.0; Template[15]=-4.0; Template[16]=0.0; Template[17]=8.0; Template[18]=0.0; Template[19]=-4.0; Template[20]=-2.0; Template[21]=-4.0; Template[22]=-4.0; Template[23]=-4.0; Template[24]=-2.0; . //调用Templat()函数 Templat( temp1,wide,height,tempH,tempW,tempMX,tempMY,Template,tempC); memcpy(p_data, temp1,wide*height); //复制处理后的图像 delete temp1; //释放内存 delete temp2; } 4 处理效果 图6-12 高斯拉普拉斯算子边缘检测 小结 图像边缘信息在图像分析和人的视觉中都是十分重要的,是图像识别中提取图像特征的一个重要特性。微分运算是图像边缘锐化的基本方法。本章介绍了纵向微分运算、横向微分运算及双方向一次微分运算。利用计算机进行图像锐化处理有两个目的,一是增强图像边缘,图像的质量有所改善,本章的梯度锐化就是介绍这方面的内容,包括直接以梯度值代替、辅以门限判断、给边缘规定一个特定的灰度级、给背景规定灰度级、根据梯度二值化图像。二是希望经过锐化处理后,目标物体的边缘鲜明,以便于计算机提取目标物体的边界,为图像理解和分析打下基础。本章的边缘检测算子就是介绍这方面的内容,包括Roberts边缘 . 检测算子、Sobel边缘检测算子、Prewitt边缘检测算子、Krisch边缘检测、LoG_Laplacian高斯-拉普拉斯算子。 习题 1.分析比较基于空域的平滑处理与锐化处理在原理、处理方式及处理效果上的异同点。 2.对于如下图像,应用何种方法,能够检测出物体的边缘。写出检测公式。 0 0 1 255 255 255 255 1 1 1 254 253 254 254 0 0 0 255 255 253 253 1 1 0 254 254 254 254 3.写出双方向一次微分运算的数学表达式。 4.简述梯度锐化的目的,比较用纵向微分运算、横向微分运算、双方向一次微分运算作为梯度,哪一种效果更好。 5。最基本的一类边缘检测算子是微分算子类。包括哪些? 6.简述Sobel边缘检测算子的实现方法。 . 因篇幅问题不能全部显示,请点此查看更多更全内容