msvc6 数学形态学细化处理的问题 【from 何东健主编《数字图像处理》CMorphPro::ThiningDIB】为何是 “5×5相邻区域像素值”?////////////////////////////////////////////////////////////////////////
//BOOL ThiningDIB()
//----------------------------------------------------------------------
//基本功能:本函数对CDibObject对象中的图象进行细化运算。
//----------------------------------------------------------------------
//参数说明:CDibObject *pDibObject 默认为NULL。
//----------------------------------------------------------------------
//返 回:BOOL
// 成功返回TRUE,失败返回FALSE。
//----------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////
BOOL CMorphPro::ThiningDIB(CDibObject *pDibObject)
{
//使用传入的CDibObject对象
if( pDibObject != NULL ) m_pDibObject = pDibObject;
//无CDibObject对象, 返回FALSE
if( m_pDibObject == NULL ) return( FALSE );
//定义变量
unsigned char *pBuffer, *pBits;
RGBQUAD *pPalette;
int nWidthBytes, nNumColors;
int lWidth,lHeight;
//获得图像指针
pBuffer = (unsigned char *) m_pDibObject->GetDIBPointer( &nWidthBytes, m_pDibObject->GetNumBits() );
if( pBuffer == NULL ) return( NULL ); //获得颜色数
nNumColors = m_pDibObject->GetNumColors();
//获得调色板指针
pPalette = (RGBQUAD *) &pBuffer[sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)];
//获得位图数据指针
pBits = (unsigned char *) &pBuffer[sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+nNumColors*sizeof(RGBQUAD)]; lWidth=m_pDibObject->GetWidth();
lHeight=m_pDibObject->GetHeight(); /////////////////////////////////////////////////////////
// 指向源图像的指针
LPSTR lpSrc;
// 指向缓存图像的指针
LPSTR lpDst;
// 指向缓存DIB图像的指针
LPSTR lpNewDIBBits;
HLOCAL hNewDIBBits; //脏标记
BOOL bModified; //循环变量
long i;
long j;
int n;
int m; //四个条件
BOOL bCondition1;
BOOL bCondition2;
BOOL bCondition3;
BOOL bCondition4; //计数器
unsigned char nCount;
//像素值
unsigned char pixel; //5×5相邻区域像素值
unsigned char neighbour[5][5]; // 暂时分配内存,以保存新图像
hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL)
{
// 分配内存失败
return FALSE;
}
// 锁定内存
lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255
lpDst = (char *)lpNewDIBBits;
memset(lpDst, (BYTE)255, lWidth * lHeight); bModified=TRUE; while(bModified)
{ bModified = FALSE;
// 初始化新分配的内存,设定初始值为255
lpDst = (char *)lpNewDIBBits;
memset(lpDst, (BYTE)255, lWidth * lHeight); for(j = 2; j <lHeight-2; j++)
{
for(i = 2;i <lWidth-2; i++)
{ bCondition1 = FALSE;
bCondition2 = FALSE;
bCondition3 = FALSE;
bCondition4 = FALSE; //由于使用5×5的结构元素,为防止越界,所以不处理外围的几行和几列像素 // 指向源图像倒数第j行,第i个象素的指针
lpSrc = (char *)pBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针
lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型
pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值
if(pixel != 255 && *lpSrc != 0)
//return FALSE;
continue;
//如果源图像中当前点为白色,则跳过
else if(pixel == 255)
continue; //获得当前点相邻的5×5区域内像素值,白色用0代表,黑色用1代表
for (m = 0;m < 5;m++ )
{
for (n = 0;n < 5;n++)
{
neighbour[m][n] =(255 - (unsigned char)*(lpSrc + ((4 - m) - 2)*lWidth + n - 2 )) / 255;
}
}
//逐个判断条件。
//判断2<=NZ(P1)<=6
nCount = neighbour[1][1] + neighbour[1][2] + neighbour[1][3] \
+ neighbour[2][1] + neighbour[2][3] + \
+ neighbour[3][1] + neighbour[3][2] + neighbour[3][3];
if ( nCount >= 2 && nCount <=6)
bCondition1 = TRUE; //判断Z0(P1)=1
nCount = 0;
if (neighbour[1][2] == 0 && neighbour[1][1] == 1)
nCount++;
if (neighbour[1][1] == 0 && neighbour[2][1] == 1)
nCount++;
if (neighbour[2][1] == 0 && neighbour[3][1] == 1)
nCount++;
if (neighbour[3][1] == 0 && neighbour[3][2] == 1)
nCount++;
if (neighbour[3][2] == 0 && neighbour[3][3] == 1)
nCount++;
if (neighbour[3][3] == 0 && neighbour[2][3] == 1)
nCount++;
if (neighbour[2][3] == 0 && neighbour[1][3] == 1)
nCount++;
if (neighbour[1][3] == 0 && neighbour[1][2] == 1)
nCount++;
if (nCount == 1)
bCondition2 = TRUE; //判断P2*P4*P8=0 or Z0(p2)!=1
if (neighbour[1][2]*neighbour[2][1]*neighbour[2][3] == 0)
bCondition3 = TRUE;
else
{
nCount = 0;
if (neighbour[0][2] == 0 && neighbour[0][1] == 1)
nCount++;
if (neighbour[0][1] == 0 && neighbour[1][1] == 1)
nCount++;
if (neighbour[1][1] == 0 && neighbour[2][1] == 1)
nCount++;
if (neighbour[2][1] == 0 && neighbour[2][2] == 1)
nCount++;
if (neighbour[2][2] == 0 && neighbour[2][3] == 1)
nCount++;
if (neighbour[2][3] == 0 && neighbour[1][3] == 1)
nCount++;
if (neighbour[1][3] == 0 && neighbour[0][3] == 1)
nCount++;
if (neighbour[0][3] == 0 && neighbour[0][2] == 1)
nCount++;
if (nCount != 1)
bCondition3 = TRUE;
} //判断P2*P4*P6=0 or Z0(p4)!=1
if (neighbour[1][2]*neighbour[2][1]*neighbour[3][2] == 0)
bCondition4 = TRUE;
else
{
nCount = 0;
if (neighbour[1][1] == 0 && neighbour[1][0] == 1)
nCount++;
if (neighbour[1][0] == 0 && neighbour[2][0] == 1)
nCount++;
if (neighbour[2][0] == 0 && neighbour[3][0] == 1)
nCount++;
if (neighbour[3][0] == 0 && neighbour[3][1] == 1)
nCount++;
if (neighbour[3][1] == 0 && neighbour[3][2] == 1)
nCount++;
if (neighbour[3][2] == 0 && neighbour[2][2] == 1)
nCount++;
if (neighbour[2][2] == 0 && neighbour[1][2] == 1)
nCount++;
if (neighbour[1][2] == 0 && neighbour[1][1] == 1)
nCount++;
if (nCount != 1)
bCondition4 = TRUE;
}
if(bCondition1 && bCondition2 && bCondition3 && bCondition4)
{
*lpDst = (unsigned char)255;
bModified = TRUE;
}
else
{
*lpDst = (unsigned char)0;
}
}
}
// 复制腐蚀后的图像
memcpy(pBits, lpNewDIBBits, lWidth * lHeight);
}
// 复制腐蚀后的图像
memcpy(pBits, lpNewDIBBits, lWidth * lHeight); // 释放内存
LocalUnlock(hNewDIBBits);
LocalFree(hNewDIBBits); // 返回
return TRUE;
}
//BOOL ThiningDIB()
//----------------------------------------------------------------------
//基本功能:本函数对CDibObject对象中的图象进行细化运算。
//----------------------------------------------------------------------
//参数说明:CDibObject *pDibObject 默认为NULL。
//----------------------------------------------------------------------
//返 回:BOOL
// 成功返回TRUE,失败返回FALSE。
//----------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////
BOOL CMorphPro::ThiningDIB(CDibObject *pDibObject)
{
//使用传入的CDibObject对象
if( pDibObject != NULL ) m_pDibObject = pDibObject;
//无CDibObject对象, 返回FALSE
if( m_pDibObject == NULL ) return( FALSE );
//定义变量
unsigned char *pBuffer, *pBits;
RGBQUAD *pPalette;
int nWidthBytes, nNumColors;
int lWidth,lHeight;
//获得图像指针
pBuffer = (unsigned char *) m_pDibObject->GetDIBPointer( &nWidthBytes, m_pDibObject->GetNumBits() );
if( pBuffer == NULL ) return( NULL ); //获得颜色数
nNumColors = m_pDibObject->GetNumColors();
//获得调色板指针
pPalette = (RGBQUAD *) &pBuffer[sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)];
//获得位图数据指针
pBits = (unsigned char *) &pBuffer[sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+nNumColors*sizeof(RGBQUAD)]; lWidth=m_pDibObject->GetWidth();
lHeight=m_pDibObject->GetHeight(); /////////////////////////////////////////////////////////
// 指向源图像的指针
LPSTR lpSrc;
// 指向缓存图像的指针
LPSTR lpDst;
// 指向缓存DIB图像的指针
LPSTR lpNewDIBBits;
HLOCAL hNewDIBBits; //脏标记
BOOL bModified; //循环变量
long i;
long j;
int n;
int m; //四个条件
BOOL bCondition1;
BOOL bCondition2;
BOOL bCondition3;
BOOL bCondition4; //计数器
unsigned char nCount;
//像素值
unsigned char pixel; //5×5相邻区域像素值
unsigned char neighbour[5][5]; // 暂时分配内存,以保存新图像
hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL)
{
// 分配内存失败
return FALSE;
}
// 锁定内存
lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255
lpDst = (char *)lpNewDIBBits;
memset(lpDst, (BYTE)255, lWidth * lHeight); bModified=TRUE; while(bModified)
{ bModified = FALSE;
// 初始化新分配的内存,设定初始值为255
lpDst = (char *)lpNewDIBBits;
memset(lpDst, (BYTE)255, lWidth * lHeight); for(j = 2; j <lHeight-2; j++)
{
for(i = 2;i <lWidth-2; i++)
{ bCondition1 = FALSE;
bCondition2 = FALSE;
bCondition3 = FALSE;
bCondition4 = FALSE; //由于使用5×5的结构元素,为防止越界,所以不处理外围的几行和几列像素 // 指向源图像倒数第j行,第i个象素的指针
lpSrc = (char *)pBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针
lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型
pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值
if(pixel != 255 && *lpSrc != 0)
//return FALSE;
continue;
//如果源图像中当前点为白色,则跳过
else if(pixel == 255)
continue; //获得当前点相邻的5×5区域内像素值,白色用0代表,黑色用1代表
for (m = 0;m < 5;m++ )
{
for (n = 0;n < 5;n++)
{
neighbour[m][n] =(255 - (unsigned char)*(lpSrc + ((4 - m) - 2)*lWidth + n - 2 )) / 255;
}
}
//逐个判断条件。
//判断2<=NZ(P1)<=6
nCount = neighbour[1][1] + neighbour[1][2] + neighbour[1][3] \
+ neighbour[2][1] + neighbour[2][3] + \
+ neighbour[3][1] + neighbour[3][2] + neighbour[3][3];
if ( nCount >= 2 && nCount <=6)
bCondition1 = TRUE; //判断Z0(P1)=1
nCount = 0;
if (neighbour[1][2] == 0 && neighbour[1][1] == 1)
nCount++;
if (neighbour[1][1] == 0 && neighbour[2][1] == 1)
nCount++;
if (neighbour[2][1] == 0 && neighbour[3][1] == 1)
nCount++;
if (neighbour[3][1] == 0 && neighbour[3][2] == 1)
nCount++;
if (neighbour[3][2] == 0 && neighbour[3][3] == 1)
nCount++;
if (neighbour[3][3] == 0 && neighbour[2][3] == 1)
nCount++;
if (neighbour[2][3] == 0 && neighbour[1][3] == 1)
nCount++;
if (neighbour[1][3] == 0 && neighbour[1][2] == 1)
nCount++;
if (nCount == 1)
bCondition2 = TRUE; //判断P2*P4*P8=0 or Z0(p2)!=1
if (neighbour[1][2]*neighbour[2][1]*neighbour[2][3] == 0)
bCondition3 = TRUE;
else
{
nCount = 0;
if (neighbour[0][2] == 0 && neighbour[0][1] == 1)
nCount++;
if (neighbour[0][1] == 0 && neighbour[1][1] == 1)
nCount++;
if (neighbour[1][1] == 0 && neighbour[2][1] == 1)
nCount++;
if (neighbour[2][1] == 0 && neighbour[2][2] == 1)
nCount++;
if (neighbour[2][2] == 0 && neighbour[2][3] == 1)
nCount++;
if (neighbour[2][3] == 0 && neighbour[1][3] == 1)
nCount++;
if (neighbour[1][3] == 0 && neighbour[0][3] == 1)
nCount++;
if (neighbour[0][3] == 0 && neighbour[0][2] == 1)
nCount++;
if (nCount != 1)
bCondition3 = TRUE;
} //判断P2*P4*P6=0 or Z0(p4)!=1
if (neighbour[1][2]*neighbour[2][1]*neighbour[3][2] == 0)
bCondition4 = TRUE;
else
{
nCount = 0;
if (neighbour[1][1] == 0 && neighbour[1][0] == 1)
nCount++;
if (neighbour[1][0] == 0 && neighbour[2][0] == 1)
nCount++;
if (neighbour[2][0] == 0 && neighbour[3][0] == 1)
nCount++;
if (neighbour[3][0] == 0 && neighbour[3][1] == 1)
nCount++;
if (neighbour[3][1] == 0 && neighbour[3][2] == 1)
nCount++;
if (neighbour[3][2] == 0 && neighbour[2][2] == 1)
nCount++;
if (neighbour[2][2] == 0 && neighbour[1][2] == 1)
nCount++;
if (neighbour[1][2] == 0 && neighbour[1][1] == 1)
nCount++;
if (nCount != 1)
bCondition4 = TRUE;
}
if(bCondition1 && bCondition2 && bCondition3 && bCondition4)
{
*lpDst = (unsigned char)255;
bModified = TRUE;
}
else
{
*lpDst = (unsigned char)0;
}
}
}
// 复制腐蚀后的图像
memcpy(pBits, lpNewDIBBits, lWidth * lHeight);
}
// 复制腐蚀后的图像
memcpy(pBits, lpNewDIBBits, lWidth * lHeight); // 释放内存
LocalUnlock(hNewDIBBits);
LocalFree(hNewDIBBits); // 返回
return TRUE;
}
Sub M__Replace(FindText, RepaceText) With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = FindText
.Replacement.Text = RepaceText
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchByte = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceAll
End WithEnd SubSub M__FormatC()
'tab
M__Replace " ", " "
M__Replace "^t", " "
'+-*/=<>
'()[]{}
M__Replace "(", " ( "
M__Replace ")", " ) "
M__Replace "[", " [ "
M__Replace "]", " ] "
M__Replace "{", " { "
M__Replace "}", " } "
',.;:
M__Replace ",", " , "
M__Replace ";", " ; "
'space
For lngI = 1 To 10
M__Replace " ", " "
Next
'line
M__Replace " ^p", "^p"
M__Replace "^p ", "^p"
For lngI = 1 To 10
M__Replace "^p^p", "^p"
Next
'Alt + F8
End Sub
//int CAreaPro::_Thin_LV( )
//----------------------------------------------------------------------
//基本功能:细化算法 吕凤军
// Copy 数字图象处理编程入门 吕凤军 编
//----------------------------------------------------------------------
//参数说明:
//----------------------------------------------------------------------
//返 回:
//----------------------------------------------------------------------
//注 意:taylor
////////////////////////////////////////////////////////////////////////
int CAreaPro::_Thin_LV()
{
//变量定义
int nX, nY;
unsigned char * pTemp; int nChanged; // 1 改 0 未改
int nStep; // 步骤
CString CStrStep;
// 8连通邻居,低位到高位排列
// 0 1 2
// 3 - 4
// 5 6 7
int nEeraseID;
int nEeraseTable [ 256 ] = // 1 删 0 不删
{
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 0, 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,
1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0,
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0
}; // 细化算法
nStep = -1 ;
do
{
nChanged = 0;
nStep ++ ;
for ( nY = 1 ; nY < _nYHeight - 1 ; nY++ )
{
//数据指针定位到图像数据每行的起始零位置
pTemp =_p256g + ( ( _nYHeight - 1 - nY ) * _nWidthBytes );
for ( nX = 1 ; nX < _nXWidth - 1 ; nX++ )
{
if ( pTemp[ nX ] == 0 )
{
nEeraseID =
_Thin_LV_Get1 ( pTemp[ nX + _nWidthBytes - 1 ] ) +
_Thin_LV_Get1 ( pTemp[ nX + _nWidthBytes ] ) * 2 +
_Thin_LV_Get1 ( pTemp[ nX + _nWidthBytes + 1 ] ) * 4 +
_Thin_LV_Get1 ( pTemp[ nX - 1 ] ) * 8 +
_Thin_LV_Get1 ( pTemp[ nX + 1 ] ) * 16 +
_Thin_LV_Get1 ( pTemp[ nX - _nWidthBytes - 1 ] ) * 32 +
_Thin_LV_Get1 ( pTemp[ nX - _nWidthBytes ] ) * 64 +
_Thin_LV_Get1 ( pTemp[ nX - _nWidthBytes + 1 ] ) * 128 ;
if ( nEeraseTable[ nEeraseID ] == 1 )
{
nChanged = 1;
pTemp[ nX ] = 255;
}
}
}
}
} while ( nChanged == 1 && nStep < 50 ); // 显示步骤
CStrStep.Format( "%d" , nStep );
AfxMessageBox( ( LPCTSTR ) CStrStep ); return 1;
}////////////////////////////////////////////////////////////////////////
//int CAreaPro::_Thin_LV_Get1(int nP127255)
//----------------------------------------------------------------------
//基本功能:细化算法 吕凤军 点变换 127 = 1, 255 = 1, other = 0
// Copy 数字图象处理编程入门 吕凤军 编
//----------------------------------------------------------------------
//参数说明:
//----------------------------------------------------------------------
//返 回:
//----------------------------------------------------------------------
//注 意:taylor
////////////////////////////////////////////////////////////////////////
int CAreaPro::_Thin_LV_Get1(int nP127255)
{
if ( nP127255 == 127 || nP127255 == 255 ) return 1;
return 0;
}
【作者】 王业琳. 宁新宝. 尹义龙.
【刊名】 南京大学学报(自然科学版) 2003年04期 编辑部Email
《中文核心期刊要目总览》来源期刊 “中国期刊方阵”入选期刊 ASPT来源刊 CJFD收录期刊
【机构】 南京大学电子科学与工程系. 山东大学计算机科学与技术学院 南京. 210093 . 济南. 250100.
【关键词】 指纹. 图像细化. 单像素宽. 模板.
【聚类检索】 同类文献 引用文献 被引用文献
【摘要】 对指纹图像的细化算法进行了较深入的研究,分析了两种常用的细化算法——快速细化算法和改进的OPTA算法各自的优缺点,针对这两种算法的不足,分析其产生的原因,并且在第二种算法的基础上,重新构建了细化模板,提出了一种新的细化算法。经过实验证明,该算法能够很好的满足细化的要求,细化完全彻底,细化以后的指纹骨架在纹线中心线,并保持了纹线原有的拓外结构和细节特征,而且光滑无毛刺,运算速度也很快。