ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenCV车道线检测实战:HLS颜色阈值+Canny+Hough变换全流程解析

OpenCV车道线检测实战:HLS颜色阈值+Canny+Hough变换全流程解析 简介这是一份OpenCV车道线检测课程设计资料包面向正在学习图像处理、需要完成Python项目或课程设计的读者。项目围绕真实车辆前置摄像头画面展开覆盖灰度化、高斯模糊、Canny边缘检测、ROI掩膜提取以及霍夫变换直线检测与车道线拟合等完整流程能够帮助理解传统计算机视觉方法在车道识别中的应用。压缩包共25个文件、约360.11MB主要包括Python源码、设计报告Word文档、真实车辆测试视频MP4以及相关测试图像。源码按处理步骤拆分为多个py脚本如边缘检测、霍夫变换、线段过滤、车道绘制等便于对照阅读和复用jpeg/bmp图片可直观查看中间结果设计报告用于课程设计文档支撑。目前已有668人学习下载。资源还附带README说明与真实路测演示视频既适合初学者按步骤复现算法流程也可作为课程设计、毕业设计中的车道检测模块参考降低从零搭建环境的门槛。1. 拿到这个 OpenCV 车道线检测项目先判断它解决什么问题OpenCV 的车道线检测.zip 这类项目核心不是识别而是用图像处理把结构化道路上的白线和黄线抠出来。在固定视角、标线清晰的场景里一套 HLS 颜色阈值加 Canny 边缘加 ROI 裁剪加 Hough 变换的流水线就能实时跑部署成本低到树莓派都能扛。它适合刚接触 OpenCV 图像处理项目的人也想弄清楚检测直线到底需要哪些步骤、每个参数动了会怎样。下面按我做这类项目的顺序把选型、代码、参数和翻车点一次讲透。2. 车道线检测流水线选型HLS 颜色阈值、Canny 与 Hough 变换为什么是黄金组合2.1 为什么传统 OpenCV 方案在固定视角场景仍能打先下结论传统 OpenCV 车道线检测能打的场景有三个特征——相机视角固定、车道线清晰、路面结构相对规整。行车记录仪固定在挡风玻璃后方拍出来的车道线在画面里的位置变化不大园区巡检机器人速度低、路线固定。这些场景里硬上深度学习反而给自己找麻烦要标注几千张图要准备带 CUDA 的机器出了偏差还说不清是数据问题、训练问题还是模型结构问题。我做过一次对比评估同样一段白天高速路视频传统 OpenCV 方案和轻量级深度学习模型的检测率差距不到三个百分点但前者的单帧耗时低一个量级纯 Python 实现就能在 960x540 分辨率下跑进 30 毫秒树莓派上降到 640x360 也能保持实时。深度学习方案真正占优的场景是无标线道路、夜晚雨天、强逆光——那些场景里传统方案确实会翻车。所以拿到这类资源后第一件事不是改代码是确认边界视频里标线清不清楚、光照正不正常、相机视角固不固定。三条成立OpenCV 路线就是成本最低的选择。另外涉及部署语言。OpenCV 的 C 接口和 Python 在单帧处理上的性能差距其实不大因为瓶颈都在 OpenCV 内部函数Python 胜在调试快适合验证算法。我一般先用 OpenCV Python 把参数调明白再按需把耗时热点用 C 重写别一上来就写 C。2.2 HLS 颜色空间白线与黄线分量的阈值范围怎么定车道线检测最常见的错误是在 BGR 空间直接做颜色阈值。白色三通道都高黄色 R、G 高、B 低看着好区分但太阳光一照白色变灰、黄色变淡三个通道同时波动固定阈值完全失效。这也是很多新人做 OpenCV 图像处理项目时最容易卡住的地方。HLS 把亮度单独拆到 L 通道色调 H 和饱和度 S 受光照影响相对小。注意 OpenCV 里 HLS 的 H 范围是 0 到 179不是 0 到 360写阈值时最容易在这踩坑我在这上面浪费过一下午。白线在 HLS 里特征是 L 高、S 低inRange 下界一般取 (0, 200, 0)上界 (180, 255, 255)。黄线特征是 H 集中在 15 到 35 之间0-179 刻度S 不能太低下界取 (15, 40, 100)上界 (35, 255, 255)。这个范围不是拍脑袋定的是对着晴天、阴影、隧道三种光照的样本图逐帧试出来的。每换一款摄像头或安装角度都要重新抓几帧典型图像单独显示颜色蒙版确认效果而不是只看最终叠加后的画线结果。2.3 Canny 边缘检测threshold1 与 threshold2 的取值逻辑Canny 是整个流水线里最需要手感的一步。它有两个阈值高阈值确定强边缘低阈值用于连接弱边缘强度介于两者之间的边缘只有和强边缘相连才被保留。官方建议比例在 1:2 到 1:3这个比例比绝对值更重要我从 50/150 起步。threshold1 太低沥青颗粒、路面裂缝全变成边缘后面的 Hough 投票分不清主次threshold2 太高车道线边缘断成一截一截Hough 的 minLineLength 根本接不起来。调法是把 ROI 裁剪后的 edges 图直接显示出来目标是既不碎、噪声又少。运行阶段如果发现检测线乱飞先回来看 edges 图不要盯着最终画线图猜——最终图离问题点太远看不出是哪一步的锅。这个习惯能省下大量调参时间Canny 调参到后期有点像玄学但线索永远在 edges 二值图上。2.4 ROI 与 Hough 变换把边缘点变成左右两条线的两个前提ROI 裁剪多数人做了但做得太粗暴。车道线只出现在画面下方一个梯形区域梯形位置由车头位置和消失点决定。梯形上沿取画面高度的 60% 是常用起手值因为再往上就是天空和远处景物梯形下沿就是画面底边但左右两侧各收 10%避免把路肩和护栏圈进来。这个数值取决于摄像头安装高度和俯仰角摄像头位置一变ROI 必须重新标。提示ROI 不要写死在代码里至少抽成函数的参数换摄像头时只改一处。Hough 变换做的事情是把每个边缘点映射到极坐标参数空间用累加器投票找共线的点。OpenCV 里的 HoughLines 返回 rho 和 theta适合检测无限长的直线车道线是虚线、有断点所以用 HoughLinesP 概率版本直接返回线段端点。这也是检测直线这类需求在车道线场景下的标准答案。如果虚线拼接始终不理想可以试 OpenCV 里的 LSD 线段检测器它基于区域梯度生长对低对比度更敏感但参数换了一套要单独调。HoughLinesP 有五个参数rho、theta、threshold、minLineLength、maxLineGap。rho 取 1 像素theta 取 np.pi/180一般不用动。threshold 是投票阈值太低会返回大量短碎线minLineLength 控制最短线段长度虚线车道线每段约 30 到 40 像素取 40 起步maxLineGap 控制同一根虚线上相邻两段的间隔虚线间隙大约 20 到 30 像素。四个参数互相牵扯改任何一个都要回看另外三个。2.5 中间结果检查每一步都保存一份可视化物整个流水线五步任何一步的偏差都会被后面放大灰度模糊、边缘检测、ROI 裁剪、Hough 投票。我的做法是每个阶段都输出一张可视化图把它们横向拼在一起任何一步变了一眼就能看出来。拼图代码很简单用 np.hstack 把灰度图、edges、roi 结果、最终画线图拼起来观察窗口开大一点逐帧过一遍。这个方法在调试阶段比打印任何日志都有用因为车道线检测的问题绝大多数是空间上的不是数值上的。3. 用 OpenCV Python 实现单帧车道线检测完整代码与参数说明3.1 安装 OpenCVpip 安装和源码编译两条路怎么选最常见也最省事的是 pip 安装预编译包python -m pip install opencv-python python -c import cv2; print(cv2.__version__)第二条命令用来确认当前 Python 解释器能加载到 cv2。很多人在这翻车是因为电脑里有多个 Python 环境pip 装到了 A 环境运行脚本用的解释器却是 B 环境的报错就是 ModuleNotFoundError: No module named cv2。用 python -m pip 而不是裸 pip能保证装到当前解释器对应的环境。如果要用 SIFT、ORB 这些非自由算法预编译包默认不带需要装 opencv-contrib-python。树莓派或者 ARM 开发板上没有预编译包走 CMake 源码编译编之前先确认打开 BUILD_opencv_python3 和 WITH_OPENCL 这类开关。源码编译主要图的是能裁剪模块、降低安装体积本地开发阶段完全没必要。3.2 灰度化、高斯模糊与 Canny先拿到干净的边缘图最小实现第一步读取图像后转灰度再做高斯模糊最后 Cannyimport cv2 import numpy as np img cv2.imread(test_frame.jpg) if img is None: raise FileNotFoundError(图像读取失败检查路径) height, width img.shape[:2] gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blur cv2.GaussianBlur(gray, (5, 5), 0) edges cv2.Canny(blur, 50, 150)灰度化是必须的Canny 的输入是单通道。高斯模糊核 (5, 5) 是起手值核越大边缘越平滑但定位越差sigma 用 0 表示由核大小自动计算。Canny 的 50 和 150 对应 2.3 节说的比例如果 edges 图太碎就把 150 降到 120太脏就把 50 提到 70。3.3 叠加 HLS 颜色掩码逆光和阴影下车道线不再断线纯 Canny 在光照均匀时够用但逆光或树荫下灰度图里白色和黄色都会变成灰色边缘断得厉害。加一道 HLS 颜色掩码hls cv2.cvtColor(img, cv2.COLOR_BGR2HLS) white_mask cv2.inRange(hls, (0, 200, 0), (180, 255, 255)) yellow_mask cv2.inRange(hls, (15, 40, 100), (35, 255, 255)) color_mask cv2.bitwise_or(white_mask, yellow_mask) edges_color cv2.bitwise_and(edges, edges, maskcolor_mask)逻辑是希望最后的输出既满足是边缘又满足是车道线的颜色所以取交集。bitwise_and 第一个参数是原图第二个参数是目标第三个参数 mask 表示只处理 mask 为白的地方。white_mask 和 yellow_mask 用 bitwise_or 合并成一张图。这里两个 inRange 的参数要重点看白色下界 L 取 200意味着强光下发灰的白线可能丢失如果白天直射场景掉线严重可以把 L 下界降到 180黄色下界 S 取 40阴影里的黄线饱和度会掉降到 25 能多救回一部分但也会引入更多浅黄色路面噪声。这个权衡只能靠图像采样去验证没有通用值。3.4 HoughLinesP 的 minLineLength 与 maxLineGap虚线车道线的关键拿到干净的边缘图后做 ROI 裁剪再丢给 HoughLinesPvertices np.array([[ (int(width * 0.1), height), (int(width * 0.45), int(height * 0.6)), (int(width * 0.55), int(height * 0.6)), (int(width * 0.9), height) ]], dtypenp.int32) mask np.zeros_like(edges_color) cv2.fillPoly(mask, vertices, 255) roi_edges cv2.bitwise_and(edges_color, mask) lines cv2.HoughLinesP( roi_edges, rho1, thetanp.pi / 180, threshold50, minLineLength40, maxLineGap20 )fillPoly 画梯形 ROIbitwise_and 把 ROI 外的边缘全清零。HoughLinesP 的返回是 shape 为 (N, 1, 4) 的数组每行是 [x1, y1, x2, y2]。threshold50 表示一条线至少要 50 个边缘点投票才被承认虚线每段约 40 像素所以 minLineLength40 是底线设太大会把短虚线段全丢掉设太小就满屏短碎线。maxLineGap20 决定虚线相邻两段能不能合成一条设过大会把护栏和路肩的平行结构错误连接。3.5 斜率分类与左右车道线分组从一堆线段到两条拟合线拿到线段后不能直接画还要按斜率分左右left_segments [] right_segments [] for line in lines: x1, y1, x2, y2 line[0] dx x2 - x1 if dx 0: continue slope (y2 - y1) / dx if slope -0.5: left_segments.append((x1, y1, x2, y2)) elif slope 0.5: right_segments.append((x1, y1, x2, y2))图像坐标系 y 轴向下所以左边车道线从画面左下到右上x 随 y 减小而增大斜率为负右侧相反斜率为正。阈值正负 0.5 是起手值意思是只保留接近 45 度的线。实际中左侧斜率在 -0.8 到 -0.4右侧在 0.4 到 0.8把范围收紧可以减少车身横跨车道线时的误分类。分完组后拟合一条直线def average_segment(segments): if not segments: return None xs, ys [], [] for x1, y1, x2, y2 in segments: xs.extend([x1, x2]) ys.extend([y1, y2]) k, b np.polyfit(xs, ys, 1) return k, b left_k, left_b average_segment(left_segments) right_k, right_b average_segment(right_segments)np.polyfit 用最小二乘法拟合一元一次多项式返回系数 k 和截距 b。把同侧所有线段端点汇总到一起拟合比重心连接两条端点稳得多对个别误检线段不敏感。最后把拟合出的直线画回原图def draw_line(img, k, b, y_top, y_bottom, color(0, 255, 0), thickness8): if k is None: return x_top int((y_top - b) / k) x_bottom int((y_bottom - b) / k) cv2.line(img, (x_top, y_top), (x_bottom, y_bottom), color, thickness) y_top int(height * 0.6) y_bottom height draw_line(img, left_k, left_b, y_top, y_bottom) draw_line(img, right_k, right_b, y_top, y_bottom)注意画线时不要从 y0 画到 height车道线投影位置只在 ROI 内有效从 0 开始画会把线拉到远处天空的位置看起来很不自然。这个细节经常被忽略但只看叠加图的人一眼就能看出违和感。4. 从单帧扩展到视频流滑动平均、透视变换与性能优化4.1 VideoCapture 逐帧读取处理好丢帧和帧率单帧逻辑跑通后下一步接视频。VideoCapture 按帧读取处理速度跟不上时会自动丢帧这是正常现象不要指望一边处理得慢一边还不丢帧cap cv2.VideoCapture(road_video.mp4) if not cap.isOpened(): print(视频打开失败) exit(1) fps cap.get(cv2.CAP_PROP_FPS) out cv2.VideoWriter( output.mp4, cv2.VideoWriter_fourcc(*mp4v), fps, (960, 540) ) while cap.isOpened(): ret, frame cap.read() if not ret: break frame cv2.resize(frame, (960, 540)) # 中间调用前面写好的单帧处理函数返回叠加画线的 frame result process_frame(frame) out.write(result) cap.release() out.release()VideoWriter 的帧率最好用原视频的 fps否则成品视频要么加速要么减速。后面如果接真实摄像头分辨率直接决定能跑多少帧960x540 是性能和效果比较均衡的档位。opencv python 拉流中断这类问题在本地视频阶段不会暴露但到摄像头时要提前处理处理一帧的耗时超过帧间隔拉流缓冲会被撑爆丢帧是正常现象不要试图补帧。4.2 滑动平均让车道线不在帧间来回跳单帧检测的抖动来自 Hough 投票的随机性——同样的车道线这一帧检测到的端点和下一帧可以差出几个像素。人对高频抖动极其敏感检测率再高都没用。解决办法是滑动平均from collections import deque left_history deque(maxlen5) right_history deque(maxlen5) def smooth(history, new_value): if new_value is None: return history, None history.append(new_value) avg np.mean(history, axis0) return history, avgdeque 的 maxlen5 表示只保留最近 5 帧的拟合结果新的进来旧的自动弹出。窗口越大曲线越平滑但滞后越大高速场景下滞后会让车道线画在上一帧的位置入弯时尤其明显所以 5 帧是兼顾平滑和响应的常用值。另一种常见做法是按比例混合新结果算出来后用 0.7 乘旧均值加上 0.3 乘新结果。alpha 是旧值的权重0.7 意味着新结果只贡献 30% 权重既能跟上变化又能抑制抖动。弯道多的路段把 alpha 降到 0.5直线路段用 0.8。和固定窗口比比例混合实现更简单但要注意初始化阶段前几帧的权重占比不对可以先跳过前 3 帧不输出。4.3 弯道处理透视变换 二次多项式拟合直线拟合在弯道上会直接失效弯道处的车道线是曲线用 ykxb 拟合的结果是一条斜割线。常见做法是先做透视变换把梯形 ROI 投影成鸟瞰图让曲线在鸟瞰视角下变成可拟合的抛物线src np.float32([ [width * 0.43, height * 0.62], [width * 0.57, height * 0.62], [width * 0.85, height], [width * 0.15, height] ]) dst np.float32([ [width * 0.3, 0], [width * 0.7, 0], [width * 0.7, height], [width * 0.3, height] ]) M cv2.getPerspectiveTransform(src, dst) warped cv2.warpPerspective(frame, M, (width, height))getPerspectiveTransform 需要四组对应点src 是原图上的梯形dst 是它在鸟瞰图上的矩形。src 的四个点必须和 ROI 的梯形顶点基本一致否则透视变换后的车道线位置是错的。src 选点是这个环节里最费时间的活我一般用 imshow 加鼠标回调取点把点坐标直接打印出来再填进代码。在鸟瞰图上跑同样的颜色阈值和 Canny然后对每一列统计非零点作为车道线样本用 np.polyfit 拟合二次多项式# left_x, left_y 是左侧车道线在鸟瞰图上的像素坐标 left_fit np.polyfit(left_y, left_x, 2) # 用拟合出的系数生成平滑曲线 plot_y np.linspace(0, warped.shape[0] - 1, warped.shape[0]) plot_x left_fit[0] * plot_y**2 left_fit[1] * plot_y left_fit[2]拟合直线和拟合曲线的区别就在这二次多项式有三个系数对应抛物线的开口方向和顶点位置。车道线检测里拟合直线这个词常常让人误以为只有直线实际弯道场景下大家都在做曲线拟合。画回原图时记得用逆透视矩阵 Minv 把鸟瞰图上的点映射回原图坐标直接画在 warped 上看不出问题叠加回原帧位置就对不上了。4.4 性能优化先降采样再灰度化ROI 越小越快实时性不够时按照性价比从高到低依次检查# 第一步降采样处理一半分辨率 frame cv2.resize(frame, (0, 0), fx0.5, fy0.5) # 第二步ROI 裁剪用数组切片替代 bitwise_and省一次全图遍历 roi_frame frame[int(height * 0.4):, :] gray cv2.cvtColor(roi_frame, cv2.COLOR_BGR2GRAY) # 第三步把缩放和灰度化合并利用 cvtColor 的 dstsize 参数 gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY, dstsize(480, 270))降采样是最划算的优化分辨率砍半像素数是原来的四分之一所有后续操作都快四倍代价是远处细线可能变糊。ROI 裁剪用切片而不是 fillPoly 加 bitwise_and是因为切片是内存视图几乎零拷贝fillPoly 那套在单帧检测里无所谓在视频循环里每帧都跑就贵了。还有一个容易忽视的点颜色掩码、Canny、灰度化三个操作都在做全图遍历如果先做了 ROI 裁剪再进颜色处理能省掉大量无效计算。但注意 ROI 裁剪要放在灰度化之后因为位运算掩码需要单通道图彩色图做 ROI 反而多一次通道拆分。5. 车道线检测常见问题排查5 个高频翻车现场与解决步骤5.1 ModuleNotFoundError: No module named cv2现象按照教程执行 pip install opencv-python 成功但运行脚本时依然报 ModuleNotFoundError: No module named cv2。原因绝大多数是 Python 环境不匹配。电脑里可能有多个解释器系统自带 Python、Anaconda 基础环境、项目虚拟环境。pip 默认装进当前 PATH 里的环境但 IDE 或脚本用的是另一个环境的解释器。另一个常见原因是装成了 opencv-python-headless这个包没有图形界面支持imshow 会直接报错。解决先确定当前解释器是哪个再装到同一个环境。which python python -m pip install opencv-python python -c import cv2; print(cv2.__version__, cv2.__file__)python -m pip 保证 pip 和 python 属于同一个环境cv2.file打印出的路径能直接验证加载的是哪个位置的包。如果需要在无显示环境跑用 opencv-python-headless但 imshow 和 VideoCapture 的显示功能会不可用调试阶段别装这个。5.2 检测出的直线一大堆车道线被噪声淹没现象HoughLinesP 返回几十条线段路面裂缝、路肩、护栏边缘全是线左右车道线反而被淹没。原因Canny 阈值过低导致边缘图太脏Hough 的 threshold 和 minLineLength 太低接受了很多短碎线ROI 梯形太大的话把路肩护栏都圈了进来。解决按顺序排查每步看输出图。先把 Canny 阈值从 50/150 提到 70/200edges 图立刻干净很多再把 Hough threshold 从 50 提到 80minLineLength 从 40 提到 60最后收紧 ROI 上沿梯形下沿左右各收 5%。这三板斧能解决九成噪声问题。如果还不行检查 maxLineGap它设得太大时护栏上平行的金属结构会被错误连接成一条线。5.3 逆光和树荫下车道线时有时无现象同一段路中午直射光下白色车道线中间断掉过树荫时黄色线完全消失暴晒后的沥青路面反光检测结果剧烈跳变。原因灰度化把白线和黄线的对比度抹掉了Canny 边缘依赖的是明暗梯度而不是颜色。直射光下白线两边都是亮路面梯度小边缘就弱树荫下黄线的亮度掉到和路面一个级别纯边缘检测找不到。解决把 HLS 颜色掩码提到主路径而不是只当补充。我的做法是 Canny 边缘和颜色掩码取交集颜色通道负责认颜色边缘通道负责对位置两个条件同时满足才认为是候选线段。对阴影敏感的路段再对 HLS 的 L 通道做一次 CLAHE 局部直方图均衡clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) l_channel clahe.apply(hls[:, :, 1]) hls[:, :, 1] l_channelclipLimit 控制对比度增强幅度太大容易出现噪点2.0 是常用值。注意只增强 L 通道不要去动 H 和 S 通道否则前面的颜色阈值范围全部失效。5.4 视频越跑越慢最后内存涨满现象处理本地视频前几秒正常越到后面延迟越大系统内存持续上涨最后进程被杀。原因两个常见元凶。一是有人为了回放方便把每一帧 result 都 append 到 list 里视频几十秒就是上千张图内存直接爆掉二是处理分辨率过高或者每帧调用多个全图 cvtColor单帧耗时接近 100 毫秒播放看起来就像越来越卡。解决回放用 VideoWriter 写文件永远不要把帧存进列表分辨率降到 960x540 或更低把耗时统计打出来定位热点start cv2.getTickCount() result process_frame(frame) ms (cv2.getTickCount() - start) / cv2.getTickFrequency() * 1000 print(fframe {idx}: {ms:.1f} ms)超过 33 毫秒就说明离 30 帧实时还差一步按 4.4 节的顺序优化。5.5 左右车道线交叉或全偏到一侧现象某几帧画出来的左右两条线在远处交叉成 X或者连续多帧只有一侧有线另一侧空白。原因斜率分组的阈值设得太宽松护栏、车身边缘被分到了左右两组里车辆变道或者路面标线磨损一侧车道线长时间缺失摄像头安装角度有偏转左右斜率整体偏移固定阈值不适用。解决收紧斜率范围到 (-0.8, -0.4) 和 (0.4, 0.8)范围外的线段直接丢弃。增加连续性检查当前帧某侧没有结果时沿用上一帧的拟合结果并标记为无效连续 10 帧无效才允许真正丢失避免短暂遮挡导致画线闪断。摄像头角度有偏转时用录像里多条直线的斜率直方图重新标定阈值不要在一个固定值上死磕。注意左右线交叉还有一个隐蔽原因——两车道中间还有一条车道分隔线它同时接近左右斜率范围的边缘分组时容易被两边各分一次。这种情况用连续性检查过滤最有效单帧静态图基本无解。6. 上量产前先做曲率验证相机标定与像素到米换算6.1 相机标定与像素到米换算检测出车道线只是第一步做辅助驾驶或车道偏离预警真正要交出去的是曲率半径和横向偏移。这两个量必须把像素坐标换成物理坐标换算的基础是相机标定和透视变换。先标定相机用棋盘格拍二三十张图cv2.findChessboardCorners 提取角点cv2.calibrateCamera 得到内参矩阵和畸变系数。做完畸变校正再做透视变换否则鸟瞰图的远近比例全错。像素到米的换算用实际场景的已知尺寸高速车道标准宽 3.7 米在鸟瞰图上量左右线之间的像素距离除法得到 xm_per_pix纵向用一段已知长度的标线比如实线段 6 米得到 ym_per_pix。6.2 曲率计算与三个验收指标曲率计算在拟合出的二次多项式系数上做# 车道线拟合曲线 x A*y^2 B*y C A, B, C left_fit y_eval 240 # 取鸟瞰图底部的纵向位置 curve_radius ((1 (2 * A * y_eval B) ** 2) ** 1.5) / abs(2 * A) # 换算物理单位每个方向分别乘对应比例 curve_radius_m curve_radius * xm_per_pix / ym_per_pix这个公式是曲率半径的标准计算公式A 是二次项系数y_eval 选在车辆当前位置对应的纵向坐标。算出来后的验收标准我一般看三个数有效检测率要高于 85%即全程视频里能给出合理拟合结果的帧占比曲率半径在直线路段要大于 500 米弯道路段和地图上的半径误差在 15% 以内左右线曲率方向一致不能出现一个算左弯一个算右弯。我现在养成的习惯是任何车道线参数改动先跑一遍录制好的三段测试视频直道、弯道、树荫道把曲率输出和时间戳一起写进 CSV再对着 CSV 找问题帧而不是盯着实时画面反复试。这套离线验证流程比任何在线调试都省时间也更能说服合作方这套方案在边界内的可靠性。如果走到这一步发现曲率在直道上乱跳、检测率上不去就别在 OpenCV 这条路上继续加码了该上深度学习就上。但绝大多数固定视角、结构化的道路场景上面这套方案跑通后是能长期用的。希望帮到你。本文还有配套的精品资源点击获取
返回列表