画像解析

表面データ STL形式とはなにか

うーん、この角度じゃないんだよなー。
電子カルテのCTってもうちょっと違う角度から見えないんですかね?
あれは画像データを連続で出してるだけだからパラパラ漫画みたいなもんだよ。
自分でいろいろいじってみたかったらCTをstl形式にするんだね。
エス・ティー・エル?
表面データだよ。
いろんな方向からみたり、
実際に消したり結合したりできるよ。

こんにちは整形外科医のDr.レオです。
臨床でプログラミングを手術などにフル活用しています。

私は整形外科医という専門上、骨をよく扱います。

骨はレントゲン、CTをもとに診断、治療を行いますが、
3次元表面データの形にするともっと扱いやすくなります。

ここでは骨など臓器を表面画像として扱える.stlデータ形式に関して説明します。

CTデータをつかうと、こんな3次元画像がつくれます。
このデータは表面データなのでいろいろな角度から観察できます。

CT画像から簡単に表面画像を作る方法はこちらの記事で紹介しています。

かんたん!表面画像をCTから作る方法 無料ソフト3D Slicer

また、細かい「メッシュ」状の表面データのため、指定の部分で切ったり、表面上の点を座標で求めたりすることができます。

表面画像を操作する方法はこちらの記事で紹介しています。

表面画像STLファイルを簡単に操作する 無料ソフトMeshLab

それで結局、STLデータってなんですか?
一般に表面データでつかうときは、点を並べて、三角形をつくる組み合わせを指定しただけだよ。

STLファイルは一般的にはバイナリ形式といって二進法で書かれているため、テキストファイルで開いても読めません。
しかし、同様のファイルはASCII(アスキー)形式でも保存できるので、こちらはテキストファイルで開けます。

ASCII形式だととても重いので、小さいファイルで書き出すことをおすすめします。

無料ソフトMeshLabでSTLファイルを開きます。

これは橈骨の手首の部分の骨データです。 
ファイルサイズが大きくならないようにトリミングしてあります。
メッシュの形が見えるようにします。

拡大すると多数の三角形の集まりであることがわかります。

メッシュを「ファイル」 → 「Export Mesh As」でstl形式で保存します。

ここでは「Binary Encoding」のチェックを外します。

バイナリとアスキーの同じ表面形状のデータの比較です。
ファイルの大きさが5倍くらいちがいますね。

ファイルをテキストアプリ(ここでは「mi」を使用しています。)から開きます。
以下のような数字データが延々と100万行にわたって書いてあります。

solid STL generated by MeshLab
  facet normal -9.774517e-01  5.569874e-02  2.036807e-01
    outer loop
      vertex   2.474473e+01 -1.155758e+02  1.405398e+02
      vertex   2.480759e+01 -1.153925e+02  1.407913e+02
      vertex   2.477012e+01 -1.153149e+02  1.405903e+02
    endloop
  endfacet
  facet normal -9.410948e-01 -1.140491e-01  3.183293e-01
    outer loop
      vertex   2.480759e+01 -1.153925e+02  1.407913e+02
      vertex   2.474473e+01 -1.155758e+02  1.405398e+02
      vertex   2.483887e+01 -1.155992e+02  1.408097e+02
    endloop
  endfacet
・
・
・
・
  facet normal  9.358256e-01 -3.104249e-01 -1.669335e-01
    outer loop
      vertex   6.251677e+01 -1.100984e+02  1.465273e+02
      vertex   6.258286e+01 -1.098526e+02  1.464406e+02
      vertex   6.263681e+01 -1.098791e+02  1.467924e+02
    endloop
  endfacet
endsolid vcg

ちなみに「e+01」とか、「e-01」とかあるのは、10の1乗をかける、10のマイナス1乗をかけるといったことの表記です。

はじめに
「これはMeshLabの表面データです」
と定義したあとに、
facet normal:法線ベクトルの方向(単位ベクトル)
vertex:(点の座標)
で書かれています。
vertex3つで三角形3つです。

延々と三角形がかかれているわけですね。
こうやってテキストでファイルを開くと、自分の知らないファイルでも理解が深まることがあるんだよ。

構造がわかれば自分でSTLファイルを記載することもできます。
例えば、x, y, z方向に長さ1の辺を持つ3角錐は

solid STL generated by MeshLab
  facet normal 0 0 -1
    outer loop
      vertex   1 0 0
      vertex   0 1 0
      vertex   0 0 0
    endloop
  endfacet
  facet normal -1 0 0
    outer loop
      vertex   0 0 0
      vertex   0 0 1
      vertex   0 1 0
    endloop
  endfacet
  facet normal 0 -1 0
    outer loop
      vertex   1 0 0
      vertex   0 0 1
      vertex   0 0 0
    endloop
  endfacet
  facet normal 0.577 0.577 0.577
    outer loop
      vertex   1 0 0
      vertex   0 1 0
      vertex   0 0 1
    endloop
  endfacet
endsolid vcg

のように書けます。

これを「test.stl」など適当に名前をつけて、MeshLabから開きます。
「テキストで書いているので、形式が合いません」のような警告がでることがありますが、問題ありません。

このように目的の四角錐が書けました。

でも何十万行も書いてられないですよ。
だから、プログラミングで書くんだってば。

補足 面の法線ベクトルについて

 
メッシュの表面には表と裏があります。
そのため同じ3点からなる三角形でも、表と裏があるのです。

形態を扱っているだけでは
「面には法線っていう要素があるんだな」
という程度でよいですが、

ソフトウェアでは表面の表を明るく、裏を暗く表示するものが多いです。
そのため、座標を移動させた時(表面画像を左右反転させた時など)に、
表面データが真っ黒になってしまうことがあります。

この時は、
「法線もひっくり返ったので表と裏がひっくり返ったんだな。」
と理解できるようにしておきましょう。

これは法線ベクトルで決まります。
一般的に、法線ベクトルは3角形の点の順番で「右ねじの法則」できまります。
1番から3番にむかってネジを回したときに進む方向です。

図のような3角形だと手前向きになるので、手前が表です。

少しマニアックな話ですが、STLファイルの法線の向きは、
「facet normalに書かれた法線の向き」と、
「3角形の点のふりかた」
の2通りで決まります。
このうち、点の順番が優先されるようです。

テキストファイルで法線ベクトルの方向をマイナスにしても、面の表裏は変わりません。

一方で、2点を入れ替えると、右ねじの方向も逆周りになりますが、このようにすると表裏が入れかわります。

これをMeshLabで読み込ませてから、stlに書き出すと、自然と法線ベクトルの向きも表裏逆になります。

自分で把握していなくても表面画像を見たり、編集したりすることはできますが、
プログラムで内容を読み込んだり、外部から編集するときは、このようなファイル形式を理解しておくと簡単になります。