`
soboer
  • 浏览: 1357872 次
文章分类
社区版块
存档分类
最新评论

二值图像的腐蚀和膨胀 .

 
阅读更多

  二值图像的腐蚀和膨胀图像数字处理中应用相当广泛,代码处理也很简单,只不过一些资料在介绍腐蚀和膨胀原理时,用一些形态学、集合上的概念和术语,搞得也有些”高深莫测“了。

    从图像处理角度看,二值图像的腐蚀和膨胀就是将一个小型二值图(结构元素,一般为3*3大小)在一个大的二值图上逐点移动并进行比较,根据比较的结果作出相应处理而已。以二值图的骨架为黑色点为例:

    作图像腐蚀处理时,如果结构元素中的所有黑色点与它对应的大图像素点完全相同,该点为黑色,否则为白色。

    作图像膨胀处理时,如果结构元素中只要有一个及以上黑色点与它对应的大图像素点相同,该点为黑色,否则为白色。也就是说,如果结构元素中的所有黑色点与它对应的大图像素点没有一个相同,该点为白色,否则为黑色。结构元素中的所有黑色点与它对应的大图像素点没有一个相同,说明大图的这些像素点都是白色的,假如二值图的骨架为白色点,这个对黑色骨架二值图的膨胀处理恰好是对白色骨架二值图的腐蚀处理。同理,对黑色骨架二值图的腐蚀处理也就是对白色骨架的膨胀处理。

    根据这个道理,我们完全可以把对黑色骨架和白色骨架分别所作的腐蚀和膨胀处理代码统一起来,使得原来所需要的四段处理代码变成二段甚至一段处理代码。

    下面是一个对32位像素格式二值图像数据的腐蚀和膨胀处理的全部代码:

view plaincopy to clipboardprint?
  1. //---------------------------------------------------------------------------   
  2.   
  3. // 定义ARGB像素结构   
  4. typedef union  
  5. {  
  6.     ARGB Color;  
  7.     struct  
  8.     {  
  9.         BYTE Blue;  
  10.         BYTE Green;  
  11.         BYTE Red;  
  12.         BYTE Alpha;  
  13.     };  
  14. }ARGBQuad, *PARGBQuad;  
  15. //---------------------------------------------------------------------------   
  16.   
  17. // 获取二值图像data的字节图数据map,骨架像素是否为黑色   
  18. VOID GetDataMap(CONST BitmapData *data, BitmapData *map, BOOL blackPixel)  
  19. {  
  20.     // 字节图边缘扩展1字节,便于处理data的边缘像素   
  21.     map->Width = data->Width + 2;  
  22.     map->Height = data->Height + 2;  
  23.     map->Stride = map->Width;  
  24.     map->Scan0 = (void*)new char[map->Stride * map->Height + 1];// +1防最末字节越界   
  25.     BYTE *ps = (BYTE*)data->Scan0;  
  26.     BYTE *pd0 = (BYTE*)map->Scan0;  
  27.     BYTE *pd = pd0 + map->Stride;  
  28.     BYTE *pt = pd;  
  29.     INT srcOffset = data->Stride - data->Width * sizeof(ARGBQuad);  
  30.     UINT x, y;  
  31.   
  32.     // 如果骨架像素为黑色,获取异或字节图   
  33.     if (blackPixel)  
  34.     {  
  35.         for (y = 0; y < data->Height; y ++, ps += srcOffset)  
  36.         {  
  37.             *pd ++ = *ps ^ 255;  
  38.             for (x = 0; x < data->Width; x ++, ps += sizeof(ARGBQuad))  
  39.                 *pd ++ = *ps ^ 255;  
  40.             *pd ++ = *(ps - sizeof(ARGBQuad)) ^ 255;  
  41.         }  
  42.   
  43.     }  
  44.     // 否则,获取正常字节图   
  45.     else  
  46.     {  
  47.         for (y = 0; y < data->Height; y ++, *pd ++ = *(ps - sizeof(ARGBQuad)), ps += srcOffset)  
  48.         {  
  49.             for (x = 0, *pd ++ = *ps; x < data->Width; x ++, *pd ++ = *ps, ps += sizeof(ARGBQuad));  
  50.         }  
  51.     }  
  52.     ps = pd - map->Stride;  
  53.     for (x = 0; x < map->Width; x ++, *pd0 ++ = *pt ++, *pd ++ = *ps ++);  
  54. }  
  55. //---------------------------------------------------------------------------   
  56.   
  57. // 按结构元素模板templet制作字节掩码数组masks   
  58. // templet低3字节的低3位对应结构元素,如下面的结构元素:   
  59. //   水平     垂直     十字     方形     其它   
  60. //   ○ ○ ○    ○ ● ○    ○ ● ○    ● ● ●    ○ ● ○   
  61. //   ● ● ●    ○ ● ○    ● ● ●    ● ● ●    ● ● ●   
  62. //   ○ ○ ○    ○ ● ○    ○ ● ○    ● ● ●    ○ ● ●   
  63. // 用templet分别表示为:0x000700, 0x020202, 0x020702, 0x070707, 0x020703   
  64. VOID GetTempletMasks(DWORD templet, DWORD masks[])  
  65. {  
  66.     for (INT i = 2; i >= 0; i --, templet >>= 8)  
  67.     {  
  68.         masks[i] = 0;  
  69.         for (UINT j = 4; j; j >>= 1)  
  70.         {  
  71.             masks[i] <<= 8;  
  72.             if (templet & j) masks[i] |= 1;  
  73.         }  
  74.     }  
  75. }  
  76. //---------------------------------------------------------------------------   
  77.   
  78. VOID Erosion_Dilation(BitmapData *data, DWORD templet, BOOL blackPixel)  
  79. {  
  80.     BitmapData map;  
  81.     GetDataMap(data, &map, blackPixel);  
  82.   
  83.     PARGBQuad pd = (PARGBQuad)data->Scan0;  
  84.     BYTE *ps = (BYTE*)map.Scan0 + map.Stride;  
  85.     INT width = (INT)data->Width;  
  86.     INT height = (INT)data->Height;  
  87.     INT dstOffset = data->Stride - width * sizeof(ARGBQuad);  
  88.     INT value = blackPixel? 0 : 255;  
  89.     INT x, y;  
  90.   
  91.     if (templet == 0x0700)  // 水平结构元素单独处理,可提高处理速度   
  92.     {  
  93.         for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)  
  94.         {  
  95.             for (x = 0; x < width; x ++, pd ++, ps ++)  
  96.             {  
  97.                 if (*(DWORD*)ps & 0x010101)  
  98.                     pd->Blue = pd->Green = pd->Red = value;  
  99.             }  
  100.         }  
  101.     }  
  102.     else  
  103.     {  
  104.         DWORD masks[3];  
  105.         GetTempletMasks(templet, masks);  
  106.   
  107.         for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)  
  108.         {  
  109.             for (x = 0; x < width; x ++, pd ++, ps ++)  
  110.             {  
  111.                 if (*(DWORD*)(ps - map.Stride) & masks[0] ||  
  112.                     *(DWORD*)ps & masks[1] ||  
  113.                     *(DWORD*)(ps + map.Stride) & masks[2])  
  114.                     pd->Blue = pd->Green = pd->Red = value;  
  115.             }  
  116.         }  
  117.     }  
  118.   
  119.     delete map.Scan0;  
  120. }  
  121. //---------------------------------------------------------------------------   
  122.   
  123. // 二值图膨胀。参数:二值图数据,结构元素模板,是否黑色像素骨架   
  124. FORCEINLINE  
  125. VOID Dilation(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE)  
  126. {  
  127.     Erosion_Dilation(data, templet, blackPixel);  
  128. }  
  129. //---------------------------------------------------------------------------   
  130.   
  131. // 二值图腐蚀。参数:二值图数据,结构元素模板,是否黑色像素骨架   
  132. FORCEINLINE  
  133. VOID Erosion(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE)  
  134. {  
  135.     Erosion_Dilation(data, templet, !blackPixel);  
  136. }  
  137. //---------------------------------------------------------------------------  

    本文的二值图像的腐蚀和膨胀处理代码有以下特点:

    1、可使用任意的3*3结构元素进行处理。

    2、可对黑色或者白色骨架二值图进行处理。

    3、在复制字节图时对边界像素作了扩展,以便对二值图的边界处理。

    4、没有采用结构元素逐点比较的作法,而是使用结构元素掩码,每次对三个像素进行逻辑运算,特别是对水平结构元素的单独处理,大大提高了处理效率。

    5、上面的代码虽然针对的是32位像素格式的二值图,但稍作修改即可适应24位或者8位像素格式二值图像数据。其实,对于32位像素格式的二值图,改用下面的处理代码可提高图像处理速度(因其使用位运算一次性对像素的R、G、B分量进行了赋值):

view plaincopy to clipboardprint?
  1. //---------------------------------------------------------------------------   
  2.   
  3. VOID _Dilation(BitmapData *data, BitmapData *map, DWORD templet)  
  4. {  
  5.     PARGBQuad pd = (PARGBQuad)data->Scan0;  
  6.     BYTE *ps = (BYTE*)map->Scan0 + map->Stride;  
  7.     INT width = (INT)data->Width;  
  8.     INT height = (INT)data->Height;  
  9.     INT dstOffset = data->Stride - width * sizeof(ARGBQuad);  
  10.     INT x, y;  
  11.   
  12.     if (templet == 0x0700)  // 水平结构元素单独处理,可提高处理速度   
  13.     {  
  14.         for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)  
  15.         {  
  16.             for (x = 0; x < width; x ++, pd ++, ps ++)  
  17.                 if (*(DWORD*)ps & 0x010101)  
  18.                     pd->Color &= 0xff000000;  
  19.         }  
  20.     }  
  21.     else  
  22.     {  
  23.         DWORD masks[3];  
  24.         GetTempletMasks(templet, masks);  
  25.   
  26.         for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)  
  27.         {  
  28.             for (x = 0; x < width; x ++, pd ++, ps ++)  
  29.                 if (*(DWORD*)(ps - map->Stride) & masks[0] ||  
  30.                     *(DWORD*)ps & masks[1] ||  
  31.                     *(DWORD*)(ps + map->Stride) & masks[2])  
  32.                     pd->Color &= 0xff000000;  
  33.         }  
  34.     }  
  35. }  
  36. //---------------------------------------------------------------------------   
  37.   
  38. VOID _Erosion(BitmapData *data, BitmapData *map, DWORD templet)  
  39. {  
  40.     PARGBQuad pd = (PARGBQuad)data->Scan0;  
  41.     BYTE *ps = (BYTE*)map->Scan0 + map->Stride;  
  42.     INT width = (INT)data->Width;  
  43.     INT height = (INT)data->Height;  
  44.     INT dstOffset = data->Stride - width * sizeof(ARGBQuad);  
  45.     INT x, y;  
  46.   
  47.     if (templet == 0x0700)  // 水平结构元素单独处理,可提高处理速度   
  48.     {  
  49.         for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)  
  50.         {  
  51.             for (x = 0; x < width; x ++, pd ++, ps ++)  
  52.                 if (*(DWORD*)ps & 0x010101)  
  53.                     pd->Color |= 0x00ffffff;  
  54.         }  
  55.     }  
  56.     else  
  57.     {  
  58.         DWORD masks[3];  
  59.         GetTempletMasks(templet, masks);  
  60.   
  61.         for (y = 0; y < height; y ++, (BYTE*)pd += dstOffset, ps += 2)  
  62.         {  
  63.             for (x = 0; x < width; x ++, pd ++, ps ++)  
  64.                 if (*(DWORD*)(ps - map->Stride) & masks[0] ||  
  65.                     *(DWORD*)ps & masks[1] ||  
  66.                     *(DWORD*)(ps + map->Stride) & masks[2])  
  67.                     pd->Color |= 0x00ffffff;  
  68.         }  
  69.     }  
  70. }  
  71. //---------------------------------------------------------------------------   
  72.   
  73. // 二值图膨胀。参数:二值图数据,结构元素模板,是否黑色像素骨架   
  74. VOID Dilation(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE)  
  75. {  
  76.     BitmapData map;  
  77.     GetDataMap(data, &map, blackPixel);  
  78.     if (blackPixel)  
  79.         _Dilation(data, &map, templet);  
  80.     else  
  81.         _Erosion(data, &map, templet);  
  82.     delete map.Scan0;  
  83. }  
  84. //---------------------------------------------------------------------------   
  85.   
  86. // 二值图腐蚀。参数:二值图数据,结构元素模板,是否黑色像素骨架   
  87. VOID Erosion(BitmapData *data, DWORD templet, BOOL blackPixel = TRUE)  
  88. {  
  89.     Dilation(data, templet, !blackPixel);  
  90. }  
  91. //---------------------------------------------------------------------------  

    下面是使用BCB2007和GDI+位图对黑色骨架二值图进行的开运算处理,也可看作是对白色骨架二值图的闭运算处理(先腐蚀后膨胀为开运算;先膨胀后腐蚀为闭运算):

view plaincopy to clipboardprint?
  1. //---------------------------------------------------------------------------   
  2.   
  3. // 图像数据data灰度同时二值化,threshold阀值   
  4. VOID GrayAnd2Values(BitmapData *data, BYTE threshold)  
  5. {  
  6.     PARGBQuad p = (PARGBQuad)data->Scan0;  
  7.     INT offset = data->Stride - data->Width * sizeof(ARGBQuad);  
  8.   
  9.     for (UINT y = 0; y < data->Height; y ++, (BYTE*)p += offset)  
  10.     {  
  11.         for (UINT x = 0; x < data->Width; x ++, p ++)  
  12.         {  
  13.             if (((p->Blue * 29 + p->Green * 150 + p->Red * 77 + 128) >> 8) < threshold)  
  14.                 p->Color &= 0xff000000;  
  15.             else  
  16.                 p->Color |= 0x00ffffff;  
  17.   
  18.         }  
  19.     }  
  20. }  
  21. //---------------------------------------------------------------------------   
  22.   
  23. // 锁定GDI+位位图扫描线到data   
  24. FORCEINLINE  
  25. VOID LockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data)  
  26. {  
  27.     Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight());  
  28.     bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite,  
  29.         PixelFormat32bppARGB, data);  
  30. }  
  31. //---------------------------------------------------------------------------   
  32.   
  33. // GDI+位图扫描线解锁   
  34. FORCEINLINE  
  35. VOID UnlockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data)  
  36. {  
  37.     bmp->UnlockBits(data);  
  38. }  
  39. //---------------------------------------------------------------------------   
  40.   
  41. void __fastcall TForm1::Button1Click(TObject *Sender)  
  42. {  
  43.     Gdiplus::Bitmap *bmp =  new Gdiplus::Bitmap(L"d:\\source1.jpg");  
  44.     Gdiplus::Graphics *g = new Gdiplus::Graphics(Canvas->Handle);  
  45.     g->DrawImage(bmp, 0, 0);  
  46.     BitmapData data;  
  47.     LockBitmap(bmp, &data);  
  48.   
  49.     GrayAnd2Values(&data, 128);  
  50.     Erosion(&data, 0x020702);  
  51.     Dilation(&data, 0x020702);  
  52.   
  53.     UnlockBitmap(bmp, &data);  
  54.     g->DrawImage(bmp, data.Width, 0);  
  55.     delete g;  
  56.     delete bmp;  
  57. }  
  58. //---------------------------------------------------------------------------  

    下面是使用本文代码所作的各种处理效果图,结构元素为“十”字形:

    左上原图,右上二值图,左中腐蚀图,右中膨胀图,左下开运算图,右下闭运算图。这是对黑色骨架二值图而言,如果是白色骨架二值图,中间和下边的左右处理效果就是相反的了。

1
0
分享到:
评论

相关推荐

    能对二值图像进行腐蚀、膨胀、开闭运算的MatLab程序(C++实现)

    本文将深入探讨使用MatLab程序,通过C++实现对二值图像进行腐蚀、膨胀、开运算和闭运算的基本原理与方法。 首先,我们要理解什么是腐蚀和膨胀操作。这两种操作是形态学图像处理中的基本操作,主要用于改变图像的...

    二值图像的腐蚀与膨胀|推荐代码

    总结,二值图像的腐蚀与膨胀是图像处理中常用的技术,它们可以帮助我们清理噪声、分离和连接物体。VB代码实现这些操作需要对图像数据进行遍历,并根据腐蚀和膨胀的逻辑更新像素值。理解这些概念和实现方式对于进行...

    二值图像腐蚀膨胀细化源程序

    1. **二值图像腐蚀**:腐蚀操作是去除二值图像中前景物体边缘的小突起或连接部分,以减小物体面积。其基本思想是用一个小结构元素(如矩形、圆形)在图像上滑动,如果该结构元素完全被前景像素覆盖,则保留这部分...

    图像腐蚀和膨胀_图像膨胀和腐蚀_

    综上所述,图像腐蚀和膨胀是图像处理中的重要工具,它们在各种应用场景中都有其独特的价值。了解并熟练掌握这两种操作,将有助于提升图像处理和分析的能力。通过实际操作和调整参数,可以更好地适应不同的图像处理...

    二值图像膨胀、腐蚀

    使用VS2005进行二值图像膨胀、腐蚀过程和代码

    OpenCV图像的腐蚀与膨胀.pdf

    在OpenCV库中,这两种操作被广泛用于改进图像质量,特别是对于二值图像处理。 腐蚀操作(Erosion)是形态学操作的一种,它的基本原理是用一个结构元素(通常是正方形、圆形或十字形)滑动过图像,取结构元素覆盖...

    图像处理 图像腐蚀膨胀和细化

    在图像处理领域,腐蚀、膨胀和细化是三种重要的形态学操作,它们被广泛应用于图像分割...对于初学者,可以从简单的二值图像开始,逐步深入到复杂场景,最终能够熟练地运用腐蚀、膨胀和细化等技术解决实际图像处理挑战。

    OpenCV图像的腐蚀与膨胀.docx

    《OpenCV图像处理》实验报告聚焦于图像的腐蚀与膨胀操作,这是形态学图像处理中的基本操作,具有显著的噪声消除、图像元素分割和连接功能。形态学操作基于形状,通过对输入图像应用特定的结构元素(如正方形、圆形...

    08.图像腐蚀与图像膨胀.pdf

    通过上述介绍,我们可以了解到图像腐蚀和图像膨胀在图像处理中的重要作用。它们不仅可以帮助我们去除噪声、细化或扩大图像中的物体边界,还可以用于更复杂的图像分析任务,如轮廓检测、形态分析等。在实际应用中,...

    图像处理 膨胀腐蚀 matlab算法实现

    首先,我们读取了一张图像,然后使用阈值化和二值化操作将图像转换为二值图像。接着,我们使用膨胀腐蚀操作对图像进行处理,包括腐蚀、膨胀、开运算和闭运算等操作。最后,我们使用 Matlab 的图形化工具将处理结果...

    二值图开运算_图像腐蚀_图像处理_二值图像腐蚀_

    在实际应用中,**二值图像腐蚀**特别适用于处理那些含有大量噪声或者小斑点的图像。例如,在文档扫描中,可以使用腐蚀和开运算来去除文字周围的噪声,使文字更加清晰;在医学图像分析中,可以去除肿瘤边缘的小亮点,...

    基于c#的.NET实现二值图像的腐蚀和膨胀(图像形态学)

    本主题将深入探讨如何使用C# .NET框架来实现二值图像的腐蚀和膨胀操作,这两种操作是形态学的核心组成部分。 首先,二值图像指的是只有黑白两种颜色的图像,通常用0表示黑色(背景),用1表示白色(前景)。这种...

    matlab图像专题:86 对二值图像进行膨胀.zip

    在图像处理领域,二值图像是一种特殊的图像类型,其中像素值仅包含两个状态,通常为0(背景)和1(前景)。膨胀操作是形态学图像处理中的一个基本操作,主要用于改变图像的边界,扩大物体的轮廓,填充物体内部的空洞...

    基于MATLAB的图像腐蚀膨胀MATLAB.7z

    在MATLAB中,可以使用imerode和imdilate函数来实现图像的腐蚀和膨胀操作。 腐蚀操作可以通过以下代码实现: img = imread('image.png'); % 读取图像 se = strel('disk', 5); % 创建一个结构元素,这里使用一个半径...

    matlab图像专题;86 对二值图像进行膨胀.zip

    在图像处理领域,二值图像是一种特殊的图像类型,它只包含两种颜色或灰度值,通常用0表示背景,1...通过学习和实践,你可以掌握如何使用MATLAB进行二值图像膨胀,从而在各种图像处理任务中提升图像的质量和分析效果。

    【水果识别】基于matlab GUI灰度+二值化+腐蚀+膨胀算法水果识别【含Matlab源码 671期】.zip

    【水果识别】基于matlab GUI灰度+二值化+腐蚀+膨胀算法的实现是一个典型图像处理项目,它涵盖了计算机视觉领域的一些基本概念和技术。在本项目中,开发者使用MATLAB这一强大的数值计算和可视化工具,构建了一个图形...

    图像腐蚀与膨胀综合示例

    本文将深入探讨“图像腐蚀与膨胀”这一关键概念,它们是形态学图像处理中的基本操作,常用于图像分割、噪声去除以及边缘检测等任务。我们将基于OpenCV 2.4.9版本,通过具体的编程实例来阐述这两个概念。 **图像腐蚀...

    图像二值化后的膨胀腐蚀运算

    对原图进行二值化后,选择不同的结构元素对其进行膨胀和腐蚀运算处理,并仿真出图像结果。

    matlab数学形态学图像处理技术:1 对二值图像进行膨胀.zip

    总结,MATLAB的数学形态学图像处理技术在二值图像膨胀中具有广泛的应用,通过合理选择结构元素和运用膨胀操作,我们可以对二值图像进行有效的形态学变换,以达到增强图像特征、提取有用信息的目的。在实际项目中,应...

    图像腐蚀、膨胀、开、闭运算

    在图像处理领域,"图像腐蚀、膨胀、开、闭运算"是重要的形态学操作,主要用于图像分割、噪声去除和形状分析。这些操作基于数学形态学理论,是图像处理中的基本工具,尤其在二值图像(黑白图像)处理中广泛应用。 1....

Global site tag (gtag.js) - Google Analytics