相比C++而言,Python適合做原型。本系列的文章介紹如何在Python中用OpenCV圖形庫,以及與C++調用相應OpenCV函數的不同之處。這篇文章介紹在Python中使用OpenCV的霍夫變換檢測直線。
提示:
- 轉載請詳細注明原作者及出處,謝謝!
- 本文介紹在OpenCV-Python中使用霍夫變換檢測直線的方法。
- 本文不介詳細的理論知識,讀者可從其他資料中獲取相應的背景知識。筆者推薦清華大學出版社的《圖像處理與計算機視覺算法及應用(第2版) 》。
霍夫變換
Hough變換是經典的檢測直線的算法。其最初用來檢測圖像中的直線,同時也可以將其擴展,以用來檢測圖像中簡單的結構。
OpenCV提供了兩種用於直線檢測的Hough變換形式。其中基本的版本是cv2.HoughLines。其輸入一幅含有點集的二值圖(由非0像素表示),其中一些點互相聯系組成直線。通常這是通過如Canny算子獲得的一幅邊緣圖像。cv2.HoughLines函數輸出的是[float, float]形式的ndarray,其中每個值表示檢測到的線(ρ , θ)中浮點點值的參數。下面的例子首先使用Canny算子獲得圖像邊緣,然后使用Hough變換檢測直線。其中HoughLines函數的參數3和4對應直線搜索的步長。在本例中,函數將通過步長為1的半徑和步長為π/180的角來搜索所有可能的直線。最后一個參數是經過某一點曲線的數量的閾值,超過這個閾值,就表示這個交點所代表的參數對(rho, theta)在原圖像中為一條直線。具體理論可參考這篇文章。
#coding=utf-8 import cv2 import numpy as np img = cv2.imread("/home/sunny/workspace/images/road.jpg", 0) img = cv2.GaussianBlur(img,(3,3),0) edges = cv2.Canny(img, 50, 150, apertureSize = 3) lines = cv2.HoughLines(edges,1,np.pi/180,118) #這里對最后一個參數使用了經驗型的值 result = img.copy() for line in lines[0]: rho = line[0] #第一個元素是距離rho theta= line[1] #第二個元素是角度theta print rho print theta if (theta < (np.pi/4. )) or (theta > (3.*np.pi/4.0)): #垂直直線 #該直線與第一行的交點 pt1 = (int(rho/np.cos(theta)),0) #該直線與最后一行的焦點 pt2 = (int((rho-result.shape[0]*np.sin(theta))/np.cos(theta)),result.shape[0]) #繪制一條白線 cv2.line( result, pt1, pt2, (255)) else: #水平直線 # 該直線與第一列的交點 pt1 = (0,int(rho/np.sin(theta))) #該直線與最后一列的交點 pt2 = (result.shape[1], int((rho-result.shape[1]*np.cos(theta))/np.sin(theta))) #繪制一條直線 cv2.line(result, pt1, pt2, (255), 1) cv2.imshow('Canny', edges ) cv2.imshow('Result', result) cv2.waitKey(0) cv2.destroyAllWindows()
結果如下:
注意:
在C++中,HoughLines函數得到的結果是一個向量lines,其中的元素是由兩個元素組成的子向量(rho, theta),所以lines的訪問方式類似二維數組。因此,可以以類似:
std::vector<cv::Vec2f>::const_iterator it= lines.begin(); float rho= (*it)[0]; float theta= (*it)[1];
這樣的方式訪問rho和theta。
而在Python中,返回的是一個三維的np.ndarray!。可通過檢驗HoughLines返回的lines的ndim屬性得到。如:
lines = cv2.HoughLines(edges,1,np.pi/180,118) print lines.ndim #將得到3
至於為什么是三維的,這和NumPy中ndarray的屬性有關(關於NumPy的相關內容,請移步至 NumPy簡明教程),如果將HoughLines檢測到的的結果輸出,就一目了然了:
#上面例子中檢測到的lines的數據 3 #lines.ndim屬性 (1, 5, 2) #lines.shape屬性 #lines[0] [[ 4.20000000e+01 2.14675498e+00] [ 4.50000000e+01 2.14675498e+00] [ 3.50000000e+01 2.16420817e+00] [ 1.49000000e+02 1.60570288e+00] [ 2.24000000e+02 1.74532920e-01]] =============== #lines本身 [[[ 4.20000000e+01 2.14675498e+00] [ 4.50000000e+01 2.14675498e+00] [ 3.50000000e+01 2.16420817e+00] [ 1.49000000e+02 1.60570288e+00] [ 2.24000000e+02 1.74532920e-01]]]
概率霍夫變換
觀察前面的例子得到的結果圖片,其中Hough變換看起來就像在圖像中查找對齊的邊界像素點集合。但這樣會在一些情況下導致虛假檢測,如像素偶然對齊或多條直線穿過同樣的對齊像素造成的多重檢測。
要避免這樣的問題,並檢測圖像中分段的直線(而不是貫穿整個圖像的直線),就誕生了Hough變化的改進版,即概率Hough變換(Probabilistic Hough)。在OpenCV中用函數cv::HoughLinesP 實現。如下:
#coding=utf-8 import cv2 import numpy as np img = cv2.imread("/home/sunny/workspace/images/road.jpg") img = cv2.GaussianBlur(img,(3,3),0) edges = cv2.Canny(img, 50, 150, apertureSize = 3) lines = cv2.HoughLines(edges,1,np.pi/180,118) result = img.copy() #經驗參數 minLineLength = 200 maxLineGap = 15 lines = cv2.HoughLinesP(edges,1,np.pi/180,80,minLineLength,maxLineGap) for x1,y1,x2,y2 in lines[0]: cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2) cv2.imshow('Result', img) cv2.waitKey(0) cv2.destroyAllWindows()
結果如下:
未完待續。。。
參考資料:
1、《Opencv2 Computer Vision Application Programming Cookbook》
2、《OpenCV References Manule》
如果覺得本文寫的還可以的話,請輕點“頂”,您的支持是我寫下去的動力之一。未完待續。。。如有錯誤請指正,本人會虛心接受並改正!謝謝!