【OpenCV-Python】教程:3-13 Hough直线变换

OpenCV Python Hough直线变换

【目标】

  • 理解Hough变换的概念
  • 学会使用Hough变换检测直线
  • cv2.HoughLines(), cv2.HoughLinesP()

【理论】

Hough 变换是一个非常有用的技术,可以检测任何形状,只要那个形状可以通过数学方程表示出来,即使检测的形状断裂或者轻微变形。

直线方程为:

y = m x + c y=mx+c y=mx+c

或者极坐标参数表示形式:

ρ = x ∗ cos ⁡ θ + y ∗ sin ⁡ θ \rho=x*\cos\theta+y*\sin\theta ρ=xcosθ+ysinθ

其中, ρ \rho ρ是原点到直线的垂直距离, θ \theta θ是垂直线与逆时针测量的水平轴形成的角度。

任何直线都可以用 ( ρ , θ ) (\rho,\theta) (ρ,θ) 来表示。Hough变换是如何检测直线的呢?首先它创建一个2D数组或累加器,并将其初始设置为 0,设行表示 ρ \rho ρ,列表示 θ \theta θ。数组的大小取决于精度,假设角度的精度为1度,则需要180列。对于 ρ \rho ρ,可能的最大距离是图像的对角线长度。因此,以一个像素的精度计算,行数可以是图像的对角线长度。

假设一个 100 ∗ 100 100*100 100100的图像,在图像中间有一个水平线,取这条线的第一个点 ( x , y ) (x,y) (x,y),计算 ( ρ , θ ) (\rho,\theta) (ρ,θ),对于每一个 ( ρ , θ ) (\rho,\theta) (ρ,θ) ,如果 ( x , y ) (x,y) (x,y)能找到对应的 ( ρ , θ ) (\rho,\theta) (ρ,θ),增加递增器的值。循环往复,对图像中所有的点都进行查找搜寻,不停的对每个 ( ρ , θ ) (\rho,\theta) (ρ,θ) 进行投票,假设在 ( 50 , 90 ) (50,90) (50,90)投票最多,请看下面的动画。

【OpenCV-Python】教程:3-13 Hough直线变换_第1张图片
Image Courtesy: Amos Storkey

【OpenCV-Python】教程:3-13 Hough直线变换_第2张图片

概率 Hough 变换

在Hough变换中,尽管一条直线只有两个参数,但是还需要很多计算量,概率 Hough 变换是其中的一种优化,它不会将所有的点都考虑进去,相反,它会考虑一些能够充分进行直线检测的随机点集。我们必须降低 threshold,流程图如下:

【OpenCV-Python】教程:3-13 Hough直线变换_第3张图片image
Image Courtesy : Franck Bettinger's home page

OpenCV 的实现基于 Robust Detection of Lines Using the Progressive Probabilistic Hough Transform by Matas, J. and Galambos, C. and Kittler, J.V. [166]. 函数为 cv2.HoughLinesP()

【代码】

【OpenCV-Python】教程:3-13 Hough直线变换_第4张图片

import cv2
import numpy as np

# 读入图像
img = cv2.imread('assets/sudoku.png')

# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 边缘检测
edges = cv2.Canny(gray, threshold1=50, threshold2=150, apertureSize = 3)

# 直线检测
lines = cv2.HoughLines(edges, rho=1, theta=np.pi/180, threshold=150 )


for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a*rho
    y0 = b*rho
    x1 = int(x0 + 1000*(-b))
    y1 = int(y0 + 1000*(a))
    x2 = int(x0 - 1000*(-b))
    y2 = int(y0 - 1000*(a))
    cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)

cv2.imshow("line", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • cv2.HoughLinesP

【OpenCV-Python】教程:3-13 Hough直线变换_第5张图片

import cv2
import numpy as np

# 读入图像
img = cv2.imread('assets/sudoku.png')

# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 边缘检测
edges = cv2.Canny(gray, threshold1=50, threshold2=150, apertureSize=3)

# 直线检测
lines = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180, threshold=100, minLineLength=100, maxLineGap=10)

for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1, y1), (x2, y2), color=(0, 255, 0), thickness=2)

cv2.imshow("line", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

【接口】

  • HoughLines
cv.HoughLines(	image, rho, theta, threshold[, lines[, srn[, stn[, min_theta[, max_theta]]]]]	) ->	lines

用标准的Hough变换找二值图像中的直线

  • image: 8位单通道二值图像,图像可能被篡改
  • lines: 输出的直线 vector/list,每个直线是 ( ρ , θ , v o t e s ) (\rho, \theta, votes) (ρ,θ,votes) 表示, ρ \rho ρ是图像原点(左上角)到直线的距离, θ \theta θ是旋转的弧度,(0~vertical_line, pi/2 ~ horizontal line), v o t e s votes votes是投票值。
  • rho: 距离精度,单位像素
  • theta: 角度精度,单位弧度
  • threshold: 累积阈值,主要用于对投票值进行限制,只返 v o t e s votes votes 大于该值的 line
  • srn: 多尺度的Hough变换,是 rho 的除数,如果srn为0和stn=0时,则使用经典Hough变换,否则,这两个参数都应为正值,
  • stn: 多尺度的Hough变换,是 theta 的除数,
  • min_theta: 对于标准和多尺度的Hough变换,检测线条的最小角度,必须介于 0 ~ max_theta 之间。
  • max_theta: 对于标准和多尺度的Hough变换,检测线条的最大角度,必须介于min_theta ~ CV_PI之间。
  • HoughLinesP
cv.HoughLinesP(	image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]	) ->	lines

利用概率 Hough 变换在二值图中找直线

  • image: 8位单通道二值图像,图像可能被篡改
  • lines: 输出的直线 vector/list,每个直线是 ( x 1 , y 1 , x 2 , y 2 ) (x1,y1, x2, y2) (x1,y1,x2,y2), 他们分别是线段的端点
  • rho: 距离精度,单位像素
  • theta: 角度精度,单位弧度
  • threshold: 累积阈值,主要用于对投票值进行限制,只返 v o t e s votes votes 大于该值的 line
  • minLineLength: 最小的直线长度,小于该长度的被拒绝掉。
  • maxLineGap: 允许同一条直线上连接两点之间最大的间隔。

【参考】

  1. OpenCV官方文档
  2. Hough Transform on Wikipedia
  3. Hough Transform

你可能感兴趣的:(#,OpenCV,opencv,python,计算机视觉)