[3D CV] Extract surface meshes from 3D points with Delaunay triangulation
3D ํฌ์ธํธ ํด๋ผ์ฐ๋์์ ์ ์ฒด๋ฅผ ๋ชจ๋ธ๋งํ ๋๋ 3D Delaunay triangulation์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
3D Delaunay triangulation์ ์ฌ๋ฉด์ฒด(tetrahedra)๋ฅผ ์์ฑํ์ง๋ง, ์ฐ๋ฆฌ๋ ํ๋ฉด ๋ฉ์๋ง ํ์ํ๋ฏ๋ก ์ฌ๋ฉด์ฒด์ ์ธ๋ถ ๋ฉด(2D surfaces)๋ง ์ถ์ถํ์ฌ ์ฌ์ฉํ ๊ฒ์ ๋๋ค.
์ด๋ฅผ ์ํด scipy.spatial import Delaunay
๋ก point cloud
์ ๋ํ Delaunay
๊ฐ์ฒด๋ฅผ tri
๋ณ์๋ก ์์ฑํ๊ณ , simplices
๋ฅผ ์ฌ์ฉํฉ๋๋ค.
simplices
In geometry, a simplex (plural: simplexes or simplices) is a generalization of the notion of a triangle or tetrahedron to arbitrary dimensions. The simplex is so-named because it represents the simplest possible polytope in any given dimension. For example,
- a 0-dimensional simplex is a point,
- a 1-dimensional simplex is a line segment,
- a 2-dimensional simplex is a triangle,
- a 3-dimensional simplex is a tetrahedron, and
- a 4-dimensional simplex is a 5-cell.
The four simplexes that can be fully represented in 3D space.
โฆ the word โsimplexโ simply means any finite set of vertices. (์ํคํผ๋์์์ ๋จ์ํ๊ฒ ํํ)
โsimplexโ๋ ๋จ์ํ ์ ๋ค์ ์งํฉ์ด๋ผ๊ธฐ๋ณด๋ค๋, ๊ทธ ์ ๋ค์ด ์ด๋ฃจ๋ ๊ตฌ์ฒด์ ์ธ ๊ธฐํํ์ ํ์์ ์๋ฏธํ๋ ๊ฒ์ด ๋ ์ ํํฉ๋๋ค.
๋ฐ๋ผ์, Delaunay ๊ฐ์ฒด์ simplices๋ vertices(์ )๋ก ์ด๋ฃจ์ด์ง ์ผ๊ฐํ(๋๋ 3D์ ๊ฒฝ์ฐ ์ฌ๋ฉด์ฒด)์ ์๋ฏธํฉ๋๋ค.
Faces are simplices themselves. (์ํคํผ๋์ ์ค๋ช )
๋ชจ๋ simplex๋ ํ์ ์ฐจ์์ simplex๋ค์ ํฌํจํ๊ณ ์์ผ๋ฉฐ, ์ด๋ฅผ face๋ผ๊ณ ๋ถ๋ฆ ๋๋ค.
์๋ฅผ ๋ค์ด:
- ์ผ๊ฐํ(2์ฐจ์ simplex)์ face๋ ๊ทธ ์ผ๊ฐํ์ ์ด๋ฃจ๋ ๋ณ(1์ฐจ์ simplex)์ ๋๋ค.
- ์ฌ๋ฉด์ฒด(3์ฐจ์ simplex)์ face๋ ๊ทธ ์ฌ๋ฉด์ฒด๋ฅผ ์ด๋ฃจ๋ ์ผ๊ฐํ(2์ฐจ์ simplex)์ ๋๋ค.
์ฌ๋ฉด์ฒด(3์ฐจ์ simplex)์์ ์ผ๊ฐํ(2์ฐจ์ simplex)๊ฐ face์ ๋๋ค.
์ฌ๋ฉด์ฒด(3์ฐจ์ simplex)๋ ๋ค ๊ฐ์ ๊ผญ์ง์ ์ผ๋ก ๊ตฌ์ฑ๋ ์ ์ฒด ๋ํ์ด๋ฉฐ, ์ด ์ฌ๋ฉด์ฒด๋ ๋ค ๊ฐ์ ์ผ๊ฐํ ๋ฉด์ ๊ฐ์ง๋๋ค. ๊ฐ๊ฐ์ ์ผ๊ฐํ ๋ฉด์ ์ฌ๋ฉด์ฒด์ face๋ฅผ ๊ตฌ์ฑํ๋ฉฐ, ์ด ์ผ๊ฐํ ๋ฉด๋ค์ด ๋ชจ์ฌ ์ฌ๋ฉด์ฒด์ ํ๋ฉด ๋ฉ์(surface mesh)๋ฅผ ํ์ฑํฉ๋๋ค.
์ค์ ์ฝ๋
Triangulation of a set of points:
import numpy as np
points = np.array([[0, 0], [0, 1.1], [1, 0], [1, 1]])
from scipy.spatial import Delaunay
tri = Delaunay(points)
points๋ 4๊ฐ์ ์ขํ๊ฐ ๋ค์ด์๋ 2์ฐจ์ NumPy ๋ฐฐ์ด์ ๋๋ค. ๊ฐ๊ฐ์ ์ขํ๋ (x, y) ํํ๋ก ๋์ด ์์ฃ .
- points[:, 0]์ ๋ชจ๋ ํ์์ ์ฒซ ๋ฒ์งธ ์ด(์ฆ, x ์ขํ๋ค)์ ์ ํํฉ๋๋ค.
- points[:, 1]์ ๋ชจ๋ ํ์์ ๋ ๋ฒ์งธ ์ด(์ฆ, y ์ขํ๋ค)์ ์ ํํฉ๋๋ค.
์๋ฅผ ๋ค์ด:
- points[:, 0]์ [0, 0, 1, 1]์ด ๋๊ณ , ์ด๋ x ์ขํ๋ค์ ๋๋ค.
- points[:, 1]์ [0, 1.1, 0, 1]์ด ๋๊ณ , ์ด๋ y ์ขํ๋ค์ ๋๋ค.
์ด ๊ฐ๋ค์ ๊ทธ๋ํ๋ฅผ ๊ทธ๋ฆด ๋ x์ถ๊ณผ y์ถ ์ขํ๋ก ์ฌ์ฉ๋ฉ๋๋ค. plt.triplot๊ณผ plt.plot์์ ๊ฐ๊ฐ x ์ขํ์ y ์ขํ๋ฅผ ์ง์ ํ๋ ์ญํ ์ ํฉ๋๋ค.
We can plot it:
import matplotlib.pyplot as plt
plt.triplot(points[:,0], points[:,1], tri.simplices)
plt.plot(points[:,0], points[:,1], 'o')
plt.show()
Point indices and coordinates for the two triangles forming the triangulation:
tri.simplices
array([[2, 3, 0], # may vary
[3, 1, 0]], dtype=int32)
Note that depending on how rounding errors go, the simplices may be in a different order than above.
points[tri.simplices]
array([[[ 1. , 0. ], # may vary
[ 1. , 1. ],
[ 0. , 0. ]],
[[ 1. , 1. ],
[ 0. , 1.1],
[ 0. , 0. ]]])
import open3d
import numpy as np
# Example mesh
# x, y coordinates:
# [0: (-1, 2)]__________[1: (1, 2)]
# \ /\
# \ (0) / \
# \ / (1)\
# \ / \
# [2: (0, 0)]\/________\[3: (2, 0)]
#
# z coordinate: 0
mesh = open3d.geometry.TriangleMesh()
np_vertices = np.array([[-1, 2, 0],
[1, 2, 0],
[0, 0, 0],
[2, 0, 0]])
np_triangles = np.array([[0, 2, 1],
[1, 2, 3]]).astype(np.int32)
mesh.vertices = open3d.Vector3dVector(np_vertices)
# From numpy to Open3D
mesh.triangles = open3d.Vector3iVector(np_triangles)
# From Open3D to numpy
np_triangles = np.asarray(mesh.triangles)
Code ๊ตฌํ
import open3d as o3d
import numpy as np
from scipy.spatial import Delaunay
def extract_surface_mesh(tetra):
# ๊ฐ ์ฌ๋ฉด์ฒด์ ๋ฉด์ ์ถ์ถ
faces = np.vstack((
tetra[:, [0, 1, 2]],
tetra[:, [0, 2, 3]],
tetra[:, [0, 1, 3]],
tetra[:, [1, 2, 3]]
))
# ์ค๋ณต ๋ฉด ์ ๊ฑฐ (ํ๋ฉด ๋ฉด๋ง ๋จ๊น)
faces = np.sort(faces, axis=1)
faces, counts = np.unique(faces, return_counts=True, axis=0)
surface_faces = faces[counts == 1]
return surface_faces
def barycentric_deformation(GT, BP, GT_colors, BP_colors):
print("\n Processing Barycentric Deformation.. \n")
gt_pcd = o3d.geometry.PointCloud()
gt_pcd.points = o3d.utility.Vector3dVector(GT)
gt_pcd.colors = o3d.utility.Vector3dVector(GT_colors / 255.0)
bp_pcd = o3d.geometry.PointCloud()
bp_pcd.points = o3d.utility.Vector3dVector(BP)
bp_colors = o3d.utility.Vector3dVector(BP_colors / 255.0)
# Create a mesh from BP using 3D Delaunay triangulation
bp_points = np.asarray(bp_pcd.points)
tri = Delaunay(bp_points)
surface_faces = extract_surface_mesh(tri.simplices)
Leave a comment