分水嶺演算法原理

2021-06-11 07:16:45 字數 4257 閱讀 3864

所謂分水嶺演算法有好多種實現演算法,拓撲學,形態學,浸水模擬和降水模擬等方式。

要搞懂就不容易了。watershed algorithm(分水嶺演算法),顧名思義,就是根據分

水嶺的構成來考慮影象的分割。現實中我們可以或者說可以想象有山有湖的景象,那

麼那一定是水繞山,山圍水的情形。而區分高山(plateaus)與水的界線,以及湖

與湖之間的間隔或都是連通的關係,就是我們可愛的分水嶺(watershed)。為了得

到乙個相對集中的集水盆,那麼讓水漲到都接近周圍的最高的山頂就可以了,再漲就

要漏水到鄰居了,而鄰居,嘿嘿,水質不同誒,會混淆自我的。那麼這樣的話,我們

就可以用來獲取邊界高度大,中間灰階小的物體區域了,它就是集水盆。

浸水法,就是先通過乙個適當小的閾值得到起點,即集水盆的底;然後是向周圍淹沒

也就是浸水的過程,直到得到分水嶺。當然如果我們要一直淹沒到山頂,即是一直處

理到影象灰階最高片,那麼,當中就會出現築壩的情況,不同的集水盆在這裡想相遇

了,我們要潔身自愛,到這裡為止,因為都碰到邊界了。不再上山。構築屬於自己的分水嶺。

在計算機圖形學中,可利用灰度表徵地貌高。影象中我們可以利用灰度高與地貌高

的相似性來研究影象的灰度在空間上的變化。這是空域分析,比如還可以通過各種

形式的梯度計算以得到演算法的輸入,進行浸水處理。分水嶺具有很強的邊緣檢測能力,

對微弱的邊緣也有較好的效果。

為會麼這麼說呢?為什麼有很強的邊緣檢測能力,而又能得到相對集中的連通的

集水盆?現實中很好辦,我們在往凹地加水的時候,直到它漲到這一塊緊湊的山嶺

邊緣就不加了;但是如果有一條小山溝存在,那沒辦法,在初始閾值分割的時候,

也就是山溝與集水盆有同樣的極小值,而且它們之間是以這個高度一直連線的。

那沒關係,我們將它連通。在影象上呢?如何實現?

看看演算法,演算法思想是這樣的:

首先準備好山和初始的水。這山就是我們的初始影象了,比如用自然獲取的影象

的梯度來表徵山地的每一點的高度吧;而初始的水就是在閾值記為thre底下,

所有的低於這個高度的整個山地都加水,直到這個閾值thre高度。從而有三個

初始量:unsigned char** ori_image、char** seed_image和int** label_image。

最後乙個是為最終的結果做準備的。當然要做好初始化,比如,ora_image賦值為

原影象(256色灰度圖)的梯度值,seed_image則是初始狀態下有水的置位,無水的

復位,而label_image則全初始化為0,最終得到的是各點對應的區域號。

接下來是考慮將已加的水進行記錄,記錄成連通的區域,也就是看看有多少個互

不相關的集水盆,有五個,那麼我們就漲出五個湖,而且盡可能的高,只要大家

想到不溢位。在演算法上,有多少個連通的區域就記錄成多少個資料結構,工夫就

在於如何將這些連通的區域連線成一塊,並由乙個資料結構來表達了。很好,

我們準備用乙個向量容器來實現初始儲存,儲存所有標記區域種子佇列的陣列,

裡面放的是種子佇列的指標vector*> vque,而且這個佇列是由一系列屬於同

乙個區域的影象點組成,我們來自乙個集水盆:);其儲存方式是這樣的:

queue *pque=new queue[256];vque.push_back(pque),這樣便將乙個成員

放進到這個區域來了,即容器--集水盆的保管都,容器中的每個指標,都指

向乙個集水盆,也就是我們要的連通區域;所以我們可以方便地由這個容器數

據結構直接讀值的方便性進行操作,乙個腳標就可以得到乙個區域(佇列指標)

的指標;而每個佇列還不簡單,並不是一列整形數那麼易搞,所以說啊,這個

演算法,真頭痛,這個佇列的乙個成員是乙個點;而注意到vque裡存放的一256

個佇列的的起始指標,真夠殘忍的。也就是說vque[i][j]就表達了乙個佇列,

這個佇列裡可以儲存操作一系列的點;顯然容量取256是因為所有的初始或者是

最終的區域中可能有0-256之間的不同的灰階的點,那麼我乙個區域分用256個

佇列來記錄這些成員點啦,很有可能,這裡就只有乙個集水盆,那麼,256個灰

階的點都存在乙個區域就有可能了。

統計初始連通區域的方法是,八連通鄰域法,即從逐一掃瞄輸入的seed_image

的每個畫素點,將所有的標記了的初始集水盆一一納入各自的區域,這是整修

影象的掃瞄,形成外迴圈。先建立乙個臨時佇列quetem,用來處理當前初始集

水盆的連通連線,將逐一掃瞄到的屬於乙個特定的初始集水盆區域的可生長點

暫存,並形成乙個內迴圈。對當前掃瞄點的處理是,首先判斷該點是否為某個

初始集水盆的點,如果不是跳過;接下來是,如果是初始集水盆的點,那麼它

的八連通域中是否存在不可生長的點(這裡的不可生長是指seed_image中沒有

標記的點),掃瞄的八連通鄰域中的點是可生長的,即有標記的,則將之加入

到臨時佇列中quetem;如果掃瞄到的連通鄰域中有不可生長的至少乙個點存在,

那麼加入到種子佇列,記當前區域號為num,當前掃瞄點為(m,n),從而當前的

灰階為ori_image[m][n],將當前點新增到種子佇列:vque[num-1]

[ori_image[m][n]].push(point(m,n))。這裡有兩個迴圈,乙個是quetem,

另乙個是seed_image。直到兩個迴圈完整結束,那麼就得到了各個連通初始集

水盆的記錄,儲存標記是區域號num;而我們同時得到了初始的分水嶺,那就放

在了儲存地點vque,這裡面標識了它們對應的區域號,和區域裡面對應的點的

灰階,即是特定區域特定灰階對應的點的集合;我們可以獲取這些分水嶺的點

所在的區域號,可以得到該區域的所有的灰階的點資訊。一句話,統計連通區

域的功能有兩個,一是標記初始區域,二是找分水嶺。

初始的區域標記好了,分嶺也找到了,那麼可以開始「水漫梁山」了。這就是

淹沒過程。淹沒過程由也是由乙個內嵌迴圈的迴圈來實現的:外迴圈是做水位

上公升(這裡迴圈次數一定要256以內),waterlevel的上公升,原來是已經做過

了初始的水位分割,那麼現在可以從thre開始了,讓水位慢慢上公升,讓它原本

的湖慢慢擴張,盡量利用其應有的空間,而又不至於淹沒到其它的鄰居湖泊。

內迴圈是掃瞄每個初始區域(當前num,從而有num個迴圈)的分水嶺的點

(在vque中),按照給定的水位進行擴張。擴張過程是這樣的:掃瞄到

的分水嶺的當前點,對其進行四連通鄰域進行逐一檢查,如果四連通域中有點

沒有標記的(那這一定是高度較高的點,較低的前面一定掃瞄過),那麼先對

該點以本區域號做標記num(注意是當前的num);再判斷它在當前水位下是否

可生長(灰階是否小於等於waterlevel),如果可生長那麼加入

到vque[num][waterlevel]種子佇列中,將會再次進入內迴圈,否則如果在

當前水位下不可生長,則加入到這個鄰域點的分水嶺集合中vque[num][ori_image[鄰域點]]

佇列中。如此往復迴圈,直到對應區域完成,乙個水位,掃瞄所有的區域的分

水嶺,這樣各自同時在乙個水位下擴張,保證了不出現跳躍的情況出現

(就是乙個水位乙個區域全域性擴張)。

最終,所有的區域在每個水位都擴張完畢,得到了分割圖,我們的大湖泊形成了。

這是分水嶺演算法的一種實現方式。仔細考察不難發現這種實現方式不能產生新

的集水盆,也就是說,由於初始集水盆的侷限性,很可能會浪費大部分沒有發

掘出來的起始點較高的集水盆地。這樣,我們就要對演算法進行修改了。實現方

式是:在淹沒的過程中,我們是由閾值thre的水位開始淹沒的,那麼我們可以

對初始區域之外的沒有標記的點(從seed_image中考察),對之進行標記,條

件是先把這一輪的內迴圈做好,然後在剩下的沒標記區域中發掘新的集水盆,

並加入到我們的種子佇列中,下乙個水位開始,就又多了乙個新成員了,讓它

們不斷膨脹,成長,擁有自己的小天的成員就會逐一的被分割出來。不過話說

回來,我們這裡是採用梯度影象,一般情況下,閾值初始分割能夠滿足我們的

要求,把灰階變化平滑的先擷取出來,梯度資訊已然足夠強大;而如果採用了

新盆地擴張,則比較適用於原始影象。

分水嶺演算法主要的分割目的在於找到影象的連通區域。利用梯度資訊作為輸入

影象,會有乙個矛盾點,如果對原始影象進行梯度計算時不作濾波平滑處理,

很容易將物體分割成多個物體,那是因為雜訊的影響;而如果進行濾波處理,

又容易造成將某些原本幾個的物體合成乙個物體。當然這裡的物體主要還是指

影象變化不大或者說是灰度值相近的目標區域。

分水嶺演算法

分水嶺變換是一種流行的影象處理演算法,用於快速將影象分割成多個同質區域。分水嶺演算法的思想是 把影象看成乙個拓撲地貌,那麼同類區域就相當於陡峭邊緣內相對平坦的盆地。分水嶺演算法通過逐步增加水位,把地貌分割成多個部分 目前比較著名的有模擬泛洪和降水 降水 水先是匯集到海拔低的地區,慢慢填充這每乙個盆地...

分水嶺演算法

在許多實際應用中,我們需要分割影象,但無法從背景影象中獲得有用資訊。分水嶺演算法在這方面往往是非常有效的。此演算法可以將影象中的邊緣轉化成 山脈 將均勻區域轉化為 山谷 這樣有助於分割目標。分水嶺演算法,是一種基於拓撲理論的數學形態學的分割方法,其基本思想是把影象看作是測地學上的拓撲地貌,影象中每一...

分水嶺分割演算法

如果影象中的目標物體是連在一起的,則分割起來會更困難,分水嶺演算法經常用於處理這類問題,通常會取得比較好的效果。分水嶺分割演算法把影象看成一副 地形圖 其中亮度比較強的地區畫素值較大,而比較暗的地區畫素比較小,通過尋找 匯水盆地 和 分水嶺界限 對影象進行分割。步驟 1.讀取影象 2.求取影象的邊界...