本文来源公众号“OpenCV与AI深度学习”,仅用于学术分享,侵权删,干货满满。
原文链接:使用OpenCV检测并计算直线角度
检测线可用于各种类型的应用,例如机器人导航、无人机导航、运动分析和交通管理。本文我们将使用HoughLinesP函数来检测线条并从线条中提取角度。

检测线
想象一下,您想要创建一架无人机或一辆可以沿着路线行驶的简单汽车。事实上,创造和使用它似乎很有趣。或者您可能想跟踪道路上的线路并根据车道对汽车进行分类。对于这些类型的程序,您需要检测线条,并且可能需要根据您的目的提取角度。OpenCV 提供了多种检测直线和提取角度的函数:
- HoughLines()
- HoughLinesP()
选择合适的功能
HoughLinesP可以检测碎片或不连续线(例如图像中的虚线或线段)时更有效。它提供有关检测到的线路的更多详细信息。
HoughLines更适合检测完整、连续的线条。当检测图像中长的、不间断的线条时,它非常有用。
我们需要一种可以检测各种形状的线条的算法,而不仅仅是直线。例如,如果道路向右成 45 度角,则 HoughLines() 函数在这种情况下可能无效。因此,我将使用HoughLinesP()函数
HoughLinesP() 函数如何工作?
我不会深入研究该HoughLinesP()函数的数学细节,因为 Google 或 Youtube 等平台上有很多可用的资源。下面简单解释一下该HoughLinesP()函数的工作原理:
OpenCV 中的函数HoughLinesP使用概率霍夫变换来检测图像中的线段。
- 从边缘检测开始提取潜在的线点,然后进行投票过程来识别经过这些点的线,在参数空间中累积投票。
- 参数空间是霍夫变换累积投票以检测图像中的线条的地方,每个维度代表被检测模型的一个参数,例如线条的斜率和截距。
- 在阈值化选择突出线之后,它提取由端点表示的线段,提供有关其位置和长度的详细信息。
这种方法可有效检测碎片或不连续的线,例如虚线或线段。
HoughLinesP() 函数的参数
HoughLinesP(image, rho, theta, threshold,minLineLength,maxLineGap)
-
image:8 位、单通道输入图像。
-
rho:累加器的距离分辨率(以像素为单位)。(1在大多数情况下是有效的)
-
theta:累加器的角度分辨率(以弧度为单位)。(np.pi/180)
-
阈值:简单的阈值。较高的阈值会导致线条更少但更准确,而较低的阈值会产生相反的效果。设置此参数的最佳方法是尝试不同的值。这完全取决于您的目的。
-
minLineLength:最小行长度。
-
maxLineGap:同一直线上的点之间允许的最大间隙以链接它们。
选择这些参数(Threshold、minLineLength 和 maxLineGap)的最佳方法是尝试不同的值组合。这些参数没有通用的最佳值;它们取决于图像的具体特征和期望的结果。
检测直线时如何使用提取的角度?
想象一下算法从直线中提取出 67 度角。等式为:
direction_x = cos(extracted_angle=67) → velocity_x=1*direction_xdirection_y = sin(extracted_angle=67) → velocity_y=1*direction_y

步骤/代码
1. 读取图像并将其转换为灰度
2. 使用 Canny 边缘检测器提取边缘。
3. 对Canny边缘检测后得到的图像应用HoughLinesP函数。
4. 获取 HoughLinesP 函数的输出,对其进行迭代,绘制线条,并使用简单的公式提取角度。
Canny 边缘检测
Canny 边缘检测器创建一个二值图像,这在使用 HoughLinesP 函数之前是必不可少的。或者,可以使用其他过滤器或检测器。
Canny 边缘检测器有助于识别图像中的边缘

检测直线并计算角度代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Read image
image = cv2.imread("resources/blog1.png")
# Convert image to gray
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Extract edges with Canny edge detector
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# Apply HoughLinesP
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=75, minLineLength=100, maxLineGap=20)
if lines is not None:
for i, line in enumerate(lines):
x1, y1, x2, y2 = line[0]
dy = (y2 - y1)
dx = (x2 - x1)
# Convert radian to degree and extract angle
angle = np.rad2deg(np.arctan2(dy, dx))
# Since the Y-axis increases downwards (in OpenCV), invert the angle.
angle = 180 - angle if angle > 0 else -angle
# Different color for every line
color = tuple(np.random.randint(0, 255, 3).tolist())
# Detected line
cv2.line(rgb_image, (x1, y1), (x2, y2), color, 3)
# Draw shape to starting and finishing points of lines
cv2.putText(rgb_image, '>', (x1, y1), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 3)
cv2.putText(rgb_image, '<', (x2, y2), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 3)
# Angle
cv2.putText(rgb_image, str(round(angle, 1)), (x1, int((y1 + y2) / 2)), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 3)
# Display the image
plt.imshow(rgb_image)
plt.show()

THE END !
文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。

212

被折叠的 条评论
为什么被折叠?



