1. 程式人生 > >直線檢測(line detection)之霍夫變換

直線檢測(line detection)之霍夫變換

前言

  [影象處理] 實驗筆記系列是以影象處理演算法為主的文章專欄,以我在演算法研究中的實驗筆記資料為基礎加以整理推出的。該系列內容涉及常見的影象處理演算法理論以及常見的演算法應用,每篇部落格都會介紹相關的演算法原理,程式碼實現和演算法在實際應用中的技巧。
  本文主要整理自筆者在一項影象處理任務中的直線檢測(line detection)部分的筆記資料,採用了基於霍夫變換(Hough Transform)的直線檢測演算法。文中給出了直線檢測常用的演算法介紹,論文資料等,以及筆者的實驗筆記和實驗結果。
  
  文章小節安排如下:
  1)直線檢測相關演算法
  2)霍夫直線檢測的基本原理
  3)霍夫直線檢測的OpenCV實現
  4)直線檢測的應用
  
  

一、直線檢測相關演算法  

1.1 霍夫變換(Hough Transform) 

  霍夫變換(Hough Transform)換於1962年由Paul Hough 首次提出,後於1972年由Richard Duda和Peter Hart推廣使用,是影象處理中從影象中檢測幾何形狀的基本方法之一。經典霍夫變換用來檢測影象中的直線,後來霍夫變換經過擴充套件可以進行任意形狀物體的識別,例如圓和橢圓。
  
  霍夫變換運用兩個座標空間之間的變換將在一個空間中具有相同形狀的曲線或直線對映到另一個座標空間的一個點上形成峰值,從而把檢測任意形狀的問題轉化為統計峰值問題。
  
  參考論文:
  [1] P.V.C. Hough,Machine Analysis of Bubble Chamber Pictures, Proc. Int. Conf. High Energy Accelerators and Instrumentation, 1959.
  [2] Duda, R. O. and P. E. Hart, “Use of the Hough Transformation to Detect Lines and Curves in Pictures,”Comm. ACM, Vol. 15, pp. 11–15 (January, 1972).
  
  

1.2 霍夫直線檢測(Hough Line Detection) 

  Hough直線檢測的基本原理在於利用點與線的對偶性,在我們的直線檢測任務中,即影象空間中的直線與引數空間中的點是一一對應的,引數空間中的直線與影象空間中的點也是一一對應的。這意味著我們可以得出兩個非常有用的結論:
  1)影象空間中的每條直線在引數空間中都對應著單獨一個點來表示;
  2)影象空間中的直線上任何一部分線段在引數空間對應的是同一個點。
  
  因此Hough直線檢測演算法就是把在影象空間中的直線檢測問題轉換到引數空間中對點的檢測問題,通過在引數空間裡尋找峰值來完成直線檢測任務。
  

1.3 LSD
 

  -待續-
  

二、霍夫直線檢測的基本原理

2.1 關於對偶性

  首先,我們通過例項來解釋一下對偶性的意義。
  1)影象空間中的點與引數空間中的直線一一對應
  在影象空間x-y中一條直線在直角座標系下可以表示為:
  

直線方程
  其中k和b是引數,對應表示斜率和截距。
  影象空間的直線
  過某一點A(x0, y0)的所有直線的引數均滿足方程y0=k*x0+b,即點A(x0, y0)確定了一族直線。
  如果我們將方程改寫為:
  直接方程形式改寫
  那麼該方程在引數空間k-b中就對應了一條直線:
  引數空間的直線
  也就是說,影象空間x-y中的點(x0,y0)對應了引數空間k-b中的直線b=-k*x0+y0。因此可以得到結論,影象空間中的點與引數空間中的直線一一對應。
  
  2)影象空間中的直線與引數空間中的點一一對應
  我們在直線y=k*x+b上再增加一個點B(x1, y1),如下圖所示:
  影象空間的直線
  那麼點B(x1, y1)在引數空間同樣對應了一條直線:
  引數空間的直線  
  可以看到,影象空間x-y中的點A和點B在引數空間k-b中對應的直線相交於一點,這也就是說AB所確定的直線,在引數空間中對應著唯一一個點,這個點的座標值(k0, b0)也就是直線AB的引數。
  
  以上就是在直線檢測任務中關於對偶性的直觀解釋。這個性質也為我們解決直線檢測任務提供了方法,也就是把影象空間中的直線對應到引數空間中的點,最後通過統計特性來解決問題。假如影象空間中有兩條直線,那麼最終在引數空間中就會對應到兩個峰值點,依此類推。
  

2.2 引數空間的選擇

  上述為了方便講解對偶性和霍夫變換的基本原理,我們的引數空間也選擇了笛卡爾直角座標系。但在實際應用中,引數空間是不能選擇直角座標系的,因為原始影象直角座標空間中的特殊直線x=c(垂直x軸,直線的斜率為無窮大)是沒辦法在基於直角座標系的引數空間中表示的。
  
  所以在實際應用中,引數空間採用極座標系ρ-θ,圖示如下:
  

引數空間選擇極座標系時的直線示意
  直線的表示式為:
  直線表示式

  化簡便可得到:
  

化簡的直線表示式
  對於直線上的點(x0, y0),可以將通過該點的直線族定義為:
  經過指定點的直線族表示式
  
  
  這就回到我們剛才的結論,引數空間的每個點(ρ,θ)都對應了影象空間的一條直線,或者說影象空間的一個點在引數空間中就對應為一條曲線。引數空間採用極座標系,這樣就可以在引數空間表示原始空間中的所有直線了。
  注意,此時影象空間(直角座標系x-y)上的一個點對應到引數空間(極座標系ρ-θ)上是一條曲線,確切的說是一條正弦曲線。
  引數空間的曲線
  

2.3 利用霍夫變換檢測直線

  如前所述,霍夫直線檢測就是把影象空間中的直線變換到引數空間中的點,通過統計特性來解決檢測問題。具體來說,如果一幅影象中的畫素構成一條直線,那麼這些畫素座標值(x, y)在引數空間對應的曲線一定相交於一個點,所以我們只需要將影象中的所有畫素點(座標值)變換成引數空間的曲線,並在引數空間檢測曲線交點就可以確定直線了。
  
  在理論上,一個點對應無數條直線或者說任意方向的直線,但在實際應用中,我們必須限定直線的數量(即有限數量的方向)才能夠進行計算。
  
  因此,我們將直線的方向θ離散化為有限個等間距的離散值,引數ρ也就對應離散化為有限個值,於是引數空間不再是連續的,而是被離散量化為一個個等大小網格單元。將影象空間(直角座標系)中每個畫素點座標值變換到引數空間(極座標系)後,所得值會落在某個網格內,使該網格單元的累加計數器加1。當影象空間中所有的畫素都經過霍夫變換後,對網格單元進行檢查,累加計數值最大的網格,其座標值(ρ0, θ0)就對應影象空間中所求的直線。
  

引數空間的量化
  
  以上就是霍夫直線檢測演算法要做的,它檢測影象中每個畫素點在引數空間對應曲線之間的交點,如果交於一點的曲線的數量超過了閾值,那就可以認為這個交點(ρ,θ)在影象空間中對應一條直線。
    
    

2.4 霍夫直線檢測的優缺點

  優點:
  Hough直線檢測的優點是抗干擾能力強,對影象中直線的殘缺部分、噪聲以及其它共存的非直線結構不敏感。
  缺點:
  Hough變換演算法的特點導致其時間複雜度和空間複雜度都很高,並且在檢測過程中只能確定直線方向,丟失了線段的長度資訊。
  
  

三、霍夫直線檢測的OpenCV實現  

  OpenCV支援三種霍夫直線檢測演算法:
  1)Standard Hough Transform(SHT,標準霍夫變換)
  2)Multiscale Hough Transform(MSHT,多尺度霍夫變換)
  3)Progressive Probability Houth Transform(PPHT,漸進概率式霍夫變換)
  

3.1 霍夫直線檢測函式定義

  在OpenCV2.1之前的版本,霍夫直線檢測函式如下:
  
  函式原型:

CVAPI(CvSeq*) cvHoughLines2( CvArr* image, void* line_storage, int method,
  double rho, double theta, int threshold,
  double param1 CV_DEFAULT(0), double param2 CV_DEFAULT(0),
  double min_theta CV_DEFAULT(0), double max_theta CV_DEFAULT(CV_PI));

  函式說明:
  cvHoughLines2老版OpenCV的霍夫直線檢測函式,通過method引數可以支援三種霍夫直線檢測演算法,分別是CV_HOUGH_STANDARD、CV_HOUGH_PROBABILISTIC =1、CV_HOUGH_MULTI_SCALE。
  
  
  在OpenCV新版本下,霍夫直線檢測演算法定義了兩個函式:HoughLines、HoughLinesP
  1)HoughLines:標準霍夫變換、多尺度霍夫變換
  函式原型:

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 );
  

  引數說明:
  InputArray image:輸入影象,必須是8位單通道影象。
  OutputArray lines:檢測到的線條引數集合。
  double rho:以畫素為單位的距離步長。
  double theta:以弧度為單位的角度步長。
  int threshold:累加計數值的閾值引數,當引數空間某個交點的累加計數的值超過該閾值,則認為該交點對應了影象空間的一條直線。
  double srn:預設值為0,用於在多尺度霍夫變換中作為引數rho的除數,rho=rho/srn。
  double stn:預設值為0,用於在多尺度霍夫變換中作為引數theta的除數,theta=theta/stn。
  
  函式說明:
  HoughLines函式輸出檢測到直線的矢量表示集合,每一條直線由具有兩個元素的向量(ρ, θ)表示,其中ρ表示直線距離原點(0, 0)的長度,θ表示直線的角度(以弧度為單位)。
HoughLines函式無法輸出影象空間中線段的長度,這也是霍夫變換本身的弱點。

  
  備註說明:
  如果srn和stn同時為0,就表示HoughLines函式執行標準霍夫變換,否則就是執行多尺度霍夫變換。
  
  
  2)HoughLinesP:漸進概率式霍夫變換
  函式原型:

CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines,
  double rho, double theta, int threshold,
  double minLineLength = 0, double maxLineGap = 0 );
  

  引數說明:
  InputArray image:輸入影象,必須是8位單通道影象。
  OutputArray lines:檢測到的線條引數集合。
  double rho:直線搜尋時的距離步長,以畫素為單位。
  double theta:直線搜尋時的角度步長,以弧度為單位。
  int threshold:累加計數值的閾值引數,當引數空間某個交點的累加計數的值超過該閾值,則認為該交點對應了影象空間的一條直線。
  double minLineLength:預設值為0,表示最小線段長度閾值(畫素)。
  double maxLineGap:預設值為0,表示直線斷裂的最大間隔距離閾值。即如果有兩條線段是在一條直線上,但它們之間有間隙,那麼如果這個間隔距離大於該值,則被認為是一條線段,否則認為是兩條線段。
  
  函式說明:
  HoughLinesP函式輸出檢測到直線的矢量表示集合,每一條直線由具有四個元素的向量(x1, y1, x2, y2)表示,其中(x1, y1)表示線段的起點,(x2, y2)表示線段的終點。
  HoughLinesP函式可以檢測出影象空間中線段的長度。

  
  

3.2 霍夫直線檢測函式使用

  霍夫直線變換是一種用來在影象空間尋找直線的方法,輸入影象要求是二值影象,同時為了提高檢測直線的效率和準確率,在使用霍夫線變換之前,最好對影象進行邊緣檢測生成邊緣二值影象,這樣的檢測效果是最好的。
  
  1)HoughLines函式
  程式碼:

std::string img_path;
cv::Mat mat_color;
cv::Mat mat_gray;
cv::Mat mat_binary;
cv::Mat mat_canny;
cv::Mat mat_board;

img_path = "line.png";
mat_color = cv::imread(img_path, 1);
mat_gray = cv::imread(img_path, 0);
mat_board = cv::Mat(mat_color.size(), mat_color.type(), Scalar::all(255));

// binary
cv::threshold(mat_gray, mat_binary, 0.0, 255.0, cv::THRESH_OTSU);
// invert color
cv::bitwise_not(mat_binary, mat_binary);

// detect edge
Canny(mat_binary, mat_canny, 50, 200, 3);

// detect line
vector<Vec2f> lines;
HoughLines(mat_canny, lines, 1, CV_PI / 180, 150, 0, 0);

// draw line
cout << "line number: " << lines.size() << endl;
for (size_t i = 0; i < lines.size(); i++)
{
    Vec2f linex = lines[i];
    cout << "radius: " << linex[0] << ", radian: "<< linex[1] << ", angle: " << 180 / CV_PI * linex[1] << endl;
    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(mat_board, pt1, pt2, Scalar(255, 0, 0), 1);
}
cv::imshow("gray", mat_gray);
cv::imshow("binary", mat_binary);
cv::imshow("canny", mat_canny);
cv::imshow("color", mat_board);
cv::waitKey();

  原圖:
  

原圖
  二值圖:
  二值圖
  邊緣圖:
  邊緣圖
  檢測效果:
  HoughLines的檢測效果
  
  2)HoughLinesP函式
  程式碼:
std::string img_path;
cv::Mat mat_color;
cv::Mat mat_gray;
cv::Mat mat_binary;
cv::Mat mat_canny;
cv::Mat mat_board;

img_path = "line.png";
mat_color = cv::imread(img_path, 1);
mat_gray  = cv::imread(img_path, 0);
mat_board = cv::Mat(mat_color.size(), mat_color.type(), Scalar::all(255));

// binary
cv::threshold(mat_gray, mat_binary, 0.0, 255.0, cv::THRESH_OTSU);
// invert color
cv::bitwise_not(mat_binary, mat_binary);

// detect edge
Canny(mat_binary, mat_canny, 50, 200, 3);

// detect line
vector<Vec4i> lines;
HoughLinesP(mat_canny, lines, 1, CV_PI / 180, 150, 50, 50);

// draw line
cout << "line number: " << lines.size() << endl;
for (size_t i = 0; i < lines.size(); i++)
{
    Vec4i linex = lines[i];
    line(mat_board, Point(linex[0], linex[1]), Point(linex[2], linex[3]), Scalar(255, 0, 0), 1);
}

cv::imshow("gray",   mat_gray);
cv::imshow("binary", mat_binary);
cv::imshow("canny", mat_canny);
cv::imshow("color", mat_board);
cv::waitKey();

  檢測效果:
  

HoughLinesP的檢測效果
  
  

四、直線檢測的應用

4.1 直線檢測的實際應用

  直線檢測是機器視覺和模式識別中最重要的任務之一,對影象理解/分析等有重要的意義。在實際應用中,直線檢測可用於機器人定位中的網格識別,板材的裂紋檢測,表單票據的格式識別,零件紋路的檢測,自動駕駛中的車道檢測等等,可以看出,在工業領域中,直線檢測以及各種影象處理技術應用是非常豐富的。
  

4.2 直線檢測在影象矯正方面的應用

  筆者最近在一個OCR專案也使用了Hough Line Detection演算法。在該專案中,待識別文字影象的內容是傾斜的(即文字是傾斜的),我們採用的測略就是通過直線檢測確定影象內容的傾斜程度並進行旋轉糾正,這樣得到的無傾斜影象更有利於OCR任務。
  原圖:
  

原圖
  矯正效果:
  矯正效果
  

五、參考資料

參考論文與書目:
[1] Duda, R. O. and P. E. Hart, “Use of the Hough Transformation to Detect Lines and Curves in Pictures,”Comm. ACM, Vol. 15, pp. 11–15 (January, 1972).
[2] 顧思妍. 機器視覺的直線檢測技術及應用研究[D].廣東工業大學,2011.
[3] 數字影象處理[M]. 電子工業出版社 , (美)RafaelC.Gonzalez,(美)RichardE.Woods,(美)StevenL.Eddins著, 2005