OpenCV 车道线识别

903 字
5 分钟
OpenCV 车道线识别

笔记整理自:https://www.bilibili.com/video/BV1qk4y1r7jw/

1 【基础操作】读取、展示、保存图片#

import cv2
img = cv2.imread('img.jpg', cv2.IMREAD_COLOR) # 读取
print(type(img)) # 获取 img 的类型,是 numpy 的矩阵
print(img.shape) # 获取 img 的大小(长、宽),位深度
cv2.imshow('image', img) # 显示图片
if cv2.waitKey(0) == ord('q'): # 直到键盘按下某个值,退出显示图片。
cv2.destoryAllWindows()
cv2.imwrite('img_gray.jpg', img) # 保存图片

其中,IMGREAD_COLOR 是读取类型,是彩色 。还有其他的类型:

  • IMREAD_GRAYSCALE:灰度图(那么 img.shape 将没有深度这一参数)

对于 imwrite() ,它会根据给定字符串中的后缀名,自动确定图片类型。必须给定合法的图片扩展名,否则会报错。

2 Canny 边缘检测#

梯度是有方向的:

代码实现:

import cv2
img = cv2.imread('img.jpg', cv2.IMREAD_GRAYSCALE)
edge_img = cv2.Canny(img, 50, 100) # 图片,上阈值,下阈值,需调节优化
cv2.imshow('edges', edge_img)
cv2.waitKey(0)

调高下边缘与上边缘,可以有效减小噪点数量。而车道线在灰度后,有非常强的边缘(黑与白),所以保持较高的阈值是方便的。

3 ROI mask - 获取要紧的区域#

ROI - Region Of Interest,感兴趣的区域。

import cv2
import numpy as np
edge_img = cv2.imread('edges_img.jpg', cv2.IMREAD_GRAYSCALE)
mask = np.zero_like(edge_img)
cv2.fillPoly(mask, np.array([[[0, 368], [240, 210], [300, 210], [640,368]]]), color=255) # 假设已经获取到了顶点坐标
masked_edge_img = cv2.bitwise_and(edge_img, mask) # 布尔和运算
cv2.imshow('masked', masked_edge_img)
cv2.waitKey(0)

4 霍夫变换,获取直线#

需要使用极坐标,(r,θ)(r, \theta) 确定一条直线。

liens = cv2.HoughLinesP(edge_img, 1, np.pi / 180, 15, minLineLength=40, maxLineGap=20)
  1. edge_img:要处理的图片
  2. 1:精度,值越大,考虑越多的线
  3. np.pi/180:精度,值越大,考虑越多的线
  4. 累加数阈值,值越小,考虑越少的线
  5. minLineLength:最短长度阈值,短于这个长度的线会被排除
  6. maxLineLength:同一直线两点之间最大距离

返回一个列表,里面是直线的两个端点的坐标。

5 离群值过滤#

因为种种情况,可能有噪点被识别为车道线,而真正的车道线未被成功识别。

def reject_abnormal_lines(lines, threshold):
slopes = [calculate_slope(line) for line in lines]
while len(lines) > 0: # 不断重新计算斜率,直到群符合条件
mean = np.mean(slopes)
diff = [abs(s - mean) for s in slopes]
idx = np.argmax(diff) # 找到差值最大的下标
if diff[idx] > threshold:
slops.pop(idx)
lines.pop(idx)
else:
break
return lines
# 分别对左、右车道线进行过滤
reject_abnormal_lines(left_lines, threshold=0.2)
reject_abnormal_liens(right_lines, threshold=0.2)

过滤后的效果:

6 最小二乘拟合 - 最后一步#

对于识别出来的这么多左车道线、右车道线,我们需要将它们合并成同一条完整的车道线。

import numpy as np
np.ravel() # 将高维数组压成一维函数(比如把矩阵变成数组)
poly = np.polyfit([0, 3, 6, 9], [0, 5, 9, 14], deg=1) # 多项式拟合,参数:几个 x 坐标,几个 y 坐标,多项式次数
np.polyval(poly, x0) # 多项式求值

ravel 示例:

7 车道线标注#

绘制直线:cv2.line

cv2.line(img, (10, 10), (200, 100), 255, 3)
# 图像,一个端点,另一个端点,色彩值(彩色图为(r, g, b)),宽度

8 视频流处理#

读取视频流:capture = cv2.VideoCapture('video.mp4') ,如果传入的是数字,就会使用相应序号的摄像头。 读取:ret, frame = capture.read() ,分别读取状态、图片帧。

capture = cv2.VideoCapture('video.mp4')
while True:
ret, frame = capture.read()
# frame = show_lane(frame)
cv2.imshow('frame', frame)
cv2.waitKey(100) # 等待 100 ms

9 值得改进的地方#

  1. 边缘检测时,有很多弱边缘,可以尝试使用高斯模糊,或给它腐蚀一下,让弱边缘变得更模糊!这样就能有效过滤掉了。
  2. 左车道线只有一部分,很容易只画出一部分(如图),可以尝试使它延伸到图像边缘。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
OpenCV 车道线识别
https://www.0x3f.foo/posts/opencvtutorial/
作者
Dignite
发布于
2024-07-09
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
Dignite
When nothing goes right, go left.
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
站点统计
文章
146
分类
5
标签
271
总字数
314,753
运行时长
0
最后活动
0 天前

目录