1. 程式人生 > >連通區域快速標記的two-pass演算法及其實現

連通區域快速標記的two-pass演算法及其實現

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]不使用。

實現程式碼如下:

  1. constint max_size = 100;  
  2. int parent[100] = {0};  
  3. // 找到label x的根節點
  4. int find(int x, int parent[]){  
  5.     int i = x;  
  6.     while(0 != parent[i])  
  7.         i = parent[i];  
  8.     return i;  
  9. }  
  10. // 將label x 和 label y合併到同一個連通域
  11. void union_label(int x, int y, int parent[]){  
  12.     int i = x;  
  13.     int j = y;  
  14.     while(0 != parent[i])  
  15.         i = parent[i];  
  16.     while(0 != parent[j])  
  17.         j = parent[j];  
  18.     if(i != j)  
  19.         parent[i] = j;  
  20. }  


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