視覺SLAM基礎:演算法精度評價指標KITTI odometry evaluation tool篇
上篇文章介紹了TUM RGB-D資料集主張使用的SLAM精度指標,這篇文章來補充一下KITTI資料集提供評價工具KITTI_odometry_evaluation_tool所使用的指標含義,假設你已經看過了上篇文章並瞭解了相對位姿誤差RPE的含義,KITTI使用的metric(以下簡稱kitti metric)將會非常容易理解。
計算公式
首先kitti metric是一種針對室外自動駕駛里程計精度的評價指標,因為它屬於相對位姿誤差的一種,與On Measuring the Accuracy of SLAM Algorithms一文中提出的計算相隔固定距離兩幀的相對位姿誤差有兩點不同,第一,KITTI metric將translation error和rotation error分別計算;第二,選擇了[100, 200, 。。。, 800]米八種距離間隔計算相對位姿誤差,取其平均值。
和
表示相隔固定距離兩幀的下標,
表示這個固定距離,在程式碼中設定為[100, 200, 。。。, 800](m),
、
分別表示取
的旋轉和平移量。
表示計算兩幀之間的相對位姿變換,
即表示從第
幀到第
幀的位姿變換。
與
分別表示位姿的估計值與真實值。 我們可以看到kitti metric獨特的一點是它將軌跡的長度納入了metric中,這使得最終的誤差結果有了比較清楚的物理意義。
關鍵程式碼
def
rotationError
(
self
,
pose_error
):
a
=
pose_error
[
0
,
0
]
b
=
pose_error
[
1
,
1
]
c
=
pose_error
[
2
,
2
]
d
=
0。5
*
(
a
+
b
+
c
-
1。0
)
return
np
。
arccos
(
max
(
min
(
d
,
1。0
),
-
1。0
))
def
translationError
(
self
,
pose_error
):
dx
=
pose_error
[
0
,
3
]
dy
=
pose_error
[
1
,
3
]
dz
=
pose_error
[
2
,
3
]
return
np
。
sqrt
(
dx
**
2
+
dy
**
2
+
dz
**
2
)
# 遍歷全部固定距離兩端位姿對應的的相對位姿誤差,計算它們的誤差。
def
calcSequenceErrors
(
self
,
poses_gt
,
poses_result
):
err
=
[]
self
。
max_speed
=
0
# pre-compute distances (from ground truth as reference)
dist
=
self
。
trajectoryDistances
(
poses_gt
)
# every second, kitti data 10Hz
self
。
step_size
=
10
# for all start positions do
# for first_frame in range(9, len(poses_gt), self。step_size):
for
first_frame
in
range
(
0
,
len
(
poses_gt
),
self
。
step_size
):
# for all segment lengths do
for
i
in
range
(
self
。
num_lengths
):
# current length
len_
=
self
。
lengths
[
i
]
# compute last frame of the segment
last_frame
=
self
。
lastFrameFromSegmentLength
(
dist
,
first_frame
,
len_
)
# Continue if sequence not long enough
if
last_frame
==
-
1
or
not
(
last_frame
in
poses_result
。
keys
())
or
not
(
first_frame
in
poses_result
。
keys
()):
continue
# compute rotational and translational errors, relative pose error (RPE)
pose_delta_gt
=
np
。
dot
(
np
。
linalg
。
inv
(
poses_gt
[
first_frame
]),
poses_gt
[
last_frame
])
pose_delta_result
=
np
。
dot
(
np
。
linalg
。
inv
(
poses_result
[
first_frame
]),
poses_result
[
last_frame
])
pose_error
=
np
。
dot
(
np
。
linalg
。
inv
(
pose_delta_result
),
pose_delta_gt
)
r_err
=
self
。
rotationError
(
pose_error
)
t_err
=
self
。
translationError
(
pose_error
)
# compute speed
num_frames
=
last_frame
-
first_frame
+
1。0
speed
=
len_
/
(
0。1
*
num_frames
)
# 10Hz
if
speed
>
self
。
max_speed
:
self
。
max_speed
=
speed
err
。
append
([
first_frame
,
r_err
/
len_
,
t_err
/
len_
,
len_
,
speed
])
return
err
# 計算全部相對位姿誤差的平均值
def
computeOverallErr
(
self
,
seq_err
):
t_err
=
0
r_err
=
0
seq_len
=
len
(
seq_err
)
for
item
in
seq_err
:
r_err
+=
item
[
1
]
t_err
+=
item
[
2
]
ave_t_err
=
t_err
/
seq_len
ave_r_err
=
r_err
/
seq_len
return
ave_t_err
,
ave_r_err
輸出含義
最終輸出結果的時候用了這兩行程式碼,ave_t_err本來的單位為m/m,乘100m後其含義為
平均100m會發生多少偏差
,如果等於1則表示每100m軌跡會產生1m的誤差。
需要注意的是程式碼打印出的RMSE這個表述應該是不對的
,誤差的統計量是平均值才對;對於ave_r_err,其含義
為每米產生的旋轉誤差
。
print (“Average sequence translational RMSE (%): {0:。4f}”。format(ave_t_err * 100))
print (“Average sequence rotational error (deg/m): {0:。4f}\n”。format(ave_r_err/np。pi * 180))