霍夫直線檢測(投票)
霍夫變換是一種在圖像中尋找直線,圓及其他簡單形狀的方法。 opencv支持兩種不同的霍夫變換:標準霍夫變換(SHT)和累積概率霍夫變換(PPHT)。
在opencv中可以使用同一個函數來使用兩種算法。
CvSeq* cvHonghLines2(CvArr* image, void* line_storage,int mehtod, double rho, double theta, int threshold, double param1 =0, double param2 =0 );
image 輸入 8-比特、單通道 (二值) 圖像
line_storage 存儲檢測到的線段,可以是序列或者單行/單列矩陣
mehtod Hough 變換變量 rho 與象素相關單位的距離精度theta 弧度測量的角度精度
threshold 閾值參數。如果相應的累計值大於 threshold, 則函數返回的這個線段
Param1:對傳統 Hough 變換,不使用(0);對概率 Hough 變換,它是最小線段長度.
Param2:對傳統 Hough 變換,不使用 (0);對概率 Hough 變換,這個參數表示在同一條直線上進行碎線段連接的最大間隔值(gap), 即當同一條直線上的兩條碎線段之間的間隔小於param2時,將其合二爲一。
二、霍夫直線檢測原理
Hough變換在計算機視覺、軍事防禦、辦公自動化等領域都得到了普遍的關注和廣泛的應用。其基本思想是將原圖像變換到參數空間,
用大多數邊界點滿足某種參數形式來描述圖像中的線,通過設置累加器進行累積,求得峯值對應的點所需要的信息。
Hough變換以其對局部缺損的不敏感,對隨機噪聲的魯棒性以及適於並行處理等優良特性,備受圖像處理、模式識別和計算機視覺領域學者的青睞。
Hough變換的突出優點就是可以將圖像中較爲困難的全局檢測問題轉換爲參數空間中相對容易解決的局部峯值檢測問題。
1962 年,Paul Hough根據數學對偶性原理提出了檢測圖像直線的方法,此後該方法被不斷地研究和發展,主要應用於模式識別領域中對二值圖像進行直線檢測。
1、Hough變換原理
a.在圖像中檢測直線的問題,其實質是找到構成直線的所有的像素點。那麼問題就是從找到直線,變成找到符合y=kx+b的所有(x,y)的點的問題。
b.進行座標系變化y=kx+b,變成b=-xk+y。這樣表示爲過點(k,b)的直線束。
c.x-y空間的直線上每一個點在k-b座標系中都表現爲經過(k,b)的直線。找到所有點的問題,轉變爲尋找直線的問題。
d.對於圖像中的每一個點,在k-b座標系中對應着很多的直線。找到直線的交點,就對應着找到圖像中的直線。
目前,opencv霍夫檢測直線常用的方法是,是將平面中任一條直線用極座標方式表示:ρ=xcosθ+ysinθ ,
其中p表示直角座標系中原點到直線的距離,θ表示x軸與p的夾角這樣,圖像平面上的一個點就對應到ρ-θ平面上的一條曲線上。
如果對位於同一直線上的n個點進行變換,原圖像空間的n個點在參數空間對應得到有n條正弦曲線,並且這些曲線相交於一點。
2、Hough檢測步驟
Hough變換在算法設計上就可以如下步驟:
a.在ρ,θ合適的最大值與最小值之間建立一個離散的參數空間,如下圖1-1。
b.將參數空間(ρ,θ) 量化成m*n(m爲ρ的等份數,n爲θ的等份數)個單元,並設置累加器矩陣,如下圖。
c.給參數空間的每一個單元分配一個累加器Q(i,j),並把累加器的初始值設置爲0
d.對圖像邊界上的每一個點(x,y)帶入ρ=xcosθ+ysinθ,求得每個θ對應的ρ值
e.在參數空間中,找到ρ和θ所對應的單元,並將該單元的累加器加1,即:Q(i,j)=Q(i,j)+1。
f.當直角座標系中的所有點都經過4和5兩步遍歷後,檢驗參數空間中每個累加器的值,累加器最大的單元所對應的ρ和θ即爲直角座標系中直線方程的參數。
注意:當直角座標系中的點分佈在 R 條直線附近時,可在第 5 步檢測累加器時,取出累加器中前 R 個值最大的單元所對應的ρk和θk(k=1,2,…,R ),
以ρk和θk爲直角座標系中直線方程式ρ=xcosθ+ysinθ的參數,即可同時實現多條直線的檢測。
3、總結
由上所述,Hough 變換的基本策略是:用圖像空間的邊緣數據點計
算參數空間中的參考點的可能軌跡,並在一個累加器中給計算出參考點的計數,最後選出峯值。該峯值表明在圖像空間上有一共線點較多的直線,
該直線的參數由累加器的ρ和θ決定,即按照 Q(i,j)=Q (i,j)+1確定,則圖像空間中滿足該式的點(x,y)就組成了該直線。
API介紹
void cv::HoughLinesP( InputArray _image, OutputArray _lines,
double rho, double theta, int threshold,
double minLineLength, double maxGap )
- image: 必須是二值圖像,推薦使用canny邊緣檢測的結果圖像;
- rho: 線段以像素爲單位的距離精度,double類型的,推薦用1.0
- theta: 線段以弧度爲單位的角度精度,推薦用numpy.pi/180 或CV_PI/180
- threshod: 累加平面的閾值參數,int類型,超過設定閾值才被檢測出線段,值越大,基本上意味着檢出的線段越長,檢出的線段個數越少。根據情況推薦先用100試試
- lines:是一個vector<Vec4i>,Vec4i是一個包含4個int數據類型的結構體,[x1,y1,x2,y2],可以表示一個線段
- minLineLength:線段以像素爲單位的最小長度,根據應用場景設置
- maxLineGap:同一方向上兩條線段判定爲一條線段的最大允許間隔(斷裂),超過了設定值,則把兩條線段當成一條線段,值越大,允許線段上的斷裂越大,越有可能檢出潛在的直線段
霍夫直線檢測實例
-
高斯(均值)模糊
-
轉灰度
-
canny邊緣提取
-
霍夫邊緣提取
以下爲具體步驟以及實現:
1. 彩色圖像RBG->灰度圖Gray
(opencv上需要注意顏色空間是RGB還是BGR,CImg中RGB分別對應0,1,2通道)
2. 去噪(高斯核)
3. 邊緣提取(梯度算子、拉普拉斯算子、canny; 此處實現用sobel)
4. 二值化(判斷此處是否爲邊緣點,就看灰度值==255),在高斯去噪和邊界提取之後都需要二值化
5. 映射到霍夫空間(此處準備兩個容器,一個CImg用來展示hough-space概況,一個數組hough-space用來儲存voting的值,因爲投票過程往往有某個極大值超過255,多達幾千,不能直接用灰度圖來記錄投票信息)
6. 取局部極大值,設定閾值,過濾干擾直線
7. 繪製直線、標定角點
示例代碼
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
Mat src1,gray_src,src2,dst;
int main()
{
src1 = imread("C:\\Users\\馬迎偉\\Desktop\\douyin.jpg");
if (src1.empty())
{
cout << "could not find src1" << endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src1);
//霍夫直線 canny邊緣提取 --> cvtcolor轉灰度 --> HoughLinesP霍夫邊緣檢測
cvtColor(src1,src1,CV_BGR2GRAY);
Canny(src1,gray_src,100,200,3,false);
cvtColor(gray_src,dst,CV_GRAY2BGR);
vector<Vec4f> lines;
//'1'生成極座標時候的像素掃描步長,'CV_PI/180'生成極座標時候的角度步長,'10'最小直線長度,'0'最大間隔(能構成一條直線)
HoughLinesP(gray_src,lines,1,CV_PI/180,10,0,0);
Scalar color = Scalar(0,0,255);
for (size_t i = 0; i < lines.size(); i++)
{
Vec4f plines=lines[i]; //一個plines裏邊是四個點一條直線
line(dst,Point(plines[0],plines[1]),Point(plines[2],plines[3]),color,3,LINE_AA);
}
imshow("output", dst);
waitKey(0);
return 0;
}