基于open3d重建点云表面

前面我们获得了PSF的点云数据,这里可以进一步通过 open3d 模块提供的泊松曲面重建功能来计算得到surface。

Pasted-image-20240927082635.png-5cf0e60e75.png

结果如上所示,分别是k3d中作的三维点云,使用alphashape方法重建的点云表面,和使用泊松重建的曲面。完整代码如下:

import matplotlib.pyplot as plt
from aicsimageio import AICSImage
from glob import glob
import numpy as np
import open3d as o3d
from sklearn.cluster import DBSCAN
fps = glob("*.czi")
a = AICSImage(fps[1])
data = a.get_image_data("ZYX", C=0)
zs, ys, xs = np.where(data>0)
locs = np.vstack([xs, ys, zs]).T
# 第一次聚类用于去噪
clustering = DBSCAN(eps=3, min_samples=3).fit(locs)
inds = np.where(clustering.labels_>-1)
locs2 = locs[inds]
# 第二次聚类用于分开不同的大cluster
clustering2 = DBSCAN(eps=10, min_samples=3).fit(locs2)
# 取其中一个点云cluster进行尝试
inds3 = np.where(clustering2.labels_==3)
locs3 = locs2[inds3]
# 转换为o3d的点云对象
pt = o3d.geometry.PointCloud()
pt.points = o3d.utility.Vector3dVector(locs3)
# 使用 alphashape 计算点云的表面
mesh1 = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pt, alpha=2)
# alpha参数越大,表面越光滑,但可能舍弃的点越多
mesh1.compute_vertex_normals()
# 查看 alphashape 方法得到的 mesh
# o3d.visualization.draw_geometries([pt, mesh1], width=400, height=300, mesh_show_back_face=True)
# 基于泊松方法重建点云表面
pt2 = mesh1.sample_points_poisson_disk(len(locs3))
# disk可以输入一个整数,代表采样密度,如果一个单位体积中点密度高,这个数值就写高点
pt2.estimate_normals()
mesh2, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pt2, depth=3)
mesh2.compute_vertex_normals()
# 按照密度上伪彩
d = np.asarray(densities)
dc = plt.get_cmap('plasma')((d-d.min())/(d.max()-d.min()))
dc = dc[:,:3]
mesh2.vertex_colors = o3d.utility.Vector3dVector(dc)
# 查看泊松重建表面效果
o3d.visualization.draw_geometries([pt, mesh2], width=400, height=300, mesh_show_back_face=True)
# 保存网格为3d文件,支持其它三维作图软件查看
o3d.io.write_triangle_mesh("psf.gltf", mesh2)

open3d 提供的渲染窗口非常简陋,所以可以导出为比较通用的三维格式比如 gltf 文件,然后使用其它软件进行渲染查看包括制作视频。这里介绍一个最简单的微软出品的 3D Viewer。

Pasted-image-20240927084948.png-66524136c9.png

打开刚刚保存的 psf.gltf 文件,可以看到我们添加的伪彩(按 density)保留了下来,而且可以自己调整环境照明,甚至是快速制作动画,但是这里只有预制的几种动画模式,不支持自定义编辑。

open3d_psf_surface_glft.gif-952f371b48.gif