形态学的击中和击不中是形状检测的基本工具。
其基本原理为:(集合X为原二值化图像的像素集合,对X取反求得~X(非X, Y表示), 选择的结构元为s1, 对结构元s1取反的结构元为s2)
首先对用s1对X进行腐蚀得到A1,, 用s2对Y(即~X)进行腐蚀得到A2。最终结果C = A1 & A2。
对本次的样例图片,我们选取以下的结构元s1:
文章图片
0 0 1 0 0
0 0 1 0 0
1 1 1 1 1
0 0 1 0 0
0 0 1 0 0
文章图片
对其取反后的结构元s2为:
1 1 0 1 1
1 1 0 1 1
0 0 0 0 0
1 1 0 1 1
1 1 0 1 1
文章图片
我们要做就是用s1腐蚀原图像X, 用s2去腐蚀对X取反的图像Y,然后对2个最终的结果相与即可。
公式为:
文章图片
文章图片
代码如下:其中m_dib为打开的bmp图像,m_dib.GetBits()为获得图像的像素
void CImgDoc::OnHit()
{
if( m_dib.IsValid() )
{
intwidth = m_dib.GetWidth();
intheight = m_dib.GetHeight();
intpitch = ( width*8+31)/32*4;
//步长unsigned char* bufNotImg = new unsigned char[height*pitch];
//原图像的反
unsigned char* bufErodeImg = new unsigned char[height*pitch];
//定义好的结构元腐蚀原图像
unsigned char* bufErodeNotImg = new unsigned char[height*pitch];
//取反的结构元腐蚀取反的原图像
unsigned char* bufRes = new unsigned char[height*pitch];
//击中击不中目标图像//初始化
memset(bufNotImg, 0x00, height*pitch);
memset(bufErodeImg, 0x00, height*pitch);
memset(bufErodeNotImg, 0x00, height*pitch);
memset(bufRes, 0x00, height*pitch);
//定义的腐蚀结构元
//0 0 1 0 0
//0 0 1 0 0
//1 1 1 1 1
//0 0 1 0 0
//0 0 1 0 0
Pt s1[9];
s1[0].x = 0;
s1[0].y = -2;
s1[1].x = 0;
s1[1].y = -1;
s1[2].x = 0;
s1[2].y = 0;
s1[3].x = 0;
s1[3].y = 1;
s1[4].x = 0;
s1[4].y = 2;
s1[5].x = -2;
s1[5].y = 0;
s1[6].x = -1;
s1[6].y = 0;
s1[7].x = 1;
s1[7].y = 0;
s1[8].x = 2;
s1[8].y = 0;
//将上面的结构元取反,共16个,比较戳的写法,将最中间的点设为原点,其余点即为相对于原点的坐标
Pt s2[16];
s2[0].x = -2;
s2[0].y = -2;
s2[1].x = -1;
s2[1].y = -2;
s2[2].x = 1;
s2[2].y = -2;
s2[3].x = 2;
s2[3].y = -2;
s2[4].x = -2;
s2[4].y = -1;
s2[5].x = -1;
s2[5].y = -1;
s2[6].x = 1;
s2[6].y = -1;
s2[7].x = 2;
s2[7].y = -1;
s2[8].x = -2;
s2[8].y = 1;
s2[9].x = -1;
s2[9].y = 1;
s2[10].x = 1;
s2[10].y = 1;
s2[11].x = 2;
s2[11].y = 1;
s2[12].x = -2;
s2[12].y = 2;
s2[13].x = -1;
s2[13].y = 2;
s2[14].x = 1;
s2[14].y = 2;
s2[15].x = 2;
s2[15].y = 2;
//1、求取反的图像
for(int y = 0;
y < height;
y ++)
{
for(int x = 0;
x < width;
x ++)
{
if(m_dib.GetBits()[y*pitch+x])
bufNotImg[y*pitch+x] = 0x0;
else bufNotImg[y*pitch+x] = 0xFF;
}}//2、经过结构元s1的源图像的腐蚀
//参数:原图像的缓冲区像素,宽度,高度,步长,目标腐蚀图像缓冲区,目标图像步长,结构元,结构元点数
Erode(m_dib.GetBits()+2*pitch+4, width-4, height-4, pitch,
bufErodeImg, pitch, s1, 9);
//3、经过结构元的反s2的源图像的反图像的腐蚀
Erode(bufNotImg+2*pitch+4, width-4, height-4, pitch,
bufErodeNotImg, pitch, s2, 16);
//4、经过求第3步的bufErodeImg和第4步的bufErodeNotImg求与
for(int y = 0;
y < height;
y ++)
for(int x = 0;
x
【【Digital|数字图像处理入门(一) 击中击不中】
腐蚀的方法如下:(方法略戳,勿喷)
void Erode( const unsigned char* srcBuf, int w, int h, int pitch,
unsigned char* dstBuf, int dstPitch, Pt pt[], int nCount )
{
for( int y = 0;
y < h;
y++ )
{
for( int x = 0;
x < w;
x++)
{
int n = 0;
for( int i = 0;
i < nCount;
i++ )
{
if( srcBuf[(y+pt[i].y)*pitch+(x+pt[i].x)] )
n++;
}
if( n == nCount )
dstBuf[y*dstPitch+x] = 0xFF;
}
}
}
推荐阅读
- FaceSDK|FSDK_LoadImageFromBuffer
- Image|LOG斑点检测
- 移动端AI|Android JNI OpenCV ROI问题探究
- Machine|Gabor滤波器与特征提取
- 移动端AI|kpu.h文件研究(完善中)
- image|Camera Binning Mode