前言算法
今天羣裏有人問到一個圖像的問題,但本質上是一個基本最小二乘問題,涉及到霍夫變換(Hough Transform),用到了就順便總結一下。app
內容爲本身的學習記錄,其中多有參考他人,最後一併給出連接。函數
1、霍夫變換(Hough)學習
A-基本原理ui
一條直線可由兩個點A=(X1,Y1)和B=(X2,Y2)肯定(笛卡爾座標)spa
另外一方面,也能夠寫成關於(k,q)的函數表達式(霍夫空間):3d
對應的變換能夠經過圖形直觀表示:code
變換後的空間成爲霍夫空間。即:笛卡爾座標系中一條直線,對應霍夫空間的一個點。orm
反過來一樣成立(霍夫空間的一條直線,對應笛卡爾座標系的一個點):blog
再來看看A、B兩個點,對應霍夫空間的情形:
一步步來,再看一下三個點共線的狀況:
能夠看出若是笛卡爾座標系的點共線,這些點在霍夫空間對應的直線交於一點:這也是必然,共線只有一種取值可能。
若是不止一條直線呢?再看看多個點的狀況(有兩條直線):
其實(3,2)與(4,1)也能夠組成直線,只不過它有兩個點肯定,而圖中A、B兩點是由三條直線匯成,這也是霍夫變換的後處理的基本方式:選擇由儘量多直線匯成的點。
看看,霍夫空間:選擇由三條交匯直線肯定的點(中間圖),對應的笛卡爾座標系的直線(右圖)。
到這裏問題彷佛解決了,已經完成了霍夫變換的求解,可是若是像下圖這種狀況呢?
k=∞是不方便表示的,並且q怎麼取值呢,這樣不是辦法。所以考慮將笛卡爾座標系換爲:極座標表示。
在極座標系下,實際上是同樣的:極座標的點→霍夫空間的直線,只不過霍夫空間再也不是[k,q]的參數,而是的參數,給出對比圖:
是否是就一目瞭然了?
給出霍夫變換的算法步驟:
對應code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
function
[ Hough, theta_range, rho_range ] = naiveHough(I)
%NAIVEHOUGH Peforms the Hough transform in a straightforward way.
%
[rows, cols] =
size
(I);
theta_maximum = 90;
rho_maximum =
floor
(
sqrt
(rows^2 + cols^2)) - 1;
theta_range = -theta_maximum:theta_maximum - 1;
rho_range = -rho_maximum:rho_maximum;
Hough =
zeros
(
length
(rho_range),
length
(theta_range));
for
row = 1:rows
for
col = 1:cols
if
I(row, col) > 0
%only find: pixel > 0
x = col - 1;
y = row - 1;
for
theta = theta_range
rho =
round
((x *
cosd
(theta)) + (y *
sind
(theta)));
%approximate
rho_index = rho + rho_maximum + 1;
theta_index = theta + theta_maximum + 1;
Hough(rho_index, theta_index) = Hough(rho_index, theta_index) + 1;
end
end
end
end
|
其實本質上就是:
交點怎麼求解呢?細化成座標形式,取整後將交點對應的座標進行累加,最後找到數值最大的點就是求解的,也就求解出了直線。
B-理論應用
這裏給出MATLAB自帶的一個應用,主要是對一幅圖像進行直線檢驗,原圖像爲:
首先是對其進行邊緣檢測:
邊緣檢測後並二值化,就能夠經過找非零點的座標肯定數據點。從而對數據點進行霍夫變換。對應映射到霍夫空間的結果爲:
找出其中數值較大的一些點,一般能夠給定一個閾值,Threshold一下。
這就完成了霍夫變換的整個過程。這個時候求解出來了其實就是多條直線的斜率k以及截距q,一般會根據直線的特性進一步判斷,從而將直線變爲線段:
不過這一步更相似後處理,其實已經不是霍夫變換自己的特性了。
給出對應的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
clc
;
clear
all
;
close
all
;
I =
imread
(
'circuit.tif'
);
rotI = imrotate(I,40,
'crop'
);
subplot
221
fig1 = imshow(rotI);
BW = edge(rotI,
'canny'
);
title
(
'原圖像'
);
subplot
222
imshow(BW);
[H,theta,rho] = hough(BW);
title
(
'圖像邊緣檢測'
);
subplot
223
imshow(imadjust(mat2gray(H)),[],
'XData'
,theta,
'YData'
,rho,...
'InitialMagnification'
,
'fit'
);
xlabel
(
'\theta (degrees)'
),
ylabel
(
'\rho'
);
axis
on,
axis
normal,
hold
on;
colormap
(hot)
P = houghpeaks(H,5,
'threshold'
,
ceil
(0.7*
max
(H(:))));
x = theta(P(:,2));
y = rho(P(:,1));
plot
(x,y,
's'
,
'color'
,
'black'
);
lines = houghlines(BW,theta,rho,P,
'FillGap'
,5,
'MinLength'
,7);
title
(
'Hough空間'
);
subplot
224, imshow(rotI),
hold
on
max_len = 0;
for
k = 1:
length
(lines)
xy = [lines(k).point1; lines(k).point2];
plot
(xy(:,1),xy(:,2),
'LineWidth'
,2,
'Color'
,
'green'
);
% Plot beginnings and ends of lines
plot
(xy(1,1),xy(1,2),
'x'
,
'LineWidth'
,2,
'Color'
,
'yellow'
);
plot
(xy(2,1),xy(2,2),
'x'
,
'LineWidth'
,2,
'Color'
,
'red'
);
% Determine the endpoints of the longest line segment
len =
norm
(lines(k).point1 - lines(k).point2);
if
( len > max_len)
max_len = len;
xy_long = xy;
end
end
% highlight the longest line segment
plot
(xy_long(:,1),xy_long(:,2),
'LineWidth'
,2,
'Color'
,
'red'
);
title
(
'直線檢測'
);
|
對比自帶的Hough與編寫的Hough:
效果仍是比較接近的。
看到Stackoverflow上的一個答案,以爲很好,收藏一下:
[2017-04-25 10:25:37]申請搜狐自媒體平臺