判斷區域B是否在區域A內部的快速演算法

2021-09-08 23:36:44 字數 2565 閱讀 6951

在影象分析中,經常需要判斷影象分割所得到的區域之間的關係。通常情況,我們通過八鄰接外輪廓(準確說法是擴充套件邊緣,但這樣又得費半天口舌解釋什麼是擴充套件邊緣)來描述乙個區域並對區域進行標註,如:

很容易判斷兩個區域是否相鄰(掃瞄區域的內外邊緣畫素,如果相鄰的畫素具有不同的標註值,則為鄰居),卻較難判斷乙個區域是否在另乙個區域的內部。

如上圖中,通過相鄰畫素的標註值的不同,可以得出a和b互為鄰居,a和c互為鄰居,卻很難知道b和c中,哪個是在a的內部。下面設計演算法進行判斷。

====

如果b在a的內部,則b的外輪廓上的每個點在a的外輪廓的內部或邊緣上;如此一來,問題就簡化為判斷點是否在多邊形的邊緣或內部。

判斷點是否在多邊形內部有乙個很經典的演算法:從該點向任意一方畫射線,數該射線與多邊形的邊的交點數量,如果為奇數則在多邊形內部,如果為偶數則在多邊形的外部。

這個演算法有兩個特例:

(1)射線和多邊形的邊重合(下圖a,b)

(2)射線經過多邊形的頂點(下圖c,d)

顯然,(a)應該算0個交點 ,(b)應該算1個交點,(c)應該算0個交點,(d)應該算1個交點。

總體上來說,這個演算法要考慮到幾種特殊情況,還是比較繁瑣的。下面,針對本文的應用來簡化該演算法。

數字影象是離散的,通過邊界跟蹤可以得到全部的輪廓點。

上圖是乙個輪廓及待判斷點。從該點向x軸畫乙個射線,與9個輪廓點相交。如果將輪廓的任意兩個相鄰點的連線作為多邊形的一邊的話,很不幸,全部交點都是特殊情況。這裡假定輪廓點的排列是有序的,也就是說,是有方向的,只考察輪廓點和它一前一後兩個輪廓點之間的關係,則有下面幾類情況:

這裡對經典的點在多邊形內部判斷演算法進行變形:

(1)如果經過a類中的中間點,則算為 0.5 或 –0.5 個交點;

(2)如果經過b類的中間點,算作1個或-1個交點;

(3)如果經過c類的中間點,算作0個交點。

計算結果——如果交點數加起來是奇數,則點在輪廓的內部,否則在外部。為了避免浮點計算,將交點個數乘於2,即a類的算1個或-1個交點,b類的算2個或-2個交點,c類的算0個交點。交點總數是4的倍數則在輪廓外部,否則,則在內部。

為什麼是1個或-1個,2個或-2個呢?這裡有方向問題。假設箭頭是從下向上的,為-1,箭頭是從上往下的,算1,如果箭頭是水平的,算0.  這樣計算的話,則上圖中a類的2種情況分別為1個、1個交點,b類的2種情況分別為2個、-2個交點,c類的2種情況全為0. 如此以來,完全滿足前面點在多變形內部的經典演算法對幾種特殊情況的處理。

為每乙個輪廓點賦予乙個分值score,這個分值只與它(current)和前後兩點(prev,next)有關,和其它任何點無關。因此,這個分值是靜態的,不變化的。我們可以把它計算出來快取在雜湊表中。

private void computeextendcontourpointxscoredic() }

更進一步,score = prev.y – next.y:

private void computeextendcontourpointxscoredic() }

_extendcontourpointxscoredic 是乙個雜湊表,儲存了輪廓點的score。因為一般的影象不會特別大,我為point新增了乙個擴充套件方法gethashcode32()來獲得雜湊值:

public static int gethashcode32(this point p)

這個雜湊表還有乙個用途——如果某點的雜湊值在雜湊表內,則該點在外輪廓上。

判斷點是否在輪廓的內部,只需要向左或向右掃瞄即可。比較向左和向右的掃瞄長度,選擇最短的掃瞄路線,將掃瞄所經過的輪廓點的雜湊值加起來,就是交點數量。該交點數量如果是4的倍數,則代表點在輪廓外,否則,則在輪廓內。

在掃瞄的過程中,向左移一點或向右移一點,對應的點的雜湊值減1或加1,因此,可以省掉移動的過程,用雜湊值的變化來表示移動。這樣又可以加速計算。如果已知a、b兩個區域的 rectangle,可以先判斷,如果b的rectangle不在a的rectangle內部,則b一定不在a的內部。這樣也可以節省不少計算。

====

參考資料:udi manber. 演算法引論——一種創造性方法.  p.189。

如何判斷元素是否在可視區域ViewPort

個性簽名 生如夏花,逝如冬雪 人生如此,何悔何怨。前言 經常需要計算元素的大小或者所在頁面的位置,offsetwidth,clientwidth,scrollwidth,scrolltop這幾個關鍵字的出現更是家常便飯,每次碰到都需要事先實驗一番。為了下次開發提高效率。在這裡一次性做個總結,以用來判...

iOS開發 判斷乙個點是否在某個區域

ios有時候需要判斷是否touch到某個圖的區域中。也就是touch到的這個點是否在某個圖的區域範圍內。解決問題的辦法很多,這裡簡單介紹一種。我們可以通過cgpath建立乙個區域,區域是由路徑做兩點間線段並閉合成的區域,然後就可以用cgpath相關函式cgpathcontainspoint判斷點是否...

檢測元素是否在介面可顯示區域

在開發windows phone應用程式的時候,可能會遇到如下的場景 對列表的項做動畫時,僅對可視區的項做動畫,可以提公升動畫效能。等等,這樣的場景還有很多,上述只列出了兩個比較常用的。但這些都有乙個共同點 需要判斷出螢幕可視區域的項,並針對這些項做處理。下面的 就足以滿足這樣的需求 indicat...