原文出處:http://blog.csdn.net/cay22/article/details/5666091
區域生長方法是根據同一物體區域內象素的相似性質來聚集象素點的方法,從初始區域(如小鄰域或甚至於每個象素)開始,將相鄰的具有同樣性質的象素或其它區域歸併到目前的區域中從而逐步增長區域,直至沒有可以歸併的點或其它小區域爲止。區域內象素的相似性度量可以包括平均灰度值、紋理、顏色等信息。
區域生長方法是一種比較普遍的方法,在沒有先驗知識可以利用時,可以取得最佳的性能,可以用來分割比較複雜的圖象,如自然景物。但是,區域增長方法是一種迭代的方法,空間和時間開銷都比較大。
區域生長是一種串行區域分割的圖像分割方法。區域生長是指從某個像素出發,按照一定的準則,逐步加入鄰近像素,當滿足一定的條件時,區域生長終止。區域生長的好壞決定於 1.初始點(種子點)的選取;2.生長準則;3.終止條件。區域生長是從某個或者某些像素點出發,最後得到整個區域,進而實現目標的提取。
區域生長的原理
區域生長的基本思想是將具有相似性質的像素集合起來構成區域。具體先對每個需要分割的區域找一個種子像素作爲生長起點,然後將種子像素和周圍鄰域中與種子像素有相同或相似性質的像素(根據某種事先確定的生長或相似準則來判定)合併到種子像素所在的區域中。將這些新像素當作新的種子繼續上面的過程,直到沒有滿足條件的像素可被包括進來。這樣一個區域就生長成了。
圖1給出已知種子點進行區域生長的一個示例。圖1(a)給出需要分割的圖像,設已知兩個種子像素(標爲深淺不同的灰色方塊),現要進行區域生長。設這裏採用的判定準則是:如果考慮的像素與種子像素灰度值差的絕對值小於某個門限T,則將該像素包括進種子像素所在的區域。圖1(b)給出了T=3時的區域生長結果,整幅圖被較好地分成2個區域;圖1(c)給出了T=1時的區域生長結果,有些像素無法判定;圖1(c)給出了T=6時的區域生長的結果,整幅圖都被分在一個區域中了。由此可見門限的選擇是很重要的。
區域生長是一種古老的圖像分割方法,最早的區域生長圖像分割方法是由Levine等人提出的。該方法一般有兩種方式,一種是先給定圖像中要分割的目標物體內的一個小塊或者說種子區域(seed point),再在種子區域基礎上不斷將其周圍的像素點以一定的規則加入其中,達到最終將代表該物體的所有像素點結合成一個區域的目的;另一種是先將圖像分割成很多的一致性較強,如區域內像素灰度值相同的小區域,再按一定的規則將小區域融合成大區域,達到分割圖像的目的,典型的區域生長法如T.
C. Pong等人提出的基於小面(facet)模型的區域生長法,區域生長法固有的缺點是往往會造成過度分割,即將圖像分割成過多的區域
區域生長實現的步驟如下:
1. 對圖像順序掃描!找到第1個還沒有歸屬的像素, 設該像素爲(x0, y0);
2. 以(x0, y0)爲中心, 考慮(x0, y0)的4鄰域像素(x, y)如果(x0, y0)滿足生長準則, 將(x, y)與(x0, y0)合併(在同一區域內), 同時將(x, y)壓入堆棧;
3. 從堆棧中取出一個像素, 把它當作(x0, y0)返回到步驟2;
4. 當堆棧爲空時!返回到步驟1;
5. 重複步驟1 - 4直到圖像中的每個點都有歸屬時。生長結束。
代碼:
// 在這個代碼中,它認爲這張圖片就是一個區域,選取了中間點爲種子點。
void RegionGrow(CDib * pDib, unsigned char * pUnRegion, int nThreshold)
{
static int nDx[]={-1,0,1,0};
static int nDy[]={0,1,0,-1};
nThreshold = 20;
// 遍歷圖象的縱座標
// int y;
// 遍歷圖象的橫座標
// int x;
// 圖象的長寬大小
CSize sizeImage = pDib->GetDimensions();
int nWidth = sizeImage.cx ;
int nHeight = sizeImage.cy ;
// 圖像在計算機在存儲中的實際大小
CSize sizeImageSave = pDib->GetDibSaveDim();
// 圖像在內存中每一行象素佔用的實際空間
int nSaveWidth = sizeImageSave.cx;
// 初始化
memset(pUnRegion,0,sizeof(unsigned char)*nWidth*nHeight);
// 種子點
int nSeedX, nSeedY;
// 設置種子點爲圖像的中心
nSeedX = nWidth /2 ;
nSeedY = nHeight/2 ;
// 定義堆棧,存儲座標
int * pnGrowQueX ;
int * pnGrowQueY ;
// 分配空間
pnGrowQueX = new int [nWidth*nHeight];
pnGrowQueY = new int [nWidth*nHeight];
// 圖像數據的指針
unsigned char * pUnchInput =(unsigned char * )pDib->m_lpImage;
// 定義堆棧的起點和終點
// 當nStart=nEnd, 表示堆棧中只有一個點
int nStart ;
int nEnd ;
//初始化
nStart = 0 ;
nEnd = 0 ;
// 把種子點的座標壓入棧
pnGrowQueX[nEnd] = nSeedX;
pnGrowQueY[nEnd] = nSeedY;
// 當前正在處理的象素
int nCurrX ;
int nCurrY ;
// 循環控制變量
int k ;
// 圖象的橫縱座標,用來對當前象素的鄰域進行遍歷
int xx;
int yy;
while (nStart<=nEnd)
{
// 當前種子點的座標
nCurrX = pnGrowQueX[nStart];
nCurrY = pnGrowQueY[nStart];
// 對當前點的鄰域進行遍歷
for (k=0; k<4; k++)
{
// 4鄰域象素的座標
xx = nCurrX + nDx[k];
yy = nCurrY + nDy[k];
// 判斷象素(xx,yy) 是否在圖像內部
// 判斷象素(xx,yy) 是否已經處理過
// pUnRegion[yy*nWidth+xx]==0 表示還沒有處理
// 生長條件:判斷象素(xx,yy)和當前象素(nCurrX,nCurrY) 象素值差的絕對值
if ( (xx < nWidth) && (xx>=0) && (yy=0)
&& (pUnRegion[yy*nWidth+xx]==0)
&& abs(pUnchInput[yy*nSaveWidth+xx] - pUnchInput[nCurrY*nSaveWidth+nCurrX])
{
// 堆棧的尾部指針後移一位
nEnd++;
// 象素(xx,yy) 壓入棧
pnGrowQueX[nEnd] = xx;
pnGrowQueY[nEnd] = yy;
// 把象素(xx,yy)設置成邏輯()
// 同時也表明該象素處理過
pUnRegion[yy*nWidth+xx] = 255 ;
}
}
nStart++;
}
// 釋放內存
delete []pnGrowQueX;
delete []pnGrowQueY;
pnGrowQueX = NULL ;
pnGrowQueY = NULL ;
}