基于索引表的细化算法大致是遍历被二值化图像的边缘,根据边缘点的八连通域情况查找索引表以确定该边缘点是否能够被删除。根据一些细化规则我们可以建立索引表,因此我们的主要工作就是不断地遍历边缘进行是否删除判断,直至边缘的每一个点都不能再被细化(删除)。
对于边缘点P,它的八连通域是指P点的周围的八个点,我们按如下顺序标识:
P0 | P1 | P2 |
P7 | P | P3 |
P6 | P5 | P4 |
那么这八个点的取值范围为{0,1} (1表示255)
对于这八个点的不同取值情况,按如下顺序表示的二进制的值也将有不同的取值
P7 | P6 | P5 | P4 | P3 | P2 | P1 | P0 | Sum | Delete Enable |
|
|
|
|
|
|
|
|
|
|
其中Sum的取值从0~255,Delete Enable为1表示可以删除,为0表示不能删除,这样我们就建立了一个索引表deletemark[256],算法实现如下:
/
//基于索引表的细化算法
//功能:对图象进行细化
//参数:lpDIBBits:代表图象的一维数组
// lWidth:图象高度
// lHeight:图象宽度
// 无返回值
/
bool ThiningDIBSkeleton (unsigned char* lpDIBBits, int lWidth, int lHeight)
{
//循环变量
long i;
long j;
long lLength;
unsigned char deletemark[256] = {
0,0,0,0,0,0,0,1, 0,0,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,1,1,1,0,1,1,
0,0,0,0,0,0,0,0, 1,0,0,0,1,0,1,1,
0,0,0,0,0,0,0,0, 1,0,1,1,1,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 1,0,0,0,1,0,1,1,
1,0,0,0,0,0,0,0, 1,0,1,1,1,0,1,1,
0,0,1,1,0,0,1,1, 0,0,0,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,1,0,0,1,1,
1,1,0,1,0,0,0,1, 0,0,0,0,0,0,0,0,
1,1,0,1,0,0,0,1, 1,1,0,0,1,0,0,0,
0,1,1,1,0,0,1,1, 0,0,0,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,
1,1,1,1,0,0,1,1, 1,1,0,0,1,1,0,0,
1,1,1,1,0,0,1,1, 1,1,0,0,1,1,0,0
};//索引表
unsigned char p0, p1, p2, p3, p4, p5, p6, p7;
unsigned char *pmid, *pmidtemp;
unsigned char sum;
int changed;
bool bStart = true;
lLength = lWidth * lHeight;
unsigned char *pTemp = (unsigned char *)malloc(sizeof(unsigned char) * lWidth * lHeight);
// P0 P1 P2
// P7 P3
// P6 P5 P4
while(bStart)
{
bStart = false;
changed = 0;
//首先求边缘点(并行)
pmid = (unsigned char *)lpDIBBits + lWidth + 1;
memset(pTemp, 0, lLength);
pmidtemp = (unsigned char *)pTemp + lWidth + 1;
for(i = 1; i < lHeight -1; i++)
{
for(j = 1; j < lWidth - 1; j++)
{
if( *pmid == 0)
{
pmid++;
pmidtemp++;
continue;
}
p3 = *(pmid + 1);
p2 = *(pmid + 1 - lWidth);
p1 = *(pmid - lWidth);
p0 = *(pmid - lWidth -1);
p7 = *(pmid - 1);
p6 = *(pmid + lWidth - 1);
p5 = *(pmid + lWidth);
p4 = *(pmid + lWidth + 1);
sum = p0 & p1 & p2 & p3 & p4 & p5 & p6 & p7;
if(sum == 0)
{
*pmidtemp = 1;
#ifdef SHOW
cvSet2D(ColorSrc,i,j,cvScalar(0,0,255));
#endif
}
pmid++;
pmidtemp++;
}
pmid++;
pmid++;
pmidtemp++;
pmidtemp++;
}
#ifdef SHOW
cvNamedWindow("color");
cvShowImage("color",ColorSrc);
cvWaitKey(0);
#endif
//现在开始串行删除
pmid = (unsigned char *)lpDIBBits + lWidth + 1;
pmidtemp = (unsigned char *)pTemp + lWidth + 1;
for(i = 1; i < lHeight -1; i++)
{
for(j = 1; j < lWidth - 1; j++)
{
if( *pmidtemp == 0)
{
pmid++;
pmidtemp++;
continue;
}
p3 = *(pmid + 1);
p2 = *(pmid + 1 - lWidth);
p1 = *(pmid - lWidth);
p0 = *(pmid - lWidth -1);
p7 = *(pmid - 1);
p6 = *(pmid + lWidth - 1);
p5 = *(pmid + lWidth);
p4 = *(pmid + lWidth + 1);
p1 *= 2;
p2 *= 4;
p3 *= 8;
p4 *= 16;
p5 *= 32;
p6 *= 64;
p7 *= 128;
sum = p0 | p1 | p2 | p3 | p4 | p5 | p6 | p7;
// sum = p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7;
if(deletemark[sum] == 1)
{
*pmid = 0;
bStart = true;
#ifdef SHOW
cvSet2D(ColorSrc,i,j,cvScalar(0,0,0));
cvNamedWindow("delcolor");
cvShowImage("delcolor",ColorSrc);
cvWaitKey(2);
#endif
}
pmid++;
pmidtemp++;
}
pmid++;
pmid++;
pmidtemp++;
pmidtemp++;
}
#ifdef SHOW
printf("过了一圈\n");
#endif
}
return true;
}
效果如图: