ドローンの自律飛行のためには、現在位置の把握と飛行ルート上の障害物の検知がとても大切となります。非GPS環境である室内での飛行においては、これまでもSLAM (Simultaneous Localization and Mapping)を用いた自己位置推定と環境地図作成の試みが行われており、LiDARを用いた高精度の点群データの作成などが実用化されています。しかし、ペイロードが大きくセンサー類が搭載可能な大型の産業用ドローンが必要となり、小型のホビードローンでは実装が困難なのが現状です。
そこで注目を浴びているのが、もともとドローンに搭載されているカメラだけでSLAMを実現する「単眼SLAM」です。今回、過去にドローンが撮影した動画データから、SfM(Structure from Motion)技術を使って高密度の3次元点群データが作成可能かどうかを検証することで、今後の「単眼SLAM」への応用の可能性を探りました。
データの準備
まず既存の動画として、別の目的で撮影したショートビデオを利用しました。内容はトイドローンTelloのサークル機能を使用して自動撮影したこちらの約38秒の動画です。撮影場所は弊社内のオープンスペースで、社内にあったオレンジ色の水難救助訓練人形の周りをドローンが周回しています。
- Telloサークル機能について~ユーザーマニュアル - Ryze Tech(PDF)
静止画の書き出し
次に、3Dデータを作成するための静止画を用意します。動画ファイルから静止画を切り出すためにフリーウェアのFFmpegを利用しました。FFmpegはクロスプラットフォームソフトウェアです。今回はWindows版を使用しました。FFmpegをインストール後、Windowsのコマンドプロンプトで以下のコマンドを実行します。
ffmpeg -i C:\sample\test.mp4 -r 3 C:\sample\save\%03d.jpg
- 動画の保存先がC:\sample、ファイル名がtest.mp4、書き出し先がC:\sample\saveの場合
- 書き出し時のファイル名が3桁の連番数字+拡張子(.jpg)となるよう指定
- 1秒間あたり3コマずつ書き出しを行うように -r オプションに3を指定
書き出された画像は全部で116カットになりましたが、最初の24カットはドローンが動き出す前の状態だったため、024.jpg~116.jpgの計93カットを使用することにしました。
書き出し間隔の検証
SfM(Structure from Motion)技術を利用するためには、「連続する2枚の写真の80%が同じ領域であること」が条件とされています。念のため、今回(秒3コマで)書き出された画像間の領域の重なり具合を調べてみました。
- 099.jpg(左上写真)と100.jpg(右上写真)の連続した2カットを使って確認
- (左下写真)2つの写真をできるだけ重なる部分が多くなるよう重ね、重なった部分が黒くなるよう特殊な方法で合成
- ほぼ重なった領域を「黒」、明らかに重ならなかった領域を「白」で塗りつぶし、全領域に対する「黒」領域の面積比を求める
全領域が921,600ピクセル(画像サイズ:1,280 X 720より)であるのに対して、「黒」領域が725,569ピクセルでした。結果は79%となり、やや足りない感じですが、このまま使用していこうと思います。
静止画の撮影条件を調べる
3Dデータの作成には、レンズの焦点距離とセンサーサイズが必要となります。デジカメで撮影した画像であれば、Exif情報から焦点距離を調べることができます。しかしドローンで撮影された動画から書き出した静止画には、そのような情報が付帯されていません。そこで「画角とセンサーサイズおよび焦点距離の関係」を参考に、写真モードのExif情報から必要な数値を計算で求めることにしました。
カメラのメーカーとモデル名、センサーサイズ
いずれも写真モードのExif情報から調べることができます。センサーサイズは、実際のレンズの焦点距離と35mm換算時の焦点距離から計算で求めることができます。
以下のExif情報から、(計算による)実際のセンサーサイズは2.8mmという結果になりました。
<Exif情報>
- カメラメーカー:RYZE
- カメラモデル:RZ001
- 焦点距離:2.0mm
- 焦点距離:25mm(35mm換算時)
<RYZE RZ001のスペック>
- センサーサイズ:2.8mm
ビデオモードの焦点距離
同じ位置とアングルで撮影された写真モードとビデオモードのサイズ比から、ビデオモードの焦点距離を計算で求めることができます。
サイズ比を調べるために、両モードの写真を重ね合わせて比率を調べました。
- 写真モードの画像にビデオモードの画像がちょうど重なるよう、サイズと位置を合わせて合成
- ビデオモードのトリミング後(16:9)の画角をトリミング前(4:3)の画角に戻したものでサイズ比を求める
その結果、トリミング前のビデオモード(縦:1,290ピクセル)が、写真モード(縦:1,932ピクセル)に対し、寸法ベースで66.7%であることが判明しました。
さらに「画角とセンサーサイズおよび焦点距離の関係」から、センサーサイズを同じ(2.8mm)とした場合、ビデオモードの見かけ上の焦点距離は3.0mmになりました。なお、実際の焦点距離は写真モードもビデオモードも同じです。焦点距離を変更したくない場合は、見かけ上のセンサーサイズを計算した値(1.9mm)をカメラのスペック情報として使用してください。
書き出した静止画にExif情報を追加する
全ての静止画にExif情報を書き込む作業は大変ですので、今回はWindows用フリーソフトF6 Exifを使って自動書き込み処理を行いました。
<Exif情報>
- カメラメーカー:RYZE
- カメラモデル:RZ001
- 焦点距離:3.0mm
Regard3Dで3Dモデルを作成
3Dデータの作成には、GUIでの操作が可能なSfMソフトRegard3Dを使用しました。Regard3Dもクロスプラットフォームに対応したフリーウェアです。3Dデータの作成の際に、先程画像ファイルに書き込まれたExif情報(カメラのメーカーやモデル、焦点距離など)と当該カメラのセンサーサイズの値が必要となります。Regard3Dの使い方については、公式ページのドキュメントを参考にしてください。
それでは、実際にRegard3Dを使って3Dモデルを生成してみます。
Picture Set
最初に画像を選択します。選択後、Exif情報と当該カメラのセンサーサイズなどが正しく認識されているかどうか確認しておきます。
Compute Matches
次に、各画像のキーポイントを見つけ出しマッチング作業を行うための設定ですが、今回はすべて初期値のまま実行しました。マッチングが終了すると、結果が確認できます。
<設定>
<結果>
Triangulate
次に、マッチングの結果を利用して三角測量を行うための設定ですが、こちらもすべて初期値のまま実行しました。
<設定>
<結果>
Densification
さらに、高密度化を行うための設定です。今回は、処理スピードより精細さを優先するため、数か所の設定値を変更しました。
- Cell size: 2 → 1
- wsize: 7 → 10
- Min image num: 3 → 5
<設定>
<結果>
Surface
最後に、表面生成を行うための設定です。すべて初期値のまま実行しました。
<設定>
<結果>
まとめ
意外な結果、というかかなりグロテスクなサーフェスの3Dモデルが出来上がりました。各ステップでの設定値を最適化することで、より正確で緻密な3Dモデルの作成ができる可能性も感じられます。
ドローンの視点動画ということもあり、天井は開放状態となっていますが、壁やオレンジ色のマネキンがここまで物体や面として認識できていれば、「既存動画から3Dモデルの生成は可能」と言えるのではないでしょうか。今回は既存の動画を利用いたしましたが、「未知の空間」で飛行を行う際にも、その場で撮影した周囲の風景動画とSLAMを用いた自律飛行も可能ではないかと思います。
機会があれば、次はPythonとOpenCVを利用した(SfM/MVSによる)3Dモデル作成にもチャレンジしてみたいと思います。