转自:http://blog.csdn.net/jiangxinyu/article/details/7999102
这里列举二值图像连通域标记算法包括直接扫描标记算法和二值图像连通域标记快速算法
一、直接扫描标记算法把连续区域作同一个标记,常见的四邻域标记算法和八邻域标记算法。
1、 四邻域标记算法:
1) 判断此点四邻域中的最左,最上有没有点,如果都没有点,则表示一个新的区域的开始。
2) 如果此点四邻域中的最左有点,最上没有点,则标记此点为最左点的值;如果此点四邻域中的最左没有点,最上有点,则标记此点为最上点的值。
3) 如果此点四邻域中的最左有点,最上都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。
2、 八邻域标记算法:
1) 判断此点八邻域中的最左,左上,最上,上右点的情况。如果都没有点,则表示一个新的区域的开始。
2) 如果此点八邻域中的最左有点,上右都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。
3) 如果此点八邻域中的左上有点,上右都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。
4) 否则按照最左,左上,最上,上右的顺序,标记此点为四个中的一个。
代码实现:
- #include <list>
- #include <vector>
- #include <algorithm>
-
- typedef struct tagMarkRegion
- {
- std::list<POINT> MarkPointList;
- RECT rect;
- }MarkRegion;
-
-
- typedef struct tagEqualMark
- { int MarkValue1;
- int MarkValue2;
- } EqualMark;
-
-
- typedef struct tagMarkMapping
- { int nOriginalMark;
- int nMappingMark;
- } MarkMapping;
-
-
-
-
-
-
-
-
-
-
-
-
- int FillAreaFlag33(LPINT I,int ImageWidth,int ImageHeight,long off,int nFlag,int iColorType,MarkRegion &markInfo)
- {
- bool bNew;
- RECT rect;
- int m,n,i,j,k,nDot=1,offset,offtemp,yMin;
- int dxy[8],x,y;
- dxy[0]=-ImageWidth-1; dxy[1]=-ImageWidth; dxy[2]=-ImageWidth+1;
- dxy[3]=-1; dxy[4]=1;
- dxy[5]=ImageWidth-1; dxy[6]=ImageWidth; dxy[7]=ImageWidth+1;
- rect.left=65535; rect.right=-1;
- rect.bottom=65535; rect.top=-1;
- markInfo.MarkPointList.clear();
- POINT ptTmp;
- if(I[off]==iColorType && I[off]!=nFlag)
- {
- I[off]=nFlag;
- x=off%ImageWidth;
- y=off/ImageWidth;
- ptTmp.x = x;
- ptTmp.y = y;
- markInfo.MarkPointList.push_back(ptTmp);
- if(x<rect.left)
- rect.left=x;
- if(x>rect.right)
- rect.right=x;
- if(y<rect.bottom)
- rect.bottom=y;
- if(y>rect.top)
- rect.top=y;
- }
- else
- {
- return 0;
- }
-
- for(i=y; i<ImageHeight; i++)
- {
- bNew=false;
- yMin=i;
- for(j=0; j<ImageWidth; j++)
- {
- offset=i*ImageWidth+j;
- if(I[offset]==nFlag)
- {
- for(k=0; k<8; k++)
- {
- if(i==0 && k<=2)
- continue;
- if(i==ImageHeight-1 && k>=5)
- continue;
- if(j==0 && (k==0 || k==3 || k==5))
- continue;
- if(j==ImageWidth-1 && (k==2 || k==4 || k==7))
- continue;
- offtemp=offset+dxy[k];
- if(I[offtemp]==iColorType && I[offtemp]!=nFlag)
- {
- I[offtemp]=nFlag;
- nDot++;
- m=offtemp/ImageWidth;
- n=offtemp%ImageWidth;
- ptTmp.x = n;
- ptTmp.y = m;
- markInfo.MarkPointList.push_back(ptTmp);
- if(n < rect.left)
- rect.left=n;
- if(n > rect.right)
- rect.right=n;
- if(m < rect.bottom)
- rect.bottom=m;
- if(m > rect.top)
- rect.top=m;
- y=offtemp/ImageWidth;
- if(y<=yMin)
- {
- yMin=y;
- if(!bNew)
- bNew=true;
- }
- }
- }
- }
- }
- if(bNew)
- {
- i=yMin-1;
- }
- }
- markInfo.rect.left = rect.left;
- markInfo.rect.right = rect.right;
- markInfo.rect.top = rect.top;
- markInfo.rect.bottom = rect.bottom;
- return nDot;
- }
-
-
-
-
-
-
-
-
-
-
-
-
- int FillAreaFlag22(LPINT I,int ImageWidth,int ImageHeight,long off,int nFlag,int iColorType,MarkRegion &markInfo)
- {
- bool bNew;
- RECT rect;
- int m,n,i,j,k,nDot=1,offset,offtemp,yMin;
- int dxy[4],x,y;
- dxy[0]=-ImageWidth; dxy[1]=1;
- dxy[2]=ImageWidth; dxy[3]=-1;
- rect.left=65535; rect.right=-1;
- rect.bottom=65535; rect.top=-1;
- markInfo.MarkPointList.clear();
- POINT ptTmp;
- if(I[off]==iColorType && I[off]!=nFlag)
- {
- I[off]=nFlag;
- x=off%ImageWidth;
- y=off/ImageWidth;
- ptTmp.x = x;
- ptTmp.y = y;
- markInfo.MarkPointList.push_back(ptTmp);
- if(x<rect.left)
- rect.left=x;
- if(x>rect.right)
- rect.right=x;
- if(y<rect.bottom)
- rect.bottom=y;
- if(y>rect.top)
- rect.top=y;
- }
- else
- {
- return 0;
- }
-
- for(i=y; i<ImageHeight; i++)
- {
- bNew=false;
- yMin=i;
- for(j=0; j<ImageWidth; j++)
- {
- offset=i*ImageWidth+j;
- if(I[offset]==nFlag)
- {
- for(k=0; k<4; k++)
- {
- if(i==0 && k==0)
- continue;
- if(i==ImageHeight-1 && k==2)
- continue;
- if(j==0 && k==3)
- continue;
- if(j==ImageWidth-1 && k==1)
- continue;
- offtemp=offset+dxy[k];
- if(I[offtemp]==iColorType && I[offtemp]!=nFlag)
- {
- I[offtemp]=nFlag;
- nDot++;
- m=offtemp/ImageWidth;
- n=offtemp%ImageWidth;
- ptTmp.x = n;
- ptTmp.y = m;
- markInfo.MarkPointList.push_back(ptTmp);
- if(n < rect.left)
- rect.left=n;
- if(n > rect.right)
- rect.right=n;
- if(m < rect.bottom)
- rect.bottom=m;
- if(m > rect.top)
- rect.top=m;
- y=offtemp/ImageWidth;
- if(y<=yMin)
- {
- yMin=y;
- if(!bNew)
- bNew=true;
- }
- }
- }
- }
- }
- if(bNew)
- {
- i=yMin-1;
- }
- }
- markInfo.rect.left = rect.left;
- markInfo.rect.right = rect.right;
- markInfo.rect.top = rect.top;
- markInfo.rect.bottom = rect.bottom;
- return nDot;
- }
-
-
- 二、二值图像连通域标记快速算法
- 算法描述
- 首先,在进行标记算法以前,利用硬件开辟独立的图像标记缓存和连通关系数组,接着在视频流的采集传输过程中,以流水线的方式按照视频传输顺序对图像进行逐行像素扫描,然后对每个像素的邻域分别按照逆时针方向和水平方向进行连通性检测和等价标记关系合并,检测出的结果对标记等价数组和标记缓存进行更新,在一帧图像采集传输结束后,得到图像的初步标记结果以及初步标记之间的连通关系,最后,根据标号对连通关系数组从小到大的传递过程进行标号的归并,利用归并后的连通关系数组对图像标记缓存中的标号进行替换,替换后的图像为最终标记结果,并且连通域按照扫描顺序被赋予唯一的连续自然数。
-
- <img src="http://img.blog.csdn.net/20130620095112281" alt="">
-
- 图 1 标记算法流程
-
- 本文快速二值图像连通域标记算法分为三个环节:
- 1.图像初步标记:为每个像素赋予临时标记,并且将临时标记的等价关系记录在等价表中
- 2.整理等价表:这一环节分为两个步骤:
- (1)将具有等价关系的临时标记全部等价为其中的最小值;
- (2)对连通区域以自然数顺序重新编号,得到临时标记与最终标记之间的等价关系。
- 3.图像代换:对图像进行逐像素代换,将临时标记代换为最终标记.经过3个环节处理后,算法输出标记后的图像,图像中连通域按照由上到下,由左至右出现的顺序被标以连续的自然数。
- 代码实现:
- #include <list>
- #include <vector>
- #include <algorithm>
-
- typedef struct tagMarkRegion
- {
- std::list<POINT> MarkPointList;
- RECT rect;
- }MarkRegion;
-
-
- typedef struct tagEqualMark
- { int MarkValue1;
- int MarkValue2;
- } EqualMark;
-
-
- typedef struct tagMarkMapping
- { int nOriginalMark;
- int nMappingMark;
- } MarkMapping;
-
-
-
-
-
-
-
-
-
-
-
- template<typename elemType> void AttachEqualMark(EqualMark &pEqualMark,elemType num1, elemType num2, int & pEqualNum, std::list< EqualMark> & plEqualMark)
- {
-
- if ( num1 < num2 )
- {
- if ( pEqualMark.MarkValue1 != num1
- || pEqualMark.MarkValue2 != num2 )
- {
- pEqualMark.MarkValue1=num1;
- pEqualMark.MarkValue2=num2;
-
- pEqualNum++;
- plEqualMark.push_back(pEqualMark);
- }
- }
-
- else
- {
- if ( pEqualMark.MarkValue2 != num1
- || pEqualMark.MarkValue1 != num2 )
- {
- pEqualMark.MarkValue1=num2;
- pEqualMark.MarkValue2=num1;
-
- pEqualNum++;
- plEqualMark.push_back(pEqualMark);
- }
- }
-
- }
-
-
-
-
-
-
-
-
-
-
- BOOL MarkImage(BYTE * lpImgBits,int & nMarkNumbers,int iColorType,long nImageWidth,long nImageHeigt,std::list< MarkRegion> &listMarkData)
- {
- BYTE * lpImgBitsMove=NULL;
- int * lpMark= NULL;
- int * lpMarkMove = NULL;
-
- long lSize = nImageWidth*nImageHeigt;
- lpMark= new int[lSize+1];
- lpMarkMove=lpMark;
- ::memset(lpMark,0,(lSize+1)*sizeof(int));
-
- int nMarkValue=1;
-
-
- int nMaxMarkValue=0;
- int i,j;
-
-
-
-
- std::list<EqualMark> lEqualMark;
-
-
- lpImgBitsMove = lpImgBits;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- int nEqualNum=0;
- EqualMark tempEqualMark;
- lpMarkMove=lpMark;
- lpImgBitsMove = lpImgBits;
-
-
-
- if ( *lpImgBitsMove==iColorType )
- {
- *lpMarkMove=nMarkValue++;
- }
- lpMarkMove++;
- lpImgBitsMove++;
-
-
- for ( i=1; i < nImageWidth; i++)
- {
-
- if ( *lpImgBitsMove==iColorType )
- {
-
- if ( *(lpMarkMove-1)==(!iColorType))
- {
- *lpMarkMove=nMarkValue++;
- }
-
- else
- {
- *lpMarkMove=*(lpMarkMove-1);
- }
- }
- lpMarkMove++;
- lpImgBitsMove++;
- }
-
-
- for ( j=1; j < nImageHeigt; j++ )
- {
- lpImgBitsMove=lpImgBits+j*nImageWidth;
- lpMarkMove=lpMark+j*nImageWidth;
-
-
-
- if ( *lpImgBitsMove==iColorType )
- {
-
- if ( *(lpMarkMove-nImageWidth)!=0 )
- {
-
- *lpMarkMove=*(lpMarkMove-nImageWidth);
- if ( *(lpMarkMove-nImageWidth)!=*(lpMarkMove-nImageWidth+1) && *(lpMarkMove-nImageWidth+1)!=0)
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-nImageWidth),*(lpMarkMove-nImageWidth+1),nEqualNum,lEqualMark);
- }
-
- }
-
- else
- {
- if ( *(lpMarkMove-nImageWidth+1)!=0 )
- {
- *lpMarkMove=*(lpMarkMove-nImageWidth+1);
- }
-
- else
- {
- *lpMarkMove=nMarkValue++;
- }
- }
- }
- lpMarkMove++;
- lpImgBitsMove++;
-
-
- for ( i=1; i<=nImageWidth-1; i++ )
- {
-
- if ( (*lpImgBitsMove)==iColorType )
- {
-
- if ( *(lpMarkMove-1)!=0 )
- {
- *lpMarkMove=*(lpMarkMove-1);
-
- if ( *(lpMarkMove-1)!=*(lpMarkMove-nImageWidth-1) && *(lpMarkMove-nImageWidth-1)!=0 )
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-1),*(lpMarkMove-nImageWidth-1),nEqualNum,lEqualMark);
- }
-
- if ( *(lpMarkMove-1)!=*(lpMarkMove-nImageWidth) && *(lpMarkMove-nImageWidth)!=0)
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-1),*(lpMarkMove-nImageWidth),nEqualNum,lEqualMark);
- }
-
- if ( *(lpMarkMove-1)!=*(lpMarkMove-nImageWidth+1) && *(lpMarkMove-nImageWidth+1)!=0)
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-1),*(lpMarkMove-nImageWidth+1),nEqualNum,lEqualMark);
- }
- }
-
- else
- {
-
- if ( *(lpMarkMove-nImageWidth-1)!=0 )
- {
- *lpMarkMove=*(lpMarkMove-nImageWidth-1);
-
- if ( *(lpMarkMove-nImageWidth-1)!=*(lpMarkMove-nImageWidth) && *(lpMarkMove-nImageWidth)!=0)
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-nImageWidth-1),*(lpMarkMove-nImageWidth),nEqualNum,lEqualMark);
- }
-
- if ( *(lpMarkMove-nImageWidth-1)!=*(lpMarkMove-nImageWidth+1) && *(lpMarkMove-nImageWidth+1)!=0)
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-nImageWidth-1),*(lpMarkMove-nImageWidth+1),nEqualNum,lEqualMark);
- }
-
-
- }
-
- else
- {
- if ( *(lpMarkMove-nImageWidth)!=0 )
- {
- *lpMarkMove=*(lpMarkMove-nImageWidth);
-
- if ( *(lpMarkMove-nImageWidth)!=*(lpMarkMove-nImageWidth+1) && *(lpMarkMove-nImageWidth+1)!=0 )
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-nImageWidth),*(lpMarkMove-nImageWidth+1),nEqualNum,lEqualMark);
- }
- }
-
- else
- {
- if (*(lpMarkMove-nImageWidth+1)!=0)
- {
- *lpMarkMove=*(lpMarkMove-nImageWidth+1);
- }
-
- else
- {
- *lpMarkMove=nMarkValue++;
- }
-
- }
- }
- }
- }
-
- lpMarkMove++;
- lpImgBitsMove++;
- }
-
-
-
-
-
- if ( (*lpImgBitsMove)==iColorType )
- {
-
- if ( *(lpMarkMove-1)!=0 )
- {
- *lpMarkMove=*(lpMarkMove-1);
-
- if ( *(lpMarkMove-1)!=*(lpMarkMove-nImageWidth-1) && *(lpMarkMove-nImageWidth-1)!=0)
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-1),*(lpMarkMove-nImageWidth-1),nEqualNum,lEqualMark);
- }
-
- if ( *(lpMarkMove-1)!=*(lpMarkMove-nImageWidth) && *(lpMarkMove-nImageWidth)!=0)
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-1),*(lpMarkMove-nImageWidth),nEqualNum,lEqualMark);
- }
-
- }
-
- else
- {
- if ( *(lpMarkMove-nImageWidth-1)!=0 )
- {
- *lpMarkMove=*(lpMarkMove-nImageWidth-1);
-
- if ( *(lpMarkMove-nImageWidth-1)!=*(lpMarkMove-nImageWidth) && *(lpMarkMove-nImageWidth)!=0)
- {
-
- AttachEqualMark(tempEqualMark,*(lpMarkMove-nImageWidth-1),*(lpMarkMove-nImageWidth),nEqualNum,lEqualMark);
- }
-
- }
-
- else
- {
- if ( *(lpMarkMove-nImageWidth)!=0 )
- {
- *lpMarkMove=*(lpMarkMove-nImageWidth);
- }
-
- else
- {
- *lpMarkMove=nMarkValue++;
- }
-
- }
- }
- }
-
- }
-
-
-
-
- nMaxMarkValue=nMarkValue-1;
-
-
-
- CPtrList exList;
- CPtrList * pInnerList;
- POSITION posExElem;
-
- if ( lEqualMark.size() !=0 )
- {
-
- CPtrList * pInnerListAdd=new CPtrList;
- ASSERT ( pInnerListAdd != NULL );
-
-
- pInnerListAdd->AddTail( (void *)lEqualMark.front().MarkValue1);
- pInnerListAdd->AddTail( (void *)lEqualMark.front().MarkValue2);
- exList.AddTail( (void *)pInnerListAdd );
- lEqualMark.pop_front();
-
-
-
- CPtrList * pFindValue1=NULL;
- CPtrList * pFindValue2=NULL;
-
-
- while ( !lEqualMark.empty() )
- {
- posExElem=exList.GetHeadPosition();
- pFindValue1=NULL;
- pFindValue2=NULL;
-
- while ( posExElem )
- {
- pInnerList=(CPtrList *)exList.GetAt(posExElem);
- if ( pInnerList->Find( (void *)lEqualMark.front().MarkValue1) )
- {
- pFindValue1=pInnerList;
- }
- if( pInnerList->Find( (void *)lEqualMark.front().MarkValue2) )
- {
- pFindValue2=pInnerList;
- }
- exList.GetNext(posExElem);
- }
-
-
- if ( pFindValue1 && pFindValue2 )
- {
-
- if ( pFindValue1!=pFindValue2 )
- {
- pFindValue1->AddTail(pFindValue2);
-
-
- POSITION posDelete = exList.Find((void *)pFindValue2);
- pFindValue2->RemoveAll();
- delete pFindValue2;
- exList.RemoveAt( posDelete );
- }
- }
-
-
- else if ( pFindValue1 )
- {
- pFindValue1->AddTail((void *)lEqualMark.front().MarkValue2 );
- }
- else if ( pFindValue2)
- {
- pFindValue2->AddTail( (void *)lEqualMark.front().MarkValue1 );
- }
-
-
- else
- {
- CPtrList * pInnerListAdd=new CPtrList;
- pInnerListAdd->AddTail( (void *)lEqualMark.front().MarkValue1 );
- pInnerListAdd->AddTail( (void *)lEqualMark.front().MarkValue2 );
- exList.AddTail((void *)pInnerListAdd);
- }
-
- lEqualMark.pop_front();
- }
- }
- else
- {
-
- int nMarkRegion=0;
-
- nMarkRegion = nMarkValue-1;
- nMarkNumbers = nMarkRegion;
- if(nMarkRegion==0)
- return FALSE;
-
- MarkRegion *pRegionData = new MarkRegion[nMarkNumbers+1];
- for (int MarkNo = 0; MarkNo<nMarkNumbers;MarkNo++)
- {
- pRegionData[MarkNo].rect.left = -1;
- pRegionData[MarkNo].rect.right = -1;
- pRegionData[MarkNo].rect.bottom = -1;
- pRegionData[MarkNo].rect.top = -1;
- pRegionData[MarkNo].MarkPointList.clear();
- }
-
- for ( j=0;j<nImageHeigt;j++ )
- {
- lpMarkMove=lpMark + j*nImageWidth;
- for ( i=0;i<nImageWidth;i++ )
- {
- if ( *lpMarkMove > 0 )
- {
- if (pRegionData[*lpMarkMove-1].rect.left == -1)
- {
- pRegionData[*lpMarkMove-1].rect.left = i;
- pRegionData[*lpMarkMove-1].rect.right = i;
- pRegionData[*lpMarkMove-1].rect.bottom = j;
- pRegionData[*lpMarkMove-1].rect.top = j;
- POINT ptInsert;
- ptInsert.x = i;
- ptInsert.y = j;
- pRegionData[*lpMarkMove-1].MarkPointList.push_back(ptInsert);
- }
- else
- {
- POINT ptInsert;
- ptInsert.x = i;
- ptInsert.y = j;
- pRegionData[*lpMarkMove-1].MarkPointList.push_back(ptInsert);
- if (pRegionData[*lpMarkMove-1].rect.left>i)
- {
- pRegionData[*lpMarkMove-1].rect.left = i;
- }
- if (pRegionData[*lpMarkMove-1].rect.right<i)
- {
- pRegionData[*lpMarkMove-1].rect.right = i;
- }
- if (pRegionData[*lpMarkMove-1].rect.top<j)
- {
- pRegionData[*lpMarkMove-1].rect.top = j;
- }
- if (pRegionData[*lpMarkMove-1].rect.bottom>j)
- {
- pRegionData[*lpMarkMove-1].rect.bottom = j;
- }
- }
- }
- lpMarkMove++;
- }
- }
- for(i=0;i<nMarkNumbers;i++)
- {
- listMarkData.push_back(pRegionData[i]);
- }
- if(pRegionData)
- {
- delete []pRegionData;
- pRegionData = NULL;
- }
- 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();
-
-
-
- std::vector<MarkMapping> vMarkMap(nMaxMarkValue);
-
-
- for ( i=0;i<nMaxMarkValue;i++ )
- {
- vMarkMap[i].nOriginalMark=i+1;
- vMarkMap[i].nMappingMark=i+1;
- }
-
- POSITION posInnerElem;
- int nMin;
- int nIndex=0;
-
- posExElem=exList.GetHeadPosition();
-
-
- 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);
- }
-
-
- posInnerElem=pInnerList->GetHeadPosition();
- while ( posInnerElem )
- {
- nIndex=(int)pInnerList->GetAt(posInnerElem)-1;
- vMarkMap[ nIndex ].nMappingMark=nMin;
- pInnerList->GetNext(posInnerElem);
- }
- exList.GetNext(posExElem);
- }
-
-
-
- std::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() );
-
-
- std::vector<int>::iterator itFind;
- std::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<nImageHeigt;j++ )
- {
- lpMarkMove=lpMark + j*nImageWidth;
- for ( i=0;i<nImageWidth;i++ )
- {
- if ( *lpMarkMove != 0 )
- {
- *lpMarkMove = vMarkMap[ *lpMarkMove-1].nMappingMark;
- }
- lpMarkMove++;
- }
- }
-
-
- posExElem = exList.GetHeadPosition();
- while( posExElem )
- {
- pInnerList = (CPtrList *)exList.GetAt( posExElem );
- pInnerList->RemoveAll();
- delete pInnerList;
- exList.GetNext( posExElem );
- }
- exList.RemoveAll();
-
-
- nMarkNumbers = nMarkRegion;
-
- if(nMarkRegion==0)
- return FALSE;
-
-
- MarkRegion *pRegionData = new MarkRegion[nMarkNumbers+1];
- for (int MarkNo = 0; MarkNo<nMarkNumbers;MarkNo++)
- {
- pRegionData[MarkNo].rect.left = -1;
- pRegionData[MarkNo].rect.right = -1;
- pRegionData[MarkNo].rect.bottom = -1;
- pRegionData[MarkNo].rect.top = -1;
- pRegionData[MarkNo].MarkPointList.clear();
- }
-
-
- for ( j=0;j<nImageHeigt;j++ )
- {
- lpMarkMove=lpMark + j*nImageWidth;
- for ( i=0;i<nImageWidth;i++ )
- {
-
-
- if ( *lpMarkMove > 0 )
- {
- if (pRegionData[*lpMarkMove-1].rect.left == -1)
- {
- pRegionData[*lpMarkMove-1].rect.left = i;
- pRegionData[*lpMarkMove-1].rect.right = i;
- pRegionData[*lpMarkMove-1].rect.bottom = j;
- pRegionData[*lpMarkMove-1].rect.top = j;
- POINT ptInsert;
- ptInsert.x = i;
- ptInsert.y = j;
- pRegionData[*lpMarkMove-1].MarkPointList.push_back(ptInsert);
- }
- else
- {
- POINT ptInsert;
- ptInsert.x = i;
- ptInsert.y = j;
- pRegionData[*lpMarkMove-1].MarkPointList.push_back(ptInsert);
- if (pRegionData[*lpMarkMove-1].rect.left>i)
- {
- pRegionData[*lpMarkMove-1].rect.left = i;
- }
- if (pRegionData[*lpMarkMove-1].rect.right<i)
- {
- pRegionData[*lpMarkMove-1].rect.right = i;
- }
- if (pRegionData[*lpMarkMove-1].rect.top>j)
- {
- pRegionData[*lpMarkMove-1].rect.top = j;
- }
- if (pRegionData[*lpMarkMove-1].rect.bottom<j)
- {
- pRegionData[*lpMarkMove-1].rect.bottom = j;
- }
- }
- }
- lpMarkMove++;
- }
- }
- for(i=0;i<nMarkNumbers;i++)
- {
- listMarkData.push_back(pRegionData[i]);
- }
- if(pRegionData)
- {
- delete []pRegionData;
- pRegionData = NULL;
- }
- return TRUE;
-
- }
http://comic.sjtu.edu.cn/thucs/GD_jsj_027y/text/chapter2/section5/part01/l1_bq2.htm
2) 种子填充算法
种子填充算法又称为边界填充算法。其基本思想是:从多边形区域的一个内点开始,由内向外用给定的颜色画点直到边界为止。如果边界是以一种颜色指定的,则种子填充算法可逐个像素地处理直到遇到边界颜色为止。
种子填充算法常用四连通域和八连通域技术进行填充操作。
从区域内任意一点出发,通过上、下、左、右四个方向到达区域内的任意像素。用这种方法填充的区域就称为四连通域;这种填充方法称为四向连通算法。
从区域内任意一点出发,通过上、下、左、右、左上、左下、右上和右下八个方向到达区域内的任意像素。用这种方法填充的区域就称为八连通域;这种填充方法称为八向连通算法。
一般来说,八向连通算法可以填充四向连通区域,而四向连通算法有时不能填充八向连通区域。例如,八向连通填充算法能够正确填充如图2.4a所示的区域的内部,而四向连通填充算法只能完成如图2.4b的部分填充。
四向连通填充算法:
a) 种子像素压入栈中;
b) 如果栈为空,则转e);否则转c);
c) 弹出一个像素,并将该像素置成填充色;并判断该像素相邻的四连通像素是否为边界色或已经置成多边形的填充色,若不是,则将该像素压入栈;
d) 转b);
e) 结束。
四向连通填充方法可以用递归函数实现如下:
算法2.3 四向连通递归填充算法:
void BoundaryFill4(int x, int y, long FilledColor, long BoundaryColor)
{
long CurrentColor;
CurrentColor = GetPixelColor(x,y);
if (CurrentColor != BoundaryColor && CurrentColor != FilledColor)
{
SetColor(FilledColor);
SetPixel (x,y);
BoundaryFill4(x+1, y, FilledColor, BoundaryColor);
BoundaryFill4(x-1, y, FilledColor, BoundaryColor);
BoundaryFill4(x, y+1, FilledColor, BoundaryColor);
BoundaryFill4(x, y-1, FilledColor, BoundaryColor);
}
}
上述算法的优点是非常简单,缺点是需要大量栈空间来存储相邻的点。一个改进的方法就是:通过沿扫描线填充水平像素段,来处理四连通或八连通相邻点,这样就仅仅只需要将每个水平像素段的起始位置压入栈,而不需要将当前位置周围尚未处理的相邻像素都压入栈,从而可以节省大量的栈空间。