3Dモデルをいろいろ作ってみたい

3Dモデルをいろいろ作ろうとがんばっています。苦労した点、役に立ちそうな情報を発信していきます。

学習用3Dデータの準備に関する備忘録

IM-NETのプログラムが掲載されているgitのリポジトリには学習用の3Dデータをどこから取得するかという点についても記述がありました。ShapeNetとうい3Dデータを集めるプロジェクトがあるんですね。

shapenet.org

Robotの顔なんていう特殊なカテゴリはありませんが、airplaneとかcarとかの3Dデータが3万個ぐらいはあるので、thingiverseから集めたロボットの顔データと組み合わせればよい学習ができそうです。

ShapeNetのデータはmat形式というmatlabで使われている形式で格納されています。scipyパッケージを使ってロードできますが、簡単なデータ圧縮が行われている状態で読み込まれるようです。圧縮を伸長して256x256x256のボクセルデータを得るコードはこんな感じ。

from scipy.io import loadmat
 
voxel_model_mat = loadmat(filename)
voxel_model_b = voxel_model_mat['b'][:].astype(np.int32)
voxel_model_bi = voxel_model_mat['bi'][:].astype(np.int32)-1
voxel_model_256 = np.zeros([256,256,256],np.uint8)
for i in range(16):
    for j in range(16):
        for k in range(16):
            voxel_model_256[i*16:i*16+16,j*16:j*16+16,k*16:k*16+16]
          = voxel_model_b[voxel_model_bi[i,j,k]]
#古いShpapeNetのフォーマットとの座標系の違いを補正
voxel_model_256 = np.flip(np.transpose(voxel_model_256, (2,1,0)),2)

上記の例だと縦、横、高さで256x256x256のデータが16x16x16個の小区画(1区画は16x16x16のボクセルデータ)に分割され”b”に1次元配列として格納されています。"bi"の3次元配列は”b”の1次元配列へのインデックスを保持しています。形状の外側は16x16x16のボクセルデータが全部0、内側は全部1になることが多いので1次元配列の長さは16x16x16=4096をワーストケースとして通常はそれよりもだいぶ短くできるわけです。

あとOBJ形式のサーフェスモデルからボクセルデータを生成する処理を自作のプログラムからshapeNet推奨のbinvoxに乗り換えることにしました。binvoxのほうが速いしサーフェスの内部を埋める処理を私のいいかげんプログラムより正確にやってくれるからです。

binvox   -rotz -rotz -rotx -rotx  5073_Spiderman_Bust_v1.04.obj

-rotz -rotxはShapeNetと私のデータとで前後の向きが逆だったのでその補正をしています。出力はbinvoxという形式ですがbinvox_rwというパッケージで簡単に生の3次元データを抜き取ることができます。

import binvox_rw as bv_rw
 
with open(file_name, 'rb') as f:
model = bv_rw.read_as_3d_array(f).data
model2 = model.reshape([model.shape[0], model.shape[1],
model.shape[2]]).astype(np.uint8)