1. 程式人生 > >Two-pass連通域標記中的union-find結構

Two-pass連通域標記中的union-find結構

Two-pass連通域標記中,第一次標記(first pass)時從左向右,從上向下掃描,會將各個有效畫素置一個label值,判斷規則如下(4鄰域為例)

1)         當該畫素的左鄰畫素和上鄰畫素為無效值時,給該畫素置一個新的label值,label ++;

2)         當該畫素的左鄰畫素或者上鄰畫素有一個為有效值時,將有效值畫素的label賦給該畫素的label值;

3)         當該畫素的左鄰畫素和上鄰畫素都為有效值時,選取其中較小的label值賦給該畫素的label值。

此時,還需維護一個關係表,記錄哪些label值屬於同一個連通域。這個關係表通常用union-find

資料結構來實現。

union-find結構中,屬於同一個連通域的label值被儲存到同一個樹形結構中,如圖1所示,{1,2,3,4,8}屬於同一個連通域,{5,6,7}屬於同一個連通域。同時,樹形結構的資料儲存到一個vectorarray中,vector的下標為label值,vector的儲存值為該label的父節點label值,當vector的儲存值為0時,說明該label是根節點。這樣,對於任意一個label,我們都可以尋找其根節點,作為所在連通域的label值,即某一連通域所有畫素都被置為同一個label值,即根節點label值。對給定的任意一個label,我們可以通過find演算法尋找其根節點,如圖2

所示。

如果知道兩個label同屬於一個連通域,要如何在vector中實現其儲存關係呢?首先,各自尋找兩個label的根節點,如果二者的根節點相同,則二者已經屬於同一個連通域;如果二者的根節點不同,那麼把其中一個根節點作為另一個的父節點即可,即將兩個label劃入同一個連通域,或者叫做連通域合併,演算法如圖3所示。

那麼這個儲存label值的vector要如何初始化呢?將vector初始化為0即可,即各個label值都是根節點,大家互不相連。同時注意,vector[0]不使用。

實現程式碼如下:

const int max_size = 100;
int parent[100] = {0};

// 找到label x的根節點
int find(int x, int parent[]){
	int i = x;
	while(0 != parent[i])
		i = parent[i];
	return i;
}

// 將label x 和 label y合併到同一個連通域
void union_label(int x, int y, int parent[]){
	int i = x;
	int j = y;
	while(0 != parent[i])
		i = parent[i];
	while(0 != parent[j])
		j = parent[j];
	if(i != j)
		parent[i] = j;
}


 reference: Shapiro, L., and Stockman, G. (2002).Computer Vision. Prentice Hall. pp. 69–73.