Summary
自動駕駛汽車的感知系統(tǒng)一般由多種傳感器組成,如lidar、carmera、radar等等。除了特斯拉基于純視覺方案來進行感知之外,大多數研究還是利用多種傳感器融合來建立系統(tǒng),其中l(wèi)idar和camera的融合研究比較多。
CenterFusion這篇文章基于nuscenes數據集研究camera和radar的特征層融合,圖像部分采用的是CenterNet,radar點云部分采用了pillar expansion后通過roi frustum來與圖像檢測到的box進行匹配,radar特征提取與CenterNet類似,利用radar點云的vx、vy以及depth分別構建heatmap后與圖像特征進行拼接來完成融合。官方代碼倉庫鏈接
總體思路還是將雷達點云投射到圖像數據中,特征層進行通道拼接,再利用卷積網絡進行回歸。檢測分為兩個階段,Primary Regression Heads的結果除了輸出外,還用來進行點云數據和box的匹配;Secondary Regression Heads由于拼接了雷達特征,可以修正Primary Regression Heads的預測結果,同時給出額外的信息,目標速度和屬性等等。
主要解決了如下問題:
問題 | 方案 |
---|---|
毫米波雷達點云數據有很多雜波,和真實物體經常是一對多的關系,難以與圖像box進行匹配 | 利用3D視椎體來過濾和篩選點云,加快匹配速度,同時過濾無效的點云 |
一般的毫米波雷達點云數據沒有高度信息,很難準確與圖像中的box進行匹配 | Pillar Expansion, 將點擴充為3D pillar,增大匹配概率 |
毫米波雷達點云數據非常稀疏,以致于表征能力弱,在整個網絡中的權重較低 | 利用與之匹配的box來擴充雷達點云覆蓋范圍,由一個點轉變成一小塊矩形區(qū)域,提取點云heatmap作為點云特征 |

-
圖片特征提取及Primary Regression
修改了CenterNet的Head,利用全卷積backbone進行特征提取的時候,進行一個初步的回歸,得到目標的2D Box 和3D Box -
雷達點云和2D圖像目標匹配
-
3D 視椎體
利用Primary Regression Heads得到的每個3D Box的深度depth、觀測角alpha、3D框尺寸dim,再加上相機標定矩陣來生成3D視椎體(每個可能的Box都生成一個),類似Roi提取,加快匹配速度的同時,過濾無效的點云。觀測角和標定矩陣是為了計算yaw角
-
雷達點云Pillar Expansion
雷達點云沒有高度信息,將點云擴充為固定大小的3D柱子,增大點云匹配的概率(相對用點表示目標物,用柱子表示能夠增加在3D空間中的體積,進而增大匹配的概率) -
點云匹配
pillar投影到pixel坐標系與2D box進行匹配; pillar投影到相機坐標系與構造的3D視椎體進行深度值匹配
-
-
雷達點云特征提取
對于每一個與視椎體關聯(lián)到雷達目標,利用圖像中2D檢測框的位置生成三張heatmap,三張heatmap concat到圖片的特征中作為額外通道,進而完成融合 -
利用融合特征進行Secondary Regression
除了估計目標速度之外,還重新估計了目標的深度和角度(結合了雷達特征,估計更精確) -
3D Box Decoder
綜合Primary和Secondary Regression Heads的輸出,還原出3D目標檢測結果(位置、大小、姿態(tài)、速度,以及類別等屬性),其中dep和rot在兩個heads里都有,則只利用準確度更高的second regression heads
背景知識
如果沒有了解過相關內容,可以按下順序來看,CenterFusion里的大部分代碼都是來自于CornerNet和CenterNet
- 3D目標檢測基礎知識
- CornerNet:目標檢測算法新思路
- 扔掉anchor!真正的CenterNet——Objects as Points論文解讀
- CenterTrack深度解析
重點內容
Backbone結構
Backbone沿用了CenterNet的DLA-34作為全卷積骨干網絡, 并將可變形卷積DeformConv引入。關于網絡結構內容可參考CenterFusion(基于CenterNet)源碼深度解讀: :DLA34
全卷積骨干網絡以圖像
I
∈
R
W
×
H
×
3
I \in R^{W \times H \times 3}
I∈RW×H×3作為輸入,生成key points heatmap:
Y
^
∈
[
0
,
1
]
W
R
×
H
R
×
C
\hat{Y} \in[0,1]^{\frac{W}{R} \times \frac{H}{R} \times C}
Y^∈[0,1]RW?×RH?×C,其中 W 和 H是圖像的寬度和高度,R是下采樣比,C 是物體類別的數量。heatmap中的每一個像素的取值在[0,1]之間。再通過回歸圖像特征的方法來實現(xiàn)對圖像上目標中心點的預測,以及對目標的 2D 大?。▽挾群透叨龋?、中心偏移量、3D 尺寸、深度和旋轉等信息的提取。以上均繼承于CenterNet。
訓練數據的圖像尺寸為 3 × 900 × 1600 3\times900\times1600 3×900×1600,下采樣比為2,為了下采樣不產生余數,入模圖像的尺寸為 3 × 448 × 800 3\times448\times800 3×448×800。
雷達點云和2D圖像目標匹配
基于視錐的匹配

-
3D視椎體縮小了匹配范圍,進而加快匹配速度
-
相比于直接將雷達點云投射到2D圖像,3D視錐能夠區(qū)分2D圖像中重疊或被遮擋的目標
-
使用參數 δ \delta δ來調節(jié) ROI 視椎體的大小,這是為了解決估計的深度值的不準確性,因為ROI視椎匹配時,使用的深度值 d ^ \hatn5n3t3z d^是通過圖像特征估計出來的。調節(jié)視椎體大小的目的是為了盡可能的給每一個box找到至少一個雷達點云來匹配,即使匹配到多個點云,后面直接取深度最小的點云來完成box內的點云去重。如下為BEV視角示意圖
只在infer階段用參數δ,實際調節(jié)的是視椎體的深度范圍, 增加此參數的目的更多是降低漏檢率。
代碼中用
frustumExpansionRatio
來表示調節(jié)參數,根據視錐體的深度范圍計算得到一個dist_thresh,
其中 δ = d i s t _ t h r e s h ? f r u s t u m E x p a n s i o n R a t i o n \delta = dist\_thresh * frustumExpansionRation δ=dist_thresh?frustumExpansionRation, d ^ \hatn5n3t3z d^是primary head輸出的3D box depth或GT depth。 圖中綠色虛線是經過調節(jié)的視錐體深度值范圍,深度值在此范圍內的雷達點云,與這個對應的box匹配。其中roi frustum和dist_thresh構造程序如下:# 對每一個3D box,計算roi frustum的8個角點, roi frustum為3D box的包圍盒, # 且roi frustum在pixel坐標系下的投影為2D box def comput_corners_3d(dim, rotation_y): # dim: 3 # location: 3 # rotation_y: 1 # return: 8 x 3 c, s = torch.cos(rotation_y), torch.sin(rotation_y) # dim是相機坐標系下的長寬高,下面計算的也是相機坐標系下的3D box的8個角點 # 自動駕駛車輛在地面上行駛,一般只考慮偏航角,利用rotation_y構造旋轉矩陣 # 航向角為繞y軸旋轉,所以旋轉矩陣為 R = torch.tensor([[c, 0, s], [0, 1, 0], [-s, 0, c]], dtype=torch.float32) l, w, h = dim[2], dim[1], dim[0] x_corners = [l/2, l/2, -l/2, -l/2, l/2, l/2, -l/2, -l/2] y_corners = [0, 0, 0, 0, -h, -h, -h, -h] z_corners = [w/2, -w/2, -w/2, w/2, w/2, -w/2, -w/2, w/2] corners = torch.tensor( [x_corners, y_corners, z_corners], dtype=torch.float32) # 相機坐標下的3D box的8個角點左乘旋轉矩陣,得到roi frustum的8個角點, # 對應的roi frustum在pixel坐標系下的投影,剛好為2D box corners_3d = torch.mm(R, corners).transpose(1, 0) return corners_3d def get_dist_thresh(calib, ct, dim, alpha): rotation_y = alpha2rot_y(alpha, ct[0], calib[0, 2], calib[0, 0]) corners_3d = comput_corners_3d(dim, rotation_y) dist_thresh = max(corners_3d[:, 2]) - min(corners_3d[:, 2]) / 2.0 return dist_thresh
雷達點云目標和圖像2D目標一般是多對一的關系,如果視錐體內有多個雷達點云,則只保留深度最?。ň嚯x最近)的點云,消除冗余的雷達點云數據。匹配結果如下:
-
top image: 將雷達點云擴充為3D Pillar后投影到pixel坐標系
-
middle image: 根據點云的深度直接將3D Pillar 投射到2D圖像。點云去重前
-
bottom image: 視錐匹配后,同時對雷達點云進行特征提取,將點云heatmap并投射到2D圖像。點云去重后

視錐的使用并不是先例, TLNet和Frustum PointNet等anchor based方法均利用了視錐來過濾anchor,因為稠密的anchor帶來巨大的計算量,2D檢測結果形成的3D視錐可以過濾掉大量背景上的anchor。
![]() |
![]() |
---|---|
TLNet | Frustum PointNet |
雷達點云特征提取
因為圖像是經過CenterNet轉換成了heatmap,同時對雷達點云和圖像中的BOX進行了一對一的匹配,為了將圖像數據和雷達點云數據更好的融合,論文將雷達點云特征轉換為heatmap,進而在通道上拼接(concat)來完成融合。
具體為,將點云數據的深度、速度x分量,速度y分量作為三個通道。對每一個與雷達點云匹配的2D Box,在2D Box內部分別以三個通道值填充一個Box(暫稱為次級Box),次級Box的中心與原始2D Box的中心重合,大小與原始Box成比例, 比例通過 α \alpha α參數控制
注: 雷達測量的速度是徑向速度
F x , y , i j = 1 M i { f i ∣ x ? c x j ∣ ≤ α w j ?and? ∣ y ? c y i ∣ ≤ α h j 0 ?otherwise? , F_{x, y, i}^{j}=\frac{1}{M_{i}}\left\{\begin{array}{ll} f_{i} & \left|x-c_{x}^{j}\right| \leq \alpha w^{j} \quad \text { and } \\ & \left|y-c_{y}^{i}\right| \leq \alpha h^{j} \\ 0 & \text { otherwise } \end{array},\right. Fx,y,ij?=Mi?1?? ? ??fi?0? ?x?cxj? ?≤αwj?and? ?y?cyi? ?≤αhj?otherwise??,
三個通道分別為 ( d , v x v y ) \left(d, v_{x}\right. \left.v_{y}\right) (d,vx?vy?),其中i是雷達的特征圖通道,且 i ∈ 1 , 2 , 3 i\in 1,2,3 i∈1,2,3, M i M_{i} Mi?是每個通道的歸一化因子, c x j , c y j c_{x}^{j}, c_{y}^{j} cxj?,cyj?是與之匹配的第 j j j個2D box的中心坐標, w j , h j w^{j}, h^{j} wj,hj是第 j j j個2D box的寬和高, α \alpha α是一個超參數,用于控制次級Box的大小。
點云heatmap的分布與CenterNet有些差異,CenterNet的heatmap是以中心點的取值生成的高斯分布,而點云heatmap是以2D box中心點生成一個成比例大小的Box,Box內取值相同,Box外取值為0。
3D Box Decoder
利用Primary Head和Secondary Head的預測結果,對3D Box進行解碼,得到3D Box的
- 中心點3D坐標、長寬高、航向角
- 中心點2D坐標
- 目標類別、速度等
通過目標的尺寸信息,可計算出3D Box角點關于目標中心的相對坐標。進而通過中心點坐標和航向信息計算出3D框體角點的全局坐標,最終返回全局坐標
其他
目標角度in-bin regression
做過機器學習的都知道,有一個重要的步驟叫做特征工程,某個變量難以直接擬合或擬合效果不好時,需要進行一些encoding。因為直接回歸角度標量有點困難,可以先大致判斷位于哪個角度區(qū)間,然后在區(qū)間內進行offset回歸
論文中不直接回歸觀測角 α \alpha α,而是將 α \alpha α取值范圍編碼為兩個bins: [ ? 7 p i 6 , p i 6 ] , [ ? p i 6 , 7 p i 6 ] [\frac{-7pi}{6}, \frac{pi}{6}], [\frac{-pi}{6}, \frac{7pi}{6}] [6?7pi?,6pi?],[6?pi?,67pi?]。每個bin包含4個標量,維度合計為8。對于一個bin,兩個值用作softmax分類,其余兩個值對每個bin中的角度中值的offset進行回歸。這里其實是沿用了CenterNet的角度回歸方式。代碼如下:
def _add_rot(self, ret, ann, k, gt_det):
if 'alpha' in ann:
ret['rot_mask'][k] = 1
alpha = ann['alpha']
if alpha < np.pi / 6. or alpha > 5 * np.pi / 6.:
ret['rotbin'][k, 0] = 1
ret['rotres'][k, 0] = alpha - (-0.5 * np.pi)
if alpha > -np.pi / 6. or alpha < -5 * np.pi / 6.:
ret['rotbin'][k, 1] = 1
ret['rotres'][k, 1] = alpha - (0.5 * np.pi)
gt_det['rot'].append(self._alpha_to_8(ann['alpha']))
else:
gt_det['rot'].append(self._alpha_to_8(0))
def _alpha_to_8(self, alpha):
ret = [0, 0, 0, 1, 0, 0, 0, 1]
if alpha < np.pi / 6. or alpha > 5 * np.pi / 6.:
r = alpha - (-0.5 * np.pi)
ret[1] = 1
ret[2], ret[3] = np.sin(r), np.cos(r)
if alpha > -np.pi / 6. or alpha < -5 * np.pi / 6.:
r = alpha - (0.5 * np.pi)
ret[5] = 1
ret[6], ret[7] = np.sin(r), np.cos(r)
return ret
CenterNet論文的附錄給出了詳細公式,,Loss分為兩部分:前半部分用softmax分類,判斷角度位于哪個bin,損失函數為cross entropy ;后半部回歸角度關于對應bin中心取值(就是角度平均值)的offset,對offset取正弦或余弦值作為角度殘差,并計算與角度殘差GT的L1 loss
L
ori?
=
1
N
∑
k
=
1
N
∑
i
=
1
2
(
softmax
?
(
b
^
i
,
c
i
)
+
c
i
∣
a
^
i
?
a
i
∣
)
L_{\text {ori }}=\frac{1}{N} \sum_{k=1}^{N} \sum_{i=1}^{2}\left(\operatorname{softmax}\left(\hat_{i}, c_{i}\right)+c_{i}\left|\hat{a}_{i}-a_{i}\right|\right)
Lori??=N1?k=1∑N?i=1∑2?(softmax(b^i?,ci?)+ci?∣a^i??ai?∣)
其中
c
i
=
1
(
θ
∈
B
i
)
,
a
i
=
(
sin
?
(
θ
?
m
i
)
,
cos
?
(
θ
?
m
i
)
)
c_{i}=\mathbb{1}\left(\theta \in B_{i}\right), a_{i}=\left(\sin \left(\theta-m_{i}\right), \cos \left(\theta-m_{i}\right)\right)
ci?=1(θ∈Bi?),ai?=(sin(θ?mi?),cos(θ?mi?)),
b
^
i
\hat_{i}
b^i?是網絡估計值, 表示該角度屬于第幾個bin,
m
i
m_{i}
mi?為第i個bin的中心取值。
觀測角的估計可以通過下面的公式得到,
j
j
j是classfication score較大的那個bin的index。即通過角度所屬bin的中值,加上一個三角函數offset,得到觀測角度。
θ
^
=
arctan
?
2
(
a
^
j
1
,
a
^
j
2
)
+
m
j
\hat{\theta}=\arctan 2\left(\hat{a}_{j 1}, \hat{a}_{j 2}\right)+m_{j}
θ^=arctan2(a^j1?,a^j2?)+mj?
代碼中將角度八元組表示為rot, 后處理時會轉換成觀測角alpha和航向角yaw(又稱rotaition_y,因為相機坐標系的重力軸為y軸,航向角為繞重力軸旋轉時,與參考方向的夾角)
def get_alpha(rot):
# rot: (B, 8) [bin1_cls[0], bin1_cls[1], bin1_sin, bin1_cos,
# bin2_cls[0], bin2_cls[1], bin2_sin, bin2_cos]
# return alpha[B, 0]
idx = rot[:, 1] > rot[:, 5]
alpha1 = torch.atan2(rot[:, 2], rot[:, 3]) + (-0.5 * 3.14159)
alpha2 = torch.atan2(rot[:, 6], rot[:, 7]) + (0.5 * 3.14159)
# return alpha1 * idx + alpha2 * (~idx)
alpha = alpha1 * idx.float() + alpha2 * (~idx).float()
return alpha
def alpha2rot_y(alpha, x, cx, fx):
"""
Get rotation_y by alpha + theta - 180
alpha : Observation angle of object, ranging [-pi..pi]
x : Object center x to the camera center (x-W/2), in pixels
rotation_y : Rotation ry around Y-axis in camera coordinates [-pi..pi]
"""
rot_y = alpha + np.arctan2(x - cx, fx)
if rot_y > np.pi:
rot_y -= 2 * np.pi
if rot_y < -np.pi:
rot_y += 2 * np.pi
return rot_y
為什么這樣進行角度估計
網絡擬合的是觀測角alpha的相關編碼,最后還是要通過相機內參轉換為航向角,那么為什么不直接擬合航向角呢?
因為航向角是相對于世界坐標系的,而觀測角是相對于相機坐標系的。所以網絡擬合的是觀測角,但是最終輸出的是航向角。除了這個原因之外,Bounding box estimation using deep learning and geometry. In CVPR, 2017
的4.1章指出:僅通過目標的圖像估計其全局偏航角是不可能的,并提出了MultiBin Orientation Estimation
,CenterNet系列論文均參考了此類方法。
由下圖可以看出,目標的偏航角保持固定的情況下,隨著位移的改變,其局部圖像上看似乎發(fā)生了旋轉,導致相對角度發(fā)生了變化。"看上去"就像汽車在旋轉一樣。這種特性對于CNN而言極其不利,因為如果采用全局偏航角作為ground truth,CNN需要將看上去轉角不同的圖像映射到同一個答案上,即多對一情況,這完全無法訓練出準確的結果。
![]() |
![]() |
---|
因此論文采用局部相對角(目標朝向相對相機射線)來作為GT,即通過估計圖中的 θ l \theta_{l} θl?,再通過幾何關系間接得到全局偏航角,圖中為 θ \theta θ。針對 θ l \theta_{l} θl?,采用了MultiBin Orientation Estimation方法,將角度劃分為幾個區(qū)間,預測落在哪個區(qū)間,以及相對區(qū)間的offset。CenterNet系列文章擬合是觀測角 α \alpha α的編碼, α \alpha α與這里的 θ l \theta_{l} θl?存在幾何關系
目標深度估計
利用單目攝像頭直接回歸中心點的深度信息非常困難,CenterNet系列的論文均參考了Depth Map Prediction from a Single Image using a Multi-Scale Deep Network
這一里程碑式的工作, 對網絡輸出的深度標量進行inverse sigmoidal transformation
, 用一個單獨的head, 基于L1 Loss對變換后的深度進行回歸。 對網絡估計的深度進行如下轉換后再計算depth loss
d
=
1
/
σ
(
d
^
)
?
1
d=1 / \sigma(\hatn5n3t3z)-1
d=1/σ(d^)?1
其中
d
^
\hatn5n3t3z
d^是網絡估計的深度值,
σ
\sigma
σ是sigmoid函數,
d
d
d是經過轉換的深度值,單位為米。
深度估計的loss定義為:
L
d
e
p
=
1
N
∑
k
=
1
N
∣
1
σ
(
d
^
k
)
?
1
?
d
k
∣
L_{d e p}=\frac{1}{N} \sum_{k=1}^{N}\left|\frac{1}{\sigma\left(\hatn5n3t3z_{k}\right)}-1-d_{k}\right|
Ldep?=N1?k=1∑N?
?σ(d^k?)1??1?dk?
?
其中
d
k
d_{k}
dk?是第k個目標的深度值GT
多模態(tài)數據時間對齊
nuscenes數據集的坐標系及關系如下圖所示

nuscenes數據集已經通過標定數據將radar點云和攝像圖片進行時間對齊,即將radar點云數據投影到全局坐標系下,經過全局坐標系再投影到另一個傳感器下達到時間對齊。借助于全局坐標系(絕對坐標系)進行運動補償,從而完成了不同傳感器之間的時間對齊。 實際工作中需要自己完成這一重要步驟。如有必要,還需要進行點radar云數據疊加,增加radar點云的稠密度

- radar外參: radar坐標系到ego(車身)坐標系的復合變換矩陣,
- camera外參: camera坐標系到ego坐標系的復合變換矩陣
- ego_pose: ego坐標系到全局坐標系的復合變換矩陣
最后的通過矩陣乘法將點云投影到當前幀的坐標系下,從而完成時間對齊
# Fuse four transformation matrices into one and perform transform.
trans_matrix = reduce(np.dot, [ref_from_car, car_from_global, global_from_car, car_from_current])
velocity_trans_matrix = reduce(np.dot, [ref_from_car_rot, car_from_global_rot, global_from_car_rot, car_from_current_rot])
current_pc.transform(trans_matrix)
關于多傳感器數據對齊,可以參考我寫的這篇文章:多傳感器時間同步
毫米波雷達點云的問題
-
置信度閾值文章來源:http://www.zghlxwxcb.cn/news/detail-494591.html
-
點云深度信息和目標中心深度不同
FMCW雷達發(fā)射的毫米波遇到物體表面就進行反射,所以測的徑向距離都是物體表面或反射面到雷達的距離,而視覺算法一般估計的深度信息是物體中心離攝像頭的距離,所以利用camera radar融合時,估計的深度和真實的車輛中心位置存在些許誤差文章來源地址http://www.zghlxwxcb.cn/news/detail-494591.html
REFERENCE
- CenterFusion
- CenterFusion(基于CenterNet)源碼深度解讀: :DLA34
- CenterNet目標檢測模型及CenterFusion融合目標檢測模型
- CenterFusion 項目網絡架構詳細論述
- Deep3DBox論文詳解
- 論文閱讀筆記 之 3D Bounding Box Estimation Using Deep Learning and Geometry
- Depth Map Prediction from a Single Image using a Multi-Scale Deep Network
- 多傳感器時間同步
到了這里,關于深入淺出CenterFusion的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!