霍夫变换的目的:检测直线(或者是简单的图形,例如矩形,圆等等)
例如在下图中检测车道:明显这是直线的检测,如果采用canny边缘检测,很明显忽略了直线这个重要的信息。于是不如换一种思维方式。
在直角坐标系中,直线通过y = k * x +b来表示,
实际上确定直线的参数就两个:k和b,这是一个一一对应的关系。
那不就是说可以如果将k设置为横坐标,b设置为纵坐标,那k - b坐标系上的一个点就可以表示x - y 坐标系中的一条直线了嘛。。。
但是不幸的是y = k * x +b不能表示x = c 的直线,所以我们将k - b更换为theta - p,theta和p具体含义如上图所示。通过一条x-y坐标系中的直线也可以用p - theta表示(也是一一对应的关系,同时解决了x = c 的问题 ),theta-p坐标系也称为参数空间。
那现在类推一下,直角坐标系中的一条直线在参数空间系中可以表达为一个点,直角坐标系中过一点的直线在参数空间中可以表示为一条曲线(为什么所有的散点会组成一条曲线?)。具体计算如下:
那再直角坐标系中检测一条直线也就是在极坐标系中判断曲线有没有交点。
那再直角坐标系中检测一条直线也就是在极坐标系中判断曲线有没有交点。这是理论上的说法。在实际中,是将hough空间量化为很多网格,如下图,跟踪每个曲线,对网格中的值累加。再将hough空间变换回直角坐标空间。
至于其他图形的检测具体就是看参数空间的选择,其核心思想就是将直角坐标系中的共线的检测转化为参数空间中曲线的交点(如果有一定偏差,那就不一定是一个交点,可能分布在其附近。。。)
python 代码:
#coding:utf-8
import matplotlib.pyplot as plt
import math
import random
#简略实现hough变换。
def floatrange(start, stop, steps = 500):
return [start + float(i) * (stop - start) / (float(steps) - 1) for i in range(steps)]
p1 = [10,5]
p2 = [20,10]
p3 = [30,15]
p4 = [-30,80]
def change_to_hough(p1):
print theta
y = []
for t in theta:
r = p1[0] * math.cos(t) + p1[1] * math.sin(t)
y.append(r)
print len(y)
return y
theta = floatrange(0.0, math.pi)
plt.plot(theta, change_to_hough(p1), 'g')
plt.plot(theta, change_to_hough(p2), 'b')
plt.plot(theta, change_to_hough(p3), 'r')
plt.plot(theta, change_to_hough(p4), 'y')
plt.xlabel('theta')
plt.ylabel('r')
plt.show()