【项目实战】基于OpenCV和BDD100K数据集的辅助驾驶车道线检测与碰撞预警系统
项目简介本文带你从零实现一个辅助驾驶视觉系统核心功能包括车道线分割使用传统图像处理算法在道路图像上绘制绿色车道线。目标检测与距离估计识别前方车辆和行人估算距离并显示在画面中。碰撞预警当距离过近时在画面显示红色警告并在控制台模拟“嘀嘀嘀”报警声。本项目的最大特点是完全离线运行不需要深度学习框架PyTorch/TensorFlow也不需要联网下载模型非常适合作为计算机视觉入门项目或课程作业。️ 数据集说明我们使用的是Kaggle上的BDD100K YOLO格式数据集由用户a7madmostafa上传。数据内容包含行车记录仪视角的道路图片。标注格式YOLO格式.txt文件每行包含class_id x_center y_center width height归一化坐标。关注类别车辆car/truck/bus、行人person等交通参与者。数据集挂载路径Kaggle环境text/kaggle/input/datasets/a7madmostafa/bdd100k-yolo/test/images 完整代码可直接运行pythonimport cv2 import numpy as np import os import matplotlib.pyplot as plt # # 1. 路径配置根据不同环境修改此处 # DATA_ROOT /kaggle/input/datasets/a7madmostafa/bdd100k-yolo IMAGE_DIR os.path.join(DATA_ROOT, test/images) LABEL_DIR os.path.join(DATA_ROOT, test/labels) # 若不存在则尝试其他路径 # 类别映射表 (BDD100K标准) CLASS_NAMES { 0: car, 1: truck, 2: bus, 3: traffic light, 4: traffic sign, 5: person, 6: bicycle, 7: motorcycle, 8: train, 9: rider } # 只关心这些类别车辆和行人 INTERESTED_CLASSES [0, 1, 2, 3, 5, 6, 7, 9] # # 2. 车道线检测前端展示绿色线条 # def detect_lanes(image): 传统OpenCV车道线检测流程 灰度化 - 高斯模糊 - Canny边缘检测 - ROI掩码 - 霍夫直线检测 gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blur cv2.GaussianBlur(gray, (5, 5), 0) edges cv2.Canny(blur, 50, 150) height, width edges.shape # 定义梯形/三角形感兴趣区域只关注前方路面 mask np.zeros_like(edges) polygon np.array([[(0, height), (width, height), (width // 2, height // 2)]], np.int32) cv2.fillPoly(mask, polygon, 255) masked_edges cv2.bitwise_and(edges, mask) # 霍夫变换检测直线 lines cv2.HoughLinesP(masked_edges, rho1, thetanp.pi/180, threshold30, minLineLength80, maxLineGap30) lane_img np.copy(image) if lines is not None: for line in lines: x1, y1, x2, y2 line[0] # 【前端】绘制绿色粗线 cv2.line(lane_img, (x1, y1), (x2, y2), (0, 255, 0), 4) return lane_img # # 3. 距离估计基于目标面积 # def estimate_distance(area, frame_area): 利用目标在画面中的面积占比粗略估算距离。 原理面积越大 - 距离越近 (反比关系)。 假设面积占比0.01时距离为10米。 if area 500: # 忽略噪声小点 return 99.0 ratio area / frame_area if ratio 0.001: # 距离太远忽略 return 99.0 return min(10.0 * (0.01 / ratio) ** 0.5, 80.0) # # 4. 解析YOLO标注文件后端数据处理 # def get_boxes_from_label(label_path, img_shape): 读取txt标注文件将归一化坐标转为像素坐标。 格式class_id x_center y_center width height (归一化0~1) height, width img_shape[:2] boxes [] if not os.path.exists(label_path): return boxes with open(label_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) if cls_id not in INTERESTED_CLASSES: continue # 解析归一化坐标 x_c, y_c, w_n, h_n map(float, parts[1:]) # 还原为像素坐标 (左上角x, y, 宽度, 高度) x int((x_c - w_n/2) * width) y int((y_c - h_n/2) * height) w int(w_n * width) h int(h_n * height) # 边界裁剪防止溢出画面 x max(0, x) y max(0, y) w min(width - x, w) h min(height - y, h) if w 0 and h 0: boxes.append((cls_id, x, y, w, h)) return boxes # # 5. 图像处理主流程前端渲染 后端计算 # def process_image(img_path, label_path): # 读取图片并缩放到统一尺寸加速处理 img cv2.imread(img_path) if img is None: return None img cv2.resize(img, (800, 450)) orig_h, orig_w img.shape[:2] frame_area orig_w * orig_h # 1. 车道线检测前端绘制绿线 result detect_lanes(img) # 2. 读取标注框后端数据 boxes get_boxes_from_label(label_path, img.shape) warning_triggered False min_distance 99.0 # 3. 遍历每个检测框 for cls_id, x, y, w, h in boxes: area w * h dist estimate_distance(area, frame_area) min_distance min(min_distance, dist) # 根据距离着色8米绿色安全8米红色危险 color (0, 255, 0) if dist 8 else (0, 0, 255) # 【前端】绘制矩形框和距离文本 cv2.rectangle(result, (x, y), (xw, yh), color, 2) label f{CLASS_NAMES.get(cls_id, obj)} {dist:.1f}m cv2.putText(result, label, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) # 触发预警逻辑 if dist 8.0: warning_triggered True # 4. 【前端】显示预警信息 if warning_triggered: cv2.putText(result, !!! WARNING: Collision Risk !!!, (30, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 3) # 控制台模拟蜂鸣声\a为ASCII响铃符 print( 嘀嘀嘀前方距离过近, end ) if min_distance 99: cv2.putText(result, fMin Dist: {min_distance:.1f}m, (30, 100), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 0), 2) # 转为RGB格式供matplotlib显示 return cv2.cvtColor(result, cv2.COLOR_BGR2RGB) # # 6. 主程序入口模拟视频流播放 # if __name__ __main__: # 检查目录是否存在 if not os.path.exists(IMAGE_DIR): print(f❌ 错误图片目录不存在请检查路径。) exit() # 获取前20张图片数据量大只取部分演示 image_files sorted([f for f in os.listdir(IMAGE_DIR) if f.endswith((.jpg, .jpeg, .png))])[:20] print(f✅ 共加载 {len(image_files)} 张图片开始处理...) # 使用matplotlib交互模式动态显示 fig, ax plt.subplots(figsize(12, 6)) plt.ion() # 打开交互模式 for img_file in image_files: img_path os.path.join(IMAGE_DIR, img_file) label_file img_file.rsplit(., 1)[0] .txt label_path os.path.join(LABEL_DIR, label_file) result_rgb process_image(img_path, label_path) if result_rgb is None: continue # 【前端】刷新显示 ax.clear() ax.imshow(result_rgb) ax.set_title(fProcessing: {img_file}) ax.axis(off) plt.draw() plt.pause(0.3) # 每0.3秒切换一张模拟视频帧率 plt.ioff() plt.show() print(\n✅ 全部处理完成) 代码核心原理解析1. 车道线检测detect_lanesCanny边缘检测提取图像中梯度变化剧烈的像素点即边缘。ROI掩码由于车道线通常只出现在图像下方区域我们用一个三角形掩码过滤掉天空、树木等无关区域大幅减少误检。霍夫变换HoughLinesP在边缘图像中寻找直线段。参数threshold30控制检测灵敏度minLineLength80过滤短线段。2. YOLO标注解析get_boxes_from_labelYOLO格式的坐标是归一化的0~1需要乘以图片的宽/高才能还原为像素值。注意这里的x_center, y_center是中心点转换为左上角坐标时需减半宽高。3. 距离估计算法estimate_distance这是一种单目视觉的简化近似假设物体在图像中的面积占比与真实距离平方成反比。虽然不如双目视觉或激光雷达精准但足以满足演示和预警逻辑的需求。实际项目中若需精准值需要进行相机标定。4. 预警逻辑距离阈值设定为8米当任意感兴趣目标小于该值时触发。前端反馈画面顶部显示红色英文警告。后端反馈控制台打印嘀嘀嘀利用\a转义符可触发系统蜂鸣声。 前端与后端的分工模块类型具体代码作用车道线绘制前端cv2.line(..., (0,255,0), 4)将检测到的直线渲染为绿色目标框绘制前端cv2.rectangle()/cv2.putText()可视化检测结果和距离预警文字前端cv2.putText(..., (0,0,255))显示红色预警提示控制台输出前端print(嘀嘀嘀...)模拟蜂鸣报警声图像显示前端plt.imshow()/plt.pause()在Notebook内展示图片序列边缘检测后端cv2.Canny()/cv2.GaussianBlur()图像预处理和特征提取直线拟合后端cv2.HoughLinesP()计算车道线几何参数坐标转换后端归一化坐标转像素坐标解析标注数据距离计算后端estimate_distance()根据面积计算距离数值⚠️ 踩坑与排障指南1. 路径找不到FileNotFoundError原因Kaggle数据集的挂载路径因用户而异。解决运行os.listdir(/kaggle/input)查看实际根目录名称修改DATA_ROOT变量。2. 找不到标签文件原因部分数据集版本只有图片没有labels文件夹。解决若缺少标注可去掉get_boxes_from_label调用仅保留车道线检测功能。或者尝试遍历os.walk()查找.txt文件位置。3. Matplotlib无法动态显示原因plt.ion()在某些Jupyter内核中不稳定。解决改用cv2.imshow()需要GUI环境或IPython.display.clear_output()刷新图片。4. 内存溢出Kaggle Kernel Died原因图片尺寸过大或一次性加载过多。解决使用cv2.resize()统一缩小至800x450仅读取前20张而非全量数据。 扩展与改进方向引入YOLOv8模型替换标注文件读取实现端到端的目标检测提升准确率。车道偏离预警计算车辆中心与车道线的横向偏移当偏离时触发警报。测距标定使用棋盘格标定相机内参将像素面积映射为真实物理距离米。多线程加速使用OpenMP或CUDA加速图像处理流水线。 结语本文完整实现了一个轻量级的辅助驾驶视觉系统无需昂贵的GPU无需深度学习仅靠OpenCV和简单的几何逻辑即可运行。适合作为计算机视觉课程的期末作业或入门项目。希望本文能帮助你理解图像处理的基础流程并激发你对自动驾驶技术的兴趣如果你在运行过程中遇到任何问题欢迎在评论区留言交流。项目环境Python 3.10 OpenCV 4.8 Matplotlib 3.7数据集来源Kaggle - BDD100K YOLO Format Dataset