障碍感知 | 基于2D激光点云的行人检测器DROW算法详解(附Python实现与ROS仿真)

目录

  • [1 DROW算法简介](#1 DROW算法简介)
  • [2 平面点云聚合算法](#2 平面点云聚合算法)
  • [3 DROW算法网络架构](#3 DROW算法网络架构)
  • [4 仿真实现](#4 仿真实现)
    • [4.1 Python实现](#4.1 Python实现)
    • [4.2 行人仿真](#4.2 行人仿真)

1 DROW算法简介

检测人类是服务机器人在应用中的关键技能,许多检测算法已在3D激光雷达中得到了发展,这些方法大致可以分为两类。第一类方法使用点云数据的有序投影,第二类方法则通过设计神经网络架构处理无序的点云数据并对其进行推理,例如PointNetVoxelNet。然而与室外场景(如自动驾驶等)不同,对于许多服务型和家用应用中的移动机器人来说,广泛采用的是水平安装的2D激光扫描仪,目前,针对使用2D激光雷达数据进行人类检测的研究仍然较少。

以往的算法大多依赖手工设计的特征,而DROW检测器是第一个基于深度学习的行人检测算法。DROW通过在网络中提供一个小的、完全在线的时间窗口进一步提高了检测精度。DROW算法提供了DROW数据集,加入了人物标注,使其成为目前最大的2D距离数据人物标注数据集,数据采集在实际环境中经过几天的记录,具有较高的多样性。

2 平面点云聚合算法

由于激光雷达点空间密度随距离变化明显,直接应用网络进行对激光雷达信息进行目标检测,网络的感受野必须覆盖物体的大部分。但是激光雷达附近的物体包含大量的激光束,而远处的物体只能被少量的激光束击中,这使得网络容易对训练场景的背景产生过拟合。

为了避免背景信息过拟合问题,DROW算法实现激光雷达数据中的人体目标检测。利用激光雷达提供的真实世界尺度信息,同时采用深度引导的滑动窗口法对激光数据点进行预处理,使待检对象在不同的距离上有大致相同的信息表现,从而降低在不同距离上隐藏层对不同特征输入的需要,归一化不同深度的特征,减小对特征工程的需求,提高目标检测准确性。

具体处理的算法阐述如下:在给定时间 t t t内由 N N N个点 { s n t } n = 1 N \{s_n^t\}{n=1}^N {snt}n=1N组成的激光雷达数据 r t ∈ R N r^t\in R^N rt∈RN,生成 N N N个局部感知的视野窗口 { c n t } n = 1 N \{c_n^t\}{n=1}^N {cnt}n=1N对应激光雷达点 s n t s_n^t snt周围欧几里得空间的固定窗口。通过计算每个点 s n t s_n^t snt的开角 α n t \alpha_n^t αnt确定窗口大小

α n t = 2 arctan ⁡ W 2 r n t \alpha_n^t=2\arctan \frac{W}{2r_n^t} αnt=2arctan2rntW

其中 W = 1.0 W =1.0 W=1.0为预先设定的窗口宽度的超参数, r n t r_n^t rnt为点 s n t s_n^t snt的距离测量值,即激光点的距离信息。之后将开角 α n t \alpha_n^t αnt邻域内的激光雷达测量数据以固定数量 M M M重新进行线性采样,将窗口内的激光数据点通过减去中心点距离 r n t r_n^t rnt使实现去均值处理。经过处理后的激光雷达点无论距离 r n t r_n^t rnt为何值,卷积神经网络的感受野总是覆盖相同尺寸的真实范围。去除在 [ − H r , + H r ] [-H_r, +H_r] [−Hr,+Hr]的深度范围之外的背景和前景数据点,其中 H r = 1.0 H_r=1.0 Hr=1.0为窗口深度的超参数。并且最后将所获得窗口 c n t c_n^t cnt中的所有值归一化至 [ − 1 , 1 ] [−1,1] [−1,1],减少不同维度取值范围的差异带来的干扰。

将归一化后的 c n t c_n^t cnt进行分类与回归,通过激活函数 S o f t M a x SoftMax SoftMax输出对每个窗口是否属于为人体腿部类别进行分类,如果为感兴趣目标,则回归窗口的中心位置进行分类投票。由于激光雷达信息作为基于距离的范围数据本质上具有旋转不变性,则以当前激光信息点为中心对齐的坐标系取代绝对坐标系 ( x , y ) (x, y) (x,y)对其偏移量 ( Δ x , Δ y ) (\Delta x, \Delta y) (Δx,Δy)进行加权投票,最后使用非极大值抑制合并投票并获得检测质心

一个由激光点云映射的二维聚合窗口实例如下所示,颜色代表距离的不同

3 DROW算法网络架构

DROW算法网络架构如下所示

其中原始的平面的激光点云通过聚合雷达窗口映射为2D类图像形式的输入,经过若干卷积池化操作,输出到特征层。最终使用两个特征提取头,分别输出一维的行人标签和二维的行人坐标

4 仿真实现

4.1 Python实现

DROW检测器的核心实现如下所示

python 复制代码
class DrowNet(nn.Module):
    def __init__(self, loss_kwargs: dict, model_kwargs: dict) -> None:
        super(DrowNet, self).__init__()

        self.dropout = model_kwargs["DROPOUT"]
        self.max_num_pts = model_kwargs["MAX_NUM_PTS"]

        self.criterion = DrowNetCriterion(loss_cfg=loss_kwargs)

        self.conv_block_1 = nn.Sequential(
            _conv1d_3(1, 64), _conv1d_3(64, 64), _conv1d_3(64, 128)
        )
        self.conv_block_2 = nn.Sequential(
            _conv1d_3(128, 128), _conv1d_3(128, 128), _conv1d_3(128, 256)
        )
        self.conv_block_3 = nn.Sequential(
            _conv1d_3(256, 256), _conv1d_3(256, 256), _conv1d_3(256, 512)
        )
        self.conv_block_4 = nn.Sequential(_conv1d_3(512, 256), _conv1d_3(256, 128))

        self.conv_cls = nn.Conv1d(128, 1, kernel_size=1)
        self.conv_reg = nn.Conv1d(128, 2, kernel_size=1)

        # initialize weights
        for m in self.modules():
            if isinstance(m, (nn.Conv1d, nn.Conv2d)):
                nn.init.kaiming_normal_(m.weight, a=0.1, nonlinearity="leaky_relu")
            elif isinstance(m, (nn.BatchNorm1d, nn.BatchNorm2d)):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)

    def __str__(self) -> str:
        return "DROW"

    def forward(self, x: Tensor) -> Tuple[Tensor, Tensor]:
        '''
        Forward process

        Parameters
        ----------
        x: Tensor
            input data with dim [B, CT, N, L] --- (batch, cutout, scan, points per cutout)
        
        Return
        ----------
        pred_cls: Tensor
            predicted class with dim [B, CT, 1]
        pred_reg: Tensor
            predicted regression with dim [B, CT, 2]
        '''
        n_batch, n_cutout, n_scan, n_pts = x.shape

        # forward cutout from all scans
        out = x.view(n_batch * n_cutout * n_scan, 1, n_pts)
        out = self._conv_and_pool(out, self.conv_block_1)  # /2
        out = self._conv_and_pool(out, self.conv_block_2)  # /4

        # (batch, cutout, scan, channel, pts)
        out = out.view(n_batch, n_cutout, n_scan, out.shape[-2], out.shape[-1])

        # combine all scans
        out = torch.sum(out, dim=2)  # (B, CT, C, L)

        # forward fused cutout
        out = out.view(n_batch * n_cutout, out.shape[-2], out.shape[-1])
        out = self._conv_and_pool(out, self.conv_block_3) 
        out = self.conv_block_4(out)
        out = F.avg_pool1d(out, kernel_size=int(out.shape[-1]))

        pred_cls = self.conv_cls(out).view(n_batch, n_cutout, -1)  
        pred_reg = self.conv_reg(out).view(n_batch, n_cutout, 2)

        return pred_cls, pred_reg

4.2 行人仿真

DROW数据集中的测试效果如下所示

其中蓝色圆圈是真值,红色圆圈是行人检测值,可以看到跟踪效果非常好

为了实际的部署,需要在ROS中进一步测试。在pedestrian.yaml文件中配置并启动DROW检测器,其中model选择DROW3ckpt_jrdb_ann_drow3_e40.pth是模型对应的权重文件

yaml 复制代码
pedestrians:
  update_rate: 5
  ped_tracker:
    enable: true
    model: DROW3
    weight: ckpt_jrdb_ann_drow3_e40.pth

实时监测效果如下

完整工程代码请联系下方博主名片获取


🔥 更多精彩专栏

👇源码获取 · 技术交流 · 抱团学习 · 咨询分享 请联系👇

相关推荐
fegxg11 分钟前
ROS Action通信解读
linux·ubuntu·机器人
AI视觉网奇36 分钟前
LivePortrait 部署笔记
笔记·计算机视觉
ChillJavaGuy39 分钟前
线性dp求解最小代价问题
java·数据结构·算法
反方向的钟儿42 分钟前
数据挖掘与机器学习(part 10)推荐算法Recommendation Algorithm & 隐语义模型(LFM)& 协同过滤算法 & SVD
人工智能·算法·机器学习·数据挖掘·推荐算法
金书世界1 小时前
自动驾驶AVM环视算法--python版本的俯视TOP投影模式
python·算法·自动驾驶
Jam-Young1 小时前
OpenCV函数及其应用
人工智能·opencv·计算机视觉
XiaoLeisj1 小时前
【递归,搜索与回溯算法 & 递归算法】递归算法入门详解:递归算法小专题
java·算法·leetcode·深度优先·推荐算法
反方向的钟儿1 小时前
数据挖掘与机器学习(part 9) 规则挖掘Rules Mining&关联规则(Association Rules)& Apriori算法
人工智能·算法·机器学习·数据挖掘
闻缺陷则喜何志丹1 小时前
【C++图论 DFS】1559. 二维网格图中探测环|1837
c++·算法·深度优先·力扣·图论··网格
TANGLONG2222 小时前
【初阶数据结构与算法】八大排序算法之选择排序(直接选择排序、堆排)
c语言·数据结构·c++·考研·算法·面试·排序算法