After awhole day of searching, in desperation, I address to you, my dear fellows. I want to draw a 3D surface of human head, for which I have found nice of 3D coordinates (you can download it from my Google drive here). Using 3D scatter plot, everything looks beautiful: enter image description here

For my further purposes, I'd like to plot it as a 3D surface as it looks like in real life. As far as I could conclude, the best way to do so in matplotlib is plot_trisurf function, where one can explicitly put ther points' coordinates and enjoy the result, however, for the same coordinates as in the scatter plot above, I recieve the following ugly result: enter image description here

问题似乎是,三角形是由随机的三个点组成的,而不是最近的点.

我试图对这些点进行排序,以最小化相邻点之间的距离,但没有效果.我还试图重现所有matplotlib示例中基本使用的基于网格的曲面绘制.所有这些都没有奏效.我也考虑过使用其他库,但它们大多要么基于matplotlib,要么是交互式的.后者有点过头了,因为我将在实时计算中使用它,因此坚持使用matplotlib API是优先的. 这个 idea 似乎很基本:通过染色最近的三个点的三角形,通过3D坐标绘制一个曲面,尽管我没有找到这样的函数.希望你们中的任何人都知道可以做些什么来克服这个问题.先谢谢你.

推荐答案

只要找到三角形顶点的正确顺序,就可以使用plt.plot_trisurf(...)函数在散点图上绘制3D曲面.SciPy有一个名为ConvexHull的函数,它可以找到数据集外部的点的简化值.这非常方便,但在这个示例中不会立即起作用,因为您的数据集不是凸的!

解决方案是通过将点扩展到远离中心直到它们形成球体来使数据凸起.有关这一点的可视化,请参见下面的内容.

Head expanding to sphere

在将头部变成球体后,现在可以调用ConvexHull(...)来进行所需的三角测量.此三角剖分可以首先应用于球形头部(见下文).然后,头部可以缩小到原来的形式,三角剖分的顶点仍然有效!

The triangulation of the spherical head

这就是最终的产品!

Rotating triangulated head

代码

import numpy as np
import matplotlib.pyplot as plt
import csv
from scipy.spatial import KDTree
from scipy.spatial import ConvexHull
from matplotlib import cm
from matplotlib import animation

plt.style.use('dark_background')

# Data reader from a .csv file
def getData(file):
    lstX = []
    lstY = []
    lstZ = []
    with open(file, newline='\n') as f:
        reader = csv.reader(f, quoting=csv.QUOTE_NONNUMERIC)
        for row in reader:
            lstX.append(row[0])
            lstY.append(row[1])
            lstZ.append(row[2])
    return lstX, lstY, lstZ

# This function gets rid of the triangles at the base of the neck
# It just filters out any triangles which have at least one side longer than toler
def removeBigTriangs(points, inds, toler=35):
    newInds = []
    for ind in inds:
        if ((np.sqrt(np.sum((points[ind[0]]-points[ind[1]])**2, axis=0))<toler) and
            (np.sqrt(np.sum((points[ind[0]]-points[ind[2]])**2, axis=0))<toler) and
            (np.sqrt(np.sum((points[ind[1]]-points[ind[2]])**2, axis=0))<toler)):
            newInds.append(ind)
    return np.array(newInds)

# this calculates the location of each point when it is expanded out to the sphere
def calcSpherePts(points, center):
    kdtree = KDTree(points) # tree of nearest points
    # d is an array of distances, i is array of indices
    d, i = kdtree.query(center, points.shape[0])
    spherePts = np.zeros(points.shape, dtype=float)
    
    radius = np.amax(d)
    for p in range(points.shape[0]):
        spherePts[p] = points[i[p]] *radius /d[p]
    return spherePts, i # points and the indices for where they were in the original lists
    

x,y,z = getData(".\coords3Ddetailed.csv")

pts = np.stack((x,y,z), axis=1)

# generating data
spherePts, sphereInd = calcSpherePts(pts, [0,0,0])
hull = ConvexHull(spherePts)
triangInds = hull.simplices # returns the list of indices for each triangle
triangInds = removeBigTriangs(pts[sphereInd], triangInds)

# plotting!
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.scatter3D(pts[:,0], pts[:,1], pts[:,2], s=2, c='r', alpha=1.0)
ax.plot_trisurf(pts[sphereInd,0], pts[sphereInd,1], pts[sphereInd,2], triangles=triangInds, cmap=cm.Blues, alpha=1.0)
plt.show()

Python相关问答推荐

Pandas或pyspark跨越列创建

pandas MultiIndex是SQL复合索引的对应物吗?

如何从. text中进行pip安装跳过无法访问的库

回归回溯-2D数组中的单词搜索

如何使用scikit-learn Python库中的Agglomerative集群算法以及集群中声明的对象数量?

如何使用PyTest根据self 模拟具有副作用的属性

Python中使用时区感知日期时间对象进行时间算术的Incredit

如何让 turtle 通过点击和拖动来绘制?

Pandas 填充条件是另一列

如果条件为真,则Groupby.mean()

使用numpy提取数据块

从收件箱中的列中删除html格式

如何过滤包含2个指定子字符串的收件箱列名?

如何创建一个缓冲区周围的一行与manim?

在pandas中使用group_by,但有条件

当我try 在django中更新模型时,模型表单数据不可见

如何启动下载并在不击中磁盘的情况下呈现响应?

在Python中调用变量(特别是Tkinter)

AES—256—CBC加密在Python和PHP中返回不同的结果,HELPPP

python中csv. Dictreader. fieldname的类型是什么?'