二值图像的腐蚀和膨胀图像数字处理中应用相当广泛,代码处理也很简单,只不过一些资料在介绍腐蚀和膨胀原理时,用一些形态学、集合上的概念和术语,搞得也有些”高深莫测“了。
从图像处理角度看,二值图像的腐蚀和膨胀就是将一个小型二值图(结构元素,一般为3*3大小)在一个大的二值图上逐点移动并进行比较,根据比较的结果作出相应处理而已。以二值图的骨架为黑色点为例:
作图像腐蚀处理时,如果结构元素中的所有黑色点与它对应的大图像素点完全相同,该点为黑色,否则为白色。
作图像膨胀处理时,如果结构元素中只要有一个及以上黑色点与它对应的大图像素点相同,该点为黑色,否则为白色。也就是说,如果结构元素中的所有黑色点与它对应的大图像素点没有一个相同,该点为白色,否则为黑色。结构元素中的所有黑色点与它对应的大图像素点没有一个相同,说明大图的这些像素点都是白色的,假如二值图的骨架为白色点,这个对黑色骨架二值图的膨胀处理恰好是对白色骨架二值图的腐蚀处理。同理,对黑色骨架二值图的腐蚀处理也就是对白色骨架的膨胀处理。
根据这个道理,我们完全可以把对黑色骨架和白色骨架分别所作的腐蚀和膨胀处理代码统一起来,使得原来所需要的四段处理代码变成二段甚至一段处理代码。
下面是一个对32位像素格式二值图像数据的腐蚀和膨胀处理的全部代码:
view plaincopy to clipboardprint?
-
-
-
-
typedef union
- {
- ARGB Color;
-
struct
- {
-
BYTE Blue;
-
BYTE Green;
-
BYTE Red;
-
BYTE Alpha;
- };
- }ARGBQuad, *PARGBQuad;
-
-
-
-
VOID GetDataMap(CONST BitmapData *data, BitmapData *map, BOOL blackPixel)
- {
-
- map->Width = data->Width + 2;
- map->Height = data->Height + 2;
- map->Stride = map->Width;
-
map->Scan0 = (void*)new char[map->Stride * map->Height + 1];
-
BYTE *ps = (BYTE*)data->Scan0;
-
BYTE *pd0 = (BYTE*)map->Scan0;
-
BYTE *pd = pd0 + map->Stride;
-
BYTE *pt = pd;
-
INT srcOffset = data->Stride - data->Width * sizeof(ARGBQuad);
-
UINT x, y;
-
-
-
if (blackPixel)
- {
-
for (y = 0; y < data->Height; y ++, ps += srcOffset)
- {
- *pd ++ = *ps ^ 255;
-
for (x = 0; x < data->Width; x ++, ps += sizeof(ARGBQuad))
- *pd ++ = *ps ^ 255;
-
*pd ++ = *(ps - sizeof(ARGBQuad)) ^ 255;
- }
-
- }
-
-
else
- {
-
for (y = 0; y < data->Height; y ++, *pd ++ = *(ps - sizeof(ARGBQuad)), ps += srcOffset)
- {
-
for (x = 0, *pd ++ = *ps; x < data->Width; x ++, *pd ++ = *ps, ps += sizeof(ARGBQuad));
- }
- }
- ps = pd - map->Stride;
-
for (x = 0; x < map->Width; x ++, *pd0 ++ = *pt ++, *pd ++ = *ps ++);
- }
-
-
-
-
-
-
-
-
-
-
VOID GetTempletMasks(DWORD templet, DWORD masks[])
- {
-
for (INT i = 2; i >= 0; i --, templet >>= 8)
- {
- masks[i] = 0;
-
for (UINT j = 4; j; j >>= 1)
- {
- masks[i] <<= 8;
-
if (templet & j) masks[i] |= 1;
- }
- }
- }
-
-
-
VOID Erosion_Dilation(BitmapData *data, DWORD templet, BOOL blackPixel)
- {
- BitmapData map;
- GetDataMap(data, &map, blackPixel);
-
- PARGBQuad pd = (PARGBQuad)data->Scan0;
-
BYTE *ps = (BYTE*)map.Scan0 + map.Stride;
-
INT width = (INT)data->Width;
-
INT height = (INT)data->Height;
-
INT dstOffset = data->Stride - width * sizeof(ARGBQuad);
-
INT value = blackPixel? 0 : 255;
-
INT x, y;
-
-
if (templet == 0x0700)
- {
-
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)
- {
-
for (x = 0; x < width; x ++, pd ++, ps ++)
- {
-
if (*(DWORD*)ps & 0x010101)
- pd->Blue = pd->Green = pd->Red = value;
- }
- }
- }
-
else
- {
-
DWORD masks[3];
- GetTempletMasks(templet, masks);
-
-
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)
- {
-
for (x = 0; x < width; x ++, pd ++, ps ++)
- {
-
if (*(DWORD*)(ps - map.Stride) & masks[0] ||
-
*(DWORD*)ps & masks[1] ||
-
*(DWORD*)(ps + map.Stride) & masks[2])
- pd->Blue = pd->Green = pd->Red = value;
- }
- }
- }
-
-
delete map.Scan0;
- }
-
-
-
- FORCEINLINE
-
VOID Dilation(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE)
- {
- Erosion_Dilation(data, templet, blackPixel);
- }
-
-
-
- FORCEINLINE
-
VOID Erosion(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE)
- {
- Erosion_Dilation(data, templet, !blackPixel);
- }
-
本文的二值图像的腐蚀和膨胀处理代码有以下特点:
1、可使用任意的3*3结构元素进行处理。
2、可对黑色或者白色骨架二值图进行处理。
3、在复制字节图时对边界像素作了扩展,以便对二值图的边界处理。
4、没有采用结构元素逐点比较的作法,而是使用结构元素掩码,每次对三个像素进行逻辑运算,特别是对水平结构元素的单独处理,大大提高了处理效率。
5、上面的代码虽然针对的是32位像素格式的二值图,但稍作修改即可适应24位或者8位像素格式二值图像数据。其实,对于32位像素格式的二值图,改用下面的处理代码可提高图像处理速度(因其使用位运算一次性对像素的R、G、B分量进行了赋值):
view plaincopy to clipboardprint?
-
-
-
VOID _Dilation(BitmapData *data, BitmapData *map, DWORD templet)
- {
- PARGBQuad pd = (PARGBQuad)data->Scan0;
-
BYTE *ps = (BYTE*)map->Scan0 + map->Stride;
-
INT width = (INT)data->Width;
-
INT height = (INT)data->Height;
-
INT dstOffset = data->Stride - width * sizeof(ARGBQuad);
-
INT x, y;
-
-
if (templet == 0x0700)
- {
-
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)
- {
-
for (x = 0; x < width; x ++, pd ++, ps ++)
-
if (*(DWORD*)ps & 0x010101)
- pd->Color &= 0xff000000;
- }
- }
-
else
- {
-
DWORD masks[3];
- GetTempletMasks(templet, masks);
-
-
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)
- {
-
for (x = 0; x < width; x ++, pd ++, ps ++)
-
if (*(DWORD*)(ps - map->Stride) & masks[0] ||
-
*(DWORD*)ps & masks[1] ||
-
*(DWORD*)(ps + map->Stride) & masks[2])
- pd->Color &= 0xff000000;
- }
- }
- }
-
-
-
VOID _Erosion(BitmapData *data, BitmapData *map, DWORD templet)
- {
- PARGBQuad pd = (PARGBQuad)data->Scan0;
-
BYTE *ps = (BYTE*)map->Scan0 + map->Stride;
-
INT width = (INT)data->Width;
-
INT height = (INT)data->Height;
-
INT dstOffset = data->Stride - width * sizeof(ARGBQuad);
-
INT x, y;
-
-
if (templet == 0x0700)
- {
-
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)
- {
-
for (x = 0; x < width; x ++, pd ++, ps ++)
-
if (*(DWORD*)ps & 0x010101)
- pd->Color |= 0x00ffffff;
- }
- }
-
else
- {
-
DWORD masks[3];
- GetTempletMasks(templet, masks);
-
-
for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)
- {
-
for (x = 0; x < width; x ++, pd ++, ps ++)
-
if (*(DWORD*)(ps - map->Stride) & masks[0] ||
-
*(DWORD*)ps & masks[1] ||
-
*(DWORD*)(ps + map->Stride) & masks[2])
- pd->Color |= 0x00ffffff;
- }
- }
- }
-
-
-
-
VOID Dilation(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE)
- {
- BitmapData map;
- GetDataMap(data, &map, blackPixel);
-
if (blackPixel)
- _Dilation(data, &map, templet);
-
else
- _Erosion(data, &map, templet);
-
delete map.Scan0;
- }
-
-
-
-
VOID Erosion(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE)
- {
- Dilation(data, templet, !blackPixel);
- }
-
下面是使用BCB2007和GDI+位图对黑色骨架二值图进行的开运算处理,也可看作是对白色骨架二值图的闭运算处理(先腐蚀后膨胀为开运算;先膨胀后腐蚀为闭运算):
view plaincopy to clipboardprint?
-
-
-
-
VOID GrayAnd2Values(BitmapData *data, BYTE threshold)
- {
- PARGBQuad p = (PARGBQuad)data->Scan0;
-
INT offset = data->Stride - data->Width * sizeof(ARGBQuad);
-
-
for (UINT y = 0; y < data->Height; y ++, (BYTE*)p += offset)
- {
-
for (UINT x = 0; x < data->Width; x ++, p ++)
- {
-
if (((p->Blue * 29 + p->Green * 150 + p->Red * 77 + 128) >> 8) < threshold)
- p->Color &= 0xff000000;
-
else
- p->Color |= 0x00ffffff;
-
- }
- }
- }
-
-
-
- FORCEINLINE
-
VOID LockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data)
- {
- Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight());
- bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite,
- PixelFormat32bppARGB, data);
- }
-
-
-
- FORCEINLINE
-
VOID UnlockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data)
- {
- bmp->UnlockBits(data);
- }
-
-
-
void __fastcall TForm1::Button1Click(TObject *Sender)
- {
-
Gdiplus::Bitmap *bmp = new Gdiplus::Bitmap(L"d:\\source1.jpg");
-
Gdiplus::Graphics *g = new Gdiplus::Graphics(Canvas->Handle);
- g->DrawImage(bmp, 0, 0);
- BitmapData data;
- LockBitmap(bmp, &data);
-
- GrayAnd2Values(&data, 128);
- Erosion(&data, 0x020702);
- Dilation(&data, 0x020702);
-
- UnlockBitmap(bmp, &data);
- g->DrawImage(bmp, data.Width, 0);
-
delete g;
-
delete bmp;
- }
-
下面是使用本文代码所作的各种处理效果图,结构元素为“十”字形:
左上原图,右上二值图,左中腐蚀图,右中膨胀图,左下开运算图,右下闭运算图。这是对黑色骨架二值图而言,如果是白色骨架二值图,中间和下边的左右处理效果就是相反的了。
分享到:
相关推荐
MatLab程序。 C++实现。 实现对二值图像进行腐蚀、膨胀、开/闭运算。 腐蚀分水平、垂直、全方位。 膨胀分水平、垂直、全方位。 能保存处理后的图,以及将处理后的图与原图进行对比。
二值图像的腐蚀与膨胀这个是在VBgood找到的源码,传到空间做个备份,
使用VS2005进行二值图像膨胀、腐蚀过程和代码
关于二值图像处理的c源程序,包括图像腐蚀、膨胀、细化等内容。
对图像进行膨胀和腐蚀操作,简单验证膨胀和腐蚀功能
对原图进行二值化后,选择不同的结构元素对其进行膨胀和腐蚀运算处理,并仿真出图像结果。
08.图像腐蚀与图像膨胀
图像处理入门C源码分析 图像腐蚀膨胀和细化
for(i=1;i;i++)//腐蚀 { for (int j=1;j;j++) { int flag = 1; { flag=0; } if(flag==0) { data[i][j] = 255; } else { data[i][j] = 0; } } }
传统二值图像膨胀腐蚀算法存在大量冗余操作,运算效率低,制约了大结构元素在实际工程上的应用。提出了一种快速膨胀腐蚀算法。首先针对结构元素建立方向-位置偏移表,然后提取图像的边界,对每一条边界用一个起始点...
图像腐蚀和膨胀案例,引用c
在图像界面中打开二值图像,可以做腐蚀和膨胀两种操作。并可保存操作后的图像。
opencv编程中的图像处理代码 图像腐蚀与膨胀 平台opencv2.4.9
原图片和索引图片、灰度图片、二值图片的转换。 以及图像简单的腐蚀和膨胀。
图像处理 膨胀腐蚀 matlab算法实现
图像腐蚀、膨胀、开、闭运算
膨胀(dilation)能够看做是腐蚀的对偶运算,其定义是:把结构元素B平移a后得到Ba,若Ba击中X,我们记下这个a点。全部满足上述条件的a点组成的集合称做X被B膨胀的结果。用公式表示为:D(X)={a | Ba↑X}=XB,例如以下图...
掌握二值图像的腐蚀、膨胀、开运算、闭运算等常见的形态学方法python,用jupyterlab 文件写的
图像预处理灰度二值自适应中值滤波腐蚀膨胀matlab基础毕设
matlab中通过腐蚀与膨胀提取物体边缘,可直接下载使用。