OpenCV:霍夫变换

一、直线检测相关算法  

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直线检测算法就是把在图像空间中的直线检测问题转换到参数空间中对点的检测问题,通过在参数空间里寻找峰值来完成直线检测任务。
  
  

二、霍夫直线检测的基本原理

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变换算法的特点导致其时间复杂度和空间复杂度都很高,并且在检测过程中只能确定直线方向,丢失了线段的长度信息。

1.轮廓检测算法检测出轮廓
2.投射到Hough空间进行形状检测
  1)直线检测
    lines = cv2.HoughLines(image, rho, theta, threshold)

    参数: 
    image: 单通道的二进制图像
    rho: (ρ,θ)中ρ的精度。
    theta: (ρ,θ)中θ的精度。
    threshold: 阈值,(ρ,θ)对应的最低投票数。>=threshold被检测为一条线。
  2)圆检测
    circles = cv2.HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None)

    参数:
    method:定义检测图像中圆的方法。目前唯一实现的方法是HOUGH_GRADIENT。
    dp:累加器分辨率与图像分辨率的反比。
      dp=1,则累加器与输入图像具有相同的分辨率;dp=2,累加器有一半的宽度和高度。
    minDist:该参数是让算法能明显区分的两个不同圆之间的最小距离。
    param1 :用于Canny的边缘阀值上限,下限被置为上限的一半。
    param2:HOUGH_GRADIENT方法的累加器阈值(最低投票数)。阈值越小,检测到的圈子越多。
    minRadius :最小圆半径。
    maxRadius:最大圆半径。
import cv2
import numpy as np

img = cv2.imread("../data/sudoku.jpg")
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)

lines = cv2.HoughLines(edges,1,np.pi/180,200)

for i in range(len(lines)):
    rho, theta=lines[i][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.imwrite('houghlines3.jpg',img)

原始图:

OpenCV:霍夫变换_第1张图片

变换图: 

OpenCV:霍夫变换_第2张图片

 

你可能感兴趣的