連通ドメイン抽出
ゾーン成長に基づく方法
単一スキャンのアルゴリズムには、領域成長に基づく連通領域マーキングアルゴリズムがあり、アルゴリズムの流れは以下の通りである.タグ対象画像bitmapを入力し、入力画像と同じサイズのタグマトリクスlabelmap、キューqueue、タグカウントlabelIndexを初期化する. 左から右、上から下の順にbitmapをスキャンし、マークされていない前景画素pをスキャンすると、labelIndexに1を加え、labelmapにp(対応する点の値はlabelIndexに与えられる)をマークするとともに、pの8隣接点をスキャンし、マークされていない前景画素が存在する場合、labelmapにマークを行い、queueに入れ、領域成長の種子とする. queueが空でない場合、queueから成長シード点p 1を取り出し、p 1の8隣接点を走査し、マークされていない前景画素が存在する場合、labelmapにマークし、queueに入れる. queueが空になるまで3を繰り返し、1つの連通領域フラグが完了する. は、画像全体がスキャンされるまで2に進み、タグマトリクスlabelmapと連通領域の個数labelIndexが得られる.
以上は領域成長に基づいて連通領域抽出を行うステップであり,実際の動作ではその中のqueueを修正し,2つのポインタ(1つのポインタヘッド,1つのポインタテール)を用いて動作した.
単一スキャンのアルゴリズムには、領域成長に基づく連通領域マーキングアルゴリズムがあり、アルゴリズムの流れは以下の通りである.
以上は領域成長に基づいて連通領域抽出を行うステップであり,実際の動作ではその中のqueueを修正し,2つのポインタ(1つのポインタヘッド,1つのポインタテール)を用いて動作した.
<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
"); 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; }