如何进行数字图像处理中的膨胀和腐蚀计算

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何进行数字图像处理中的膨胀和腐蚀计算相关的知识,希望对你有一定的参考价值。

腐蚀的算法:
用3x3的结构元素,扫描图像的每一个像素
用结构元素与其覆盖的二值图像做“与”操作
如果都为1,结果图像的该像素为1。否则为0。
结果:使二值图像减小一圈
定义:E = B  S = x,y | SxyB

膨胀的算法:
用3x3的结构元素,扫描图像的每一个像素
用结构元素与其覆盖的二值图像做“与”操作
如果都为0,结果图像的该像素为0。否则为1
结果:使二值图像扩大一圈
定义:E = B  S = x,y | Sxy∩B ≠Ф

膨胀源码

BOOL Dilation(HWND hWnd,BOOL Hori)



DWORD OffBits,BufSize;

LPBITMAPINFOHEADER lpImgData;

LPSTR lpPtr;

HLOCAL hTempImgData;

LPBITMAPINFOHEADER lpTempImgData;

LPSTR lpTempPtr;

HDC hDc;

HFILE hf;

LONG x,y;

unsigned char num;

int i;

//为了处理的方便,仍采用256级灰度图,不过只调色板中0和255两项

if( NumColors!=256)

MessageBox(hWnd,"Must be a mono bitmap with grayscale palette!",

"Error Message",MB_OK|MB_ICONEXCLAMATION);

return FALSE;



OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);

//BufSize为缓冲区大小

BufSize=OffBits+bi.biHeight*LineBytes;

//为新的缓冲区分配内存

if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)



MessageBox(hWnd,"Error alloc memory!","Error Message",

MB_OK|MB_ICONEXCLAMATION);

return FALSE;



lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);

lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);

//拷贝头信息和位图数据

memcpy(lpTempImgData,lpImgData,BufSize);

if(Hori)



//在水平方向进行膨胀运算

for(y=0;y<bi.biHeight;y++)

//lpPtr指向原图数据,lpTempPtr指向新图数据

lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes)+1;

lpTempPtr=(char*)lpTempImgData+

(BufSize-LineBytes-y*LineBytes)+1;

for(x=1;x<bi.biWidth-1;x++)

//注意为防止越界,x的范围从1到宽度-2

num=(unsigned char)*lpPtr;

//原图中是黑点的,新图中肯定也是,所以要考虑的是那些原图

//中的白点,看是否有可能膨胀成黑点

if (num==255)

*lpTempPtr=(unsigned char)255; //先置成白点

for(i=0;i<3;i++)

num=(unsigned char)*(lpPtr+i-1);

//只要左右邻居中有一个是黑点,就膨胀成黑点

if(num==0)

*lpTempPtr=(unsigned char)0;

break;







//原图中就是黑点的,新图中仍是黑点

else *lpTempPtr=(unsigned char)0;

//指向下一个象素

lpPtr++;

lpTempPtr++;







else

//在垂直方向进行腐蚀运算

for(y=1;y<bi.biHeight-1;y++) //注意为防止越界,y的范围从1到高度-2

lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes);

lpTempPtr=(char *)lpTempImgData+(BufSize-LineBytes-y*LineBytes);

for(x=0;x<bi.biWidth;x++)

num=(unsigned char)*lpPtr;

if (num==255)

*lpTempPtr=(unsigned char)255;

for(i=0;i<3;i++)

num=(unsigned char)*(lpPtr+(i-1)*LineBytes);

//只要上下邻居中有一个是黑点,就膨胀成黑点

if(num==0)

*lpTempPtr=(unsigned char)0;

break;







else *lpTempPtr=(unsigned char)0;

lpPtr++;

lpTempPtr++;







if(hBitmap!=NULL)

DeleteObject(hBitmap);

hDc=GetDC(hWnd);

//产生新的位图

hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,

(LONG)CBM_INIT,

(LPSTR)lpTempImgData+

sizeof(BITMAPINFOHEADER)+

NumColors*sizeof(RGBQUAD),

(LPBITMAPINFO)lpTempImgData,

DIB_RGB_COLORS);

//起不同的结果文件名

if(Hori)

hf=_lcreat("c:\\hdilation.bmp",0);

else

hf=_lcreat("c:\\vdilation.bmp",0);

_lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));

_lwrite(hf,(LPSTR)lpTempImgData,BufSize);

_lclose(hf);

//释放内存及资源

ReleaseDC(hWnd,hDc);

LocalUnlock(hTempImgData);

LocalFree(hTempImgData);

GlobalUnlock(hImgData);

return TRUE;



腐蚀源码

BOOL Erosion(HWND hWnd,BOOL Hori)



DWORD OffBits,BufSize;

LPBITMAPINFOHEADER lpImgData;

LPSTR lpPtr;

HLOCAL hTempImgData;

LPBITMAPINFOHEADER lpTempImgData;

LPSTR lpTempPtr;

HDC hDc;

HFILE hf;

LONG x,y;

unsigned char num;

int i;

//为了处理方便,仍采用256级灰度图,不过只用调色板中0和255两项

if( NumColors!=256)

MessageBox(hWnd,"Must be a mono bitmap with grayscale palette!",

"Error Message",MB_OK|MB_ICONEXCLAMATION);

return FALSE;



OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);

//BufSize为缓冲区大小

BufSize=OffBits+bi.biHeight*LineBytes;

//为新的缓冲区分配内存

if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)



MessageBox(hWnd,"Error alloc memory!","Error Message",

MB_OK|MB_ICONEXCLAMATION);

return FALSE;



lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);

lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);

//拷贝头信息和位图数据

memcpy(lpTempImgData,lpImgData,BufSize);

if(Hori)



//在水平方向进行腐蚀运算

for(y=0;y<bi.biHeight;y++)

//lpPtr指向原图数据,lpTempPtr指向新图数据

lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes)+1;

lpTempPtr=(char*)lpTempImgData+

(BufSize-LineBytes-y*LineBytes)+1;

for(x=1;x<bi.biWidth-1;x++)

//注意为防止越界,x的范围从1到宽度-2

num=(unsigned char)*lpPtr;

if (num==0) //因为腐蚀掉的是黑点,所以只对黑点处理

*lpTempPtr=(unsigned char)0; //先置成黑点

for(i=0;i<3;i++)

num=(unsigned char)*(lpPtr+i-1);

if(num==255)

//自身及上下邻居中若有一个不是黑点,则将该点腐

//蚀成白点

*lpTempPtr=(unsigned char)255;

break;







//原图中就是白点的,新图中仍是白点

else *lpTempPtr=(unsigned char)255;

//指向下一个象素

lpPtr++;

lpTempPtr++;







else

//在垂直方向进行腐蚀运算

for(y=1;y<bi.biHeight-1;y++) //注意为防止越界,y的范围从1到高度-2

//lpPtr指向原图数据,lpTempPtr指向新图数据

lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes);

lpTempPtr=(char *)lpTempImgData+(BufSize-LineBytes-y*LineBytes);

for(x=0;x<bi.biWidth;x++)

num=(unsigned char)*lpPtr;

if (num==0) //因为腐蚀掉的是黑点,所以只对黑点处理

*lpTempPtr=(unsigned char)0; //先置成黑点

for(i=0;i<3;i++)

num=(unsigned char)*(lpPtr+(i-1)*LineBytes);

if(num==255)

//自身及上下邻居中若有一个不是黑点,则将该点腐

//蚀成白点

*lpTempPtr=(unsigned char)255;

break;







//原图中就是白点的,新图中仍是白点

else *lpTempPtr=(unsigned char)255;

//指向下一个象素

lpPtr++;

lpTempPtr++;







if(hBitmap!=NULL)

DeleteObject(hBitmap);

hDc=GetDC(hWnd);

//产生新的位图

hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,

(LONG)CBM_INIT,

(LPSTR)lpTempImgData+

sizeof(BITMAPINFOHEADER)+

NumColors*sizeof(RGBQUAD),

(LPBITMAPINFO)lpTempImgData, DIB_RGB_COLORS);

//起不同的结果文件名

if(Hori)

hf=_lcreat("c:\\herosion.bmp",0);

else

hf=_lcreat("c:\\verosion.bmp",0);

_lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));

_lwrite(hf,(LPSTR)lpTempImgData,BufSize);

_lclose(hf);

//释放内存及资源

ReleaseDC(hWnd,hDc);

LocalUnlock(hTempImgData);

LocalFree(hTempImgData);

GlobalUnlock(hImgData);

return TRUE;

参考技术A 去看OPENCV的源码,不想自己实现,可以调用OPENCV的库函数。 参考技术B 想用什么软件实现?

形态学操作-腐蚀与膨胀

参考技术A 1.形态学操作
形态学操作就是基于形状的一系列图像处理操作。一般情况下对二值化的图像进行操作。腐蚀与膨胀是最基本的形态学操作
应用:
(1)消除噪声
(2)分割(isolate)独立的图像元素,以及连接(join)相邻的元素
(3)寻找图像中的明显的极大值区域或者极小值区域
2.膨胀(最大值dilate)
此操作是将图像A与任意形状(通常为正方形或圆形)的内核B,,进行卷积。
内核B有一个可定义的 锚点, 通常定义为内核中心点。
进行膨胀操作时,将内核B划过图像,将内核B覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )

src——输入图像.
dst——输出图像.
element——用于膨胀的结构元素。若为 NULL, 则使用 3×3 长方形的结构元素
iterations——膨胀的次数
3.腐蚀(erode)
腐蚀提取的是内核覆盖下的相素最小值。进行腐蚀操作时,将内核B划过图像,将内核B覆盖区域的最小相素值提取,并代替锚点位置的相素。

src——输入图像.
dst——输出图像.
element——用于腐蚀的结构元素。若为 NULL, 则使用 3×3 长方形的结构元素
iterations——腐蚀的次数
4.结构元素
我们一般使用函数 getStructuringElement配合膨胀或腐蚀算法使用
Mat strElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3), new Point(-1, -1));
其中有三种内核形状可以选择:
矩形: MORPH_RECT
交叉形: MORPH_CROSS
椭圆形: MORPH_ELLIPSE
再指定内核大小,以及锚点位置。不指定锚点位置,则默认锚点在内核中心位置。
5.图像的开运算
开运算:先腐蚀后膨胀,移除小的对象时候很有用
6.图像的闭运算
闭运算:先膨胀后腐蚀,被用来填充前景物体中的小洞,或者抹去前景物体上的小黑点

7.梯度:膨胀与腐蚀图之差
可以用来突出边缘,可以保留物体的边缘轮廓
8.顶帽:原图与开运算结果之差
开运算放大了裂缝或者局部低亮度的区域,所以,从原图中减去开运算后的图,得到的结果突出了比原图轮廓周围的区域更明亮的区域,这个操作与选择的核的大小有关。TopHat运算一般用来分离比邻近点亮一些的斑块,可以使用这个运算提取背景
9.黑帽运算:闭运算的结果与原图之差
黑帽运算的结果突出了比原图轮廓周围区域更暗的区域,所以黑帽运算用来分离比邻近点暗一些的斑块。

参考: https://www.jianshu.com/p/6147d69c879f

以上是关于如何进行数字图像处理中的膨胀和腐蚀计算的主要内容,如果未能解决你的问题,请参考以下文章

数字图像处理图像开运算与闭运算

数字图像处理:形态学操作腐蚀膨胀开运算闭运算

图像开运算和闭运算

图像的腐蚀与膨胀

膨胀和腐蚀 - 解决图像缺陷问题

二值形态学——开闭运算