写真から3Dモデルを作製する (8): サイズが問題

出来上がった3Dモデル、折角だからプリンタで出力したいよね。DMMとかKinkosとかで出力サービスやってるし、値段も、まあ本気なら出せる額だし。出力サービスの要綱を読むと、サイズが分かるように1cm角の立方体をモデルに添えろ、などと書いてある。「ばっかじゃねーの」と思ったが、待て待てと。ちょっと調べてみよう。

ちょっと調べてみたら、なんと、STLにもPLYにも長さの単位がない!おお、初めてフォントの大きさ変えてみたよ。そのくらい衝撃だ。一体ばかはどいつだ。PLYはヘッダファイルまで見てみたので間違いない。

ま、多分、誰も責められないんだよね。建築なのか産業機械なのか精密機械なのか光学素子なのか分からないものを相手にするとなると、有限な桁を有効に使うためには、単位を任意として都度定義するしかないんだよね。

ただ、実際問題として3Dモデルに寸法は必要だ。航空写真から地形を起こす場合などはあらゆる手段で寸法の精度を上げたいだろう。VisualSFMにもそういった機能は実装されており、カメラ座標をGPSで与えて寸法校正するもの(GPS-based Transform)、モデル上の点に座標を与えて校正するもの(GCP-based Transform)の二種がある。

ただ、ワシが腑に落ちないのは次の点だ。写真にはEXIFが付いていて、焦点距離をVisualSFMでは利用しているとのことだった。それなら実寸法出てるんじゃねえの、と思うわけだ。EXIF自体いい加減なのは知ってる。焦点距離と35mm換算する時の係数に分かれて保存されていたり、いなかったり、とか。そういうことから類推すると、少なくとも、同じセンサ(カメラ)、同じ焦点距離(レンズ)で撮影した写真を元に作製した3Dモデルについてはスケールの一貫性があるんじゃないかな、と。*1

そこで、こういう実験をしようと思う。やってみて確認するしかない。

  1. 金尺などを撮影して、VisualSFMにて3Dモデルを作り、寸法校正する。
  2. MeshLabにインポートして3Dモデルのサイズを測定して確認する。
  3. Blenderにインポートして3Dモデルのサイズを測定して確認する。
  4. 校正係数を求める。
  5. 別のモデルを作り、求めた校正係数で拡大縮小して確認。

金尺のモデル作製と寸法校正

金尺のモデルを作ったら、[Filters] > [More Functions] > [GCP-based Transform]と辿る。ダイアログに従って点と座標を入力する。Ctrl+LMB (Left Mouse Button)で点を指定すると寸法を訊いてくるので、次のように入力する。

0.05 0 0, 0


金尺の上の0, 5, 10 cmで校正するつもりなので、それぞれの点をメートル単位で入力する。コンマの後は連番で適当に入れれば良い。3点入力し終わったところで、

Transformation estimated successfully!


と表示されるはずだ。これで寸法校正は終わり。モデルを保存するのだが、先にも述べたとおり、PLYには寸法は無い。プロジェクトとして保存する。もう一度[Dense Reconstruction]を実行すると、PLYファイルと同じフォルダにALNという拡張子の付いたファイルが保存される。

MeshLabで測定

MeshLabで先ほどのファイルを開く。PLYのインポートじゃないよ。[File] > [Open Project]と辿って、*.alnつうファイルを指定する。で、右上の方にある巻尺のアイコンをポチッて測定する。ほら、ほぼ完璧。


ここで、種明かしをする。このALNつうファイルには、PLYファイルの名前と、変換マトリックスが書かれているだけだ。MeshLab側では参照先のPLYを読んできて、変換してるだけ。多分単位も無いままだ。なので、このままPLYのエクスポートをやっても、変換前のPLYがそのまま書き出されるだけで、折角やった校正結果は反映されない。

モデルのエクスポートをする前に、変換を反映させよう。[Filters] > [Normals, Curvatures and Orientation] > [Freeze Current Matrix]と辿る。なにか起こったように見えないが、これで大丈夫。PLYをエクスポートしましょう。

Blenderで確認

Sceneの設定で、単位をMetricに設定し、モデルをインポートする。下は、長さ10cm、幅1cmのPlaneと並べたところだ。寸法が校正されているのが分かる。

校正係数を求める

さっきのALNファイルの中身はこうだ。

 1
 1.0.ply
 #
 0.1584075507185057 -0.03476768458167236 0.002724310501963919  0.1450277098648572
 -0.03487425639181098 -0.1579234750372918 0.01237449622335581 0.1966065307430072
 0 -0.01267083361476104 -0.161705336519933 0.2774558312818179
 0 0 0 1
 0


#の下4行にそれぞれ4つの数字、都合16の数字が羅列されている。これが変換行列だ。詳しい説明をすっ飛ばすと、最初の3行のうちどれでも良いので、最初の3つの数字をそれぞれ自乗して足し合わせて、平方根を取ると係数が求まる。計算すると、0.1622となった。次のモデルでは、何も考えずに0.1622倍してやれば寸法が合う、はず。

*1:ご指摘いただいた。焦点距離はあっても、被写体距離が無い・いい加減なので相対的なカメラ位置しか分からないのだそうだ。被写体(ピント)距離の表示はNikonの特許だし、写真のEXIFのみから自動的にサイズが決まることは今後も無さそう。