3次元映像の研究をしていて,再生サンプルに点群データを使うことが多いのですが,フリー,かつアニメーションで入手できる点群データはなかなか無いので,手軽な変換方法のメモです.シンプルな点群情報だけのバイナリファイルに変換します.
#使うもの
- Cloud Compare
- Blender
- Python
#手順
-
TurboSquid等の3Dデータ投稿サイトから,適当なデータ形式の3Dモデルデータを入手します.
形式(Blenderなど),Price, Animated等を選択して絞り込み
- 以降,Blender形式のアニメーション情報付きデータを想定します.3Dアニメーションの各フレームがCloudCompareで読み込める形式で出力できる環境があれば,入力形式は何でも良いと思います.1フレームだけなら直接CloudCompareに読み込めば良いです.
- ダウンロードしたデータをBlenderに読み込み,全フレームをOBJ(wavefront)形式でエクスポートします.
ファイル > エクスポート > Wavefront(.obj)を選択
アニメーションにチェックを入れて「OBJをエクスポート」を選択.全フレームがOBJとMTLファイルとして出力されます.
- CloudCompareでOBJを点群情報に変換します.CloudCompareは通常起動するとGUIになりますが,CLIモードも備えています.同じ実行ファイルで対応しています.パスを通しておくと便利だと思います.
- 先ほど出力したOBJファイルがあるフォルダでコマンドプロンプトを開きます.以下のコマンドを実行すると,OBJがCSV形式の点群情報ファイルになります.ここで,私の用途ではX,Y,Z座標だけあれば良いので,RGBと法線ベクトルの情報は,それぞれ-REMOVE_RGB -REMOVE_NORMALSオプションを指定して,取り除いています.また,オプションとして,
-SAMPLE_MESH POINTS 20000
を指定していますが,これは,出力する点群数です(が,実際の出力は20000をちょっと超えるので,よくわかりません).より詳細なオプションは,CloudCompareの仕様ページを参照してください.
OBJ2PLS.bat
CloudCompare -SILENT -O hoge.obj -NO_TIMESTAMP -C_EXPORT_FMT ASC -SEP COMMA -EXT csv -SAMPLE_MESH POINTS 20000 -REMOVE_RGB -REMOVE_NORMALS -SAVE_CLOUDS
- 上のOBJ2PLS.batを実行すると,hoge.objを入力として,hoge_SAMPLED_POINTS.csvが出力されます.各列にx,y,zを含んだ点群情報が入っています.複数フレームがある場合は,バッチスクリプトを下のように変えれば良いです.Windows前提で話していますが,今回使用するソフトウェアはMac, Linuxでも動くはずなので,スクリプトは適当に読み替えてください.
OBJ2PLS.bat
for %%i in (*.obj) do (
CloudCompare -SILENT -O %%i -NO_TIMESTAMP -C_EXPORT_FMT ASC -SEP COMMA -EXT csv -SAMPLE_MESH POINTS 20000 -REMOVE_RGB -REMOVE_NORMALS -SAVE_CLOUDS
)
- 最後に,CSVを必要に応じてバイナリ形式の点群情報に変換します.計算機ホログラムのソフトウェアだと読み込み速度がシビアに実行速度に効いてくるので,このようにします.以下のPythonコードで変換できます.実行時の第1引数に変換したいファイルを指定して下さい.我々の研究チームでよく使う3dfという独自フォーマットで出力していますが,[(int)点群数][(float)1点目のx座標][(float)1点目のy座標][(float)1点目のz座標][(float)2点目のx座標]...が延々続くだけのファイルです.
csv23df.py
import csv
from struct import *
import sys
import os
objData = []
inFile = sys.argv[1]
outFile = os.path.splitext(os.path.basename(inFile))[0] + ".3df"
with open(inFile) as f:
reader = csv.reader(f)
for row in reader:
objData.append(row)
with open(outFile, "wb") as ofs:
data = pack('i',int(len(objData)))
ofs.write(data)
for d in objData:
d_array = pack('fff',float(d[0]),float(d[1]),float(d[2]))
ofs.write(d_array)
以上の手順で,適当な点群データセットを公開されているフリーの3Dデータから,難なく作成できます.