04. 使用预训练的 Monodepth2 Pose 模型对图像序列测试 PoseNet

这是一个使用 GluonCV Monodepth2 模型(用于 KITTI)在真实世界图像上进行快速演示。如果您尚未安装 MXNet 和 GluonCV,请遵循安装指南进行安装。本教程分为三个部分:准备 KITTI Odometry 数据集,通过 GluonCV 获取预训练的 PoseNet,以及在数据集上测试 PoseNet。

立即开始测试

提示

您可以随时跳过本教程,因为测试脚本是完整的并且可以直接运行。

下载 完整的 Python 脚本: test_pose.py

PoseNet 测试命令示例

python test_pose.py --model_zoo_pose monodepth2_resnet18_posenet_kitti_mono_stereo_640x192 --data_path ~/.mxnet/datasets/kitti/kitti_odom --eval_split odom_9 --pretrained_type gluoncv --png

更多训练命令选项,请运行 python test_pose.py -h 请查看 模型库 获取复现预训练模型的训练命令。

深入探讨

import os
import mxnet as mx
from mxnet import gluon
import gluoncv
# using cpu
ctx = mx.cpu(0)

KITTI Odometry 数据集

KITTI 数据集在 gluoncv.data 中提供。例如,我们可以轻松获取 KITTI Odometry 数据集(我们假设您已按照深入探讨训练 Monodepth2 模型中描述的方式准备了分割文件)。

from gluoncv.data.kitti import readlines, dict_batchify_fn

splits_dir = os.path.join(os.path.expanduser("~"), ".mxnet/datasets/kitti", "splits")

eval_split = "odom_9"

sequence_id = int(eval_split.split("_")[1])

data_path = os.path.join(
    os.path.expanduser("~"), '.mxnet/datasets/kitti/kitti_odom')
filenames = readlines(
    os.path.join(splits_dir, "odom",
                 "test_files_{:02d}.txt".format(sequence_id)))

dataset = gluoncv.data.KITTIOdomDataset(
    data_path=data_path, filenames=filenames, height=192, width=640, frame_idxs=[0, 1],
    num_scales=4, is_train=False, img_ext=".png")
dataloader = gluon.data.DataLoader(
    dataset, batch_size=1, shuffle=False, batchify_fn=dict_batchify_fn, num_workers=0,
    pin_memory=True, last_batch='keep')

这里,frame_idxs 参数是 [0, 1]。这意味着数据加载器提供当前帧和下一帧作为输入。PoseNet 需要预测两帧之间的相对姿态。

请查看完整的 test_pose.py 获取完整的实现。

预训练的 PoseNet

接下来,我们从我们的模型库获取一个预训练模型,

from gluoncv.model_zoo import get_model

model_zoo = 'monodepth2_resnet18_posenet_kitti_mono_stereo_640x192'

posenet = get_model(model_zoo, pretrained_base=False, num_input_images=2,
                    num_input_features=1, num_frames_to_predict_for=2, pretrained=True, ctx=ctx)

输出

Downloading /root/.mxnet/models/monodepth2_resnet18_posenet_kitti_mono_stereo_640x192-c14979bb.zip from https://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/gluon/models/monodepth2_resnet18_posenet_kitti_mono_stereo_640x192-c14979bb.zip...

  0%|          | 0/56016 [00:00<?, ?KB/s]
  0%|          | 102/56016 [00:00<01:10, 798.02KB/s]
  1%|          | 510/56016 [00:00<00:25, 2203.01KB/s]
  4%|3         | 2185/56016 [00:00<00:07, 7166.04KB/s]
 14%|#4        | 7870/56016 [00:00<00:02, 23928.26KB/s]
 26%|##5       | 14466/56016 [00:00<00:01, 37597.52KB/s]
 41%|####      | 22754/56016 [00:00<00:00, 51959.05KB/s]
 53%|#####3    | 29877/56016 [00:00<00:00, 57967.43KB/s]
 68%|######8   | 38270/56016 [00:00<00:00, 65967.08KB/s]
 81%|########1 | 45426/56016 [00:00<00:00, 67674.96KB/s]
 95%|#########5| 53368/56016 [00:01<00:00, 69627.11KB/s]
56017KB [00:01, 49968.80KB/s]

测试

  • PoseNet 的推理

    首先,我们需要通过 PoseNet 生成两帧之间的变换。PoseNet 将直接输出轴角(axisangle)和位移(translation),我们将其转换为变换矩阵。然后,我们将预测的姿态存储到姿态序列中。

请查看完整的 test_pose.py 获取完整的实现。这是一个测试示例

pred_poses = []
print("-> Computing pose predictions")

opt.frame_ids = [0, 1]  # pose network only takes two frames as input
tbar = tqdm(dataloader)
for i, data in enumerate(tbar):
    for key, ipt in data.items():
        data[key] = ipt.as_in_context(context=opt.ctx[0])

    all_color_aug = mx.nd.concat(*[data[("color_aug", i, 0)] for i in opt.frame_ids], dim=1)
    axisangle, translation = posenet(all_color_aug)

    pred_poses.append(
        transformation_from_parameters(
            axisangle[:, 0], translation[:, 0]).as_in_context(mx.cpu()).asnumpy()
    )

pred_poses = np.concatenate(pred_poses)
  • 计算 ATE

    这里,我们使用绝对轨迹误差(ATE)来评估 PoseNet 的性能。由于 PoseNet 也属于单目系统,它存在尺度模糊问题。为了使用地面实况(ground truth)姿态评估模型,我们将第一个姿态与地面实况对齐,并通过比较预测姿态和地面实况姿态来计算比例因子。

ATE 函数定义为

def compute_ate(gtruth_xyz, pred_xyz_o):
    offset = gtruth_xyz[0] - pred_xyz_o[0]
    pred_xyz = pred_xyz_o + offset[None, :]

    # Optimize the scaling factor
    scale = np.sum(gtruth_xyz * pred_xyz) / np.sum(pred_xyz ** 2)
    alignment_error = pred_xyz * scale - gtruth_xyz
    rmse = np.sqrt(np.sum(alignment_error ** 2)) / gtruth_xyz.shape[0]
    return rmse

您可以立即开始测试

参考文献

Godard19

Clement Godard, Oisin Mac Aodha, Michael Firman 和 Gabriel Brostow。“深入探讨自监督单目深度估计”(Digging Into Self-Supervised Monocular Depth Estimation)。IEEE 计算机视觉会议(ICCV)论文集。2019年。

脚本总运行时间: ( 0 分钟 1.850 秒)

由 Sphinx-Gallery 生成的图库