圖像處理中,檢測直線或者圓等有固定方程式表示的物體時,可以考慮用霍夫變換來做。
對于一個二值圖像,
如下圖:
這個變換的思路:
1 利用兩點的坐标計算出直線的斜率k和截距b,由于k的取值有無窮大的值,表示起來不方便,所以将k用角度來表示,即arctan(k)得到直線與水平線的夾角。b其實也需要做一些映射,将[負無窮,正無窮]映射到[-N,N] 上。
2 取圖像上任意一對點的坐标,計算他們對應直線的arctan(k), 和b 。不同的一對點,計算得到的arttan(k),b有可能相同,如果兩隊點都共線。
3 假設圖像上有M對點,那麼我們一共得到M個 [arctan(k),b]
4 統計arctan(k)取值 -90度至90度之間,b取值-N,至N之間時,對應于每個特定的[arctan(k),b]的直線數目。比如統計出[arctan(k)=45度,b=0]對應的直線數據,統計出[arctan(k)=-20度,b=35]對應的直線數目。
最終,我們得到一個180*2N的矩陣,如下圖:
橫軸是b,縱軸是arctan(k)
可以看到,圖片的右下部分最亮,圖像的下邊緣對應的是斜率接近90度的直線,說明原圖中,存在垂直的直線。
圖片的中間部分有數量不多的點,中間部分對應于斜率為零的直線,說明原圖上有一些水平線。
以往都是直接調用opencv庫的,但是有些情況下,是不能調用庫的,必須自己寫了,
下面是我寫的代碼:
60 def get_line_list(point_list):
61 import numpy as np
62 k_dist_list=np.zeros(181)
63 k_b_matrix=np.zeros((181,181))
64 N=len(point_list)
65 for i in range(0,N):
66 p1 = point_list[i]
67 for j in range(i 1,N):
68 p2 = point_list[j]
69 dist,k,b=get_line_coef_length(p1,p2)
70 if np.abs(b)<=90:
71 k_b_matrix[k,int(b 90)] =1
72 if dist>k_dist_list[k]:
73 k_dist_list[k]=dist
74 return k_dist_list,k_b_matrix
point_list是python中的list,裡面取的就是上面二值圖上所有點的坐标。
63行聲明了一個矩陣:181*181的
69行計算了兩個點p1,p2所在直線的斜率k和截距b,
71行是統計語句,将矩陣中k行,int(b 90)位置 1,遇到斜率為k,截距為int(b 90]的直線時,就在矩陣中相應位置 1.
這裡主要有個函數get_line_coef_length,代碼如下:
44 def get_line_coef_length(p1,p2):
45 import numpy as np
46 x1,y1=p1
47 x2,y2=p2
48 xe=x1-x2
49 ye=y1-y2
50 dist = np.sqrt(xe*xe ye*ye)
51 k=float(y2)-float(y1)
52 if x2-x1==0:
53 return dist,180,y1
54 k=k/(float(x2)-float(x1))
55 k_theta = int(np.arctan(k)/3.14*180.0 90.0)
56 b = y1-k*x1
57 #線段長度,角度
58 return dist,k_theta,b
51行--55行是計算斜率的,這裡當斜率為無窮大時,我們将其設定為180,為什麼呢?
因為角度的取值範圍是[-90,90],這個下标是從-90開始的,但是我們矩陣k_b_matrix的下标是從零開始的,所以将[-90,90]映射到了[0,180].
也正是因為如此,在55行,有個 90.0.
這就是霍夫變換了,原理簡答,比形态學的方法找直線好用很多。
需要整份代碼的可以私信我。
另外我這裡有源碼寫的提取聯通區域,計算聯通區域最小外接矩形,沒有調用任何庫,可以寫在任何設備上,需要的話,可以向我咨詢。
我這裡還有幾個例子:
原圖2
原圖2對應的霍夫變換
原圖3
原圖3對應的霍夫變換
原圖4
圖4對應的霍夫變換
,