OpenCV-Python教程(9、使用霍夫變換檢測直線)


相比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》

如果覺得本文寫的還可以的話,請輕點“頂”,您的支持是我寫下去的動力之一。未完待續。。。如有錯誤請指正,本人會虛心接受並改正!謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM