源生视界

100ms 跑完车道线检测:RV1126B 端侧推理与集成实录

车道线检测是自动驾驶与智能驾驶辅助系统的基础感知能力——通过计算机视觉或深度学习技术识别道路图像中的车道线位置、形状与走向,为车道保持、路径规划与安全行驶提供关键输入。

与云端方案相比,端侧部署能降低数据传输延迟、减少对云端计算与网络连接的依赖,并增强道路图像数据的隐私安全性——避免因网络延迟、信号不稳定或通信中断导致检测结果无法及时获取,保障车辆在弱网或无网环境下仍能持续进行车道线检测。这正是自动驾驶及智能驾驶辅助系统对实时性、可靠性与环境适应性的硬要求。

灵眸科技在 EASY-EAI-PI2(RV1126B) 上完成了 lane-detect 算法的端侧适配,单次推理 100ms(含预处理及后处理),并通过封装好的 EASY-EAI API 提供标准化调用接口。本文记录从源码下载、模型部署、例程编译到 API 调用的完整链路,并逐段拆解例程代码的四个环节。

3392870e-de46-11f1-9642-92fbcf53809c.png

车道线检测网络架构示意图

01

为什么车道线检测要跑在端侧

把车道线检测放在端侧,不止"算力够不够",还有三个云端方案绕不开的结构性问题:

延迟不可控—— 网络往返时间随信号质量波动,而车道保持对时延有硬约束

弱网即失效—— 隧道、偏远路段信号中断时,云端方案直接不可用

数据出域—— 道路图像持续上传,涉及隐私与合规风险

对量产车型与商用车队而言,这三项都属于无法通过优化云端算力解决的约束,只能靠端侧部署绕开。

02

快速上手:从环境到结果

开发环境准备:

若初次使用,需先按《入门指南/开发环境准备/Easy-Eai编译环境准备与更新》完成编译环境部署。在 PC 端 Ubuntu 中执行run.sh进入 EASY-EAI 编译环境。

版本一致性要求:开发环境版本必须与开发板正在运行的系统版本一致。若开发板是其它版本固件,可修改./run.sh参数(如 2204)进入对应编译环境,或将开发板烧录为与编译环境匹配的固件。

通过串口或 SSH 登录开发板,执行lsb_release -a可查看系统版本。

源码下载:

在编译环境下创建管理目录并克隆仓库:

cd/optmkdirEASY-EAI-ToolkitcdEASY-EAI-Toolkitgitclonehttps://github.com/EASY-EAI/EASY-EAI-Toolkit-1126B.git

注意:若需手动下载,请下载整个仓库,不能只下载本实例对应的目录——例程依赖仓库中的公共库与头文件。

模型部署:

下载车道线检测模型(网盘链接见文末),并将模型文件复制粘贴到Release/目录下。

例程编译:

cdEASY-EAI-Toolkit-1126B/Demos/algorithm-lane_detect/./build.sh cpres

两个前提:① 依赖库部署在板卡上,交叉编译过程中必须保持/mnt挂载;②build.sh带cpres参数时,会把Release/目录下的所有资源拷贝到开发板。

例程运行:

在板卡后台执行:

cd/userdata/Demo/algorithm-lane_detect/./test-lane-detect lane_detect.model test.jpg

第一个参数指定模型路径,第二个参数指定推理图像。Demo 会进行 10 次推理计算平均延迟,然后绘制推理结果并保存为result.jpg。

03

API 说明:五个函数与四组数据结构

为便于在本地工程中直接调用,EASY-EAI 将车道线检测封装为标准 API 库。

引用方式:

其中lane_detect.h声明初始化、运行与释放接口;utils.h声明结果转换与车道线绘制等辅助接口。

接口注释:

数据结构:

理解这几个结构体的关系,是正确调用 API 的关键。

lane_detect_context—— 运行周期内使用的模型上下文,含rknn_ctx、io_num、输入/输出张量属性、以及inference_width/inference_height(模型的推理宽高,可用于坐标归一化)。

detect_result—— 模型输出的原生数据:

33e1283c-de46-11f1-9642-92fbcf53809c.png

lane—— 转换后的车道线,核心成员points为std::vector,存储一条车道线上的有效采样点(原图坐标系)。

postprocess_info—— 由lane_detect_run()内部预处理流程生成的辅助信息,含ratio_y、ratio_x、croped_y(图像纵向从上往下被裁掉的行数),作为参数传给results_to_lanes()。

两个设计意图值得注意:

results_to_lanes()未集成进lane_detect_run(),是为了保留模型的原始推理结果,便于开发者按实际需求做进一步处理。

调用results_to_lanes()时应使用与该次推理结果相匹配的postprocess_info,且不要在调用前手动修改结构体成员值,否则会影响检测结果到原图坐标系的转换。

33f17ad4-de46-11f1-9642-92fbcf53809c.png

04

算法说明:预处理为什么裁顶部

例程test-lane-detect.cpp分为四个环节:模型初始化 → 图像读取 → 模型运行与释放 → 结果转换与绘制。

在了解代码前,需要说明一个容易被忽略但直接影响效果的预处理策略。

算法默认摄像头安装时,天空或无车道区域位于采集图像上方。模型推理采用2:1 宽高比,并根据输入图像的宽高比采用不同预处理方式:

宽高比 < 2:1(更接近正方形):先将图像宽度放大至预设推理尺寸(当前版本 384),再裁去高度方向超出推理范围的区域。裁切从图像顶部进行。以 350×192 为例,宽度缩放至 384 后高度约 210 像素,超出部分约 18 像素被裁掉。

宽高比 > 2:1(更狭长):直接将图像 Resize 至预设推理尺寸。

以 1920×1080 输入为例,其宽高比约 1.78:1,触发第一种逻辑:等比缩放宽度至 384 像素并裁剪顶部,在确保水平方向图像信息完整保留且不产生形变的前提下,去除主要由天空构成的顶部冗余区域。

工程价值:这个策略的巧妙之处在于——被裁掉的恰恰是对车道线检测无贡献的天空区域,既满足了模型输入尺寸要求,又不会对检测效果造成负面影响。这也是为什么算法能接受任意宽高比输入,而无需调用方自己做 letterbox 填充。

05

例程代码逐段拆解

模型初始化:

创建并清零lane_detect_context,调用lane_detect_init()加载模型:

lane_detect_context ctx;memset(&ctx,0,sizeof(ctx));ret =lane_detect_init(&ctx, model_path);if(ret !=0) { printf("Failed to initialize lane detection model.\n"); return-1;}

提示:inference_width和inference_height仅用于特殊需求下的坐标归一化,运行期间修改这两个值不会改变模型底层的实际推理尺寸。

图像读取:

cv::Matinput_image =cv::imread(image_path,cv::IMREAD_COLOR);

输入图像必须严格满足三项格式约束(这是最常见的调用失败原因):

3411d63a-de46-11f1-9642-92fbcf53809c.png

lane_detect_run()内部已包含必要的数值预处理,因此调用前无需额外做数值归一化;但若业务图像不满足上述约束,必须在传入前完成格式转换。

模型运行:

std::vector model_results;postprocess_info info;floatscore_threshold =0.41f; // 默认置信度阈值int nms_threshold =50; // 默认临近距离阈值for(inti =0; i < 10; ++i) {    ret = lane_detect_run(&ctx, input_image, model_results, info,                          score_threshold, nms_threshold);    ...}

性能统计采用 10 次推理取平均的方式。

一个容易踩的坑:lane_detect_run()每次调用会自动清空传入的results容器。因此务必在下一次推理调用前,完成当前推理结果的提取或存储(例如调用results_to_lanes()转换)。容器内仅保留有效检测结果,可直接通过model_results.size()获取当前帧检测到的车道线总数。

可调参数:

3424e2a2-de46-11f1-9642-92fbcf53809c.png

结果转换与绘制:

std::vectorlanes;ret = results_to_lanes(model_results, lanes, info);cv::Matoutput_image = input_image.clone();draw_line(output_image, lanes);cv::imwrite("result.jpg", output_image);

转换后lanes与results严格一对一映射、顺序完全一致(model_results.size() == lanes.size())。

lane.points是cv::Point容器,可直接调用 OpenCV 的cv::polylines高效绘制:

cv::polylines(image, lane.points, false, cv::Scalar(0,255,0),3, cv::LINE_AA);

同样需注意:results_to_lanes()也会自动清空传入的lanes容器,请在下一次调用前妥善保存或已使用已转换数据。

模型释放:

ret= lane_detect_release(&ctx);

调用后上下文被彻底销毁,此后不可再调用任何依赖该上下文的推理函数。

结语

对正在评估车道线检测方案的团队而言,100ms 的端侧推理耗时(含预处理与后处理)意味着该算法可以嵌入实时视频流水线;而标准化的-llane_detect库链接方式,则意味着集成成本主要集中在图像格式转换,而非算法本身。

灵眸科技旗下产品 EASY-EAI-PI2(RV1126B)已内置 lane-detect 算法支持,本文所用源码、模型与例程均可通过社区获取。

  • 随机文章
  • 热门文章
  • 热评文章