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