HAVRMの空空活動誌

「空空」は「うつらうつら」と読むらしいです.まぁ常に寝不足なもんで...

WSLでSfMをやってみる

こんにちは,HAVRMです.
ここ数か月忙しかったのと,あまりにたくさんの問題が発生し,ブログに手を付けれていませんでした.
最近ようやく休日に好きなことをできるぐらいには余裕ができたので少しずつブログを更新していきます.

今回は以前から気になっていたSfMStructure from Motion)に手を付けてみました.ほかの人がブログに書いているし,昔からある技術でオープンソースも充実しているから簡単だろうと思っていたら,実際にできるまで休日が丸一日潰れました...
オープンソースのアップデート等でいろいろ変わっていて,それに記事が対応できてないみたいなのでそのあたりをまとめます.

SfMに関して

SfMというのは多数の画像や動画から立体情報を復元する技術・プログラムです.
簡単に言えば人間が両眼で見て立体を認識している方法を複数の視点から行っています.両眼視(ステレオ視)で立体を認識は理論上できますが,人間が簡単に行っている複数画像における同じ個所を認識することがコンピュータでは難しく,高精度化するには大量の画像を使う必要があります.
ステレオ視を使った立体認識はそれこそ昔のロボットで使われていて,比較的処理が軽いため70年台のロボットでもおそらく使っているはずです(世界初の人型知能ロボットであるWABOT-1には胴体部分にカメラが2台載っています).ただカメラを複数同時に使用するのは機材の準備やカメラ間距離の正確性等求められるため,コンピュータ性能が向上した現在ではあまり使われておりません.
SfMは最近話題のV-SLAM(Visual SLAM)と同じような考えで,V-SLAMではカメラの軌道をあらかじめ用意されたマップから計算しますが,SfMでは対象オブジェクトの画像データの変化からカメラ軌道を計算し,同時に対象オブジェクトの形状も計算するものになります.
SfMについては例えば焼失した首里城のデジタル復元等で使われています.
www.our-shurijo.org

SfMとLiDAR,Depthカメラの違い

物を3次元計測する際に使われるものにLiDARとDepthカメラがあります.あくまで個人的な考えにはなりますが,

  • LiDAR:レーザー光を3次元的に出力し,そのレーザー光が返ってきた時間(dToF,ToFはTime of Flight?)または帰ってきた量(iToF)で距離を測定する(2次元のものはLRF).
  • Depthカメラ:赤外線等の不可視な光でパターンを投影(プロジェクション)してそのパターンの形状変化から平面の距離情報を面的に取得する

iPhoneで考えると

  • LiDAR:高レンジ(数m)で比較的高精度に計測できるので暗所での被写体深度(被写体までの距離)を計測しピント合わせを高速化,部屋の間取等をスキャンするとき使う(iPhoneの12,13のPro,iPad Proに搭載).
  • Depthカメラ:Face IDでつかうTrue Depthセンサにあたり,短距離(~1m)で高精度に取得できるので顔の特徴を検出するときに使う.比較的小型のものであってもスキャンできる
  • SfM:写真や動画を使う.CPU・GPUをめっちゃ使えば画素レベルで高精度化可能?

HAVRMは現在iPhone 13 Proを買って様々なものをスキャンしてみました.LiDARでは部屋レベル,True Depthでは顔ぐらいがきれいに計測できてそれより小さいもの(マウスやミニカー)などは形がつぶれました.
なお使ったAppは次の2つです.

LiDAR

3d Scanner App™

3d Scanner App™

  • Laan Labs
  • ユーティリティ
  • 無料
apps.apple.com

True Depth(2022/4/11現在Appがない?)
www.producthunt.com

またSfMをやっていると思われるアプリも実際に使ってみました(クラウド側で処理するのと無料でできるのは5回まで?です).
Metascan - 3D Scanner

Metascan - 3D Scanner

  • Abound Labs Inc.
  • 写真/ビデオ
  • 無料
apps.apple.com
実際のスキャン結果(アプリから動画として出力しました.20枚の画像から出力しています.対象はガチャガチャのミニカーです.最低枚数の20枚でもきれいに3D出力できています.透明部がへこんだりするのはカメラ映像を使うのでしょうがないです)
youtube.com
例えばLiDARは自動運転の広域の3次元計測に使われているとか,DepthカメラはKinectで使われている技術とかだったりするので,実際に使いたい場合は目的に応じて選んでください.

SfMをやってみる

SfMについては結構前からオープンソースがありました.
openSfMやopenMVG+openMVSとかです.この中で今回は比較的高画質に生成できるopenMVGとopenMVSを使う方法を選びました.簡単に言えばopenMVGでカメラ軌道を計算し,openMVSで高画質に3D生成する感じです.

参考ブログ・サイト

基本的には以下のブログを参考にしています.
一番もとにしているのはこのブログ↓
qiita.com
インストールの時はこのサイトも参考に↓
openMVGとopenMVSを使うメモ · GitHub

実行はこのサイトを参考に↓
aicam.jp
言うまでもないですが,それぞれのGitのサイトも参考にしています.
openMVG
github.com
openMVS
github.com

使用OS

少し順番が前後してしまいますが,ここで使用OSを書きます.
今回自分はWSL上のUbuntu 20.04.4 LTSを使用しています.
最初Ubuntu 18.04を使っていたのですがopenMVSのコンパイルができないため諦めました.詳細は後程

openMVGのインストール

基本的にgitに書いてある通りすればいいです.
github.com
このBUILD.mdに詳しく書いてあります.
初めての際は最初のインストールの時にgccとg++もインストールしておいた方がいいでしょう.

$ sudo apt-get install libpng-dev libjpeg-dev libtiff-dev libxxf86vm1 libxxf86vm-dev libxi-dev libxrandr-dev
# ↑を次に変更
$ sudo apt-get install libpng-dev libjpeg-dev libtiff-dev libxxf86vm1 libxxf86vm-dev libxi-dev libxrandr-dev gcc g++

また最後のcmakeについてはジョブ数(並列作業数)を指定しておくと早く終わります.
ジョブ数は物理コア数+1にしておくといいそうです.ただWSLはWindows上なのでCPUをすべて使いたくなかったので物理コア数-1でしていました.物理コア数は次のコマンドで確認できます.

$ grep cpu.cores /proc/cpuinfo | sort -u | sed 's/[^0-9]//g'
8

(この辺りは以下のブログで調べました)
qiita.com
実際の指定は次のように行います.

$ cmake -DCMAKE_BUILD_TYPE=RELEASE ../openMVG/src/
$ cmake --build . -j 9 --target install

「-j 9」を「--build」の前に置くとエラーになるので注意

参考ブログのほうでは最後に「make」もやっていましたが,なくてもよさそうです.一応自分はやっていました.「$ make test」のほうは「-DOpenMVG_BUILD_TESTS=ON」のオプションをcmakeにつけない限り不要です.

openMVSのインストール

ここもGithubのBUILD.mdにある通り進めますが次の問題が起きました
github.com

Ubuntu 18.04でコンパイルできない

最初のファイルから「filesystem : no such file or directory」というエラーが出ました.Ubuntu18.04で使えるgccコンパイラーのバージョンが古い(7系)なのが問題みたいで8系にすれば解決できるそうですが,cmakeでのコンパイラの指定がわからなくて諦めました.「#include <filesystem>」を「#include <std::filesystem>」みたいにすればいいという記述も見つけましたが大量にあるファイルを逐一修正するのは無理です...

Ubuntu 16.04でコンパイルできない

(そもそもcmakeが古すぎました...)

Ubuntu 20.04でコンパイルできない→修正して実行可能

この場合途中までコンパイルは進みますが50%を過ぎたあたりで「Mesh.cpp」のコンパイル時にエラーが起きました.これについてはすでにissueで解決されている通り,ブランチを「master」から「develop」に変更することで解決できます.
github.com

$ git clone https://github.com/cdcseacave/openMVS.git openMVS
# ↑を次に変える
$ git clone -b develop https://github.com/cdcseacave/openMVS.git openMVS

実際にSfMをしてみる.

基本的には先に挙げた以下のサイトにあるように進めればいいです.
aicam.jp

しかし,openMVGのほうで一部APIが変わっておりそれによってコマンドが変わっています.
github.com
「openMVG_main_IncrementalSfM」がなくなり「openMVG_main_SfM」となり,オプションで「Incremental」を指定します.
上記サイトのようにファイルを作ったうえで次のように実行しました.

$ openMVG_main_SfMInit_ImageListing -i SfMTest/images/ -d SfMTest/sensor_width_camera_database.txt -o SfMTest/matches/
$ openMVG_main_ComputeFeatures -i SfMTest/matches/sfm_data.json -o SfMTest/matches/
$ openMVG_main_PairGenerator -i SfMTest/matches/sfm_data.json -o SfMTest/matches/pairs.bin
$ openMVG_main_ComputeMatches -i SfMTest/matches/sfm_data.json -p SfMTest/matches/pairs.bin -o SfMTest/matches/matches.putative.bin
$ openMVG_main_GeometricFilter -i SfMTest/matches/sfm_data.json -m SfMTest/matches/matches.putative.bin -g f -o SfMTest/matches/matches.f.bin
$ openMVG_main_SfM --sfm_engine INCREMENTAL --input_file  SfMTest/matches/sfm_data.json --match_dir SfMTest/matches --output_dir SfMTest/outReconstruction
$ openMVG_main_openMVG2openMVS -i SfMTest/outReconstruction/sfm_data.bin -d SfMTest/outReconstruction/ -o SfMTest/outReconstruction/scene.mvs
$ ~/openMVS_build/bin/DensifyPointCloud SfMTest/outReconstruction/scene.mvs

この結果,「SfMTest/outReconstruction/scene_dense.ply」というファイルが生成され,実際にMeshLabで確認しました.
なお「sensor_width_camera_database.txt」にiPhone 13 Proは登録されていなかったので(iPhone 6まででした...)「Apple iPhone 13 Pro;7.5」を追加してあります.今回は広角カメラで撮影し,以下のサイトにセンササイズが「1/1.67」とあったので「1/1.7」と同じと考え,「7.5 mm」にしています.
2ndart.hatenablog.com
(実際に正確なサイズ等出力したいならこの値はしっかりしたほうがいいと思います)

まとめ

いかがだったでしょうか.インストールするのに半日以上,SfMをエラーなく実行できるまで数時間かかったものの,解決は簡単(?)なのでこれを見れば数時間でできるようになると思います(インストールとコンパイルに時間がかかるので...).
ただあくまでこれは自分が行った2022/4/10時点の話なのでまた変わることがあるのでそこは注意してください.
また自分はとりあえず11枚の適当な写真から出力してみましたが案の定一部が作れているだけでした.実際に行う場合はきちんとたくさんの画像を用意しましょう.

※追記
ここ最近いろいろなことがありすぎて記事にすることがたまりにたまっているので随時更新していきます.先にG-tuneとCF-XZ6についてかな...