# .ply文件内部啥样、数字单位是多少 是二进制文件。坐标单位是米。有坐标、颜色、法线信息,无协方差信息。 # google上有吗? ## ~~https://jose-llorens-ripolles.medium.com/stockpile-volume-with-open3d-fa9d32099b6f~~ 只适用于土堆等(stockpile)堆在平地上的、从上方向地面看去表面一览无余的物体 ## https://stackoverflow.com/questions/76752991/open3d-how-to-calculate-the-volume-of-a-mesh-created-by-point-cloud 对alpha shaped mesh求体积时报错:invalid tetra in TetraMesh,是因为mesh内部而非表面也有点。 可通过计算每个点到表面的距离来去除内部和外部的点。 用tri_mesh.is_watertight()判断是否封闭。 ~~用这个算法同样不能确保封闭。create_from_point_cloud_ball_pivoting~~ ~~也不用考虑Poisson surface reconstruction,这个算法可以保证mesh封闭,但open3d没有实现。~~ ## Struggling to create watertight meshes out of point cloud data using Open3D in Python 三个表面重构方法都不能保证封闭。但泊松方法洞最少,alpha shapes方法洞最多。 用PyVista配合pymeshfix倒是可以修复mesh的漏洞、计算体积。但如何从点云得到PyVista mesh???这又是一个未知领域。 ``` import pymeshfix import numpy as np import pyvista as pv pv.set_plot_theme('document') array = np.genfromtxt('ct_prostate_contour_data.csv', delimiter=',') point_cloud = pv.PolyData(array) surf = point_cloud.reconstruct_surface(nbr_sz=20, sample_spacing=2) mf = pymeshfix.MeshFix(surf) mf.repair() repaired = mf.mesh pl = pv.Plotter() pl.add_mesh(point_cloud, color='k', point_size=10) pl.add_mesh(repaired) pl.add_title('Reconstructed Surface') pl.show() ``` ## ~~https://stackoverflow.com/questions/61269980/open3d-crop-pointcloud-with-polygon-volume~~ 讨论如何裁剪点云。 提问者的代码已过时,而且肯定有问题他才会提问。所以不管了。 第一个回答者的代码??? 第二个回答者的代码??? ## https://stackoverflow.com/questions/70449880/how-to-crop-a-point-cloud-in-open3d-by-using-a-polygon-volume 裁剪相关 ## https://github.com/isl-org/Open3D/pull/1218 裁剪相关 # 我的流程 ## open3d 前提:明确点云遗漏的漏洞最大直径r(即直径多少的球刚好能掉入漏洞)不超过多少。显然r完美情况下是0.01 点云降采样(颗粒度g,10厘米?) (丢弃噪点?remove_statistical_outlier, https://jose-llorens-ripolles.medium.com/stockpile-volume-with-open3d-fa9d32099b6f) 表面重构,采用的参数依据r和g中较大者。 (mesh简化?) (mesh求连同区域,舍弃零碎的?) 求体积 ### 切割后补点 提供原始点和切割多面体 # 测试环境管理帐号 * 88888888888 * 2222222222a # 下载点云文件 https://laser-data.oss-cn-shenzhen.aliyuncs.com/testdata/SG-t-MnQ0zoEQIBX/data/SG-t-MnQ0zoEQIBX_ply.zip # 查看方框的四个点 控制台输入: ``` viewer.modules.clipping.getAllBoxes().filter(e=>!e.isNew).map(e=>e.box.geometry.vertices.map(p=>p.clone().applyMatrix4(e.matrixWorld))) ``` # 结果 ## demo * 0.0104 * 0.0983 ## https://uat-laser.4dkankan.com/uat/index.html?m=SG-t-MnQ0zoEQIBX#/ * (按尺寸标注计算:0.470立方米) * stockpile voxel: 0.45 立方米 ## https://uat-laser.4dkankan.com/uat/index.html?m=SG-t-AsSRO3iA0XT#/ * (按尺寸标注计算:0.689立方米) * stockpile voxel: 0.74立方米 ## https://uat-laser.4dkankan.com/uat/index.html?m=SG-t-cp3kSewxMKi#/ * (按尺寸标注计算:0.689立方米) * stockpile voxel: 0.69立方米 ## https://uat-laser.4dkankan.com/uat/index.html?m=SG-t-kuuv0moEP0C#/ * (按尺寸标注计算:0.689立方米) * stockpile voxel: 0.77立方米