形态学细化指纹图像

        基于指纹细化有一种算法叫OPTA(one-pass thinning algorithm),基于该算法有些缺点,如毛刺较多。所以有一种基于形态学的细化算法。

       一个好的细化算法应该遵守如下一些要求:收敛性、连通性、拓扑性、保持性、细化性、中轴性和快速性。

收敛性:迭代必须是收敛的;

连通性:不破坏纹线的连接性;

拓扑性:保持原图像的基本结构特性;

保持性:保护指纹的细节特征;

细化性:骨架纹线的宽度为1个像素,即单像素宽;(单像素的定义:端点,连接点,分叉点在其8领域的前景点个数分别为1,2,3,其实我觉得这个定义是不对的。)

中轴性:骨架尽可能地接近条纹中心线;

快速性:算法简单,速度快。

  

        宏观的总结一句话:形态学细化就是在不是端点的边界处的点才能删除,删除后如果不改变拓扑结构和连通性就可以删除

        

简单列举了8邻域的几种情况

(1)不可以删除,不是边界点。

(2)不可以删除,不是边界点。

(3)可以删除,是边界点,左边界的点且删除后不改变拓扑性和连通性。

(4)不可以删除,删除后改变了连通性。

(5)可以删除,是边界点,是左边界和下边界的点且删除后不改变拓扑行和连通性。

(6)不可以删除,是端点

     那我们就一次从上下左右4个方向依次对图像进行细化,直到每个方向都细化完成后那么整幅指纹就细化完成了。

 

<span style="font-family:Microsoft YaHei;font-size:18px;">void Thinning()
{
	IplImage* pMark = cvCreateImage(cvGetSize(m_pSkelImage), IPL_DEPTH_8U, 1);
	cvSetZero(pMark);

	for(int i = 0; i < 4; i++)
		no_more[i] = 0;

	int thin_dir = UP;
	while(!(no_more[0] && no_more[1] && no_more[2] && no_more[3]))
	{
		if(!no_more[thin_dir])
			thin(m_pSkelImage, thin_dir, pMark);
		thin_dir = next_thin_dir(thin_dir);
	}

	cvReleaseImage(&pMark);
}

// The one-pixel wide border has been set as zero.
void thin(IplImage* img, int thin_dir, IplImage* pMark)
{
	int	y, x;

	switch(thin_dir)
	{
	case DOWN :
		for(y = 1 ; y < m_iHeight - 1; y ++)
			for(x = 1; x < m_iWidth - 1; x ++)
				if(IMG(img,y,x) == 1)
					if(IMG(img,y-1,x) == 0)
						check_neighbors_8simple_down(img,pMark,y,x);
		break;
	case UP :
		for(y = 1 ; y < m_iHeight - 1; y ++)
			for(x = 1; x < m_iWidth - 1; x ++)
				if(IMG(img,y,x) == 1)
					if(IMG(img,y+1,x) == 0)
						check_neighbors_8simple_up(img,pMark,y,x);
		break;
	case LEFT :
		for(y = 1 ; y < m_iHeight - 1; y ++)
			for(x = 1; x < m_iWidth - 1; x ++)
				if(IMG(img,y,x) == 1)
					if(IMG(img,y,x+1) == 0)
						check_neighbors_8simple_left(img,pMark,y,x);
		break;
	case RIGHT :
		for(y = 1 ; y < m_iHeight - 1; y ++)
			for(x = 1; x < m_iWidth - 1; x ++)
				if(IMG(img,y,x) == 1)
					if(IMG(img,y,x-1) == 0)
						check_neighbors_8simple_right(img,pMark,y,x);
		break;
	}

	bool bChange = false;

	for(y = 1; y < m_iHeight - 1; y ++)
	{
		for(x = 1; x < m_iWidth - 1; x ++)
		{
			if(IMG(pMark,y,x) == 1)
			{
				IMG(img,y,x) = 0;
				IMG(pMark,y,x) = 0;
				bChange = true;
			}
		}
	}

	if(!bChange)
		no_more[thin_dir] = 1;
}

int next_thin_dir(int thin_dir)
{
	int next_dir;

	switch(thin_dir)
	{
	case UP :
		next_dir=LEFT;
		break;
	case RIGHT :
		next_dir=DOWN;
		break;
	case DOWN :
		next_dir=UP;
		break;
	case LEFT :
		next_dir=RIGHT;
		break;
	}
	return  next_dir;
}

void check_neighbors_8simple_down(IplImage* img, IplImage* pMark, int y, int x)
{
	int neighbors = IMG(img,y-1,x-1) + IMG(img,y-1,x+1)
		+ IMG(img,y,x+1) + IMG(img,y+1,x+1) + IMG(img,y+1,x)
		+ IMG(img,y+1,x-1) + IMG(img,y,x-1);
	if(neighbors == 1)
		return;

	if( IMG(img,y,x+1) == 0 && IMG(img,y-1,x+1) == 1 )
		return;
	if( IMG(img,y,x-1) == 0 && IMG(img,y-1,x-1) == 1 )
		return;
	if( IMG(img,y+1,x) == 0 )
		if( IMG(img,y,x+1) == 1 || IMG(img,y+1,x+1) == 1 )
			if(IMG(img,y,x-1) ==1 || IMG(img,y+1,x-1) == 1 )
				return;

	IMG(pMark,y,x) = 1;
}

void check_neighbors_8simple_up(IplImage* img, IplImage* pMark, int y, int x)
{
	int neighbors = IMG(img,y-1,x-1) + IMG(img,y-1,x+1)
		+ IMG(img,y,x+1) + IMG(img,y+1,x+1) + IMG(img,y-1,x)
		+ IMG(img,y+1,x-1) + IMG(img,y,x-1);
	if(neighbors == 1)
		return;
	if( IMG(img,y,x+1) == 0 && IMG(img,y+1,x+1) == 1 )
		return;
	if( IMG(img,y,x-1) == 0 && IMG(img,y+1,x-1) == 1 )
		return;
	if( IMG(img,y-1,x) == 0 )
		if( IMG(img,y,x+1) == 1 || IMG(img,y-1,x+1) == 1 )
			if(IMG(img,y,x-1) || IMG(img,y-1,x-1) == 1 )
				return;
	IMG(pMark,y,x) = 1;
}

void check_neighbors_8simple_left(IplImage* img, IplImage* pMark, int y, int x)
{
	int neighbors = IMG(img,y-1,x-1) + IMG(img,y-1,x+1)
		+ IMG(img,y-1,x) + IMG(img,y+1,x+1) + IMG(img,y+1,x)
		+ IMG(img,y+1,x-1) + IMG(img,y,x-1);
	if(neighbors == 1)
		return;

	if( IMG(img,y-1,x) == 0 && IMG(img,y-1,x+1) == 1 )
		return;
	if( IMG(img,y+1,x) == 0 && IMG(img,y+1,x+1) == 1 )
		return;
	if( IMG(img,y,x-1) == 0 )
		if( IMG(img,y-1,x-1) == 1 || IMG(img,y-1,x) == 1 )
			if(IMG(img,y+1,x-1) ==1 || IMG(img,y+1,x) == 1 )
				return;

	IMG(pMark,y,x) = 1;

}

void check_neighbors_8simple_right(IplImage* img, IplImage* pMark, int y, int x)
{
	int neighbors = IMG(img,y-1,x-1) + IMG(img,y-1,x+1)
		+ IMG(img,y-1,x) + IMG(img,y+1,x+1) + IMG(img,y+1,x)
		+ IMG(img,y+1,x-1) + IMG(img,y,x+1);
	if(neighbors == 1)
		return;

	if( IMG(img,y-1,x) == 0 && IMG(img,y-1,x-1) == 1 )
		return;
	if( IMG(img,y+1,x) == 0 && IMG(img,y+1,x-1) == 1 )
		return;
	if( IMG(img,y,x+1) == 0 )
		if( IMG(img,y-1,x) == 1 || IMG(img,y-1,x+1) == 1 )
			if(IMG(img,y+1,x) ==1 || IMG(img,y+1,x+1) == 1 )
				return;

	IMG(pMark,y,x) = 1;
}
</span>


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值