数字图像处理入门(一) 击中击不中

形态学的击中和击不中是形状检测的基本工具。

其基本原理为:(集合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() )
	{
        int  width = m_dib.GetWidth();
		int  height = m_dib.GetHeight();
		int  pitch = ( 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 <width; x ++)
				bufRes[y*pitch+x] = bufErodeImg[y*pitch+x] & bufErodeNotImg[y*pitch+x];

		CDib::SaveImg8("G:\\bufNotImg.bmp", bufNotImg, width, height, pitch);
		CDib::SaveImg8("G:\\bufErodeImg.bmp", bufErodeImg, width, height, pitch);
		CDib::SaveImg8("G:\\bufErodeNotImg.bmp", bufErodeNotImg, width, height, pitch);
		CDib::SaveImg8("G:\\bufRes.bmp", bufRes, width, height, pitch);

		delete[] bufRes;
		delete[] bufErodeNotImg;
		delete[] bufErodeImg;
		delete[] bufNotImg;
	}

}


腐蚀的方法如下:(方法略戳,勿喷)
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;
		}
	}
}


你可能感兴趣的:(数字图像处理,形态学,击中击不中)