1. 程式人生 > 其它 >[轉]霍夫變換 - 瘋狂奔跑

[轉]霍夫變換 - 瘋狂奔跑

 

前言

今天群裡有人問到一個影象的問題,但本質上是一個基本最小二乘問題,涉及到霍夫變換(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部落格文章一鍵轉載外掛