cv2.HoughTransformP
如果您使用传统的实现,而不是概率霍夫变换实现,则cv2.HoughTransform
线在参数空间 (ρ,Θ) 中表示。参数空间与实际点坐标的关系为 ρ=xcosθ+ysinθ 其中 ρ 是从原点到直线的垂直距离,θ 是该垂直线与逆时针测量的水平轴形成的角度。
lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
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 + 10000*(-b))
y1 = int(y0 + 10000*(a))
x2 = int(x0 - 10000*(-b))
y2 = int(y0 - 10000*(a))
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),1)
正如您在下面看到的,消失线的投影已经开始出现。

现在,如果我们使用此特定图像的参数并跳过已经平行的垂直线,我们可以获得一组更好的消失线。
# fine tune parameters
lines = cv2.HoughLines(edges, 0.7, np.pi/120, 120, min_theta=np.pi/36, max_theta=np.pi-np.pi/36)
for line in lines:
rho,theta = line[0]
# skip near-vertical lines
if abs(theta-np.pi/90) < np.pi/9:
continue
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 10000*(-b))
y1 = int(y0 + 10000*(a))
x2 = int(x0 - 10000*(-b))
y2 = int(y0 - 10000*(a))
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),1)

在这一步,有多个选项可以找到线的交点,即消失点。我将在下面列出其中的一些。
- 最佳近似:所有这些线都有一个已知的 (ρ,θ),并且(理想情况下)只满足两个 (x,y) 点,我们称左边的 (x0,y0) 和右边的 (x1,y1)。如果使用上面的方程 ρ=xcosθ+ysinθ 创建一个包含所有这些变量的线性系统,则可以将其写为 ρ_n=[xy][cosθ_n sinθ_n]T。这会将问题转化为线性回归,您可以求解最佳 (x,y) 点。您可以根据斜率对线进行排序,并为 (x0,y0) 和 (x1,y1) 创建两个线性系统。
- 繁琐的解决方案:如评论之一所述,您可以找到所有线的成对交点,然后根据邻近度对它们进行聚类,并根据交点数量对聚类进行阈值处理。然后您可以输出两个人口最多的集群的集群均值。
- 简单的基于图像的解决方案:由于您已经有了交叉点的图像,您可以进行一些图像处理来找到点。这绝不是一个精确的解决方案,它是一个快速和近似的解决方案。您可以通过与您的线条大小相同的内核进行侵蚀来消除线条。然后,您可以通过使用更大内核的膨胀来加强交叉点。然后,如果您使用稍大的内核进行关闭操作,则只会保留最强的交叉点。您可以将这些 blob 的平均值输出为消失点。
下面,您可以看到之前的线条图像,以及运行下面的代码后生成的左右 blob 图像。
# delete lines
kernel = np.ones((3,3),np.uint8)
img2 = cv2.erode(img2,kernel,iterations = 1)
# strengthen intersections
kernel = np.ones((9,9),np.uint8)
img2 = cv2.dilate(img2,kernel,iterations = 1)
# close remaining blobs
kernel = np.ones((11,11),np.uint8)
img2 = cv2.erode(img2,kernel,iterations = 1)
img2 = cv2.dilate(img2,kernel,iterations = 1)
cv2.imwrite('points.jpg', img2)
