我现在要求二值图像的连通区域的面积,找了一段程序,但是关键步骤没看懂,大侠们,谁帮忙解释一下,主要是讲解清楚当第一次扫描图像找出所有的等价对以后,如何找出所有的映射关系并重新映射。有懂的大侠们,一定要帮小弟给解释一下啊,搞了好久了,已经浪费了好长时间了,着急上火的,嘴都起泡了大侠们,小弟先谢谢了!如果分数低,可以追加!
以下是代码:void CMipView::OnProcess1() 
{

/*受篇幅限制以上省略了,寻找等价对的过程,以下是分析等价对,寻找等价关系的过程*/
/********************* 主要是以下代码看不懂,希望大侠们帮忙分析,讲讲这个理论知识 ********************/// 定义双层链表的外层链表,它的元素是一个指向内层链表的指针。
// 内层链表的型别也是CptrList,其元素是标记值。 
CPtrList exList;
CPtrList * pInnerList;
POSITION posExElem; if ( lEqualMark.GetCount() !=0 )
{
// pInnerListAdd,每次向exList中添加的新元素
CPtrList * pInnerListAdd=new CPtrList;     
ASSERT ( pInnerListAdd != NULL ); // 添加第一个等价对到exList的第一个元素所指向的InnerList中。  
pInnerListAdd->AddTail( (void *)lEqualMark.GetHead().MarkValue1);
pInnerListAdd->AddTail( (void *)lEqualMark.GetHead().MarkValue2);
exList.AddTail( (void *)pInnerListAdd );
lEqualMark.RemoveHead();

//定义pFindValue1和pFindValue2, 存放在所有内层链表中找到特定值
//的某个内层链表的头指针,也就是外层链表的某个元素值。 
CPtrList * pFindValue1=NULL;
CPtrList * pFindValue2=NULL; //整理剩余的等价对
while ( !lEqualMark.IsEmpty() )
{
posExElem=exList.GetHeadPosition();
pFindValue1=NULL;
pFindValue2=NULL; while ( posExElem )
{
pInnerList=(CPtrList *)exList.GetAt(posExElem);
if ( pInnerList->Find( (void *)lEqualMark.GetHead().MarkValue1) )
{
pFindValue1=pInnerList;
}
if( pInnerList->Find( (void *)lEqualMark.GetHead().MarkValue2) ) 
{
pFindValue2=pInnerList;
}
exList.GetNext(posExElem);
} //该等价对中两个值都在已经整理过的等价关系中
if ( pFindValue1 && pFindValue2 )
{
//当两个地址不一样时,对链表进行调整
if ( pFindValue1!=pFindValue2 )
{
pFindValue1->AddTail(pFindValue2);
//清除链表元素,通过new得到的CptrList 类型,
//必须采用delete进行删除,否则会造成内存泄露。
POSITION posDelete = exList.Find((void *)pFindValue2);
pFindValue2->RemoveAll();
delete pFindValue2;
exList.RemoveAt( posDelete );
}
}
//只在已经整理过的等价关系中找到Value1,
//那么将Vaule2加到Value1所在的链表中。 
else if ( pFindValue1 )
{
pFindValue1->AddTail((void *)lEqualMark.GetHead().MarkValue2 );
}
else if ( pFindValue2)
{
pFindValue2->AddTail( (void *)lEqualMark.GetHead().MarkValue1 );
}
//等价对中两个值在整理过的等价关系中都
//没有找到,则在exList中增加新元素。 
else
{
CPtrList * pInnerListAdd=new CPtrList;
pInnerListAdd->AddTail( (void *)lEqualMark.GetHead().MarkValue1 );
pInnerListAdd->AddTail( (void *)lEqualMark.GetHead().MarkValue2 );
exList.AddTail((void *)pInnerListAdd);
}
//去掉此时等价对的头元素
lEqualMark.RemoveHead(); 
}  // while ( !lEqualMark.IsEmpty() )循环结束
}  // if ( lEqualMark.GetCount() !=0 )语句结束
// 等价对链表大小为0,说明第一次扫描之后没有产生等价对,标记已经完成。 
// else   
// {return TRUE; } //等价关系整理完成,下面建立第一次扫描的标记值和
//第二次扫描的标记值之间的映射关系。 int nTotalEqualNum=0; //列入等价关系的标记个数
int nMarkRegion=0;   //图像中连通区域个数 posExElem=exList.GetHeadPosition();
while ( posExElem )
{
pInnerList=(CPtrList *)exList.GetAt(posExElem);
nTotalEqualNum += pInnerList->GetCount();
exList.GetNext(posExElem);
}
nMarkRegion=nMaxMarkValue-nTotalEqualNum+exList.GetCount(); //定义第一次扫描和第二次扫描之间的映射向量,要使用vector,
//应该#include <vector>并且使用std命名空间。 
vector<MarkMapping> vMarkMap(nMaxMarkValue);  //初始化映射向量,令其做自身映射
for ( i=0;i<nMaxMarkValue;i++ )
{
vMarkMap[i].nOriginalMark=i+1;
vMarkMap[i].nMappingMark=i+1;
} POSITION posInnerElem; //InnerList中元素的位置
int nMin;              //InnerList中最小值
int nIndex=0; posExElem=exList.GetHeadPosition();
//while循环实现了如下功能:找到每个等价组中最小的标记值,
//然后将映射向量中nMappingMark设定为其所在等价组的最小的标记值。
while ( posExElem )
{
pInnerList=(CPtrList *)exList.GetAt(posExElem);
nMin=(int)pInnerList->GetHead();
posInnerElem=pInnerList->GetHeadPosition();
pInnerList->GetNext(posInnerElem); while ( posInnerElem )
{
if ( (int)pInnerList->GetAt(posInnerElem)<nMin )
{
nMin=(int)pInnerList->GetAt(posInnerElem);
}
pInnerList->GetNext(posInnerElem);
} //根据每组等价关系中的最小的标记值对Mapping向量做出调整。
posInnerElem=pInnerList->GetHeadPosition();
while ( posInnerElem )
{
nIndex=(int)pInnerList->GetAt(posInnerElem)-1;
vMarkMap[ nIndex ].nMappingMark=nMin;
pInnerList->GetNext(posInnerElem);
}
exList.GetNext(posExElem);
} // 将映射向量nMappingMark中不重复的部分找出并对其进行排序。
//使用find()和sort()这两种泛型算法,应该#include <algorithm>。
vector <int> vSortMark(nMarkRegion); //排序向量
nIndex=0; for ( i=0; i<nMaxMarkValue; i++ )
{
if  ( find( vSortMark.begin(),vSortMark.end(), vMarkMap[i].nMappingMark )
==vSortMark.end() )
{
vSortMark[nIndex++]= vMarkMap[i].nMappingMark;
}
}
sort ( vSortMark.begin(),vSortMark.end() ); //根据排序后的标记在vSortMark向量中的位置,对映射向量做出重新调整。 
vector<int>::iterator itFind;
vector<int>::iterator itBegin;
itBegin=vSortMark.begin(); for ( i=0;i<nMaxMarkValue;i++ )
{
itFind = find ( vSortMark.begin(),vSortMark.end(), vMarkMap[i].nMappingMark );
vMarkMap[i].nMappingMark= ( itFind-itBegin + 1);
} //根据映射向量对标记数组进行调整
for ( j=0;j<m_lngHeight;j++ )
{
m_lpnMarkMove=m_lpnMark + j*m_lngWidthBytes;
for ( i=0;i<m_lngWidth;i++ )
{
if ( *m_lpnMarkMove != 0 )
{
*m_lpnMarkMove = vMarkMap[ *m_lpnMarkMove-1 ].nMappingMark;
}
m_lpnMarkMove++;
}
} //删除链表结构中通过new得到的元素
posExElem = exList.GetHeadPosition();
while( posExElem )
{
pInnerList = (CPtrList *)exList.GetAt( posExElem );
pInnerList->RemoveAll();
delete pInnerList;
exList.GetNext( posExElem );
}
exList.RemoveAll(); m_lpnMarkMove = m_lpnMark;
m_lpImgBitsMove = m_lpImgBits; unsigned long MaxPoNum;
MaxPoNum = (unsigned long) m_lngWidth*m_lngHeight/nMarkRegion+0.5;
//记录连通区域的几何特征 tagAREA *lpAREA,*lpAREAMove; 
lpAREA = new tagAREA[nMarkRegion];
lpAREAMove = lpAREA;
// nMarkValue = 1; 
unsigned long ASize;int n=0;
POINT PositionXY;
for(m=1;m<=nMarkRegion;m++)
{
m_lpnMarkMove = m_lpnMark;
lpAREAMove->id = m;
lpAREAMove->flag = TRUE;
n=0;
for(i=0;i<m_lngHeight;i++)
{
for(j=0;j<m_lngWidth;j++)
{
if(*m_lpnMarkMove == m)
{
PositionXY.x=i;
PositionXY.y=j;
lpAREAMove->points.push_back(PositionXY);
// lpAREAMove->points[n].y = j;
// n++;
}
m_lpnMarkMove++;
}
}
lpAREAMove++;
}
ASize = lpAREA->points.size(); //通过类成员变量来记录连通区域的个数
m_nMarkNumbers = nMarkRegion; char msg[256];
sprintf(msg,"一共有%d个连通域,第一个连通域面积为%d",m_nMarkNumbers,ASize);
MessageBox(msg);/* if( pDoc->m_hDibProc != NULL )
{
::GlobalFree((HGLOBAL)pDoc->m_hDibProc);
} // 在此处调用你的处理函数。例如:
// (zhf 2004-11-7)
pDoc->m_hDibProc = (HDIB)::ProcFunc(hDIB); ASSERT(pDoc->m_hDibProc != NULL);
CDlgShow dlg(this);
dlg.DoModal();*/
}