Hough變換算法

1、算法思想

邊緣檢測比如canny算子可以識別出圖像的邊緣,但是實際中由於噪聲和光照不均勻等因素,很多情況下獲得的邊緣點是不連續的,必須通過邊緣連接將他們轉換為有意義的邊緣。Hough變化是一個重要的檢測間斷點邊界形狀的方法,它通過將圖像座標空間變化到參數空間來實現直線和曲線的擬合。

霍夫變換於1962年由Paul Hough 首次提出,後於1972年由Richard Duda和Peter Hart推廣使用,經典霍夫變換用來檢測圖像中的直線,後來霍夫變換擴展到任意形狀物體的識別,多為圓和橢圓。

Hough變換是圖像處理中從圖像中識別幾何形狀的基本方法之一。Hough直線檢測的基本原理在於利用點與線的對偶性,在我們的直線檢測任務中,即圖像空間中的直線與參數空間中的點是一一對應的,參數空間中的直線與圖像空間中的點也是一一對應的。這意味著我們可以得出兩個非常有用的結論:

1)圖像空間中的每條直線在參數空間中都對應著單獨一個點來表示;

2)圖像空間中的直線上任何一部分線段在參數空間對應的是同一個點。

因此Hough直線檢測算法就是把在圖像空間中的直線檢測問題轉換到參數空間中對點的檢測問題,通過在參數空間裡尋找峰值來完成直線檢測任務,也即把檢測整體特性轉化為檢測局部特性。

2、算法原理

1)圖像空間和參數空間

霍夫變換的數學理解是“換位思考”,比如一條直線y=a*x+b有兩個參數,在給定座標系下,這條直線就可以用a和b進行完整的表述。如果我們把x和y看作參數,把a和b看作變量的話,那麼圖像空間下的座標點(x1,y1)對應著參數空間裡的一條直線q=-x1*k+y1, 圖像空間直線上的點(x1,y1)就是參數空間的斜率和截距,其中k,q為參數空間的自變量。

2)參數空間轉換過程

下面用不同空間下的點和線的變換過程示例說明。

一條直線可由兩個點A=(X 1 ,Y 1 )和B=(X 2 ,Y 2 )確定(笛卡爾座標)。

Hough變換算法

另一方面,y=kx+q也可以寫成關於(k,q)的函數表達式(霍夫空間):

Hough變換算法

對應的變換可以通過圖形直觀表示:

Hough變換算法

變換後的空間成為 霍夫空間 。即: 笛卡爾座標系中一條直線,對應霍夫空間的一個點

反過來同樣成立( 霍夫 空間的一條直線,對應笛卡爾座標系的一個點

):

Hough變換算法

再來看看 A、 B兩個點,對應霍夫空間的情形:

Hough變換算法

再看一下三個點共線的情況:

Hough變換算法

可以看出如果笛卡爾座標系的點共線,這些點在霍夫空間對應的直線交於一點:這也是必然,共線只有一種取值可能。

如果不止一條直線呢?再看看多個點的情況(有兩條直線):

Hough變換算法

其實(3,2)與(4,1)也可以組成直線,只不過它有兩個點確定,而圖中A、B兩點是由三條直線匯成,這也是 霍夫變換的後處理的基本方式選擇由儘可能多直線匯成的點

Hough變換算法

到這裡問題似乎解決了,已經完成了霍夫變換的求解,但是如果像下圖這種情況呢?

Hough變換算法

k=∞是不方便表示的,而且q怎麼取值呢,這樣不是辦法。因此考慮 將笛卡爾座標系換為:極座標表示 。(參考文件裡大佬博客裡面的圖錯了,下圖是正確的極座標表示方法,並且給出了輔助線幾何解釋)

Hough變換算法

在極座標系下,其實是一樣的:極座標的點→霍夫空間的直線,只不過霍夫空間不再是 [k,q]的參數,而是 [ ρ , θ ]的參數,給出對比圖:

Hough變換算法

從上面可以看到,參數空間的每個點 (ρ ,θ )都對應了圖像空間的一條直線,或者說圖像空間的一個點在參數空間中就對應為一條曲線。這樣就把在圖像空間中檢測直線的問題轉化為在極座標參數空間中找通過點 (r,θ )的最多正弦曲線數的問題。霍夫空間中,曲線的交點次數越多,所代表的參數越確定,畫出的圖形越飽滿。

霍夫直線檢測就是把圖像空間中的直線變換到參數空間中的點,通過統計特性來解決檢測問題。具體來說,如果一幅圖像中的像素構成一條直線,那麼這些像素座標值( x, y)在參數空間對應的曲線一定相交於一個點,所以我們只需要將圖像中的所有像素點(座標值)變換成參數空間的曲線,並在參數空間檢測曲線交點就可以確定直線了。

下面給出霍夫變換的算法步驟:

Hough變換算法

總結:使用霍夫變換檢測直線具體步驟:

1.彩色圖像->灰度圖

2.去噪(高斯核)

3.邊緣提取(梯度算子、拉普拉斯算子、canny、sobel)

4.二值化(判斷此處是否為邊緣點,就看灰度值==255)

5.映射到霍夫空間(準備兩個容器,一個用來展示hough-space概況,一個數組hough-space用來儲存voting的值,因為投票過程往往有某個極大值超過閾值,多達幾千,不能直接用灰度圖來記錄投票信息)

6.取局部極大值,設定閾值,過濾干擾直線

7.繪製直線、標定角點

3、代碼測試

函數原型:

<code>CV_EXPORTS_W void HoughLines( InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double srn = 0, double stn = 0,
double min_theta = 0, double max_theta = CV_PI );
/<code>
Hough變換算法

測試代碼如下:

<code>int main() {
Mat src_img;
Mat dst_img, cdst, cdst2;

src_img = imread("D:\\\\WORK\\\\5.OpenCV\\\\LeanOpenCV\\\\pic_src\\\\pic18.bmp");
imshow("原圖", src_img);

Canny(src_img, dst_img, 50, 200, 3);
imshow("Canny圖", dst_img);


cdst = src_img.clone();
cdst2 = dst_img.clone();
vector<vec2f> lines;
HoughLines(dst_img, lines, 1, CV_PI / 180, 100, 0, 0);

for (size_t i = 0; i < lines.size(); i++)
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a * rho, y0 = b * rho;
pt1.x = cvRound(x0 + 1000 * (-b));
pt1.y = cvRound(y0 + 1000 * (a));
pt2.x = cvRound(x0 - 1000 * (-b));
pt2.y = cvRound(y0 - 1000 * (a));
line(cdst, pt1, pt2, Scalar(0, 0, 255), 1, LINE_AA);
line(cdst2, pt1, pt2, Scalar(255, 255, 255), 1, LINE_AA);
}

imshow("detected lines", cdst);
imshow("detected lines2", cdst2);

waitKey(0);
}
/<vec2f>/<code>

測試效果圖如下,canny邊緣檢測有不連續的邊緣,霍夫變換直線檢測可以連接不連續的直線邊緣。

Hough變換算法


分享到:


相關文章: