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=(X1,Y1)和B=(X2,Y2)確定(笛卡爾坐標)。
另一方面,y=kx+q也可以寫成關於(k,q)的函數表達式(霍夫空間):
對應的變換可以通過圖形直觀表示:
變換后的空間成為霍夫空間。即:笛卡爾坐標系中一條直線,對應霍夫空間的一個點。
反過來同樣成立(霍夫空間的一條直線,對應笛卡爾坐標系的一個點):
再來看看A、B兩個點,對應霍夫空間的情形:
再看一下三個點共線的情況:
可以看出如果笛卡爾坐標系的點共線,這些點在霍夫空間對應的直線交於一點:這也是必然,共線只有一種取值可能。
如果不止一條直線呢?再看看多個點的情況(有兩條直線):
其實(3,2)與(4,1)也可以組成直線,只不過它有兩個點確定,而圖中A、B兩點是由三條直線匯成,這也是霍夫變換的后處理的基本方式:選擇由盡可能多直線匯成的點。
到這里問題似乎解決了,已經完成了霍夫變換的求解,但是如果像下圖這種情況呢?
k=∞是不方便表示的,而且q怎么取值呢,這樣不是辦法。因此考慮將笛卡爾坐標系換為:極坐標表示。(參考文件里大佬博客里面的圖錯了,下圖是正確的極坐標表示方法,並且給出了輔助線幾何解釋)
在極坐標系下,其實是一樣的:極坐標的點→霍夫空間的直線,只不過霍夫空間不再是[k,q]的參數,而是[ρ, θ]的參數,給出對比圖:
從上面可以看到,參數空間的每個點(ρ,θ)都對應了圖像空間的一條直線,或者說圖像空間的一個點在參數空間中就對應為一條曲線。這樣就把在圖像空間中檢測直線的問題轉化為在極坐標參數空間中找通過點(r,θ)的最多正弦曲線數的問題。霍夫空間中,曲線的交點次數越多,所代表的參數越確定,畫出的圖形越飽滿。
霍夫直線檢測就是把圖像空間中的直線變換到參數空間中的點,通過統計特性來解決檢測問題。具體來說,如果一幅圖像中的像素構成一條直線,那么這些像素坐標值(x, y)在參數空間對應的曲線一定相交於一個點,所以我們只需要將圖像中的所有像素點(坐標值)變換成參數空間的曲線,並在參數空間檢測曲線交點就可以確定直線了。
下面給出霍夫變換的算法步驟:
總結:使用霍夫變換檢測直線具體步驟:
1.彩色圖像->灰度圖
2.去噪(高斯核)
3.邊緣提取(梯度算子、拉普拉斯算子、canny、sobel)
4.二值化(判斷此處是否為邊緣點,就看灰度值==255)
5.映射到霍夫空間(准備兩個容器,一個用來展示hough-space概況,一個數組hough-space用來儲存voting的值,因為投票過程往往有某個極大值超過閾值,多達幾千,不能直接用灰度圖來記錄投票信息)
6.取局部極大值,設定閾值,過濾干擾直線
7.繪制直線、標定角點
3、代碼測試
函數原型:
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 );
測試代碼如下:
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); }
測試效果圖如下,canny邊緣檢測有不連續的邊緣,霍夫變換直線檢測可以連接不連續的直線邊緣。
4、參考文獻
1、《數字圖像處理與機器視覺》
第二版。 張錚、徐超、任淑霞、韓海玲等編著。
2、霍夫變換直線檢測(Line Detection)原理及示例
https://blog.csdn.net/leonardohaig/article/details/87907462
3、霍夫變換
https://www.cnblogs.com/php-rearch/p/6760683.html
4、霍夫變換-----特征提取
https://blog.csdn.net/m0_37264397/article/details/72729423
5、霍夫線變換
6、霍夫圓變換
7、經典霍夫變換(Hough Transform)
https://blog.csdn.net/YuYunTan/article/details/80141392
8、霍夫變換(Hough Transform)的原理以及代碼(Matlab&C)實現
https://blog.csdn.net/ljwcdtj/article/details/89091060
個人博客,轉載請注明。