本文介紹一種區域生長法進行圖像分割的數據組織方式和實現方法,給出了核心代碼,可用該方法實現立體匹配中的非法點檢測。
區域生長法圖像分割是直接根據像素的相似性和連通性來對圖像進行聚類的算法。基本原理是,給出若干種子點,然後依次對這些種子點進行如下操作,直到種子點集合爲空:判斷種子點四鄰域或八鄰域的像素點是否和種子點相似(灰度相似或其他測度相似),如果相似則將該點加入種子點集合,否則不作處理。
該算法原理很簡單,但在數據結構的組織上卻需要技巧,本文介紹一種簡易的數據組織方式實現該算法。
如上圖所示,左圖爲一幅W*H大小的圖像示意圖,利用區域生長法圖像分割算法,該圖像被分割(聚類)爲7塊;右圖爲相應的數據結構,圖像分割的結果屬於圖像空間數據,其實就是一系列的像素點座標數組或與像素點座標直接關聯的屬性數組如FLAG的數組等,這個數組的維度一定是W*H,而分割結果體現在數組元素的排列順序:同一類別的元素連續存儲。然而類別的界限無法用該數組表明,而只能用另外一個描述數組,這裏我們稱之爲圖像空間數據的“元數據”數據,這個數組的有效維度爲空間數據的類別數,即7,每個元素代表的是空間數據數組中每個類別的元素個數,其實也就相應地表明瞭每個類別的指針位置。
下面,我們說明這個算法的代碼實現過程:
首先定義圖像空間數據的結構體和幾個重要變量:
typedef struct{
unsigned short x;
unsigned short y;
}seedpoint;
enum FLAG{VALID, INVALID, VALID_SEG,INVALID_SEG};//圖像空間數據標示
FLAG *flag;//圖像空間數據標示數組
seedpoint *InvalidSeedPts;//種子點數組
int num_InvalidSeedPts;//種子點數量
seedpoint *segmentation_invalidpts;//存儲分割結果的數組
seedpoint *temp_invalidpts;//算法中臨時變量
int num_classes;//分割類別數目
int *num_class;//空間數據“元數據”數組,存儲分割結果每個類別的數目
區域生長法圖像分割的算法實現爲:
void Segmentation(int delt_connect)
{
int counter=0;
int temp_num_invalidpts=0;
seedpoint point,temppoint;
for (int i=0;i<num_InvalidSeedPts;i++)
{
point = InvalidSeedPts[i];
if (flag[point.x*width+point.y] == VALID)
{
segmentation_invalidpts[counter] = point;
counter++;
temp_num_invalidpts=0;
temp_invalidpts[temp_num_invalidpts] = point;
temp_num_invalidpts++;
int j=0;
flag[point.x*width+point.y] = VALID_SEG;
while (j<temp_num_invalidpts)
{
point = temp_invalidpts[j];
if ((point.x>0)&&(point.x<(height-1))&&(point.y>0)&&(point.y<(width-1)))
{
int index1 = point.x*width+point.y;
if((flag[(point.x-1)*width+point.y]==VALID))
{
temppoint.x = point.x-1;
temppoint.y = point.y;
int index2 = temppoint.x*width+temppoint.y;
int delt = abs(buf[index1] - buf[index2]);
if(delt < delt_connect)
{
segmentation_invalidpts[counter] = temppoint;
counter++;
temp_invalidpts[temp_num_invalidpts] = temppoint;
temp_num_invalidpts++;
flag[(point.x-1)*width+point.y]=VALID_SEG;
}
}
if((flag[(point.x+1)*width+point.y]==VALID))
{
temppoint.x = point.x+1;
temppoint.y = point.y;
int index2 = temppoint.x*width+temppoint.y;
int delt = abs(buf[index1] - buf[index2]);
if(delt < delt_connect)
{
segmentation_invalidpts[counter] = temppoint;
counter++;
temp_invalidpts[temp_num_invalidpts] = temppoint;
temp_num_invalidpts++;
flag[(point.x+1)*width+point.y]=VALID_SEG;
}
}
if((flag[point.x*width+point.y+1]==VALID))
{
temppoint.x = point.x;
temppoint.y = point.y+1;
int index2 = temppoint.x*width+temppoint.y;
int delt = abs(buf[index1] - buf[index2]);
if(delt < delt_connect)
{
segmentation_invalidpts[counter] = temppoint;
counter++;
temp_invalidpts[temp_num_invalidpts] = temppoint;
temp_num_invalidpts++;
flag[point.x*width+point.y+1]=VALID_SEG;
}
}
if((flag[point.x*width+point.y-1]==VALID))
{
temppoint.x = point.x;
temppoint.y = point.y-1;
int index2 = temppoint.x*width+temppoint.y;
int delt = abs(buf[index1] - buf[index2]);
if(delt < delt_connect)
{
segmentation_invalidpts[counter] = temppoint;
counter++;
temp_invalidpts[temp_num_invalidpts] = temppoint;
temp_num_invalidpts++;
flag[point.x*width+point.y-1]=VALID_SEG;
}
}
}
j++;
}
num_class[num_classes] = temp_num_invalidpts;
num_classes++;
}
}
}
利用該算法,我們檢測一幅立體匹配視差圖中非法點,其實就是對分割結果進行檢測,即將類別元素數小於一定閾值的類別標示爲非法點,檢測結果如下:
其中,左圖爲原始結果,中圖爲非法點檢測結果,右圖爲非法點FLAG圖像。