圖像的細化主要是針對二值圖而言
所謂骨架,可以理解為圖像的中軸,,一個長方形的骨架,是它的長方向上的中軸線,
圓的骨架是它的圓心,直線的骨架是它自身,孤立點的骨架也是自身。
骨架的獲取主要有兩種方法:
(1)基于烈火模擬
設想在同一時刻,將目標的邊緣線都點燃,火的前沿以勻速向內部蔓延,當前沿相交時火焰熄滅,
火焰熄滅點的結合就是骨架。
(2)基于最大圓盤
目標的骨架是由目標內所有內切圓盤的圓心組成
我們來看看典型的圖形的骨架(用粗線表示)
細化的算法有很多種,但比較常用的算法是查表法
細化是從原來的圖中去掉一些點,但仍要保持原來的形狀。
實際上是保持原圖的骨架。
判斷一個點是否能去掉是以8個相鄰點(八連通)的情況來作為判據的,具體判據為:
1,內部點不能刪除
2,鼓勵點不能刪除
3,直線端點不能刪除
4,如果P是邊界點,去掉P后,如果連通分量不增加,則P可刪除
看看上面那些點。
第一個點不能去除,因為它是內部點
第二個點不能去除,它也是內部點
第三個點不能去除,刪除后會使原來相連的部分斷開
第四個點可以去除,這個點不是骨架
第五個點不可以去除,它是直線的端點
第六個點不可以去除,它是直線的端點
對于所有的這樣的點,我們可以做出一張表,來判斷這樣的點能不能刪除
我們對于黑色的像素點,對于它周圍的8個點,我們賦予不同的價值,
若周圍某黑色,我們認為其價值為0,為白色則取九宮格中對應的價值
對于前面那幅圖中第一個點,也就是內部點,它周圍的點都是黑色,所以他的總價值是0,對應于索引表的第一項
前面那幅圖中第二點,它周圍有三個白色點,它的總價值為1+4+32=37,對應于索引表中第三十八項
我們用這種方法,把所有點的情況映射到0~255的索引表中
我們掃描原圖,對于黑色的像素點,根據周圍八點的情況計算它的價值,然后查看索引表中對應項來決定是否要保留這一點
我們很容易寫出程序
import cv
def Thin(image,array):
h = image.height
w = image.width
iThin = cv.CreateImage(cv.GetSize(image),8,1)
cv.Copy(image,iThin)
for i in range(h):
for j in range(w):
if image[i,j] == 0:
a = [1]*9
for k in range(3):
for l in range(3):
if -1<(i-1+k)<h and -1<(j-1+l)<w and iThin[i-1+k,j-1+l]==0:
a[k*3+l] = 0
sum = a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128
iThin[i,j] = array[sum]*255
return iThin
def Two(image):
w = image.width
h = image.height
size = (w,h)
iTwo = cv.CreateImage(size,8,1)
for i in range(h):
for j in range(w):
iTwo[i,j] = 0 if image[i,j] < 200 else 255
return iTwo
array = [0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,\
1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0]
image = cv.LoadImage('pic3.jpg',0)
iTwo = Two(image)
iThin = Thin(iTwo,array)
cv.ShowImage('image',image)
cv.ShowImage('iTwo',iTwo)
cv.ShowImage('iThin',iThin)
cv.WaitKey(0)
我們來看看運行效果:
(下圖最左邊的原圖若涉及版權問題,請作者與我聯系,謝謝)
效果差強人意,總覺得有點不對頭,但又說不出哪里不對
好吧,我們來看看最簡單的事例
按照前面的分析,我們應該得到一條豎著的線,但實際上我們得到了一條橫線
我們在從上到下,從左到右掃描的時候,遇到第一個點,我們查表可以刪除,遇到第二個點,我們查表也可以刪除,整個第一行都可以刪除
于是我們查看第二行時,和第一行一樣,它也被整個刪除了。這樣一直到最后一行,于是我們得到最后的結果是一行直線
解決的辦法是:
在每行水平掃描的過程中,先判斷每一點的左右鄰居,如果都是黑點,則該點不做處理。另外,如果某個黑店被刪除了,則跳過它的右鄰居,處理下一點。對矩形這樣做完一遍,水平方向會減少兩像素。
然后我們再改垂直方向掃描,方法一樣。
這樣做一次水平掃描和垂直掃描,原圖會“瘦”一圈
多次重復上面的步驟,知道圖形不在變化為止
這一改進讓算法的復雜度的運行時間增大一個數量級
我們來看看改進后的算法:
import cv
def VThin(image,array):
h = image.height
w = image.width
NEXT = 1
for i in range(h):
for j in range(w):
if NEXT == 0:
NEXT = 1
else:
M = image[i,j-1]+image[i,j]+image[i,j+1] if 0<j<w-1 else 1
if image[i,j] == 0 and M != 0:
a = [0]*9
for k in range(3):
for l in range(3):
if -1<(i-1+k)<h and -1<(j-1+l)<w and image[i-1+k,j-1+l]==255:
a[k*3+l] = 1
sum = a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128
image[i,j] = array[sum]*255
if array[sum] == 1:
NEXT = 0
return image
def HThin(image,array):
h = image.height
w = image.width
NEXT = 1
for j in range(w):
for i in range(h):
if NEXT == 0:
NEXT = 1
else:
M = image[i-1,j]+image[i,j]+image[i+1,j] if 0<i<h-1 else 1
if image[i,j] == 0 and M != 0:
a = [0]*9
for k in range(3):
for l in range(3):
if -1<(i-1+k)<h and -1<(j-1+l)<w and image[i-1+k,j-1+l]==255:
a[k*3+l] = 1
sum = a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128
image[i,j] = array[sum]*255
if array[sum] == 1:
NEXT = 0
return image
def Xihua(image,array,num=10):
iXihua = cv.CreateImage(cv.GetSize(image),8,1)
cv.Copy(image,iXihua)
for i in range(num):
VThin(iXihua,array)
HThin(iXihua,array)
return iXihua
def Two(image):
w = image.width
h = image.height
size = (w,h)
iTwo = cv.CreateImage(size,8,1)
for i in range(h):
for j in range(w):
iTwo[i,j] = 0 if image[i,j] < 200 else 255
return iTwo
array = [0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,\
1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0]
image = cv.LoadImage('pic3.jpg',0)
iTwo = Two(image)
iThin = Xihua(iTwo,array)
cv.ShowImage('image',image)
cv.ShowImage('iTwo',iTwo)
cv.ShowImage('iThin',iThin)
cv.WaitKey(0)
我們在調用函數的時候可以控制掃描的次數,而不是判斷是否掃描完成
好啦,我們來看看運行效果吧。
效果確實比剛才好多了
我們來看看對復雜圖形的效果
(上圖中左圖若有版權問題,請與我聯系,謝謝)
好啦,圖像的細化就講到這里了
之后一段時間要準備考研,雖然并不認為自己還來得及復習,但總得做出點姿態(tài)
呵呵,可能之后兩個星期不再更新
聯系客服