画像解析

PLYファイルについて

表面形状をあつかうファイル形式に、.ply形式のファイルがあります。

これはPolygon File Formatといって3次元データを値付きで保存している形式になります。

PLYファイルは3Dスキャンしたデータなどに用いられていますが、3次元データに色をつけて可視化できるという点で、様々な形態解析に用いることができます。

このページの目標
  • PLYファイルの構造を知る
  • 自分でデータを入れてPLYファイルを作成する

1 PLYファイルの構造を見てみる

PLYファイルは

  • ヘッダー
  • 点情報と値(色、Quality)
  • 面を構成する点情報と値(色、Quality)

の順に記載されている。

まずはPLYファイルがどのような構造になっているか見てみます。
例えば、手首の骨を見た時に、骨1(bone1)と骨2(bone2)の距離を図り、骨1に色付けしたとします。

MeshLabで開いたPLYファイル

赤はより近い部分、青はより遠い部分になるように色付けされています。

このとき、実際に骨1の表面データには
「距離という値」
が入っています。
これが色で図示されているわけです。

このファイルの距離の情報はSTLでは保存されませんが、PLYというファイル形式であれば保存されます。
ここではPLY形式のASCII形式で保存して、テキストファイルで開いてみます。

bone1.ply

format ascii 1.0
comment VCGLIB generated
element vertex 23866
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
property uchar alpha
property float quality
element face 23802
property list uchar int vertex_indices
property uchar red
property uchar green
property uchar blue
property uchar alpha
end_header
-126.7488 -31.52647 -816.0538 0 0 255 255 120.3788
-126.4972 -31.27693 -815.8904 0 0 255 255 120.3788
-126.4011 -31.52209 -816.0673 0 0 255 255 120.3788
-127.0804 -31.64915 -816.0208 0 0 255 255 120.3788
-127.0749 -31.37141 -815.8459 0 0 255 255 120.3788
-127.4964 -31.62467 -815.8231 0 0 255 255 120.3788
-123.8012 -32.81599 -816.433 0 0 255 255 120.3788



3 13771 13847 13851 255 255 255 255
3 13776 13771 13851 255 255 255 255
3 13777 13776 13852 255 255 255 255
3 13776 13851 13852 255 255 255 255
3 13853 13852 13854 255 255 255 255
3 13853 13778 13852 255 255 255 255
3 13778 13777 13852 255 255 255 255
3 13778 13853 13780 255 255 255 255



謎の英語のあとに数字の羅列がみられます。

よくみると数字は2つの部分からできています。

element vertexというのが点の数、
element faceというのが面の数ですね

始めの数字の1行目をとってみると、

-126.7488 -31.52647 -816.0538 0 0 255 255 120.3788

となります。
これが
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
property uchar alpha
property float quality
の部分に対応します。 
つまり、

-126.7488 -31.52647 -816.0538
が点の x, y, z座標

0 0 255 255
は色(赤 緑 青 透明度)

120.3788
が値(この場合は距離)

です。

この
float qualityに値を入れているのがポイントです。

3 13771 13847 13851 255 255 255 255
3 13776 13771 13851 255 255 255 255
3 13777 13776 13852 255 255 255 255
3 13776 13851 13852 255 255 255 255
3 13853 13852 13854 255 255 255 255
3 13853 13778 13852 255 255 255 255
3 13778 13777 13852 255 255 255 255
3 13778 13853 13780 255 255 255 255


property list uchar int vertex_indices
property uchar red
property uchar green
property uchar blue
property uchar alpha
に対応しています。

始めの
3
は、3つの点から面が構成されていることを示します。

13771 13847 13851
は3点を表します。
ここで、点は始めの数字列の中で出てきた番号を示しています。

255 255 255 255
は色(赤 緑 青 透明度)です。
このモデルはすべて255なので、面自体には色付けされていないことがわかります。
Meshlab上でもColorの欄をVertからFaceに切り替えると真っ白になります。

Vert(頂点)だと色がついています

Face(面)にすると真っ白です
 

2 PLYデータの作成

形式を知ると、自分で計算した結果をplyファイルで表示できるようになります。
結果を可視化できるという面で、いろいろな解析に使用できます。

順序としては

stlファイルから点情報と面情報を取り出す

stlで計算を行う

値をstlから得た点にひも付けする。

ply形式で書き出す。

という流れです。

点が数万個になっちゃうと大変そうですね。
だからPythonで書き出すんだってば。

(1)stlデータから点と面データの抽出

例として、犬の形をしたstlのデータを使用します。

dog.stl

stlデータの抽出にはnumpy-stlを用います。

import numpy as np
from stl import mesh

surface = mesh.Mesh.from_file('dog.stl')
point_list = surface.points.reshape([-1, 3])
print(len(point_list))
# 298272
print(point_list)

[[-2.6301 6.9699 15.6182]
[-2.6115 7.205 15.5955]
[-2.7722 7.1841 15.4071]

[ 2.8899 -9.5252 24.7799]
[ 2.8352 -9.4917 24.8507]
[ 2.8318 -9.478 24.8437]]

これは三角形を構成する点同士がたくさんならんでいる状態です。

三角形1の点1のx,y,z
三角形1の点2のx,y,z
三角形1の点3のx,y,z
三角形2の点1のx,y,z
三角形2の点2のx,y,z
三角形2の点3のx,y,z
三角形3の点1のx,y,z

という状態なので、plyの形式どおり、

  • 点のデータ
  • 三角形の頂点の番号

にわけたいと思います。
重複を削除するために
「numpy.unique」
を使用します。

vertices, vertex_indices = np.unique(point_list, return_inverse=True, axis=0)

point_listの中で重複を削除したリストがverticesに入り、
それぞれの点のverticesのインデックス番号がvertex_indicesに入ります。

print(len(vertices))
# 49714
print(vertices)
#[[-5.7769 16.6657  0.4585]
# [-5.7701 16.8729  0.5121]
# [-5.7679 16.8331  0.6828]
# ...

print(vertex_indices)
# [12173 12257 11565 ... 38652 38419 38407]
# 重複をリストにし、verticesに対応するリストのインデックスを返す

 
3つずつくくってやると、三角形のインデックス番号が並びます。

index_triangle = vertex_indices.reshape([-1, 3])
print(index_triangle)

[[12173 12257 11565]
[12173 11565 11472]
[12062 12173 11472]

[38875 38669 38652]
[38652 38669 38419]
[38652 38419 38407]]

(2)plyに書き込む

plyファイルはヘッダーで指定してやれば点の座標値とqualityだけでも成立します。

ここではテストとして、犬のstlのデータの
qualityにy座標の値を指定
して.plyファイルを作成してみます。

構造は以下の通りです。

作成するplyファイル

ply
format ascii 1.0
element vertex “点の数”
property float x
property float y
property float z
property float quality
element face “三角形の数”
property list uchar int vertex_indices
end_header
点1のx, y, z, quality
点2のx, y, z, quality


3, 三角形1の点1のインデックス,点2のインデックス, 点3のインデックス,
3, 三角形2の点1のインデックス,点2のインデックス, 点3のインデックス,


これをPythonで記載します。
座標データとqualityデータの結合にはnumpy.concatenateを使用しています。

import numpy as np
from stl import mesh

"""Extract point and face data from .stl file"""
file_name =('dog_test.ply')
dog_stl = mesh.Mesh.from_file('dog.stl')
points = dog_stl.points.reshape([-1, 3])
vertices, vertex_indices = np.unique(points, return_inverse=True, axis=0)
#点の重複を削除し、それぞれのインデックスを取得
index_triangle = vertex_indices.reshape([-1, 3])
#三角形を構成する点のインデックス一覧を取得

"""write header"""
header = (
'ply\n\
format ascii 1.0\n\
element vertex {}\n\
property float x\n\
property float y\n\
property float z\n\
property float quality\n\
element face {}\n\
property list uchar int vertex_indices\n\
end_header\n').format(len(vertices),len(index_triangle)
)
# element vertexとelement faceの部分はstlからの値を代入
  
with open(file_name, 'w') as f:
    f.write(header)

"""write text for point data"""
qualities = np.array([vertices[:, 1]]).T
# y座標をqualityに設定し、縦1列の行列にする
vertices_text = np.concatenate([vertices, qualities], axis=1)
# x,y,z座標の後ろにqualityを付け加える

with open(file_name, 'a') as f:
    np.savetxt(f, vertices_text, fmt='%.5f')
# 'a'モードで点情報を上書き追記する

"""write text for face data"""
first_indices = np.full([len(index_triangle), 1], 3)
face_txt =np.concatenate([first_indices, index_triangle], axis=1)
# 三角形である'3'を先頭に記載してから三角形の点インデックスを記載する

with open(file_name, 'a') as f:
    np.savetxt(f, face_txt, fmt='%i')
#上書きで三角形の情報を追記する

“dog_test.ply”というplyデータが作成されました。

3 PLYデータの確認

“dog_test.ply”をテキストファイルで開くと

dog_test.ply

ply
format ascii 1.0
element vertex 49714
property float x
property float y
property float z
property float quality
element face 99424
property list uchar int vertex_indices
end_header
-5.77690 16.66570 0.45850 16.66570
-5.77010 16.87290 0.51210 16.87290
-5.76790 16.83310 0.68280 16.83310


3 12173 12257 11565
3 12173 11565 11472
3 12062 12173 11472
3 12062 11472 11382
3 12173 12062 12870
3 12173 12870 12997


qualityの欄にy座標の値が入っています。

これをMeshlabで開きます。

右上のカラフルなうさぎのボタンをおすと、「QualityMapperDialog」というウィンドウが開きます。
これは、Qualityにカラーマップを付けくれるダイアログです。
「Apply」を押すとMapperが適応されて、plyに色がつきます。

Y軸の大きいほうがQualityの大きい赤色になっていることがわかります。
 
Qualityの範囲の点だけ選ぶこともできます。

「Filters」 ⇒ 「Quality Measure and Computation」⇒ 「Select by Vertex Quality」を選びます。

Previewをクリックしてから、Qualityの範囲を選ぶと、範囲内のQualityをもった点が選択されます。

表面データの点や面に対応した値を計算し、それを可視化できるととてもわかりやすいです。 PLYはそういった点で便利な形式ですね。