5

我正在使用 python 开发基于 OpenCV 的项目,我必须计算/提取并直观地显示现有行的消失点。

我的第一个任务是检测线条,这很容易使用 Canny 和 HoughLinesP 函数:

import cv2
import numpy as np

img = cv2.imread('.image.jpg')

gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
edges = cv2.Canny(gray, 500, 460)
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30, maxLineGap=250)
for line in lines:
   x1, y1, x2, y2 = line[0]
   cv2.line(img, (x1, y1), (x2, y2), (0, 0, 128), 1)

cv2.imwrite('linesDetected.jpg', img)

在此处输入图像描述

但我想计算/推断所有线的消失点,以找到(并绘制)它们相互交叉的位置,如下图所示。

我知道我需要添加一个更大的框架来绘制线条的延续,以找到十字(消失点),但在这一点上我很迷茫。

太感谢了!!

消失点提取,视觉

4

2 回答 2

7

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)

在此处输入图像描述

在这一步,有多个选项可以找到线的交点,即消失点。我将在下面列出其中的一些。

  1. 最佳近似:所有这些线都有一个已知的 (ρ,θ),并且(理想情况下)只满足两个 (x,y) 点,我们称左边的 (x0,y0) 和右边的 (x1,y1)。如果使用上面的方程 ρ=xcosθ+ysinθ 创建一个包含所有这些变量的线性系统,则可以将其写为 ρ_n=[xy][cosθ_n sinθ_n]T。这会将问题转化为线性回归,您可以求解最佳 (x,y) 点。您可以根据斜率对线进行排序,并为 (x0,y0) 和 (x1,y1) 创建两个线性系统。
  2. 繁琐的解决方案:如评论之一所述,您可以找到所有线的成对交点,然后根据邻近度对它们进行聚类,并根据交点数量对聚类进行阈值处理。然后您可以输出两个人口最多的集群的集群均值。
  3. 简单的基于图像的解决方案:由于您已经有了交叉点的图像,您可以进行一些图像处理来找到点。这绝不是一个精确的解决方案,它是一个快速和近似的解决方案。您可以通过与您的线条大小相同的内核进行侵蚀来消除线条。然后,您可以通过使用更大内核的膨胀来加强交叉点。然后,如果您使用稍大的内核进行关闭操作,则只会保留最强的交叉点。您可以将这些 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)

在此处输入图像描述 在此处输入图像描述

于 2020-03-03T21:32:58.017 回答
-1

如果你想从图像中找到消失点,你需要画线。为此,您可以使用霍夫变换。它做了什么,它会在图像上绘制所有可能的线条。您可以根据需要调整它的参数。它将为您提供大多数线相交的交点。虽然这是一种不完全正确的估计,但你可以说它是完全估计的。您也可以根据需要使用其他形式的霍夫。

在这种情况下,标准霍夫变换就足够了。

于 2020-03-03T09:14:17.473 回答