霍夫變換(Hough Transform)是圖像處理中的一種特徵提取技術,它通過一種投票算法檢測具有特定形狀的物體。該過程在一個參數空間中通過計算累計結果的局部最大值得到一個符合該特定形狀的集合作爲霍夫變換結果。霍夫變換於1962年由Paul Hough 首次提出[53],後於1972年由Richard Duda和Peter Hart推廣使用[54],經典霍夫變換用來檢測圖像中的直線,後來霍夫變換擴展到任意形狀物體的識別,多爲圓和橢圓.
經過幾天的學習,發現各位大牛的理解方式之前都是有一些區別的,但是核心的思想沒有變化,因此記錄一下自己對霍夫變換直線檢測的認識。
一、原理介紹:
1、對於直角座標系中的任意一點A(x0,y0),經過點A的直線滿足Y0=k*X0+b.(k是斜率,b是截距)
2、那麼在X-Y平面過點A(x0,y0)的直線簇可以用Y0=k*X0+b表示,但對於垂直於X軸的直線斜率是無窮大的則無法表示。因此將直角座標系轉換到極座標系就能解決該特殊情況。
3、在極座標系中表示直線的方程爲ρ=xCosθ+ySinθ(ρ爲原點到直線的距離),如圖所示:
4、如上圖,假定在一個8*8的平面像素中有一條直線,並且從左上角(1,8)像素點開始分別計算θ爲0°、45°、90°、135°、180°時的ρ,圖中可以看出ρ分別爲1、(9√2)/2、8、(7√2)/2、-1,並給這5個值分別記一票,同理計算像素點(3,6)點θ爲0°、45°、90°、135°、180°時的ρ,再給計算出來的5個ρ值分別記一票,此時就會發現ρ = (9√2)/2的這個值已經記了兩票了,以此類推,遍歷完整個8*8的像素空間的時候ρ = (9√2)/2就記了5票, 別的ρ值的票數均小於5票,所以得到該直線在這個8*8的像素座標中的極座標方程爲 (9√2)/2=x*Cos45°+y*Sin45°,到此該直線方程就求出來了。(PS:但實際中θ的取值不會跨度這麼大,一般是PI/180)。
二、Opencv實現直線檢測:
1、Opencv1.0版本:
#include<cv.h>
#include<highgui.h>
int main()
{
IplImage* pImgSrc = NULL; //源圖像
IplImage* pImg8u = NULL; //灰度圖
IplImage* pImgCanny = NULL; //邊緣檢測後的圖
IplImage* pImgDst = NULL; //在圖像上畫上檢測到的直線後的圖像
CvSeq* lines = NULL;
CvMemStorage* storage = NULL;
/*邊緣檢測*/
pImgSrc = cvLoadImage(".\\res\\street.jpg", 1);
pImg8u = cvCreateImage(cvGetSize(pImgSrc), IPL_DEPTH_8U, 1);
pImgCanny = cvCreateImage(cvGetSize(pImgSrc), IPL_DEPTH_8U, 1);
pImgDst = cvCreateImage(cvGetSize(pImgSrc), IPL_DEPTH_8U, 1);
cvCvtColor(pImgSrc, pImg8u, CV_BGR2GRAY);
cvCanny(pImg8u, pImgCanny, 20, 200, 3);
/*檢測直線*/
storage = cvCreateMemStorage(0);
lines = cvHoughLines2(pImgCanny, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 80, 200, 10);
pImgDst = cvCreateImage(cvGetSize(pImgSrc), IPL_DEPTH_8U, 3);
cvCvtColor(pImg8u, pImgDst, CV_GRAY2BGR);
/*在pImgDst上畫出檢測到的直線*/
for (int i = 0; i < lines->total; i++)
{
CvPoint* line = (CvPoint*)cvGetSeqElem(lines, i);
cvLine(pImgDst, line[0], line[1], CV_RGB(255, 0, 0), 3, 8);
}
cvNamedWindow("src", 1);
cvNamedWindow("canny", 1);
cvNamedWindow("hough", 1);
cvShowImage("src", pImgSrc);
cvShowImage("canny", pImgCanny);
cvShowImage("hough", pImgDst);
cvWaitKey(0);
cvReleaseImage(&pImgSrc);
cvReleaseImage(&pImg8u);
cvReleaseImage(&pImgCanny);
cvReleaseImage(&pImgDst);
cvReleaseMemStorage(&storage);
return 0;
}
2、Opencv2.4.9版本:
#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat Image = imread(".//res//street.jpg", 0);
Mat CannyImg;
Canny(Image, CannyImg, 140, 250, 3);
imshow("CannyImg", CannyImg);
Mat DstImg;
cvtColor(Image, DstImg, CV_GRAY2BGR);
vector<Vec4i> Lines;
HoughLinesP(CannyImg, Lines, 1, CV_PI / 360, 170,30,15);
for (size_t i = 0; i < Lines.size(); i++)
{
line(DstImg, Point(Lines[i][0], Lines[i][1]), Point(Lines[i][2], Lines[i][3]), Scalar(0, 0, 255), 2, 8);
}
imshow("HoughLines_Detect", DstImg);
imwrite(".//res//HoughLines_Detect.jpg", DstImg);
waitKey(0);
return 0;
}
3、效果圖:
三、推薦一個國外公路直線檢測的大神的個人主頁(有很多資源和源碼):
Mohamed Aly:http://www.vision.caltech.edu/malaa/research/
他研究了公路上的直線(斑馬線)等的檢測。