基于区域生长的方法
单次扫描的算法有一种基于区域生长的连通区域标记算法,算法流程如下:
- 输入待标记图像bitmap,初始化一个与输入图像同样尺寸的标记矩阵labelmap,一个队列queue以及标记计数labelIndex;
- 从左至右、从上至下的顺序扫描bitmap,当扫描到一个未被标记的前景像素p时,labelIndex加1,并在labelmap中标记p(相应点的值赋为labelIndex),同时,扫描p的八邻域点,若存在未被标记的前景像素,则在labelmap中进行标记,并放入queue中,做为区域生长的种子;
- 当queue不为空时,从queue中取出一个生长种子点p1,扫描p1的八邻域点,若存在未被标记过的前景像素,则在labelmap中进行标记,并放入queue中;
- 重复3直至queue为空,一个连通区标记完成;
- 转到2,直至整幅图像都被扫描完毕,得到标记矩阵labelmap和联通区的个数labelIndex。
<pre name="code" class="cpp">typedef struct _IVT_QUEUE
{
IVT_POINT point;
int nIndex;
}IVT_QUEUE,*pIVT_QUEUE;
typedef struct _IVT_BLOB_
{
IVT_RECT BlobRect;
int nArea;
}IVT_BLOB;
int* m_pLabelmap = NULL;
m_pLabelmap = new int[m_nMulti];
<pre name="code" class="cpp">int ConnectedComponentROI(unsigned char* pImgData, IVT_BLOB* pBlob)
{
IVT_QUEUE *pHead,*pEnd;
int labelIndex=0,nIndex,i,cx,cy;
int nCreateBlobNum=0;
memset(m_pLabelmap, 0, m_nMulti * sizeof(int));
for (cy=1; cy<m_nHeight-1; cy++)
{
for(cx=1;cx<m_nWidth-1;cx++)
{
nIndex = cy*m_nWidth+cx;
if (pImgData[nIndex]&(!m_pLabelmap[nIndex]))
{
pEnd = pHead = m_pQueue;
m_pNewBlob->nTop = cy;
m_pNewBlob->nLeft = cx;
m_pNewBlob->nRight = cx;
m_pNewBlob->nBottom = cy;
pHead->nIndex = nIndex;
pHead->point.x = pInder->nWidth;
pHead->point.y = pInder->nHeight;
labelIndex++;
SearchNeighbor(pImgData,pHead,labelIndex, nIndex, m_pLabelmap, pEnd);
while(pHead!=pEnd)
{
SearchNeighbor(pImgData, pHead,labelIndex, m_pLabelmap, pEnd);
pHead++;;
}
if (nCreateBlobNum>999)
{
printf("BlobNum too many!\r\n");
return -1;
}
pBlob[nCreateBlobNum].BlobRect = m_pNewBlob;
nCreateBlobNum++;
}
}
nCreateBlobNum = CombineBlob(nCreateBlobNum,pBlob);
nCreateBlobNum = DeleteSmallBlob(nCreateBlobNum,pBlob);
return nCreateBlobNum;
}
void SearchNeighbor(unsigned char* pImgData,IVT_QUEUE *pQueue, int labelIndex,int* &pLabelmap,IVT_QUEUE* &pEnd)
{
int searchIndex,i;
int nCx,nCy;
pLabelmap[pQueue->nIndex] = labelIndex;
nCx = pQueue->point.x;
nCy = pQueue->point.y;
//邻域{0,1}
searchIndex = pQueue->nIndex + 1;
if ( (searchIndex>=0) && (nCx+1 <m_nWidth) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+1?m_pNewBlob->nRight:nCx+1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+1;
pEnd->point.y = nCy;
pEnd++;
}
//邻域{1,1}
searchIndex = pQueue->nIndex + m_nWidth + 1;
if ((searchIndex>=0) && (nCx+1<m_nWidth) && (nCy+1<m_nHeight) && (255 == pImgData[searchIndex]) && (!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+1?m_pNewBlob->nRight:nCx+1;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+1?m_pNewBlob->nBottom:nCy+1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+1;
pEnd->point.y = nCy+1;
pEnd++;
}
//邻域{1,0}
searchIndex = pQueue->nIndex + m_nWidth;
if ((searchIndex>=0) && (nCy+1<m_nHeight) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+1?m_pNewBlob->nBottom:nCy+1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx;
pEnd->point.y = nCy+1;
pEnd++;
}
//邻域{1,-1}
searchIndex = pQueue->nIndex + m_nWidth - 1;
if ((searchIndex>=0) && (nCx-1>=0) && (nCy+1<m_nHeight) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-1?m_pNewBlob->nLeft:nCx-1;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+1?m_pNewBlob->nBottom:nCy+1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-1;
pEnd->point.y = nCy+1;
pEnd++;
}
//邻域{0,-1}
searchIndex = pQueue->nIndex - 1;
if ((searchIndex>=0) && (nCx-1>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-1?m_pNewBlob->nLeft:nCx-1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-1;
pEnd->point.y = nCy;
pEnd++;
}
//邻域{-1,-1}
searchIndex = pQueue->nIndex - m_nWidth - 1;
if ((searchIndex>=0) && (nCx-1>=0) && (nCy-1>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-1?m_pNewBlob->nLeft:nCx-1;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-1?m_pNewBlob->nTop:nCy-1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-1;
pEnd->point.y = nCy-1;
pEnd++;
}
//邻域{-1,0}
searchIndex = pQueue->nIndex - m_nWidth;
if ((searchIndex>=0) && (nCy-1>=0) && (255 == pImgData[searchIndex]) && (!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-1?m_pNewBlob->nTop:nCy-1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx;
pEnd->point.y = nCy-1;
pEnd++;
}
//邻域{-1,1}
searchIndex = pQueue->nIndex - m_nWidth + 1;
if ((searchIndex>=0) && (nCx+1<m_nWidth) && (nCy-1>=0) && (255 == pImgData[searchIndex]) &(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+1?m_pNewBlob->nRight:nCx+1;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-1?m_pNewBlob->nTop:nCy-1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+1;
pEnd->point.y = nCy-1;
pEnd++;
}
//邻域{-2,-2}
searchIndex = pQueue->nIndex - 2 * m_nWidth - 2;
if ( (searchIndex>=0) && (nCx-2>=0) && (nCy-2>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-2?m_pNewBlob->nLeft:nCx-2;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-2?m_pNewBlob->nTop:nCy-2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-2;
pEnd->point.y = nCy-2;
pEnd++;
}
//邻域{-2,-1}
searchIndex = pQueue->nIndex - 2 * m_nWidth - 1;
if ( (searchIndex>=0) && (nCx-1>=0) && (nCy-2>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-1?m_pNewBlob->nLeft:nCx-1;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-2?m_pNewBlob->nTop:nCy-2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-1;
pEnd->point.y = nCy-2;
pEnd++;
}
//邻域{-2,0}
searchIndex = pQueue->nIndex - 2 * m_nWidth;
if ( (searchIndex>=0) && (nCy-2>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-2?m_pNewBlob->nTop:nCy-2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx;
pEnd->point.y = nCy-2;
pEnd++;
}
//邻域{-2,1}
searchIndex = pQueue->nIndex - 2 * m_nWidth + 1;
if ( (searchIndex>=0) && (nCx+1<m_nWidth) && (nCy-2>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+1?m_pNewBlob->nRight:nCx+1;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-2?m_pNewBlob->nTop:nCy-2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+1;
pEnd->point.y = nCy-2;
pEnd++;
}
//邻域{-2,2}
searchIndex = pQueue->nIndex - 2 * m_nWidth + 2;
if ( (searchIndex>=0) && (nCx+2<m_nWidth) && (nCy-2>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+2?m_pNewBlob->nRight:nCx+2;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-2?m_pNewBlob->nTop:nCy-2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+2;
pEnd->point.y = nCy-2;
pEnd++;
}
//邻域{-1,-2}
searchIndex = pQueue->nIndex - m_nWidth - 2;
if ( (searchIndex>=0) && (nCx-2>=0) && (nCy-1>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-2?m_pNewBlob->nLeft:nCx-2;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-1?m_pNewBlob->nTop:nCy-1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-2;
pEnd->point.y = nCy-1;
pEnd++;
}
//邻域{-1,2}
searchIndex = pQueue->nIndex - m_nWidth + 2;
if ( (searchIndex>=0) && (nCx+2<m_nWidth) && (nCy-1>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+2?m_pNewBlob->nRight:nCx+2;
m_pNewBlob->nTop = m_pNewBlob->nTop<nCy-1?m_pNewBlob->nTop:nCy-1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+2;
pEnd->point.y = nCy-1;
pEnd++;
}
//邻域{0,-2}
searchIndex = pQueue->nIndex - 2;
if ( (searchIndex>=0) && (nCx-2>=0) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-2?m_pNewBlob->nLeft:nCx-2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-2;
pEnd->point.y = nCy;
pEnd++;
}
//邻域{0,2}
searchIndex = pQueue->nIndex + 2;
if ( (searchIndex>=0) && (nCx+2<m_nWidth) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+2?m_pNewBlob->nRight:nCx+2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+2;
pEnd->point.y = nCy;
pEnd++;
}
//邻域{1,-2}
searchIndex = pQueue->nIndex + m_nWidth - 2;
if ( (searchIndex>=0) && (nCx-2>=0) && (nCy+1<m_nHeight) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-2?m_pNewBlob->nLeft:nCx-2;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+1?m_pNewBlob->nBottom:nCy+1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-2;
pEnd->point.y = nCy+1;
pEnd++;
}
//邻域{1,2}
searchIndex = pQueue->nIndex + m_nWidth + 2;
if ( (searchIndex>=0) && (nCx+2<m_nWidth) && (nCy+1<m_nHeight) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+2?m_pNewBlob->nRight:nCx+2;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+1?m_pNewBlob->nBottom:nCy+1;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+2;
pEnd->point.y = nCy+1;
pEnd++;
}
//邻域{2,-2}
searchIndex = pQueue->nIndex + 2 * m_nWidth - 2;
if ( (searchIndex>=0) && (nCx-2>=0) && (nCy+2<m_nHeight) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-2?m_pNewBlob->nLeft:nCx-2;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+2?m_pNewBlob->nBottom:nCy+2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-2;
pEnd->point.y = nCy+2;
pEnd++;
}
//邻域{2,-1}
searchIndex = pQueue->nIndex + 2 * m_nWidth - 1;
if ( (searchIndex>=0) && (nCx-1>=0) && (nCy+2<m_nHeight) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nLeft = m_pNewBlob->nLeft<nCx-1?m_pNewBlob->nLeft:nCx-1;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+2?m_pNewBlob->nBottom:nCy+2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx-1;
pEnd->point.y = nCy+2;
pEnd++;
}
//邻域{2,0}
searchIndex = pQueue->nIndex + 2 * m_nWidth;
if ( (searchIndex>=0) && (nCy+2<m_nHeight) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+2?m_pNewBlob->nBottom:nCy+2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx;
pEnd->point.y = nCy+2;
pEnd++;
}
//邻域{-2,1}
searchIndex = pQueue->nIndex + 2 * m_nWidth + 1;
if ( (searchIndex>=0) && (nCx+1<m_nWidth) && (nCy+2<m_nHeight) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+1?m_pNewBlob->nRight:nCx+1;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+2?m_pNewBlob->nBottom:nCy+2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+1;
pEnd->point.y = nCy+2;
pEnd++;
}
//邻域{-2,2}
searchIndex = pQueue->nIndex + 2 * m_nWidth + 2;
if ( (searchIndex>=0) && (nCx+2<m_nWidth) && (nCy+2<m_nHeight) && (255 == pImgData[searchIndex]) &&(!pLabelmap[searchIndex]))
{
pLabelmap[searchIndex] = labelIndex;
m_pNewBlob->nRight = m_pNewBlob->nRight>nCx+2?m_pNewBlob->nRight:nCx+2;
m_pNewBlob->nBottom = m_pNewBlob->nBottom>nCy+2?m_pNewBlob->nBottom:nCy+2;
pEnd->nIndex = searchIndex;
pEnd->point.x = nCx+2;
pEnd->point.y = nCy+2;
pEnd++;
}
}
/************************************************************************/
/* 目标连通域较近的进行合并 */
/************************************************************************/
int CombineBlob(int nNum, IVT_BLOB *pBlob)
{
int i=0,nFlag,j,k=0;
IVT_RECT *p1,*p2;
IVT_BLOB *pB1;
if (nNum<2||pBlob==NULL)
{
return nNum;
}
for (i=0;i<nNum; i++,k=0)
{
p1 = &pBlob[i].BlobRect;
for (;k<nNum; k++)
{
if (i!=k)
{
p2 = &pBlob[k].BlobRect;
nFlag = RectsIfMerge(p1,p2);
if (nFlag == 1)
{
if (k>i)
{
for (j=k;j<nNum-1;j++)
{
pBlob[j] = pBlob[j+1];
}
}
else
{
for (j=k;j<nNum-1;j++)
{
pBlob[j] = pBlob[j+1];
}
i--;
p1 = &pBlob[i].BlobRect;
}
nNum--;
k = -1;
}
}
}
}
return nNum;
}
/************************************************************************/
/* 两个目标框离得是否近
1——近
0——远*/
/************************************************************************/
int RectsIfMerge(IVT_RECT *ptRectI, IVT_RECT *pRectJ)
{
int x1, y1, x11, y11, x2, y2, x22, y22,Wi, Hi,Wj, Hj,Ow, Oh,Uw, Uh;
int nCenter_x1,nCenter_y1,nCenter_x2,nCenter_y2,nIndex1,nIndex2,nLocation1,nLocation2,nIndexMin;
int nMax_X,nMax_Y,nMin_X,nMin_Y;
nCenter_x1 = (ptRectI->nLeft+ptRectI->nRight)>>1;
nCenter_y1 = (ptRectI->nTop+ptRectI->nBottom)>>1;
nIndex1 = nCenter_y1*m_nWidth+nCenter_x1;
nLocation1 = m_pImageROI_Data[nIndex1].nIndex;
nCenter_x2 = (pRectJ->nLeft+pRectJ->nRight)>>1;
nCenter_y2 = (pRectJ->nTop+pRectJ->nBottom)>>1;
nIndex2 = nCenter_y2*m_nWidth+nCenter_x2;
nLocation2 = m_pImageROI_Data[nIndex2].nIndex;
if (abs(nLocation1-nLocation2)>1)
{
return 0;
}
nIndexMin = nLocation1<nLocation2?nLocation1:nLocation2;
x1 = ptRectI->nLeft;
y1 = ptRectI->nTop;
x11 = ptRectI->nRight;
y11 = ptRectI->nBottom;
x2 = pRectJ->nLeft;
y2 = pRectJ->nTop;
x22 = pRectJ->nRight;
y22 = pRectJ->nBottom;
nMax_X = MaxInt(x11, x22);
nMin_X = MinInt(x1, x2);
nMax_Y = MaxInt(y11, y22);
nMin_Y = MinInt(y1, y2);
if ((((y2<y11)&&(y1<y2))||((y22<y11)&&(y22>y1)))
&&(((x2<x11)&&(x1<x2))||((x22<x11)&&(x1<x22))))
{
ptRectI->nLeft = nMin_X;
ptRectI->nTop = nMin_Y;
ptRectI->nRight = nMax_X;
ptRectI->nBottom = nMax_Y;
return 1;
}
if (((y1<y22)&&(y2<y1)||(y11<y22)&&(y11>y2))
&&((x1<x22)&&(x1>x2)||(x22>x11)&&(x2<x11)))
{
ptRectI->nLeft = nMin_X;
ptRectI->nTop = nMin_Y;
ptRectI->nRight = nMax_X;
ptRectI->nBottom = nMax_Y;
return 1;
}
Wi = x11 - x1;
Hi = y11 - y1;
Wj = x22 - x2;
Hj = y22 - y2;
Uw = nMax_X - nMin_X;
Uh = nMax_Y - nMin_Y;
Ow = Uw - Wi - Wj;
Oh = Uh - Hi - Hj;
if((Ow<Trow[nIndexMin])&&(Oh<Troh[nIndexMin]))
{
ptRectI->nLeft = nMin_X;
ptRectI->nTop = nMin_Y;
ptRectI->nRight = nMax_X;
ptRectI->nBottom = nMax_Y;
return 1;
}
return 0;
}
int MaxInt(int n, int m)
{
return m>n?m:n;
}
int MinInt(int n, int m)
{
return m<n?m:n;
}