基于指纹细化有一种算法叫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>