Mesh

Open3D には三角メッシュのためのデータ構造がある。

注意: コードを走らせる環境に注意すること。TestDataディレクトリがカレント(作業)ディレクトリからみて、祖先ディレクトリの下にあることを確認しよう

In [2]:
# examples/Python/Basic/mesh.py

import copy
import numpy as np
import open3d as o3d

if __name__ == "__main__":
    # (1)Print vertices and triangles
    print("Testing mesh in open3d ...")
    mesh = o3d.io.read_triangle_mesh("../../TestData/knot.ply")
    print(mesh)
    print(np.asarray(mesh.vertices))
    print(np.asarray(mesh.triangles))
    print("")
    # (2)Visualize 3D mesh
    print("Try to render a mesh with normals (exist: " +
          str(mesh.has_vertex_normals()) + ") and colors (exist: " +
          str(mesh.has_vertex_colors()) + ")")
    o3d.visualization.draw_geometries([mesh])
    print("A mesh with no normals and no colors does not seem good.")
    # (3)Surface normal estimation
    print("Computing normal and rendering it.")
    mesh.compute_vertex_normals()
    print(np.asarray(mesh.triangle_normals))
    o3d.visualization.draw_geometries([mesh])
    # (4)Crop mesh
    print("We make a partial mesh of only the first half triangles.")
    mesh1 = copy.deepcopy(mesh)
    mesh1.triangles = o3d.utility.Vector3iVector(
        np.asarray(mesh1.triangles)[:len(mesh1.triangles) // 2, :])
    mesh1.triangle_normals = o3d.utility.Vector3dVector(
        np.asarray(mesh1.triangle_normals)[:len(mesh1.triangle_normals) //
                                           2, :])
    print(mesh1.triangles)
    o3d.visualization.draw_geometries([mesh1])
    # (5)Paint mesh
    print("Painting the mesh")
    mesh1.paint_uniform_color([1, 0.706, 0])
    o3d.visualization.draw_geometries([mesh1])
Testing mesh in open3d ...
geometry::TriangleMesh with 1440 points and 2880 triangles.
[[  4.51268387  28.68865967 -76.55680847]
 [  7.63622284  35.52046967 -69.78063965]
 [  6.21986008  44.22465134 -64.82303619]
 ...
 [-22.12651634  31.28466606 -87.37570953]
 [-13.91188431  25.4865818  -86.25827026]
 [ -5.27768707  23.36245346 -81.43279266]]
[[   0   12   13]
 [   0   13    1]
 [   1   13   14]
 ...
 [1438   11 1439]
 [1439   11    0]
 [1439    0 1428]]

Try to render a mesh with normals (exist: False) and colors (exist: False)
A mesh with no normals and no colors does not seem good.
Computing normal and rendering it.
[[ 0.79164373 -0.53951444  0.28674793]
 [ 0.8319824  -0.53303008  0.15389681]
 [ 0.83488162 -0.09250101  0.54260136]
 ...
 [ 0.16269924 -0.76215917 -0.6266118 ]
 [ 0.52755226 -0.83707495 -0.14489352]
 [ 0.56778973 -0.76467734 -0.30476777]]
We make a partial mesh of only the first half triangles.
std::vector<Eigen::Vector3i> with 1440 elements.
Use numpy.asarray() to access data.
Painting the mesh

(ノードと三角の表示)

次はexamples/Python/Basic/mesh.pyの最初の部分コード:

In [ ]:
    # (1)Print vertices and triangles
    print("Testing mesh in open3d ...")
    mesh = o3d.io.read_triangle_mesh("../../TestData/knot.ply")
    print(mesh)
    print(np.asarray(mesh.vertices))
    print(np.asarray(mesh.triangles))
    print("")

この出力は

TriangleMesh with 1440 points and 2880 triangles.
[[  4.51268387  28.68865967 -76.55680847]
 [  7.63622284  35.52046967 -69.78063965]
 [  6.21986008  44.22465134 -64.82303619]
 ...,
 [-22.12651634  31.28466606 -87.37570953]
 [-13.91188431  25.4865818  -86.25827026]
 [ -5.27768707  23.36245346 -81.43279266]]
[[   0   12   13]
 [   0   13    1]
 [   1   13   14]
 ...,
 [1438   11 1439]
 [1439   11    0]
 [1439    0 1428]]

TriangleMeshクラスには、頂点や三角形などのいくつかのデータフィールドがある。 Open3Dは、numpy配列を介してこれらのフィールドへの直接的なメモリ・アクセスを提供する。

Visualize 3D mesh

3D メッシュの可視化

次はexamples/Python/Basic/mesh.pyの2番めの部分コード:

In [ ]:
    # (2)Visualize 3D mesh
    print("Try to render a mesh with normals (exist: " +
          str(mesh.has_vertex_normals()) + ") and colors (exist: " +
          str(mesh.has_vertex_colors()) + ")")
    o3d.visualization.draw_geometries([mesh])
    print("A mesh with no normals and no colors does not seem good.")

これによりメッシュを可視化する。 http://www.open3d.org/docs/release/_images/without_shading.png

メッシュを回転したり移動したりすることはできるが、灰色で均一に塗られており、「3d」のように見えない。その理由は、この時点のメッシュに頂点や面の法線がないためである。 したがって、より洗練されたPhongシェーディングの代わりに、均一なカラーシェーディングが使用される。

Surface normal estimation

(表面法線推定) 表面法線でメッシュを書くことにしよう。

次はexamples/Python/Basic/mesh.pyの3番目の部分コード:

In [ ]:
    # (3)Surface normal estimation
    print("Computing normal and rendering it.")
    mesh.compute_vertex_normals()
    print(np.asarray(mesh.triangle_normals))
    o3d.visualization.draw_geometries([mesh])
Computing normal and rendering it.
[[ 0.79164373 -0.53951444  0.28674793]
 [ 0.8319824  -0.53303008  0.15389681]
 [ 0.83488162 -0.09250101  0.54260136]
 ...
 [ 0.16269924 -0.76215917 -0.6266118 ]
 [ 0.52755226 -0.83707495 -0.14489352]
 [ 0.56778973 -0.76467734 -0.30476777]]

これはmeshモジュールの関数のcompute_vertex_normalspaint_uniform_color を用いて次のような表示を行う: http://www.open3d.org/docs/release/_images/with_shading.png

Crop mesh

この三角メッシュとtriangle_normalsデータに直接操作し、半分くらいを削除しよう。それにはnumpy配列を介して行う。

次はexamples/Python/Basic/mesh.pyの4番目の部分コード:

In [ ]:
    # (4)Crop mesh
    print("We make a partial mesh of only the first half triangles.")
    mesh1 = copy.deepcopy(mesh)
    mesh1.triangles = o3d.utility.Vector3iVector(
        np.asarray(mesh1.triangles)[:len(mesh1.triangles) // 2, :])
    mesh1.triangle_normals = o3d.utility.Vector3dVector(
        np.asarray(mesh1.triangle_normals)[:len(mesh1.triangle_normals) //
                                           2, :])
    print(mesh1.triangles)
    o3d.visualization.draw_geometries([mesh1])

その結果は: http://www.open3d.org/docs/release/_images/half.png

Paint mesh

メッシュの色付けは、ポイントクラウドと同様に行える。

次はexamples/Python/Basic/mesh.pyの最後の部分コード:

In [ ]:
    # (5)Paint mesh
    print("Painting the mesh")
    mesh1.paint_uniform_color([1, 0.706, 0])
    o3d.visualization.draw_geometries([mesh1])

その結果: http://www.open3d.org/docs/release/_images/half_color.png