[英]Delaunay Triangulation of points from 2D surface in 3D with python?
我有一个 3D 点的集合。 这些点以恒定水平 (z=0,1,...,7) 采样。 一张图片应该清楚:
这些点位于称为X
的形状为(N, 3)
的 numpy ndarray 中。 上面的图是使用以下方法创建的:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
X = load('points.npy')
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_wireframe(X[:,0], X[:,1], X[:,2])
ax.scatter(X[:,0], X[:,1], X[:,2])
plt.draw()
我只想对这个对象的表面进行三角测量,然后绘制表面。 但是,我不想要这个对象的凸包,因为这会丢失我希望能够检查的细微形状信息。
我试过ax.plot_trisurf(X[:,0], X[:,1], X[:,2])
,但这导致以下混乱:
有什么帮助吗?
这是生成代表问题的 3D 数据的片段:
import numpy as np
X = []
for i in range(8):
t = np.linspace(0,2*np.pi,np.random.randint(30,50))
for j in range(t.shape[0]):
# random circular objects...
X.append([
(-0.05*(i-3.5)**2+1)*np.cos(t[j])+0.1*np.random.rand()-0.05,
(-0.05*(i-3.5)**2+1)*np.sin(t[j])+0.1*np.random.rand()-0.05,
i
])
X = np.array(X)
这是原始数据的粘贴箱:
以下是沿常数 z 的切片:
这是我在更新 2 中描述的具体示例。如果您没有用于可视化的mayavi
,我建议使用edm install mayavi pyqt matplotlib
通过 edm安装它。
from matplotlib import path as mpath
from mayavi import mlab
import numpy as np
def make_star(amplitude=1.0, rotation=0.0):
""" Make a star shape
"""
t = np.linspace(0, 2*np.pi, 6) + rotation
star = np.zeros((12, 2))
star[::2] = np.c_[np.cos(t), np.sin(t)]
star[1::2] = 0.5*np.c_[np.cos(t + np.pi / 5), np.sin(t + np.pi / 5)]
return amplitude * star
def make_stars(n_stars=51, z_diff=0.05):
""" Make `2*n_stars-1` stars stacked in 3D
"""
amps = np.linspace(0.25, 1, n_stars)
amps = np.r_[amps, amps[:-1][::-1]]
rots = np.linspace(0, 2*np.pi, len(amps))
zamps = np.linspace
stars = []
for i, (amp, rot) in enumerate(zip(amps, rots)):
star = make_star(amplitude=amp, rotation=rot)
height = i*z_diff
z = np.full(len(star), height)
star3d = np.c_[star, z]
stars.append(star3d)
return stars
def polygon_to_boolean(points, xvals, yvals):
""" Convert `points` to a boolean indicator mask
over the specified domain
"""
x, y = np.meshgrid(xvals, yvals)
xy = np.c_[x.flatten(), y.flatten()]
mask = mpath.Path(points).contains_points(xy).reshape(x.shape)
return x, y, mask
def plot_contours(stars):
""" Plot a list of stars in 3D
"""
n = len(stars)
for i, star in enumerate(stars):
x, y, z = star.T
mlab.plot3d(*star.T)
#ax.plot3D(x, y, z, '-o', c=(0, 1-i/n, i/n))
#ax.set_xlim(-1, 1)
#ax.set_ylim(-1, 1)
mlab.show()
if __name__ == '__main__':
# Make and plot the 2D contours
stars3d = make_stars()
plot_contours(stars3d)
xvals = np.linspace(-1, 1, 101)
yvals = np.linspace(-1, 1, 101)
volume = np.dstack([
polygon_to_boolean(star[:,:2], xvals, yvals)[-1]
for star in stars3d
]).astype(float)
mlab.contour3d(volume, contours=[0.5])
mlab.show()
我现在这样做:
matplotlib.path
来确定轮廓内外的点。 使用这个想法,我将每个切片中的轮廓转换为一个布尔值图像,该图像组合成一个布尔值体积。skimage
的marching_cubes
方法获取表面的三角剖分以进行可视化。这是该方法的一个示例。 我认为数据略有不同,但您绝对可以看到结果更清晰,并且可以处理断开连接或有孔的表面。
好的,这是我想出的解决方案。 这在很大程度上取决于我的数据大致是球形的,并且我认为在 z 中均匀采样。 其他一些评论提供了有关更强大解决方案的更多信息。 由于我的数据大致是球形的,因此我根据数据点的球坐标变换对方位角和天顶角进行三角测量。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.tri as mtri
X = np.load('./mydatars.npy')
# My data points are strictly positive. This doesn't work if I don't center about the origin.
X -= X.mean(axis=0)
rad = np.linalg.norm(X, axis=1)
zen = np.arccos(X[:,-1] / rad)
azi = np.arctan2(X[:,1], X[:,0])
tris = mtri.Triangulation(zen, azi)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(X[:,0], X[:,1], X[:,2], triangles=tris.triangles, cmap=plt.cm.bone)
plt.show()
使用来自上述 pastebin 的样本数据,这会产生:
我意识到您在问题中提到您不想使用凸包,因为您可能会丢失一些形状信息。 我有一个简单的解决方案,适用于您的“抖动球形”示例数据,尽管它确实使用了scipy.spatial.ConvexHull
。 我想无论如何我都会在这里分享它,以防万一它对其他人有用:
from matplotlib.tri import triangulation
from scipy.spatial import ConvexHull
# compute the convex hull of the points
cvx = ConvexHull(X)
x, y, z = X.T
# cvx.simplices contains an (nfacets, 3) array specifying the indices of
# the vertices for each simplical facet
tri = Triangulation(x, y, triangles=cvx.simplices)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.hold(True)
ax.plot_trisurf(tri, z)
ax.plot_wireframe(x, y, z, color='r')
ax.scatter(x, y, z, color='r')
plt.draw()
在这种情况下它做得很好,因为您的示例数据最终位于或多或少的凸面上。 也许您可以制作一些更具挑战性的示例数据? 环面将是一个很好的测试用例,凸包方法显然会失败。
从点云映射任意 3D 表面是一个非常棘手的问题。 这是一个相关的问题,其中包含一些可能有用的链接。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.