繁体   English   中英

将行进立方体中的索引转换为原始 x、y、z 空间 - 可视化等值面 3d skimage

[英]Converting indices in marching cubes to original x,y,z space - visualizing isosurface 3d skimage

我想在 x1、x2、x3 空间中绘制一个体积。 该体积是由 skimage 中的行进立方体算法找到的等值线。 生成卷的 function 是pdf_grid = f(x1,x2,x3)


我想绘制 pdf = 60% max(pdf) 的体积。

我的问题是行进立方体算法生成顶点和面,但我如何 map 将它们返回到 x1、x2、x3 空间?

我(相当有限)对行进立方体的理解是“顶点”指的是体积中的索引(在我的例子中是 pdf_grid)。 如果“顶点”仅包含网格中的确切索引,这将很容易,但“顶点”包含浮点数而不是整数。 似乎行进立方体在网格点之间做了一些插值(根据https://www.cs.carleton.edu/cs_comps/0405/shape/marching_cubes.html ),所以问题是如何准确恢复 x1 的值,x2,x3?

import numpy as np
import scipy.stats
import matplotlib.pyplot as plt

#Make some random data
cov = np.array([[1, .2, -.5],
                [.2, 1.2, .1],
                [-.5, .1, .8]])
dist = scipy.stats.multivariate_normal(mean = [1., 3., 2], cov = cov)
N = 500
x_samples = dist.rvs(size=N).T

#Create the kernel density estimator - approximation of a pdf
kernel = scipy.stats.gaussian_kde(x_samples)
x_mean = x_samples.mean(axis=1)
#Find the mode
res = scipy.optimize.minimize(lambda x: -kernel.logpdf(x),
                                 x_mean #x0, initial guess
                                 )
x_mode = res["x"]

num_el = 50 #number of elements in the grid
x_min = np.min(x_samples, axis = 1)
x_max = np.max(x_samples, axis = 1)
x1g, x2g, x3g = np.mgrid[x_min[0]:x_max[0]:num_el*1j,
                         x_min[1]:x_max[1]:num_el*1j,
                         x_min[2]:x_max[2]:num_el*1j
                         ]

pdf_grid = np.zeros(x1g.shape) #implicit function/grid for the marching cubes
for an in range(x1g.shape[0]):
    for b in range(x1g.shape[1]):
        for c in range(x1g.shape[2]):
            pdf_grid[a,b,c] = kernel(np.array([x1g[a,b,c],
                                      x2g[a,b,c],
                                      x3g[a,b,c]]
                                      ))

from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from skimage import measure

iso_level = .6 #draw a volume which contains pdf_val(mode)*60%
verts, faces, normals, values = measure.marching_cubes(pdf_grid, kernel(x_mode)*iso_level)

#How to convert the figure back to x1,x2,x3 space? I just draw the output as it was done in the skimage example here https://scikit-image.org/docs/0.16.x/auto_examples/edges/plot_marching_cubes.html#sphx-glr-auto-examples-edges-plot-marching-cubes-py so you can see the volume

# Fancy indexing: `verts[faces]` to generate a collection of triangles
mesh = Poly3DCollection(verts[faces], 
                        alpha = .5, 
                        label = f"KDE = {iso_level}"+r"$x_{mode}$",
                        linewidth = .1)
mesh.set_edgecolor('k')


fig, ax = plt.subplots(subplot_kw=dict(projection='3d'))

c1 = ax.add_collection3d(mesh)
c1._facecolors2d=c1._facecolor3d
c1._edgecolors2d=c1._edgecolor3d

#Plot the samples. Marching cubes volume does not capture these samples
pdf_val = kernel(x_samples) #get density value for each point (for color-coding)
x1, x2, x3 = x_samples
scatter_plot = ax.scatter(x1, x2, x3, c=pdf_val, alpha = .2, label = r" samples")
ax.scatter(x_mode[0], x_mode[1], x_mode[2], c = "r", alpha = .2, label = r"$x_{mode}$")

ax.set_xlabel(r"$x_1$")
ax.set_ylabel(r"$x_2$")
ax.set_zlabel(r"$x_3$")
# ax.set_box_aspect([np.ptp(i) for me in x_samples])  # equal aspect ratio

cbar = fig.color bar(scatter_plot, ax=ax)
cbar.set_label(r"$KDE(w) \approx pdf(w)$")
ax.legend()

#Make the axis limit so that the volume and samples are shown.
ax.set_xlim(- 5, np.max(verts, axis=0)[0] + 3)
ax.set_ylim(- 5, np.max(verts, axis=0)[1] + 3)
ax.set_zlim(- 5, np.max(verts, axis=0)[2] + 3)

在此处输入图像描述

这可能是帮助 OP 的答案太晚了,但如果其他人遇到这篇文章寻找解决这个问题的方法,问题源于行进立方体算法输出数组空间中的相关顶点。 该空间由网格每个维度的元素数量定义,行进立方体算法确实在该空间中进行了一些插值(解释了浮点数的存在)。

无论如何,为了将顶点转换回 x1、x2、x3 空间,您只需要按适当的数量缩放和移动它们。 这些量分别由范围、网格的元素数量和每个维度中的最小值定义。 因此,使用 OP 中定义的变量,以下将提供顶点的实际位置:

verts_actual = verts*((x_max-x_min)/pdf_grid.shape) + x_min

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM