如何进行数字图像处理中的膨胀和腐蚀计算
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何进行数字图像处理中的膨胀和腐蚀计算相关的知识,希望对你有一定的参考价值。
腐蚀的算法:用3x3的结构元素,扫描图像的每一个像素
用结构元素与其覆盖的二值图像做“与”操作
如果都为1,结果图像的该像素为1。否则为0。
结果:使二值图像减小一圈
定义:E = B S = x,y | SxyB
膨胀的算法:
用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
以上是关于如何进行数字图像处理中的膨胀和腐蚀计算的主要内容,如果未能解决你的问题,请参考以下文章