📷

MonoDepth2でKITTI Datasetを単眼Depth推定してみる

6 min read

はじめに

単眼Depth推定とは

ステレオカメラでは左右カメラ視差により深度推定しているのに対し、
単眼Depth推定では、あるフレームと、その前後時間で撮影したフレームとの視差で深度推定を行う

モデルの概要

目的

自己教師あり学習によるアプローチで、単眼深度推定を行う

コアとなるアイディア

  • 単眼Depth推定を教師なし学習によって行う
  • Depth CNNとPose CNNの二つのネットワークで構成される
  • Depth CNNはターゲット画像(It)から深度マップを生成する
  • Pose CNNはターゲット画像付近の時間軸画像(It-1, It+1)から対応点(P)の動きを推定
  • DepthとPoseの結果から合成画像を生成し、ターゲット画像と比較を行い損失計算する

SfMLearner

教師なしによる単眼Depth推定の先駆け的モデル

ネットワーク

  • Depth network
    • スキップ接続を用いたencoder-decoder構造
    • 深度スケールの調整を行う
  • Pose network
    • ターゲット画像とソース画像を入力。出力はターゲットとソースの相対的な姿勢
    • 各層で畳み込み後、global average poolingにより全空間位置の予測値を集約
    • Explainability Maskという試みにより動く物体については損失計算しない

損失関数

  • ターゲット画像と合成画像の比較による損失
    • 合成画像とターゲット画像とで全ピクセルの絶対誤差を最小化
  • 深度マップのsmoothness-loss
    • 深度マップのグラデーションを滑らかにするため、予測された深度マップの2次勾配のL1ノルムを最小化

問題点や課題

  • オクルージョンの推定に難あり(下画像の4,5行目)
  • 深度マップにスケール不定性が残っている

MonoDepth2

SfMLearner以降に改良されたモデル

ネットワーク

  • SfMLearnerと同様にU-Net構造のDepthとPoseネットワークを持つ

改良点

  • SfMLearnerで課題となっていたオクルージョンへの対応
    • ターゲット画像と近い時間の画像(ソース画像)からいくつかの合成画像を生成し、それら合成画像から損失が最も小さいソース画像が選択されるようにする
  • フレーム間で変化の無い物や並進している物体など、深度が無限大となる領域に対し損失の対象としないようマスクする
  • 低解像度部分の深度マップにおける低テクスチャ領域が無限大として推定されてしまう問題への対応
    • 低解像度の深度マップの解像度をアップサンプリングし、誤差計算を行う

問題点や課題

  • 歪み、反射、色が飽和している領域に対して深度推定できないことがある(下画像)
  • 深度マップにスケール不定性が残っている

動かしてみる

今回は学習済みMonodepth2を使って、kitti datasetの単眼depth推定を行います。
そのため、スクラッチで学習は行いません。

データセット準備

KITTI Datasetからテスト用のraw dataを取得
今回は、お試しとしてCityの2011_09_26から始まる以下のファイルを取得する

  • Data category: City
    • 2011_09_26_drive_0117(synced+rectified data, calibration)
    • 2011_09_26_drive_0104(synced+rectified data)
    • 2011_09_26_drive_0096(synced+rectified data)
    • 2011_09_26_drive_0093(synced+rectified data)
    • 2011_09_26_drive_0084(synced+rectified data)
    • 2011_09_26_drive_0009(synced+rectified data)

http://www.cvlibs.net/datasets/kitti/raw_data.php
上記URLにアクセスし、以下の画像の項目から、上記ファイルを取得する(raw data全て欲しい場合は、monodepth2のgithubページからwgetなどで取得する方法が記してありますので、そちらを参考に)

[synced+rectified data]は角度などが補正されたデータ、[calibration]はカメラ固有の補正パラメータとなります。

モデル準備

  • 下記URLのリポジトリからMonodepth2と学習済みモデルを取ってきます。
    https://github.com/FangGet/tf-monodepth2
  • Eval Result(with pretrained model link)の部分からmono_640x192_pt(ours)を取ってきます(取ってきたモデルは、tf-monodepth2-masterの直下に置いてください)。

前処理

  • 先程取得したデータセットに対して以下の前処理を行います。
    • PoseNetにターゲット画像とソース画像を渡すために、t-1,t,t+1の3枚をconcatした画像を作成する
    • データセットを学習用とテスト用に分ける

  • まず、以下のように取得したデータをdata/kitti/2011_09_26下に置き、caribrationファイルの中身を同じディレクトリに配置します。
~
├── data
│   ├── __init__.py
│   ├── cityscapes
│   │   ├── __init__.py
│   │   └── cityscapes_loader.py
│   ├── kitti
│   │ 	├── 2011_09_26
│   │   │   ├── 2011_09_26_drive_0117_sync
│   │   │   ├── 2011_09_26_drive_0104_sync
│   │   │   ├── 2011_09_26_drive_0096_sync
│   │   │   ├── 2011_09_26_drive_0093_sync
│   │   │   ├── 2011_09_26_drive_0094_sync
│   │   │   ├── 2011_09_26_drive_0084_sync
│   │   │   ├── 2011_09_26_drive_0009_sync
│   │   │   ├── calib_cam_to_cam.txt
│   │   │   ├── calib_imu_to_velo.txt
│   │   │   └── calib_velo_to_cam.txt
│   │   ├── __init__.py
│   │   ├── kitti_odom_loader.py
│   │   ├── kitti_raw_loader.py
│   │   ├── static_frames.txt
│   │   ├── test_files_eigen.txt
│   │   ├── test_files_stereo.txt
│   │   ├── test_scenes_eigen.txt
│   │   └── test_scenes_stereo.txt
│   └── prepare_train_data.py
~
  • 上記のようなディレクトリ構造となったら、以下コマンドを叩き、前処理を開始します。
$ python data/prepare_train_data.py --dataset_dir=data/kitti/ --dataset_name='kitti_raw_eigen' --dump_root=dump_data/ --seq_length=3 --img_width=640 --img_height=192 --num_threads=4
progress 0/312....

scipyのversionが1.3以上の場合、kitti_raw_loader.py及びprepare_train_data.pyにて、scipy.miscによるエラーとなります。

学習

今回は学習済みモデルを使用するため、学習は行いません。

  • 学習を行いたい場合は、以下のようにmonodepth2_kitti.ymlを設定し、自分のデータ数に合わせてパラメータを設定し直してください。
  • 論文では学習用データ40000枚に対しバッチサイズ12で20epoch回しているため、論文と同様の実験をしたい場合は、config/monodepth2_kitti.ymlでそのように設定してください。
    ::: message aleart
    dump_data/train.txtを開き、学習データの数がバッチサイズの12で除算できる数に調整します。例として20枚の学習データがtrain.txtにある場合、13行までを学習データとして残し、残りの行は削除します。(13行目としているのは、最後の学習データが使用されない構造となっているため、結果として13-1枚が使用されることとなります)
    :::
  • スクラッチ学習の場合、以下コマンドを叩いて学習を開始します。
python monodepth2.py train config/monodepth2_kitti.yml created_model

テスト

  • 学習により生成されたモデル、又は学習済みモデルがtf-monodepth2-maseterの直下に存在していることが確認できたら、テスト用のconfigファイルを作成します。
  • 以下のようにして、monodepth_kitti.ymlをコピーしてテスト用に作成してください。
config/mondepth_kitti_test.yml
dataset:
    root_dir: 'dump_data'
    image_height: 192
    image_width: 640
    min_depth: 0.1
    max_depth: 100.
    preprocess: True
model:
    root_dir: ''
    learning_rate: 1e-4
    batch_size: 12
    num_source: 3
    num_scales: 4
    epoch: 1
    beta1: 0.9
    reproj_alpha: 0.85
    smooth_alpha: 1e-3
    batch_norm_decay: 0.95
    batch_norm_epsilon: 1e-5
    pose_scale: 1e-2
    auto_mask: True
    continue_ckpt: ''
    torch_res18_ckpt: ''
    summary_freq: 1
    pose_type: 'seperate' # seperate or shared
  • 最後に以下コマンドを叩き、テストを行います。
python monodepth2.py test config/monodepth2_kitti.yml 作成したmodel名 or 学習済みmodel名

結果

  • 以下は評価されたデータセットの一枚となります。車や木など距離が近いほど明るく描画されていて、人に対してもそれらしい形が描画されていることが確認できます。

最後に

今回は学習済みモデルを用いた試みですが、自分で撮影した画像を用いて学習するのも面白そうです(次回で試してみます)。

参考文献

Discussion

ログインするとコメントできます