ARTICLE DETAIL

资讯详情

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

基于CNN的语义SLAM实现:动态点剔除与八叉树地图构建

基于CNN的语义SLAM实现:动态点剔除与八叉树地图构建 简介这份PDF文档包含发表于《科学技术与工程》2019年第19卷第9期的学术论文《基于卷积神经网络的语义同时定位以及地图构建方法》。面向智能车辆、自动驾驶与视觉SLAM方向的研究者论文提出一种融合CNN语义分割的四线程双目SLAM方案用以解决传统SLAM在复杂室外环境中仅构建几何地图、无法解析场景语义信息的问题。全文详细介绍了追踪、局部地图构建、回环检测、稠密地图构建四个并行线程的协作机制并阐述将RGB与视差图融合成四通道输入以提升语义分割精度、进而构建稠密3D语义地图的方法实验表明该方法在KITTI数据集上可达10帧/s全局精确率73.1%。资源仅含1个PDF文件体积约793KB便于离线阅读目前已有171人学习下载适合作为智能车环境感知、深度学习与SLAM交叉领域的学习参考资料。1. 为什么语义信息是SLAM从定位走向理解的那道分水岭设想一个自主移动机器人穿过地铁站传统视觉SLAM算法通过ORB特征点跟踪墙面和静态柱子一切顺利。直到一个人从它正前方走过——那些属于行人的特征点被当成静态地标位姿估计开始漂移甚至整条轨迹被带偏。更实际的问题是即使地图建得非常精确机器人也无法回答“可充电插座在哪”“哪扇门通向会议室”这类任务级问题。我们常说的语义SLAM便是把卷积神经网络CNN从像素级识别得到的语义信息注入到同时定位与地图构建框架中让机器人既知道自己在哪里也认识那里有什么。这套方案适合已经接触过ORB-SLAM、VINS或LOAM又不想停留在纯几何层面的工程师。下面从模块拆解出发给出能够直接改到现有SLAM前端的实现思路、参数与验证方法。2. 卷积神经网络在语义SLAM中的角色拆解从像素分类到特征先验2.1 几何SLAM为什么需要CNN动态物体与类别无关的地图表达传统几何SLAM把环境建模为稀疏点云或稠密深度观测核心假设是场景静态、外观稳定。一旦遇到行人、车辆、摆动的手臂前端特征点里就会出现非刚性运动的部分后端图优化和回环检测都会受污染。CNN带给我们的是“逐像素类别”这个强先验如果算法知道某个特征点落在一只“狗”的轮廓内它就不应该被当作路标点参与定姿。语义信息还具有较强视角不变性不同角度看到的“红绿灯”比“一堆角点”更容易用来做回环检测。这也是当前视觉SLAM研究中卷积网络通常不是接一个分类头而是与位姿图、深度图并行的语义分支的原因。从工程角度看语义信息还有助于解决长时间建图中的“感知灾难”同一面白墙在不同光照下特征波动剧烈但“白墙”这个语义类别却不会变。哪怕CNN误判了几帧只要地图层做概率累加整体建图质量依然优于纯几何方式。需要注意这里说的CNN不一定是最新的Transformer结构部署时往往优先考虑轻量分割网络。因为SLAM系统本身已经占用大量CPU留给语义推理的算力有限MobileNetV3、RegNet这类编码器足够提供可用的像素语义。2.2 数据流设计语义分支该在哪个环节进入SLAM管线常见的做法是采用模块化架构前端仍然是基于特征点或直接法的几何里程计CNN作为旁路对每帧RGB或RGBD图像输出语义分割结果。端到端方法即让卷积网络同时回归位姿和语义图虽然研究热度高但部署时对训练数据、传感器内外参标定极其敏感。更换相机、改变光照、换一个环境网络表现都可能发生明显退化通用性不如模块化方案。我一般建议先以模块化方式把语义信息接进里程计验证收益后再对网络做量化蒸馏。语义分支进入SLAM管线有两个合适位置一是在前端特征提取之后、匹配之前用语义掩码过滤掉动态类别的特征点二是在后端优化结束后、地图更新之前把关键帧的像素语义投影到3D空间做概率积分。前一个位置解决“定位被干扰”后一个位置解决“地图带标签”。两条数据流互不阻塞语义推理可以独立线程运行。如果算力紧张可以只在关键帧上做语义分割而非每帧都推理这样对位姿实时性几乎没有影响。2.3 网络输出与前端的数据对齐和格式约定CNN输出的是一张与输入图像同分辨率的概率张量维度为H×W×CC为语义类别数。传入SLAM前端之前必须把它变成 label_map 和 conf_map前者是每个像素最大概率对应的类别索引后者是最大概率的置信度。对于普通彩色相机输入的帧CNN推理用的分辨率经常会比原始图像低需要记录插值策略否则在地图投影时会差出几个像素。下面是我常用的对齐参数表输入尺寸网络输出与SLAM对齐方式RGB帧1920×1080960×540概率图双线性插值后取出置信度深度图1280×720语义标签图用相机内参和深度投影到3D点类别列表20类COCO网络训练类别固定手动维护一份类别名与索引映射提示别把网络输出直接当作“语义真值”。预训练模型在类别边界上往往会抖动置信度低于0.5的像素建议在掩码里标记为忽略区避免把错误标签累加进地图。3. 基于CNN的语义SLAM最小实现动态点剔除与语义八叉树地图3.1 用PyTorch搭建语义分割前端接入现有ORB-SLAM3框架要复现一个语义SLAM的最小版本最直接的做法是改造ORB-SLAM3的Tracking线程。首先准备语义分割模块import cv2 import torch import numpy as np from torchvision.models.segmentation import deeplabv3_mobilenet_v3_large class SemanticEncoder: def __init__(self, devicecuda): self.device device self.model deeplabv3_mobilenet_v3_large( pretrainedTrue, num_classes21).eval().to(device) torch.no_grad() def encode(self, img_bgr): resized cv2.resize(img_bgr, (320, 320)) rgb cv2.cvtColor(resized, cv2.COLOR_BGR2RGB) tensor torch.from_numpy(rgb).permute(2, 0, 1).unsqueeze(0) tensor tensor.float().div(255.0).to(self.device) out self.model(tensor)[out] # shape: 1, C, 320, 320 return out.argmax(dim1).cpu().numpy()[0]这段代码将RGB图缩放成320×320输出类别索引图。argmax(dim1)取出每个通道概率最大的类别索引。由于SLAM前端原始帧分辨率比320高标签图需要按原比例放回原始尺寸。这里要使用最近邻插值而不是双线性是为了避免类别边界出现“混合像素”否则后面的动态点过滤会把一个点判给两个类别。注意网络前处理用div(255.0)还不够torchvision预训练模型通常要求先算ImageNet的均值方差实际部署时需要在归一化参数里补上mean[0.485,0.456,0.406],std[0.229,0.224,0.225]否则分割精度下降明显。3.2 用语义掩码过滤ORB特征点的代码与参数拿到分割标签图后要做的不是直接把它放进优化器而是先过滤掉属于动态类别集合的匹配点。核心过滤逻辑可以写成这样dynamic_classes {person: 15, bicycle: 2, dog: 18, car: 7} def filter_dynamic_features(kps, label_map, conf_map, min_conf0.25): keep [] for idx, kp in enumerate(kps): x, y int(round(kp.pt[0])), int(round(kp.pt[1])) if not (0 y label_map.shape[0] and 0 x label_map.shape[1]): continue label label_map[y, x] conf conf_map[y, x] if label in dynamic_classes.values() and conf min_conf: continue keep.append(idx) return keepmin_conf0.25的含义是只有当网络对这个像素属于动态类别的置信度高于25%时才过滤低于该值则保留避免误分类导致特征枯竭。过滤动作发生在帧间匹配之前否则运算会浪费在动态点上。实际项目里car类别并不总是动态的停着的车可以作为路标行驶中的车不能。我的建议是给car单独加一个后验判定比如结合IMU或光流检查该区域所有特征点的速度若整体位移超过阈值才把这片区域判为动态并剔除。3.3 把语义标签累计进八叉树地图得到可查询的带标签3D结构当里程计输出关键帧位姿后需要把深度图反投影到世界坐标系并将语义标签做概率积分。常见做法是维护一个带类别标签的语义八叉树节点每次观测时先判断该像素深度是否有效再根据置信度更新节点类别概率。体素级更新可以这样近似int count node-semanticCount[label]; count (conf 0.5f ? 1 : 0); if (count node-maxCount) { node-maxCount count; node-semanticLabel label; }这样建图结果对单帧网络误判不敏感。参数方面我会把最小保留概率设为0.5室内环境的八叉树分辨率设成0.05m。如果要填充因遮挡或传感器噪声产生的体素空洞可以用一个3D卷积神经网络对局部语义体素块做空洞修复但这一步不是必需的。在部署初期先实现轻量概率累加体素分辨率设成0.1m地图生成速度能快一倍且语义标签更平滑。4. 在公开数据集与ROS环境里跑通语义SLAM关键命令和参数设置4.1 数据集准备彩色图、深度图与位姿真值的时间对齐推荐直接用TUM RGB-D或者KITTI Odometry来验证。TUM数据集中RGB和Depth相机具有不同的内参和时间戳偏移如果直接跑单目分割再对应投影深度图会造成位置错位。建议先运行一次rosbag检查rosbag info freiburg2_desk_with_person.bag # 观察 /camera/rgb/image_color 与 /camera/depth/image 的时间间隔若时间偏移大于20ms需要做时间同步。KITTI包含左侧灰度相机、右侧彩色相机但两者之间的外参需要从标定表读取统一坐标系否则CNN拿到彩色图、特征点却来自灰度图像素坐标会偏差大约10个像素。这部分建议写一个预对齐节点输出同一帧下完全对齐的RGB、深度图以及相机内参。4.2 启动语义SLAM节点的命令、阈值与topic映射下面是一套验证语义SLAM时的launch文件片段launch node namesemantic_slam pkgsemantic_slam typesemantic_slam_node outputscreen param nameslam_mode valuergbd / param namevoc_file value$(find semantic_slam)/config/ORBvoc.txt / param nameseg_threshold value0.3 / param namedynamic_classes value15,2,18 / param nameinverse_model value0.4 / remap fromrgb/image to/camera/rgb/image_color / remap fromdepth/image to/camera/depth/image / /node /launch参数里最重要的是seg_threshold和dynamic_classes。前者控制过滤器生效的最低置信度设在0.3能够在动态场景下取得较好精度与召回后者要严格匹配网络训练类别索引。inverse_model是八叉树概率更新时上一帧观测的权重值越大越信任最新观测对快速移动的机器人适合值越小则越平滑适合静态建图。4.3 减小推理延迟的关键做法关键帧后台分割与模型压缩第一次跑通后会发现CPU推理要300ms实时性完全不够。我的做法是把语义分割放到与Tracking独立的后台线程输入队列只缓存最近关键帧的彩色图这样前端始终维持30fps。代价是位姿估计和分割结果之间存在最多一帧延迟但因为是关键帧级别约束对滤波和地图更新影响不大。如果用TensorRT或OpenVINO把网络量化为INT8分辨率降到256×256普通PC上单帧推理可以压在50ms以内。下表给出不同硬件组合的参考环境输入分辨率语义分割延迟推荐用途桌面RTX 3070320×32012ms实时调试Intel NUC核显256×256 OpenVINO35ms移动机器人Jetson Orin320×320 TensorRT18ms嵌入式视觉SLAM注意量化后类别概率整体会变得偏平需要同步提高seg_threshold否则动态点过滤数量会明显减少。5. 验证语义约束是否真提升了SLAM指标、可视化与回环检测技巧5.1 用evo对比绝对轨迹误差做消融实验评估语义过滤是否有效建议做“有语义过滤”和“无语义过滤”两组实验并用evo计算ATE。命令如下evo_traj tum filtered_trajectory.txt --refgroundtruth.txt -a -p # 对比两组轨迹 evo_ape tum original_trajectory.txt filtered_trajectory.txt -va重点关注RMSE是否下降尤其序列中行人较多的时间段。相对RPE的下降往往比ATE更明显因为动态点干扰的主要是帧间约束所以同时建议观察RPE的旋转误差项。如果ATE下降不到5%优先检查dynamic_classes的类别索引是否与预训练网络不一致而不是否定语义过滤思路。5.2 物体级语义特征给回环检测带来的额外约束回环检测若只用视觉词袋光照变化下很容易失效。一个提高鲁棒性的做法是出现候选回环帧时把关键帧中的物体实例区域裁剪出来用同一套CNN提取全局描述子再做类别和空间几何校验。这比单纯比较两张分割图的IoU更稳因为视角变化大时像素级IoU不可靠而物体级“类别质心相对位置”是强约束。提示保存物体质心时别直接存世界坐标先存相对当前关键帧相机坐标的观测值等回环优化完成后再重新投影更新质心。这样能避免在闭环修正前用错误位姿把语义物体写入地图。本文还有配套的精品资源点击获取
返回列表