边缘提取是图像处理中的一种重要的手段,目前在大型的图像处理软件中得到了广泛的应用。边缘提取能够勾画出目标物体的轮廓,对于图像的特征提取,以及图像增强有着重要的意义。这次大作业通过应用几种重要的边缘提取算子来观察边缘提取的效果,进而比较各种算子的适用范围,优势以及局限性,进一步加深对于边缘提取技术的理解。
同之前两次作业相同,此次开发语言仍使用C#
。
边缘提取技术报告概述目录一、边缘提取原理二、常用的边缘提取算子1. Roberts算子1. 数学原理2. C#实现3. 效果展示2. Sobel算子1. 数学原理2. C#实现3. 效果展示3. Prewitt算子1. 数学原理2. C#实现3. 效果展示4. Laplacian算子(拉普拉斯)1. 数学原理2. C#实现3. 效果展示5. Gauss-Laplacian算子(高斯-拉普拉斯)1. 数学原理2. C#实现3. 效果展示6. Krisch算子1. 数学原理2. C#实现3. 效果展示三、常用的边缘提取算子比较参考资料
图像中的边缘是图像局部特性不连续的结果,可能是灰度值的突变,颜色的突变,纹理的突变等导致。其中边缘像素灰度变化示意图如下:
根据微分原理我们可以得到:对于每行像素灰度变化不大的区域,其一阶导数趋于0,而图像的边缘由于相邻像素的灰度变化剧烈,所以一阶导数较大。因而可以使用一阶导数的大小可以判断图像是否有边缘以及边缘所在的位置。
对于二阶导数,其符号可以判断一个边缘的像素是在亮的一侧还是在暗的一侧,并且通过零点的位置就是边缘的位置。
梯度对应着一阶导数,对于一个连续的函数f(x,y)
,它在点f(x,y)
处的梯度是一个矢量,定义为:
其中, 和分别为沿方向和方向的梯度,梯度的幅度和方向角分别为:
由上式可知,梯度的数值就是在其最大变化率方向上的单位距离所增加的量,对于数字图像而言,梯度是由差分代替微分来实现的其中式(1.2)可以写为:
公式(1.4)中的偏导数需要对每个像素的位置进行运算,在实际中常用小区域模板进行卷积来近似计算,对和需各使用一个模板,所以需要两个模板组合起来构成一个梯度算子。
令为输入图像,为输出图像,则Roberts边缘梯度可以由下式求出
写成模板形式如下:
AخAprivate int Roberts(byte[] rgbValues, BitmapData bmpData,int i,int j,int rgb)
{
float f1 = rgbValues[i * bmpData.Stride + (j + 3) + rgb] - rgbValues[(i + 1) * bmpData.Stride + j + rgb];
float f2 = rgbValues[i * bmpData.Stride + j + rgb] - rgbValues[(i + 1) * bmpData.Stride + (j + 3) + rgb];
int t = (int)(Math.Sqrt(f1 * f1 + f2 * f2) + 0.5);
if (t > 255)
t = 255;
return t;
}
Sobel算子模板如下:
xxxxxxxxxx
public int Sobel(byte[] rgbValues, BitmapData bmpData, int i, int j, int rgb)
{
float f1 = rgbValues[(i - 1) * bmpData.Stride + (j + 3) + rgb]
+ 2 * rgbValues[i * bmpData.Stride + (j + 3) + rgb]
+ rgbValues[(i + 1) * bmpData.Stride + (j + 3) + rgb]
- rgbValues[(i - 1) * bmpData.Stride + (j - 3) + rgb]
- 2 * rgbValues[i * bmpData.Stride + (j - 3) + rgb]
- rgbValues[(i + 1) * bmpData.Stride + (j - 3) + rgb];
float f2 = rgbValues[(i - 1) * bmpData.Stride + (j - 3) + rgb]
+ 2 * rgbValues[(i - 1) * bmpData.Stride + j + rgb]
+ rgbValues[(i - 1) * bmpData.Stride + (j + 3) + rgb]
- rgbValues[(i + 1) * bmpData.Stride + (j - 3) + rgb]
- 2 * rgbValues[(i + 1) * bmpData.Stride + j + rgb]
- rgbValues[(i + 1) * bmpData.Stride + (j + 3) + rgb];
int t = (int)(Math.Sqrt(f1 * f1 + f2 * f2) + 0.5);
if (t > 255)
t = 255;
return t;
}
Prewitt算子模板如下:
xxxxxxxxxx
public int Prewitt(byte[] rgbValues, BitmapData bmpData, int i, int j, int rgb)
{
float f1 = rgbValues[(i - 1) * bmpData.Stride + (j + 3) + rgb]
+ rgbValues[i * bmpData.Stride + (j + 3) + rgb]
+ rgbValues[(i + 1) * bmpData.Stride + (j + 3) + rgb]
- rgbValues[(i - 1) * bmpData.Stride + (j - 3) + rgb]
- rgbValues[i * bmpData.Stride + (j - 3) + rgb]
- rgbValues[(i + 1) * bmpData.Stride + (j - 3) + rgb];
float f2 = rgbValues[(i - 1) * bmpData.Stride + (j - 3) + rgb]
+ rgbValues[(i - 1) * bmpData.Stride + j + rgb]
+ rgbValues[(i - 1) * bmpData.Stride + (j + 3) + rgb]
- rgbValues[(i + 1) * bmpData.Stride + (j - 3) + rgb]
- rgbValues[(i + 1) * bmpData.Stride + j + rgb]
- rgbValues[(i + 1) * bmpData.Stride + (j + 3) + rgb];
int t = (int)(Math.Sqrt(f1 * f1 + f2 * f2) + 0.5);
if (t > 255)
t = 255;
return t;
}
Laplacian两个算子模板如下:
xxxxxxxxxx
public int Laplacian(byte[] rgbValues, BitmapData bmpData, int i, int j, int rgb)
{
/*float f1 = rgbValues[(i - 1) * bmpData.Stride + j + rgb]
+ rgbValues[(i + 1) * bmpData.Stride + j + rgb]
+ rgbValues[i * bmpData.Stride + (j - 3) + rgb]
+ rgbValues[i * bmpData.Stride + (j + 3) + rgb]
- 4 * rgbValues[i * bmpData.Stride + j + rgb];*/
float f2 = rgbValues[(i - 1) * bmpData.Stride + (j - 3) + rgb]
+ rgbValues[(i - 1) * bmpData.Stride + j + rgb]
+ rgbValues[(i - 1) * bmpData.Stride + (j + 3) + rgb]
+ rgbValues[(i + 1) * bmpData.Stride + (j - 3) + rgb]
+ rgbValues[(i + 1) * bmpData.Stride + j + rgb]
+ rgbValues[(i + 1) * bmpData.Stride + (j + 3) + rgb]
+ rgbValues[i * bmpData.Stride + (j - 3) + rgb]
+ rgbValues[i * bmpData.Stride + (j + 3) + rgb]
- 8 * rgbValues[i * bmpData.Stride + j + rgb];
int t = (int)(Math.Sqrt(f2 * f2) + 0.5);
if (t > 255)
t = 255;
return t;
}
Laplacian算子对于噪声比较敏感,而Gauss-Laplacian算子把高斯平滑滤波器和拉普拉斯边缘检测算子结合起来,先平滑掉噪声,在进行边缘检测,效果比较好,其中Gauss-Laplacian算子模板如下:
xpublic int GaussLaplacian(byte[] rgbValues, BitmapData bmpData, int i, int j, int rgb)
{
int[] mask = { -2, -4, -4, -4, -2,
-4, 0, 8, 0, -4,
-4, 8, 24, 8, -4,
-4, 0, 8, 0, -4,
-2, -4, -4, -4, -2};
float f2=0;
if ((i - 2) >= 0 && (i + 2) < bmpData.Height && (j - 6) >= 0 && (j + 6) < bmpData.Width*3)
{
for (int k = 0; k < 5; k++)
{
for (int s = 0; s < 5; s++)
{
f2 += mask[k * 5 + s] * rgbValues[(i + k - 2) * bmpData.Stride + (j + (s - 2)*3) + rgb];
}
}
int t = (int)(Math.Abs(f2) + 0.5);
if (t > 255)
t = 255;
return t;
}
else
{
return rgbValues[i * bmpData.Stride + j + rgb];
}
}
Krisch算子模板是由8个模板组成的方向算子,8个模板代表8个方向,图像中的每一个点都用8个模板进行卷积,取8个方向中的最大值作为边缘幅度图像的输出,其中所用到的8个模板如下:
xxxxxxxxxx
public int Krisch(byte[] rgbValues, BitmapData bmpData, int i, int j, int rgb)
{
int[,] mask = { { 5, 5, 5, -3, 0, -3, -3, -3, -3 },
{ -3, 5, 5, -3, 0, 5, -3, -3, -3 },
{ -3, -3, 5, -3, 0, 5, -3, -3, 5 },
{ -3, -3, -3, -3, 0, 5, -3, 5, 5 },
{ -3, -3, -3, -3, 0, -3, 5, 5, 5 },
{ -3, -3, -3, 5, 0, -3, 5, 5, -3 },
{ 5, -3, -3, 5, 0, -3, 5, -3, -3 },
{ 5, 5, -3, 5, 0, -3, -3, -3, -3 } };
int tmp = 0;
for (int k = 0; k < 8; k++)
{
float f2 = mask[k, 0] * rgbValues[(i - 1) * bmpData.Stride + (j - 3) + rgb]
+ mask[k, 1] * rgbValues[(i - 1) * bmpData.Stride + j + rgb]
+ mask[k, 2] * rgbValues[(i - 1) * bmpData.Stride + (j + 3) + rgb]
+ mask[k, 3] * rgbValues[i * bmpData.Stride + (j - 3) + rgb]
+ mask[k, 4] * rgbValues[i * bmpData.Stride + j + rgb]
+ mask[k, 5] * rgbValues[i * bmpData.Stride + (j + 3) + rgb]
+ mask[k, 6] * rgbValues[(i + 1) * bmpData.Stride + (j - 3) + rgb]
+ mask[k, 7] * rgbValues[(i + 1) * bmpData.Stride + j + rgb]
+ mask[k, 8] * rgbValues[(i + 1) * bmpData.Stride + (j + 3) + rgb];
int t = (int)(Math.Abs(f2)+0.5);
if (t > tmp)
tmp = t;
}
if (tmp > 255)
tmp = 255;
return tmp;
}
上述的几个边缘提取算子的比较如下,下面分别是(上左:Roberts算子,上右:Sobel算子,中左,Prewitt算子,中右:Laplace算子,下左:Gauss-Laplace算子,下右:Krisch算子)
从上图中可以看出:Roberts算子是2x2算子,对于边缘定位比较准确,所以分割结果的边界宽度不像后面的其他分割那样宽,在图像噪声较少的情况下,分割的结果较好。
Sobel算子、Prewitt算子、Krisch算子都是3x3的算子,他们对于灰度渐变和噪声较多的情况图像处理的较好,Prewitt算子并不是各向同性的,边缘并不是完全联通的,有一定程度的断开。
Laplacian算子是二阶微分算子,对于噪声比较敏感,所以分割结果中在一些像素上出现了散碎的边缘像素点,Laplacian算子是各向同性的,即与坐标轴方向无关,坐标轴旋转后梯度的结果不变,对于边缘的定位比较准确。
各个算子的特性比较如下: