本文原創,如轉載請注明出處。
Hough Transform 是一種能提取圖像中某種特定形狀特征的方法,可以將其描述成一種把圖像空間中的像素轉換成Hough空間中直線或曲線的一種映射函數。通過利用Hough空間的一些性質,我們可以找到並識別一些有共同特性的點(如在同一條直線上)。這樣我們就得到足夠的信息去畫出這些圖形(如直線)。其輸入圖像通常為二值邊緣圖像。
1.原理:
圖像空間是所有像素所屬於的圖像的空間。Hough空間是一種變量混合空間,實際上它與圖像相關但是卻不存在物理實質性。
我們可以把圖像空間的坐標通過下式表達成Hough空間:
X = Ρ·cosΘ
Y = Ρ·sinΘ
where
P = sqrt(x2+y2) , 是坐標原點到直線的距離
,是距離與x坐標軸的夾角
通常我們寫成如下形式:
通過下圖我們可以更加容易理解上述式子:
經過Hough變換我們將圖像空間中的一個點映射到Hough空間,如下圖我們得到了一條正弦曲線。
在這里正弦曲線的形狀取決於,點到我們所定義原點的距離。通常,距離越大,正弦曲線的振幅越大,反之則會變小。為了使曲線顯示我們把縱坐標設置成如上,當然我也可以用π表示。
以同樣的方法我們可以再次映射一個點,而我們知道在圖像空間中兩個點總在一條直線上。而在Hough空間中我們可以看到兩條正弦曲線可能會相交如下圖:
在這里我們可以把每一個交點看成是一次投票,也就是
計算完所有邊緣點后,我們可以設置一個閾值,投票大於這個閾值的點這是我們要找的直線。如下分別為原圖,閾值為30,20時候檢測到的直線。
對於大於閾值的點我們有其Hough space的參數對(p,Θ), 通過逆映射我們可以得到圖像空間中的直線:
2.opencv示例:
步驟如下:
1.載入圖像
2.應用canny或其他邊緣檢測算子得到邊緣的二值圖像
3.應用Hough transform(Houghline())
4.在原圖像上畫出直線
void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
1 #include "opencv2/highgui/highgui.hpp" 2 #include "opencv2/imgproc/imgproc.hpp" 3 #include <iostream> 4 5 using namespace cv; 6 using namespace std; 7 8 int main() 9 { 10 Mat src = imread("building.jpg", 0); 11 12 Mat dst, cdst; 13 Canny(src, dst, 50, 200, 3); 14 cvtColor(dst, cdst, CV_GRAY2BGR); 15 16 vector<Vec2f> lines; 17 // detect lines 18 HoughLines(dst, lines, 1, CV_PI/180, 150, 0, 0 ); 19 20 // draw lines 21 for( size_t i = 0; i < lines.size(); i++ ) 22 { 23 float rho = lines[i][0], theta = lines[i][1]; 24 Point pt1, pt2; 25 double a = cos(theta), b = sin(theta); 26 double x0 = a*rho, y0 = b*rho; 27 pt1.x = cvRound(x0 + 1000*(-b)); 28 pt1.y = cvRound(y0 + 1000*(a)); 29 pt2.x = cvRound(x0 - 1000*(-b)); 30 pt2.y = cvRound(y0 - 1000*(a)); 31 line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA); 32 } 33 34 imshow("source", src); 35 imshow("detected lines", cdst); 36 37 waitKey(); 38 return 0; 39 }
結果: