[轉]霍夫變換 - 瘋狂奔跑
前言
今天群裡有人問到一個影象的問題,但本質上是一個基本最小二乘問題,涉及到霍夫變換(Hough Transform),用到了就順便總結一下。
內容為自己的學習記錄,其中多有參考他人,最後一併給出連結。
一、霍夫變換(Hough)
A-基本原理
一條直線可由兩個點A=(X1,Y1)和B=(X2,Y2)確定(笛卡爾座標)
另一方面,也可以寫成關於(k,q)的函式表示式(霍夫空間):
對應的變換可以通過圖形直觀表示:
變換後的空間成為霍夫空間。即:笛卡爾座標系中一條直線,對應霍夫空間的一個點。
反過來同樣成立(霍夫空間的一條直線,對應笛卡爾座標系的一個點):
再來看看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]申請搜狐自媒體平臺
---------------------
作者:瘋狂奔跑
來源:CNBLOGS
原文:https://www.cnblogs.com/php-rearch/p/6760683.html
版權宣告:本文為作者原創文章,轉載請附上博文連結!
內容解析By:CSDN,CNBLOG部落格文章一鍵轉載外掛