赞
踩
博主初学3D目标检测,此前没有相关学习背景,小白一枚~现阶段的学习重点是点云相关的3D检测。
本文是阅读文章:3D Object Detection for Autonomous Driving: A Review and New Outlooks 后的学习笔记和总结(强烈推荐大家去看下原文:https://arxiv.org/pdf/2206.09474.pdf,对我个人来说收获颇多)。其中还包含经典论文VoxelNet、Second、PointPillar、CenterPoint、PV-RCNN的学习笔记。
希望能为大家带来一些帮助,也期待各位同学来交流~
激光雷达数据:
点云数据以浮点二进制文件格式存储,每行包含8个数据,每个数据由四位十六进制数表示(浮点数),每个数据通过空格隔开。一个点云数据由四个浮点数数据构成,分别表示点云的x、y、z、r(强度 or 反射值)。KITTI激光雷达文件夹下的训练点云数量有7481个,即7481个bin文件,共13.2GB大小。测试点云数量有7518个,即7518个bin文件,共13.4GB大小。
标注数据label_2:
标注文件中16个属性,即16列。但我们只能够看到前15列数据,因为第16列是针对测试场景下目标的置信度得分,也可以认为训练场景中得分全部为1但是没有专门标注出来。下图是000001.txt的标注内容和对应属性介绍。
目标类别type,截断程度truncated,遮挡程度occlude,观测角度alpha(-pi,pi),二维检测框bbox(左上,右下),三维物体尺寸dimensions(高度宽度长度),中心坐标location,旋转角rotation_y,置信度分数score(仅在测试时用)
#### 图像数据image_2:
KITTI数据集种共包含了4相机数据,2个灰度相机和2个彩色相机,其中image_2存储了左侧彩色相机采集的RGB图像数据(RGB)。
存储方式为png格式。KITTI相机的分辨率是1392x512,而image_2种存储的图像是矫正后的图像,分辨率为1242x375。训练集共7481张图片;测试集共7518张图片。
#### 标定校准数据calib:
标定校准文件主要作用是把 激光雷达坐标系 测得的点云坐标 转换到相机坐标中 去,相关参数存在data object calib中,共包含7481个训练标定文件和7518个测试标定文件。标定文件的存储方式为txt文本文件。
内参矩阵、外参矩阵、R0校准矩阵、点云坐标到相机坐标。
内参矩阵:把点云坐标投影到相机坐标系
外参矩阵:点云位置坐标投影到相机坐标系前,需要转换到世界坐标系下。
R0校准矩阵:R0_rect 为0号相机的修正矩阵,大小为3x3,目的是为了使4个相机成像达到共面的效果,保证4个相机光心在同一个xoy平面上。在进行外参矩阵变化之后,需要于R0_rect相乘得到相机坐标系下的坐标。
点云坐标到相机坐标:点云坐标在相机坐标系中的坐标=内参矩阵 * 外参矩阵 * R0校准矩阵 * 点云坐标
三个坐标系
激光雷达坐标系 蓝色
相机坐标系 红色
图像坐标系
点云可视化:https://blog.csdn.net/qq_45752541/article/details/126370448
针对3D目标检测的评价,一种是将2D任务的AP指标扩展到3D,比如KITTI就包括 AP-3D、AP-BEV指标,分别用到预测值与真值的3D-IoU、BEV-IoU来衡量。其它比如基于中心距离的匹配,或者匈牙利匹配等。另一种则通过下游任务来衡量,只有对下游任务(运动规划)有帮助的检测方法,才能在实际应用中确保驾驶安全。
直接从原始点数据来预测3D目标。将点云通过基于点的主干网络,通过点云算子来提取点云特征,基于下采样的点和特征预测3D框。基于点的3D目标检测器主要组成部分为:点云采样和特征学习。
点云采样。PointNet++[208]的FPS在基于点的检测器中被广泛采用,这种检测器从原始点集中依次选择最远处的点。PointRCNN[234]是一项开创性的工作,它采用FPS逐步下采样输入的点云,并从下采样点中生成3D候选。类似的设计范式在随后的许多工作中也被采用,并进行了分割引导滤波[318]、特征空间抽样[321]、随机抽样[189]等改进。
特征学习。上下文点首先用一个预定义的查询球半径进行选择,然后上下文点和特征经过多层感知机和max-pooling,得到新的特征。其它点云操作,包括图操作、注意力操作、Transformer等。
基于点的3D目标检测器受制于特征学习中采用的上下文点数量和上下文半径。增加上下文点数量可以获得更强的表达能力,但会增加内存,在球查询中,上下文半径太小,会造成上下文信息不足,半径太大,造成3D细粒度信息丢失。
对于大部分的基于点的3D目标检测器,推理时间上的瓶颈是点云采样。随机均匀采样因为可以并行,效率最高,但激光雷达扫描点分布不均匀,随机均匀采样会对点云密度高的地方过采样,而稀疏的地方欠采样。最远点采样及其变体通过从已有的点集中依次选择最远点获得更加均匀的采样结果,但其不能并行,耗时较大,较难做到实时。
基于网格的3D目标检测器首先将点云栅格化为离散的网格表示,即体素voxel、柱体pillar和鸟瞰视图(BEV)特征图。然后应用传统的2D卷积神经网络或3D稀疏神经网络提取特征。最后,可以从BEV网格中检测出3D目标。下图展示了基于网格的3D目标检测的示例,下表给出了基于网格的检测器的分类。网格检测有两个基本组成部分:基于网格的表示和基于网格的神经网络。
基于网格的表示。目前有3种主要的网格表示类型:体素、柱体和BEV特征图。
体素。体素是3D立方体,体素细胞内包含点。点云可以很容易地通过体素化转化为体素。由于点云分布稀疏,3D空间中的大部分体素细胞都是空的,不包含点。在实际应用中,只有那些非空体素被存储并用于特征提取。VoxelNet[359]是一项利用稀疏体素网格的开创性工作,提出了一种新的体素特征编码(VFE)层,从体素细胞内的点提取特征。此外,还有两类方法试图改进用于3D目标检测的体素表示:
1. 多视图体素。一些方法从不同的视角提出了一种动态体素化和融合方案,例如从鸟瞰图和透视图[360],从圆柱形和球形视图[34],从深度视图[59]等。
2. 多尺度体素。一些论文生成不同尺度的体素[323]或使用可重构体素。
柱体。柱体可以被视为特殊的体素,其中体素的大小在垂直方向上是无限的。通过PointNet将点聚集成柱状特征[207],再将其分散回去,构建二维BEV图像进行特征提取。PointPillars[117]是一个开创性的工作,介绍了柱体表示,随后的是[283,68]。
BEV特征图。鸟瞰特征图是一种密集的二维表示,其中每个像素对应一个特定的区域,并对该区域内的点信息进行编码。BEV特征图可以由体素和柱体投影到鸟瞰图中获得,也可以通过汇总像素区域内的点统计数据,直接从原始点云中获得。常用的统计数据包括二进制占用率[314,313,2]和局部点云高度和密度[40,10,342,3,245,346,8,119]。
基于网格的神经网络。目前主要有两种基于网格的网络:用于BEV特征图和柱体的2D卷积神经网络,以及用于体素的3D稀疏神经网络。
与BEV特征图和柱体2D表示相比,体素包含更多结构化的3D信息。此外,可以通过3D稀疏网络学习深度体素特征。但是,3D神经网络会带来额外的时间和内存成本。BEV特征图是最有效的网格表示,它直接将点云投影到2D伪图像中,而无需专门的3D算子,如稀疏卷积或柱体编码。2D检测方法也可以在BEV特征图上无缝应用,无需太多修改。
基于BEV的检测方法通常可以获得高效率和实时推理速度。然而,简单地汇总像素区域内的点统计信息会丢失太多的3D信息,与基于体素的检测相比,这会导致检测结果不太准确。
基于柱体的检测方法利用PointNet对柱体单元内的3D点信息进行编码,然后将特征分散回2D伪图像中进行有效检测,从而平衡3D目标检测的效果和效率。
选择合适大小的网格单元是所有基于网格的方法都必须面对的关键问题。通过将连续点坐标转换为离散网格索引,网格表示本质上是点云的离散形式。在转换过程中不可避免地会丢失一些3D信息,其效果很大程度上取决于网格单元的大小:网格小,分辨率高,可以保持更细粒度的细节,对于准确检测3D目标至关重要。然而,减小网格单元又会导致2D网格表示(如BEV特征图或柱体)的内存消耗呈二次方增长。至于像体素这样的3D网格表示,问题可能会变得更加严重。因此,如何平衡更小网格尺寸带来的效果和内存增加影响效率,仍然是所有基于网格的3D目标检测方法的一个挑战。
VoxelNet: End-to-End Learning for Point Cloud Based 3D Object Detection (CVPR2018)
Motivation
为了将高度稀疏的激光雷达点云与区域建议网络(RPN)连接,大多数现有的工作都集中在手工制作的特征表示上,例如,鸟瞰图投影。这项工作消除了人工特征工程对三维点云的需求,提出了VoxelNet,一种将特征提取和box预测统一为一个单阶段、端到端可训练的深度通用三维检测网络。具体来说:
● 提出了VoxelNet,一种通用的三维检测框架,它可以从点云中同时学习区分特征表示,并以端到端的方式预测精确的三维边界框。
● 设计了一种新的体素特征编码(VFE)层,通过将点特征与局部聚集特征相结合,实现了体素内部的点间交互,通过叠加多个VFE层可以学习复杂特征来表征局部3D形状信息。
● VoxelNet将点云划分为等间距的三维体素,通过叠加的VFE层对每个体素进行编码,然后三维卷积进一步聚集局部体素特征,将点云转化为高维体素表示。
● RPN使用体积表示并产生检测结果。这种有效的算法既有稀疏点结构的优点,又有体素网格上高效并行处理的优点。
● 本网络主要面向RPN+点云操作,并没有建立类别级的分类,作为一个通用的面向激光雷达点云操作的RPN框架使用。
Method
VoxelNet将3D点云数据看作一个个的Voxel进行处理。网络结构分为三个部分:1. 特征学习网络;2. 中部卷积层;3. RPN层。
特征学习层:
1. Voxel Partition:将空间划分为一个个堆叠的、相同大小的Voxel;
2. Grouping:将3D点云数据装进一个个的Voxel中,实现分组;
3. Random Sampling:3D点云数据量往往都是10万以上的,要直接在这个数量级上进行特征提取,非常消耗计算资源,而且可能会引发检测偏差(bias the detection)。所以这里提出了随机采样方法,将点云数量超过T的Voxel中的点云数量降至T。
4. Stacked Voxel Feature Encoding:提出了VFE层(Voxel Feature Encoding)。
a. 3个点云数据经过一个全连接卷积层提取特征,获得3个point-wise feature。
b. 引入element-wise maxpool,获得local aggregated feature,反应这些点的一个局部关系。
c. 将point-wise feature和locally aggregated feature进行简单的堆叠融合,作为下一个VFE层的输入。
d. 连续堆叠几次VFE后,获得更丰富的特征表示。最后用一个element-wise maxpool获得最后一个voxel-wise feature。
中间卷积层:
点云数据通过特征学习网络后可以被表示成一个稀疏的4D张量,维度记做 (C,D′,H′,W′) 。其中, C 为Voxel-wise Feature的向量维度(也就是图3中向量的高度), D′,H′,W′ 为空间的深度、高度和宽度(单位为Voxel数量)。
因为张量是4维的,作者就用3D卷积来构建这个中间卷积层。目的显然是为了扩大感受野,增加更多的信息描述。
- class CML(nn.Module):
- def __init__(self):
- super(CML, self).__init__()
- self.conv3d_1 = Conv3d(128, 64, 3, s=(2, 1, 1), p=(1, 1, 1))
- self.conv3d_2 = Conv3d(64, 64, 3, s=(1, 1, 1), p=(0, 1, 1))
- self.conv3d_3 = Conv3d(64, 64, 3, s=(2, 1, 1), p=(1, 1, 1))
-
- def forward(self, x):
- x = self.conv3d_1(x)
- x = self.conv3d_2(x)
- x = self.conv3d_3(x)
- return x
RPN层:
RPN层主要用来根据学习到的特征,并结合Anchor,在原图中找到物体所在检测框和对应的类别。
一般而言,RPN层有两个分支,一个用来输出类别的概率分布(通常叫做Score Map),一个用来输出Anchor到真实框的变化过程(通常叫做 Regression Map)。
作者提出的RPN层的结构如下图所示。该网络以中间卷积层的输出特征图为输入,分别经过三次下采样(每次stride=2)获得三个不同维度的特征图。作者将这个三个特征图缩放至同一维度后进行拼接,有点FPN(特征金字塔网络)的感觉。最后,拼接的特征被映射成两个输出特征图。
损失函数:
本文中,作者引入了 个正anchor和个负anchor。一个gt-3D检测框可以用一个7维向量表示,分别为 。前三项 为框的中心点坐标,为框的长宽高。为绕Z轴的偏航旋转角。
假设与gt-bbox匹配的positive anchor的参数为 。那么RPN层中的regression分支要学的东西,就是从positive anchor到gt-bbox的变化过程参数,定义如下:
损失函数由分类损失(positive anchor和negative anchor)和回归损失组成:
Sparsely Embedded Convolutional Detection (sensor 2018),是voxelnet的升级版
Motivation
(1)考虑到VoxelNet论文在运算过程中运算量较大,且速度不佳。作者引入了稀疏3D卷积去代替VoxelNet中的3D卷积层,提高了检测速度和内存使用;
(2)VoxelNet论文有个比较大的缺点就是在训练过程中,与真实的3D检测框相反方向的预测检测框会有较大的损失函数,从而造成训练过程不好收敛。
顺带着动机,作者又提出了一些其他的创新点:
(1)比如数据增强这块,作者使用了数据库采样的操作;
(2)对于正负样本数量的极度不平衡问题,作者借鉴了RetinaNet中采用的Focal Loss。
Method
考虑到VoxelNet通过Feature Learning Network后获得了稀疏的四维张量,而采用3D卷积直接对这四维的张量做卷积运算的话,确实耗费运算资源。SECOND作为VoxelNet的升级版,用稀疏3D卷积替换了普通3D卷积。
在VoxelNet的结构图的基础上进行修改,获得SECOND的网络结构图。
Convolutional middle layers替换为Sparse convolutional middle layers:
黄:sparse convolution
白:submanifold convolution
红:sparse-to-dense layer
稀疏卷积:
稀疏卷积流程:
● 将稀疏的输入特征通过gather操作获得密集的gather特征;
● 然后使用GEMM对密集的gather特征进行卷积操作,获得密集的输出特征;
● 通过预先构建的输入-输出索引规则矩阵,将密集的输出特征映射到稀疏的输出特征。
输入-输出索引规则矩阵的生成规则:
● 迭代输入点以获取每个输入点对应的输出,并将对应的索引存储到规则中
● 迭代过程中,建立一个表来检查每个输出位置是否真实存在
具体实现:
1. 收集输入索引(input indexes)和相关的空间索引(associated spatial indexes),并复制输出位置(Duplicate output locations);
2. 在空间索引上执行unique parallel算法,获得输出索引(output indexes)和对应的空间索引(associated spatial indexes)。
3. 生成一个与稀疏数据的相同空间维度的缓冲区,用于查找表
4. 最后,对规则进行迭代,并使用存储的空间索引来获得每个输入索引对应的输出索引。
方向回归:
在最后的RPN层(原来是两个分支,用来物体分类和位置回归)多引入了一个分支(如下图5所示),用来对物体方向进行分类。
在VoxelNet中,一个3D BBox被建模为一个7维向量表示,分别为(x_c,y_c,z_c,l,w,h,θ)
训练过程中,对这7个变量采用Smooth L1损失进行回归训练。
当同一个3D检测框的预测方向恰好与真实方向相反的时候,上述的7个变量的前6个变量的回归损失较小,而最后一个方向的回归损失会很大,这其实并不利于模型训练。为了解决这个问题,作者引入了对方向角的回归损失,定义如下:
θ_p为预测的方向角, θ_t 为真实的方向角。
那么当 θ_p=θ_t±π 的时候,该损失趋向于0,这样更利于模型训练。但是这样容易使模型预测方向与真实方向相差180度,为此 引入了RPN中的direction classifer分支,将车头是否区分正确直接通过一个softmax loss来约束。如果theta>0为正, theta<0为负,转换为一个二分类问题。
Region proposal network替换为:
PointPillars: Fast Encoders for Object Detection from Point Clouds (CVPR2019)
Motivation
截止CIA-SSD论文发表前,PointPillars的检测速度都是遥遥领先的,而且精度也不低。
现有的一些研究喜欢将不规则、稀疏的点云数据按照以下两种方式进行处理,然后引入RPN层进行3D Bbox Proposal,这两种方法为:
(1)将点云数据划纳入一个个体素(Voxel)中,构成规则的、密集分布的体素集。常见的有VoxelNet和SECOND;
(2)从俯视角度将点云数据进行处理,获得一个个伪图片的数据。常见的模型有MV3D和AVOD,这也说过了。
本文采用了一种不同于上述两种思路的点云建模方法。从模型的名称PointPillars可以看出,该方法将Point转化成一个个的Pillar(柱体),从而构成了伪图片的数据。
然后对伪图片数据进行BBox Proposal就很简单了,作者采用了SSD的网络结构进行了Proposal。
Method
数据处理:
1. pointcloud -> stacked pillars 点云数据张量化
按照点云数据所在的X,Y轴(不考虑Z轴)将点云数据划分为一个个的网格,凡是落入到一个网格的点云数据被视为其处在一个pillar里,或者理解为它们构成了一个Pillar。
每个点云用一个 D=9 维的向量表示,分别为 。其中为该点云的真实坐标信息(三维)和反射强度;为该点云所处Pillar中所有点的几何中心; 为,反应了点与几何中心的相对位置。
假设每个样本中有 P 个非空的pillars,每个pillar中有 N 个点云数据,则这个样本可以用一个 (D,P,N) 张量表示。
怎么保证每个pillar中有 N 个点云数据呢?如果每个pillar中的点云数据数据超过N 个,那么我们就随机采样至 N 个;如果每个pillar中的点云数据数据少于N 个,少于的部分我们就填充为0;
2. stacked pillars -> learned features 特征提取
特征提取可以理解为对点云的维度进行处理,原来的点云维度为 D=9 ,处理后的维度为 C ,那么我们就获得了一个 (C,P,N)的张量。接着,按照Pillar所在维度进行Max Pooling操作,即获得了 (C,P) 维度的特征图。
3. learned features -> pseudo image 特征转伪图片
为了获得伪图片特征,作者将 P 转化为 (H,W) ,即 P→H×W 。那么我们就获得了形如 (C,H,W) 的伪图片了。
整体网络结构:
伪图片化后,用2D CNN来进一步提取图片特征。该2D CNN采用了两个网络。其中一个网络不断缩小特征图的分辨率,同时提升特征图的维度,因此获得了三个不同分辨率的特征图。另一个网络对三个特征图进行上采样至相同大小,然后进行concatenation。
损失函数:
采用了SECOND中类似的损失函数,每个3D BBox用一个7维的向量表示,分别为。
回归用SmoothL1:
分类用focal loss:
总损失:
CenterPoint:Center-based 3D Object Detection and Tracking (CVPR2021)
Motivation
该文章是Center-based系列工作(CenterNet、CenterTrack、CenterPoint)的扩展,于2020年作者在arxiv公开了第一版CenterPoint,后续进一步将CenterPoint扩充成了一个两阶段的3D检测追踪模型,相比单阶段的CenterPoint,性能更佳,额外耗时很少。本文的主要贡献是提出了一个两阶段的Center-based的目标检测追踪模型,在第一阶段(如图1中的a,b,c),使用CenterPoint检测三维目标的检测框中心点,并回归其检测框大小,方向和速度。在第二阶段(如图1中的d)设计了一个refinement模块,对于第一阶段中的检测框,使用检测框中心的点特征回归检测框的score并进行refinement。
Contribution:
1. 使用点表示目标,简化三维目标检测任务:与图像目标检测不同,在点云中的三维目标不遵循任何特定的方向,box-based的检测器很难枚举所有的方向或为旋转的对象拟合一个轴对齐的检测框。但Center-based的方法没有这个顾虑。点没有内转角。这极大地减少了搜索空间,同时保持目标的旋转不变性。(AblationStudy的结果可以看到Center-based方法对模型效果提升非常明显)
2. Center-based的方法可以简化追踪任务:作者表明由于该方法不需要额外的运动模型(如Kalman滤波),所以追踪计算时间可以忽略不计,在检测的基础上仅需要运行1毫秒。
3. 使用一个基于点特征的refinement模块作为网络的第二阶段。保障模型预测性能,同时也比现在大多数的refinement方法更快。由于“检测--追踪”的多目标追踪流程对检测阶段的错误预测非常敏感,本文通过第二阶段预测bbox的score来降低CenterPoint第一阶段中产生的错误预测,提升目标检测的质量,同时进一步提升了追踪的结果。
Method
First stage -- CenterPoint:
网络的输入为雷达点云数据。网络的3D encoder部分使用了现有的网络模型,CenterPoint提供了两种主干网实现方式,分别为VoxelNet 和PointPillar。
网络的输出为基于类的Heatmap、目标的大小、转角和速度。其中Heatmap的生成方式与CenterNet类似。首先,我们回顾一下CenterNet热力图的回归方式:对于任意尺寸为W*H*3的图像,我们会生成一个尺寸为W/R * H/R * K的热力图,其中K是检测的类别数。热力图的中元素的取值为0或1,其中若热力图该点为1,则图像中该点是一个检测框的中心,若为0,则该出在图像中为背景。唯一的区别是:由于三维空间中目标分布离散且三维目标不会像图像中目标一样近大远小,如果按照CenterNet的方式生成Heatmap,那么Heatmap中将大部分都是背景。作者的解决方法是设置高斯半径公式为σ = max(f(wl); τ),其中τ = 2为最小高斯半径值,f为CenterNet的高斯半径求解方法。
Second stage:
根据第一阶段的目标检测框和主干网featuremap,作者提取目标检测框每个面的中心点的在featuremap上的点特征值,将该特征值送入如图一d的全连接网络中,得到该目标检测框的检测置信度和精修结果。具体地,由于目标检测框的顶面、地面的中心在birdview上为同一个点,故实际选择四个向外的面的中心在birdview上的点特征(具体的四个点的投影如图一c所示),作为全连接网络的输入值。同时,对于每个点特征,在实际提取时使用双线性插值从主干网的birdview的特征图中提取。
训练时:
置信度score:
损失:
预测时:
基于点-体素的方法采用了一种混合架构,利用点和体素进行3D目标检测。主要分为两类:单阶段检测框架和两阶段检测框架。下图显示了这两个类别的示例及分类:
单阶段基于点-体素的3D目标检测器通过骨干网络中的点-体素和体素-点的变换来连接点和体素的特征。点包含细粒度的几何信息,体素计算效率高,在特征提取阶段将它们结合在一起更加有利。代表性工作包括:PVCNN、SPVNAS、SA-SSD、PVGNet等。
两阶段的基于点-体素的3D目标检测器,在第一阶段,使用基于体素的检测器来生成一组3D候选目标。在第二阶段,首先从输入点云中采样关键点,然后通过新的点算子对关键点进行进一步细化。代表工作包括:PV-RCNN、LiDAR R-CNN、Pyramid R-CNN、CT3D等等。
与纯体素检测方法相比,基于点-体素的3D目标检测方法在增加推理时间的同时,可以获得更好的检测精度。
PV-RCNN: Point-Voxel Feature Set Abstraction for 3D Object Detection (CVPR 2020)
Motivation
提取点云特征的方式:
1. PointNet++中提出的Point-based Set Abstraction(SA),在原始点云上做,保留了准确的位置信息且通过自定义球的半径使得感受野更为灵活
2. 转化为规则voxel后的voxel-based sparse convolution,在voxel上做,速度往往更快,并且在自动驾驶场景下结合anchor可以产生更高质量的3D proposal
为了综合利用上面两种特征提取操作各自的优势,我们就在考虑怎么能将这两种点云特征提取算法深度结合到一个网络中,提升网络的结构多样性以及表征能力。从另一个方面讲,我们之前一直专注于二阶段的高性能3D网络检测框架(PointRCNN[3], PartA2-Net[4]),经验告诉我们,在point上进行3D RoI pooling比BEV map上效果更好(保留更精细的特征)。所以,怎么得到表征能力更强的point-wise特征,也是我们需要做的。
因此,我们接着考虑,怎么能将整个场景编码到少量的keypoint上,用这些point-wise的keypoint特征来做第二阶段的RoIPooling,也就是将其作为桥梁,来连接检测框架的两个阶段。
然后我们就自然而然的关注到了Set Abstraction这个操作上了。在Set Abstraction的原本设计中,球中心的点是从整个点云中采样出来的,其与周围的点同宗同源,中心点的特征即通过球内周围点的特征聚合而来。然而,我们发现,其实球中心点无需与周围的点同宗同源,球中心点是可以任意给定的。所以,Set Abstraction本身就可以作为一个很好的操作,来结合上面两种点云特征提取操作(球中心与周围点可以分别来自于point与voxel)。
Method
Voxel Set Abstraction
将Sparse Convolution主干网络中多个scale的sparse voxel及其特征投影回原始3D空间,然后将少量的keypoint (从点云中sample而来) 作为球中心,在每个scale上去聚合周围的voxel-wise的特征。这个过程实际上结合了point-based和voxel-based两种点云特征提取的结构,同时将整个场景的multi-scale的信息聚合到了少量的关键点特征中,以便下一步的RoI-pooling。
Predicted Keypoint Weighting
通过从3D标注框中获取的免费点云分割标注,来更加凸显前景关键点的特征,削弱背景关键点的特征。
RoI-grid Pooling
与前面不同,这次我们在每个RoI里面均匀的sample一些grid point,然后将grid point当做球中心,去聚合周围的keypoint的特征。这样做的好处有两个: (1) 球半径灵活,甚至可以包括proposal框外围的关键点,从而获取更多有效特征。(2) 球互相覆盖,每个keypoint可以被多个grid point使用,从而得到更紧密的RoI特征表达。另一方面,这其实也是另一个point (keypoint)与voxel (grid point)特征交互的过程。
通过Voxel-to-keypoint与keypoint-to-grid这两个point-voxel特征交互的过程,显著增强了PV-RCNN的结构多样性,使其可以从点云数据中学习更多样性的特征,来提升最终的3D检测性能。
Range图像是一种密集而紧凑的2D表示,其中每个像素包含3D深度信息,而不是RGB值。需要针对Range图设计模型和算子,并要选择合适的视图。
Range图是2D的,可以借鉴2D目标检测方法,比如LaserNet,还有一些借鉴了U-Net、RPN、R-CNN、FCN、FPN等。
Range图的像素包含的是距离信息,而非颜色值,因此传统的2D标准卷积算子无法完全适用,滑动窗口中的像素在3D空间中可能会相距很远。一些工作采用了新算子来有效地从Range像素中提取特征,包括深度扩张卷积range dilated convolutions[11]、图算子graph operators[26]和元核卷积meta-kernel convolutions[67]等。
Range图是从Range视图(Range View)中获取的,RangeView是点云的球面投影。对于许多基于range图的方法[178,11,67,26]来说,直接从Range视图检测3D目标是很自然的。然而,从Range视图进行检测不可避免地会遇到球面投影所带来的遮挡和尺度变化问题。为了规避这些问题,许多方法尝试利用其他视图来预测3D目标,例如[219]中利用的圆柱形视图(CYV),其它方案尝试Range视图和鸟瞰视图(BEV)、点视图(PV)的组合。
Range视图由于可以借鉴2D卷积的优点,做特征提取比较好,但由于遮挡和尺度问题,直接在上面做检测效果不好,需要结合BEV来做检测,所以现在一般是Range图做特征提取,BEV上做检测。
3D目标检测的学习目标主要是针对小目标(相比检测范围,目标太小),另一方面是由于点云的稀疏性,如何准确估计其目标的中心和尺寸也是一个长期挑战。
anchor是预定义的长方体,具有固定的形状,可以放置在3D空间中。3D目标可以基于正anchor进行预测,这些正anchor与GT的IoU最大。anchor-based的3D目标检测方法一般是从鸟瞰图上检测3D目标,将3D anchor放置在BEV特征图的每个网格单元上进行。3D anchor通常对于每个类别都有一个固定的尺寸,因为同一类别的目标有相似的大小。
anchor-based的损失函数包括了分类损失、回归损失、偏航角损失等。分类损失常用的是二值交叉熵、Focal loss,回归则是SmoothL1,航向角需要注意使用bin-based航向估计较好。除了这些单独的损失函数外,将整个3D目标作为整体去考虑,也有使用IoU loss的,再辅以corner loss,让3D目标的检测更加稳定。
下面是anchor-based方法的示意图和主要目标损失函数:
second, pointpillar:
voxelnet:
pvrcnn:
anchor-free方法去掉了复杂的anchor设计阶段,可灵活应用于BEV、点视图和Range视图等。没有了anchor,就需要找其它正负样本分配方法。比如基于一些网格(BEV网格单元、体素、柱体)进行分配正负样本,比如PIXOR、CenterPoint等。还有基于点的分配策略,大部分都是先将前景点分割出来,在3D目标内或附近的作为正样本,并学习这些前景点。基于Range的分配主要是将Range像素在3D目标内的作为正样本,并且回归的时候不是以整个3D坐标系统为基础,而是以目标为中心的回归坐标系。DETR提出了一种集合到集合的分配方式,利用匈牙利算法预测结果自动分配到对应的GT。
anchor-free方法设计灵活,不引入其它先验,学习过程简化了很多,其中基于中心的方法[329(centorpoint)]对小目标检测有较大潜力可挖。虽然优点不少,但不可否认,anchor-free方法如何选择合适的正样本来生成预测结果是个问题,相比于anchor-based中使用高IoU正样本,anchor-free可能会选到一些不好的正样本,造成预测结果出现偏差。
下面显示了anchor-free方法和一些里程碑方法。
利用辅助任务来增强3D目标的空间特征,并能对3D目标检测提供一些隐性的指导。常用的辅助任务包括:语义分割、IoU分支预测、目标形状补全、部件识别。
语义分割。前景分割可以提供目标的位置隐含信息;利用语义上下文知识可以增强空间特征;语义分割可以作为预处理方法,过滤背景样本,提升3D检测效率。
IoU预测分支可以辅助校正目标的置信度,比如预测置信度可以用分类置信度和IoU值的乘积来表示。经过IoU分支的校正,更容易选择高质量的3D目标作为最终预测结果。
形状补全,因为点云具有稀疏性,远处的目标只能接收几个点,因此从稀疏点云中补全目标形状可以为后面的检测提供帮助。
识别目标内部的零部件有助于3D目标检测,部件可以揭示细粒度3D信息。
除此之外,还有一些比如场景流估计可以识别静态和动态目标,可以在点云序列中跟踪同一个3D目标,可以得到该目标更准确的估计。
主要的基于相机的3D目标检测方案分为:单目3D、双目、多相机3D等
本身从单目图像中检测3D空间的目标是一个病态问题,因为单目无法提供足够的3D信息,很难预测3D目标准确的位置信息。很多方法利用几何约束和形状先验从图像中推断深度信息,也是一种优化单目3D目标定位问题的思路。但是和激光雷达比,还是相差较远。
受到2D检测方法的启发,单目3D目标检测最直接的解决方案是通过卷积神经网络从图像中直接回归3D框参数。直接回归的方法借鉴了2D检测网络架构的设计,可以端到端训练。这些方法可以分为单阶段、两阶段,或anchor-based/anchor-free方法。
基于anchor的方法主要预先设置好3D-anchor、2D-anchor、深度anchor,然后图像经过卷积网络后得到2D和3D的预测偏置,最终解码及转换过程如下所示:
anchor-free的方法也是通过2D卷积对图像进行处理,利用多个头去预测3D目标。具体包括一个分类头、一个关键点头预测粗粒度中心点、一个预测基于粗粒度中心点的偏置的头、预测深度的头、预测目标尺寸的头以及预测观测角的头。
两阶段单目检测方法通常将传统的两阶段2D检测体系扩展到3D目标检测。具体来说,在第一阶段利用2D检测器从输入图像生成2D目标框。然后在第二阶段,通过从2D ROI中预测3D目标参数,将2D框提升到3D空间。ROI-10D[168]扩展了传统的Faster RCNN[222],在第二阶段用一种新颖的头来预测3D目标参数。
基于纯图像的方法可以直接使用2D目标检测的最新进展,而且价格便宜,可以端到端训练,效率也很高。只是从单张图像预测深度比较困难。
下图及表展示了相关方法:
深度估计是单目3D目标检测的关键。为了获得更准确的单目检测结果,许多论文采用预训练辅助深度估计网络的方法。具体来说,单目图像首先通过预训练的深度估计器,如MonoDepth[83]或DORN[76],生成深度图像。然后,主要有两类方法处理深度图像和单目图像。
基于深度图像的方法将图像和深度映射与专门的神经网络融合,生成深度感知特征,可以提高检测性能。
基于伪激光雷达的方法将深度图像转换为伪激光雷达点云,然后在点云上应用基于激光雷达的3D检测器来检测3D目标。
具体如下表及图所示。
许多方法利用图像中目标的形状和场景几何等先验知识,解决病态的单目3D目标检测问题。通过引入预训练的子网络或辅助任务来学习先验知识,这些子网络或辅助任务可以提供额外的信息或约束来帮助精确定位3D目标。广泛采用的先验知识包括目标形状、几何一致性、时间约束和分割信息。如下表所示。
通过重建目标形状,可以从图像中获得更详细的目标形状信息,有利于3D目标检测。但形状重建通常需要增加重建网络预训练模型,单目检测流程无法做到端到端训练。而且目标的形状通常是从CAD模型而不是现实世界的实例中学习的,重建的目标形状和真实场景有较大差异。
采用几何一致性,有助于提高检测精度。然而,一些方法将几何一致性表示为一个优化问题,在后处理中优化目标参数会比较耗时,阻碍了端到端训练。
图像分割是单目3D检测中的重要信息。然而,训练分割网络需要的标注样本比较贵。用外部数据集预训练的分割模型存在泛化问题。
基于双目的3D目标检测是指从一对图像中检测出3D物体。与单目图像相比,双目提供了额外的几何约束,可用于推断更准确的深度信息。基于双目方法通常比基于单目的方法获得更好的检测性能。当然,基于双目的方法与基于激光雷达的方法在性能上仍有很大的差距。
双目方法与单目检测方法相比,可以通过立体匹配技术获得更精确的深度和视差估计,从而带来更强的目标定位能力,显著提高了3D目标检测能力。具体方法见下图及表。
自动驾驶汽车通常会配备多个摄像头,从多个视角获取完整的周边环境信息。然而,如何利用多视图图像进行3D目标检测还没有得到广泛的研究。多摄像头3D目标测的一个关键问题是如何识别不同图像中的同一目标,并从多视角输入中聚合目标特征。
一些论文通过利用跨视图几何约束[227]或目标重识别[52]来解决多视图目标定位问题。其他工作通过引入3D目标查询从不同视图裁剪图像特征[286]或转换不同视图的特征来处理多视图特征聚合问题。
主要介绍LiDAR-相机、雷达、地图融合等方法。
相机可以提供颜色信息,从中提取丰富的语义特征,而LiDAR传感器擅长3D定位,提供丰富的3D结构信息。很多工作已经能够将相机和激光雷达信息进行融合来提升3D目标检测精度。由于基于LiDAR的检测方法比基于相机的检测方法性能要好得多,目前SOTA方法主要是基于激光雷达的检测方法,并尝试将图像信息融入到不同阶段的激光雷达检测流程中。鉴于基于LiDAR和基于相机的检测系统的复杂性,将两种模式结合在一起不可避免地会带来额外的计算开销和推断时间延迟。因此,如何有效地融合多模态信息仍然是具有挑战性的。
前融合指的是在点云还没有进入基于LiDAR的检测器前,将图像的知识整合到点云中。因此,前融合框架一般采用顺序构建的方式:首先利用2D检测或分割网络从图像中提取知识,然后将图像知识传递给点云,最后将增强后的点云反馈给基于LiDAR的点云3D目标检测器。根据融合类型的不同,前融合方法可分为区域级知识融合和点级知识融合两类,具体见下图。
前融合主要是通过图像知识来增强点云,大多数方法都兼容大部分的LiDAR 3D目标检测器,并可以作为一种相当有效的预处理步骤,以提高检测性能。然而,前融合方法通常是顺序进行多模态融合和3D目标检测的,这带来了额外的推理延迟。考虑到融合步骤通常需要复杂的2D目标检测或语义分割网络,多模态融合带来的时间成本通常很高。因此,如何在前期有效地进行多模态融合成为关键。
中融合方法试图在基于LiDAR的3D目标检测器的中间阶段,例如在骨干网络中,在proposal生成阶段,或在RoI细化阶段,融合图像和激光雷达特征。具体分类见下图。
中融合方法建议对多模态表示进行更深入的融合,并产生更高质量的3D框。然而,相机和激光雷达的特征本质上是异构的,来自不同的视角,因此在融合机制和视角对齐方面还存在一些问题。因此,如何有效地融合异构数据,以及如何处理来自多个视角的特征聚合,仍然是研究领域面临的挑战。
后融合就是将图像得到的2D结果和LiDAR得到的3D结果进行融合的方法。该方法采用相机与激光雷达并行进行目标检测,并将输出的2D和3D框进行融合,得到更精确的3D检测结果。CLOCs[194]引入了一个包含成对的2D-3D框的稀疏张量,并从这个稀疏张量学习最终的目标置信度。[195]改进了[194],引入了一种轻量级的3D检测器提示图像检测器。下图为后融合示意图。
后融合方法以实例级融合为核心,仅对不同模态的输出进行多模态融合,避免了中间特征或输入点云上复杂的交互。因此,这些方法比其他方法更有效。然而,由于不依赖于相机和激光雷达传感器的深度特征,这些方法无法整合不同模式的丰富语义信息,限制了这类方法的潜力。
在自动驾驶系统中,雷达不可缺少,相比LiDAR,在实际应用中主要有四点优势:便宜、不太容易受到极端天气影响、探测距离较大、提供额外的速度测量。然而,与产生密集点云的激光雷达相比,雷达只提供稀疏和有噪声的测量。主要的融合方式包括雷达-LiDAR融合、雷达-相机融合。
高精地图(HD maps)包含道路形状、道路标记、交通标志、障碍物等详细的道路信息。高精地图提供了丰富的周围环境语义信息,可以作为辅助3D目标检测的有力手段。如何将地图信息整合到3D目标检测器中呢?高精地图可以很容易地转换为鸟瞰视图,并与栅格化BEV点云或特征图融合。融合可以通过简单地将鸟瞰图上的栅格化点云和高精地图的通道连接起来进行[313],或者将LiDAR点云和高精地图分成单独的主干,融合两种模式的输出特征图[70]。还有其他地图类型,如可见性地图[100]等。
基于时序的3D目标检测主要分为三种:激光雷达序列检测,流输入检测,从视频中检测。
大多数方法专注于从单帧点云中检测,也有许多方法利用多帧点云来实现更准确的3D目标检测。它们通过各种时间建模工具融合多帧特征来解决时序检测问题,也有通过将多帧目标点合并到单一帧中来获得更完整的3D形状。时序3D目标检测在离线3D自动打标签流程中取得了巨大的成功,但在实时应用中,这些方法仍然存在延迟问题,合并多帧不可避免地会带来额外的时间和内存成本。具体方法见下图示意。
激光雷达点云本质上是一个流式数据源,其中激光雷达数据包在扫描中顺序记录。激光雷达传感器完整扫描360度,大约需要50-100毫秒,这意味着当点云产生时,已经不能精确的反应实时的场景信息了。而自动驾驶通常需要最少的反应时间来保证驾驶安全。利用流数据的方法通常在动态LiDAR数据中检测3D目标,而不用等完整扫描完成。与完整激光雷达扫描检测相比,基于流式的3D目标检测是一种更准确、低延迟的车辆感知解决方案。具体过程如下图所示。
自动驾驶应用中很容易获取视频数据。相比基于单图像的3D目标检测,基于视频的3D检测得益于序列图像间的时间关系。大量的研究工作集中在基于单幅图像的3D目标检测,研究视频中的3D目标检测问题的较少,主要也是通过跟踪和融合相同目标来进行3D目标的检测。
前面的一些3D目标检测方法主要默认都是全监督学习,并且是在某个特定的域内进行。实际情况则不可避免的遇到跨域和标注数据缺少的问题。针对这些问题,主要从这方面去优化:域自适应、弱监督学习、半监督学习和自监督学习。
在数据收集过程中,某些域空白现象是普遍存在的。不同传感器的设置和安装、不同的地理位置和不同的天气将导致完全不同的数据域。在大多数情况下, 在某一域内训练的3D目标检测器在其他域表现不佳。研究人员提出了许多技术来解决3D目标检测的域适配问题,例如利用源域和目标域的一致性,目标域的自训练等。然而,大多数方法只关注于解决一个特定的领域转移问题。设计一种能够普遍应用于3D目标检测中任何领域转移任务的域自适应方法将是一个有前途的研究方向。域自适应包括跨数据集的、跨天气的、跨传感器的、以及仿真到现实的域适应,具体参考下图及表。
现有的3D目标检测方法依赖大量人工标记的3D目标框,但这些3D框的标注相当昂贵。弱监督学习是解决这一问题的一个很有前途的方案,其中弱监督信号,如更容易标的2D标注,被用来训练3D目标检测模型。弱监督的3D目标检测在数据标注方面需要的人力较少,但弱监督方法与全监督方法之间仍存在不可忽视的性能差距。
弱监督3D目标检测方法利用弱监督,而不是完全的标注3D框数据训练3D目标检测器。弱监督包括图像2D框[291,199]、预训练图像检测器[218]、BEV目标中心和车辆实例[175, 176]。这些方法通常会设计新颖的学习机制来跳过3D框的监督,学习从弱信号中挖掘有用信息来实现3D目标检测。详见下图示意。
在现实应用中,数据标注比数据收集需要更多的人力。通常情况下,一辆数据采集车一天可以收集超过200k帧的点云,而熟练的人类每天只能标注100-200帧,大量未标注数据没有很好的利用。半监督学习利用少量标注数据和大量无标注数据,共同训练出更强的模型,这是一个很有前途的方向。将3D目标检测与半监督学习相结合可以提高检测性能。
半监督3D目标检测主要有两类方法:伪标签和教师-学生方法。伪标签方法[17,265]首先用有标签的数据训练一个3D目标检测器,然后用这个3D检测器对未标注域的数据打上伪标签。最后,用未标注域上的伪标签重新训练3D目标检测器。教师-学生方法[354]将Mean Teacher[255]范式应用于3D目标检测。首先在标注域上训练教师检测器,然后教师检测器通过约束两种检测模型输出的一致性来指导学生检测器在未标记域上的训练。具体示意见下图。
自监督预训练(Self-supervised pre-training)被广泛应用于许多计算机视觉任务中,首先以自监督的方式在大规模的无标注数据上对模型进行预训练,然后在有标注的数据集上进行微调,以获得更好的性能。在自动驾驶场景中,用于3D目标检测的自监督预训练还没有得到广泛的探索。已有的方法试图将对比学习等自监督方法应用于3D目标检测问题,但多模态数据中丰富的语义信息没有得到很好的利用。如何有效地处理原始点云和图像,以预训练出高性能3D目标检测器仍是一个挑战。自监督方法通常将对比学习技术[94,41]应用到3D目标检测。具体来说,首先通过数据增强将输入点云转化为两个视图,然后使用对比学习来约束两个点云视图中相同3D位置的特征一致性,最后将这个预训练模型在有标签数据集上进行微调,得到更好性能。下图为示意图。
3D目标检测是感知系统的关键组成部分,3D目标检测器的性能将对跟踪、预测和规划等下游任务产生深远影响。因此,从系统的角度来看,3D目标检测模型与其他感知任务以及下游任务联合训练,将是更好的自动驾驶解决方案。一个挑战是如何将所有驾驶任务包含在一个统一框架中,并以端到端的方式联合训练这些任务。
联合感知和预测。很多方法通过感知和跟踪3D目标,然后以端到端的方式预测它们的未来轨迹。FaF[160]是一项开创性工作,它提出使用单个3D卷积联合预测3D目标检测、跟踪和轨迹预测。这种设计范式被许多论文改进,例如[21]利用地图信息,[125]引入交互式 Transformer,[350]设计时空交互式网络,[298]提出时空金字塔网络,[138]循环执行所有任务,[204]涉及将定位任务引入系统。
联合感知、预测和规划。很多工作努力将感知、预测和规划纳入一个统一的框架。与联合感知和预测方法相比,整个系统可以通过将运动规划添加到端到端流程中,并从规划反馈信息中得到收益。很多方法提出来改善这个框架,例如[229]引入语义占用图以产生可解释的中间表示,[290]将空间注意力纳入框架,[341]提出深度结构化网络,[22]提出无地图方法,[53] 产生一组不同的未来轨迹。
一个完整的端到端自动驾驶系统应该是这样子的:自动驾驶车辆接受传感器输入,在一个循环中依次执行感知、预测、规划和运动控制,最终给驾驶系统提供转向和速度信号。[12]首先介绍了这个想法,并用卷积神经网络实现了基于图像的端到端驱动系统。[302]提出了一种具有多模式输入的端到端架构。[51]和[106]提出分别通过条件模仿学习和深度强化学习来学习端到端自动驾驶系统。具体的端到端的自动驾驶示意如下图所示。
3D目标检测模型通常需要大量数据进行训练。虽然可以在现实世界场景中收集数据,但现实世界的数据通常会受到长尾分布的影响。例如,交通事故或极端天气的场景很少被采集到,但对于训练强大的3D目标检测器非常重要。模拟仿真是解决长尾数据分布问题的一种很有前途的方案,因为我们可以为那些罕见但关键的场景创建人造数据。模拟的一个公开挑战是如何创建更真实的人造数据。
视觉模拟。很多方法在驾驶场景中生成逼真的合成图像。这些方法的想法包括利用图形引擎[1, 226]、利用纹理映射面元[320]、利用真实世界数据[47]和学习可控神经模拟器[108]。
激光雷达模拟。除了生成合成图像,许多方法试图通过模拟生成LiDAR点云。一些方法[69, 188, 71]通过模拟现实世界的效果提出了新颖的点云渲染机制。一些方法[169]利用真实世界的实例来重建3D场景。其他论文侧重于安全关键场景[267]或恶劣天气条件下[89]的模拟。
驾驶模拟。许多论文试图建立一个交互式驾驶模拟平台,虚拟车辆可以在其中感知虚拟环境并与虚拟环境交互,最终规划车辆路径。CARLA[61]是一个开创性的自动驾驶开源模拟器。其他论文利用图形引擎[232]或开发数据驱动方法[4]进行驾驶模拟。还有一些工作模拟交通流[253、252]或通过模拟测试车辆的安全性[296]。
基于学习的3D的目标检测方法容易受到攻击,比如给传感器输入中添加一些噪声或目标,就可能造成3D目标检测器失效,造成漏检,如何更好的防御攻击是个问题。
许多论文提出通过对抗性机器学习攻击传感器并欺骗目标检测器。这些方法针对不同的目标,例如LiDAR检测器[18, 294, 257, 248, 366],多模态检测器[19, 259],协作感知模型[258],车辆轨迹[130] 等。他们提出了不同的技术来欺骗检测器,包括在道路上添加对抗性障碍物[18]、在车辆上放置真实的样本[294]、在对抗性位置放置任意目标[366]、利用对抗性纹理网格[259]、放弃临界值[294],和利用被遮挡的点云模式[248]等。
现有的3D目标检测方法主要基于本车单车,但是只用单车会造成无法解决目标遮挡和远处目标的稀疏性问题。于是很多研究提出,利用多车协同方案。本车与其它车或基础设施进行通信,根据其它代理(车或基础设施)反馈的信息提高感知精度。协同感知的一个挑战是如何适当地平衡精度提高和通信带宽要求。协同3D目标检测方法融合来自多个代理的信息以提高3D目标检测器的性能。融合的信息可以是来自其他代理的原始输入[33, 345],其通信带宽消耗很小,并且对于检测非常有效,也可以是压缩的特征图 [32, 276, 260, 129],其通信带宽成本不可忽略,但检测效果通常会更好。还有一些论文研究何时与其他代理通信[150]以及与哪个代理通信[151]。
3D目标检测的评价指标从原来的2D的AP已经逐渐变为AP-3D和AP-BEV,更好的衡量3D检测效果。基于LiDAR的方法在数据集的选择上也从KITTI逐渐变为更大和更多样的nuScenes和WaymoOpen数据集。部署依然很难,因为很多方法为了提高性能,并没有太在乎推理时间,造成实时性较差。
目前来看,基于LiDAR的方法中,基于体素和点体素的方法性能有较大提升。基于柱体的方法运行快,效率高,但性能比基于体素的差。基于Range和BEV的方法不错,推理时间也可以接受。基于点的检测器效果好,但是推理速度受采样和处理算子的影响较大。
基于相机的3D目标检测方法中,双目比单目好,多相机的研究也是前景广泛。多模态比单模态效果好,但引入了额外的计算开销,前融合方法更严重。现在很多方法只用了前视图和对应点云进行融合,而在nuScenes上提供了多视图图像、点云和高精地图,模型可以得到更好的结果。
从系统级别来看,以速度和精度为主导因素,则基于LiDAR和多模态的方法是最佳解决方案;如果以成本为最重要因素,那么基于相机的方法可能是最佳选择。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。