二值图像是一种简单的图像格式,它只有两个灰度级,即"0"表示黑色的像素点,"255"表示白色的像素点。二值图像处理在图像处理领域占据很重要的位置,在具体的图像处理应用系统中,往往需要对于获得的二值图像进行处理,以有利于后期的识别工作。二值图像处理运算是从数学形态学下的集合论方法发展起来的基本运算很简单,但是却可以产生复杂的效果。常用的二值图像处理操作有许多方法,如腐蚀、膨胀、细化、开运算和闭运算等等。
一、腐蚀和膨胀
形态学是一门新兴科学,它的用途主要是获取物体拓扑和结果信息,它通过物体和结构元素相互作用的某些运算,得到物体更本质的形态。它在图像处理中的应用主要是:
1.利用形态学的基本运算,对图像进行观察和处理,从而达到改善图像质量的目的;
2.描述和定义图像的各种几何参数和特征,如面积,周长,连通度,颗粒度,骨架和方向性。
二值图像基本的形态学运算是腐蚀和膨胀,
简单的腐蚀是消除物体的所有边界点的一种过程,其结果是使剩下的物体沿其周边比原物体小一个像素的面积。如果物体是圆的,它的直径在每次腐蚀后将减少两个像素,如果物体在某一点处任意方向上连通的像素小于三个,那么该物体经过一次腐蚀后将在该点处分裂为二个物体。
简单的膨胀运算是将与某物体接触的所有背景点合并到该物体中的过程。过程的结果是使物体的面积增大了相应数量的点,如果物体是圆的,它的直径在每次膨胀后将增大两个像素。如果两个物体在某一点的任意方向相隔少于三个像素,它们将在该点连通起来。
下面给出具体的实现腐蚀和膨胀的函数代码:
// 二值图像腐蚀操作函数
BOOL ImageErosion(BYTE *pData, int Width, int Height)
{
// pData为图像数据的指针,Width和Height为图像的宽和高;
BYTE * pData1;
int m, n, i, j, sum, k, sum1;
BOOL bErosion;
if (pData == NULL)
{
AfxMessageBox("图像数据为空,请读取图像数据");
return FALSE;
}
// 申请空间,pData1存放处理后的数据;
pData1 = (BYTE * )new char[WIDTHBYTES(Width * 8) * Height];
if (pData1 == NULL)
{
AfxMessageBox("图像缓冲数据区申请失败,请重新申请图像数据缓冲区");
return FALSE;
}
memcpy(pData1,pData,WIDTHBYTES(Width * 8) * Height);
for (i = 10;i < Height - 10;i++)
for (j = 32;j < Width - 32;j++)
{
bErosion = FALSE;
sum = *(pData + WIDTHBYTES(Width * 8) * i + j);
// 当前像素为黑色
if(sum == 0)
{
for (m = -1;m < 2;m++)
{
for (n = -1;n < 2;n++)
{
// 周围只要有一个像素为白色,则把当前像素设置为白色
sum1 = *(pData+WIDTHBYTES(Width * 8) *(i + m) + j + n);
if(sum1 == 255)
{
*(pData1 + WIDTHBYTES(Width * 8) * i + j)=255;
bErosion = TRUE;
break;
}
}
if(bErosion)
{
bErosion = FALSE;
break;
}
}
}
}
memcpy(pData,pData1,WIDTHBYTES(Width * 8) * Height);
return TRUE;
}
// 二值图像的膨胀操作
BOOL ImageDilation(BYTE *pData, int Width, int Height)
{
BYTE * pData1;
int m,n,i,j,sum,k,sum1;
BOOL bDilation;
if(pData == NULL)
{
AfxMessageBox("图像数据为空,请读取图像数据");
return FALSE;
}
// 申请空间,pData1存放处理后的数据;
pData1 = (BYTE * )new char[WIDTHBYTES(Width * 8) * Height];
if(pData1 == NULL)
{
AfxMessageBox("图像缓冲数据区申请失败,请重新申请图像数据缓冲区");
return FALSE ;
}
memcpy(pData1,pData,WIDTHBYTES(Width * 8) * Height);
for (i = 10;i < Height - 10;i++)
for (j = 32;j < Width - 32;j++)
{
bDilation = FALSE;
sum = *(pData+WIDTHBYTES(Width * 8) * i + j);
// 当前像素为白色
if(sum == 255)
{
for (m = - 1;m < 2;m++)
{
for (n = - 1;n < 2;n++)
{
// 周围像素只要有一个像素为黑色,则把当前像素设置为黑色
sum1 = *(pData+WIDTHBYTES(Width * 8) *(i + m) + j + n);
if(sum1 == 0)
{
*(pData1 + WIDTHBYTES(Width * 8) * i+j) = 0;
bDilation = TRUE;
break;
}
}
if(bDilation)
{
bDilation = FALSE;
break;
}
}
}
}
memcpy(pData, pData1, WIDTHBYTES(Width * 8) * Height);
return TRUE;
}
从上面的说明可以看出,腐蚀可以消除图像中小的噪声区域,膨胀可以填补物体中的空洞。对一个图像先进行腐蚀运算然后再膨胀的操作过程称为开运算,它可以消除细小的物体、在纤细点处分离物体、平滑较大物体的边界时不明显的改变其面积。如果对一个图像先膨胀然后再收缩,我们称之为闭运算,它具有填充物体内细小的空洞、连接邻近物体、在不明显改变物体面积的情况下平滑其边界的作用。通常情况下,当有噪声的图像用阈值二值化后,所得到的边界是很不平滑的,物体区域具有一些错判的孔洞,背景区域散布着一些小的噪声物体,连续的开和闭运算可以显著的改善这种情况,这时候需要在连接几次腐蚀迭代之后,再加上相同次数的膨胀,才可以产生所期望的效果。