title: Struggling to create watertight meshes out of point cloud data using Open3D in Python
body: <p>I am trying to create a watertight mesh out of point cloud representing organ contour data from cone beam CT images. My goal is to take two meshes and calculate the volume of intersection between the two of them.</p>
  <p>I have tried using each of the methods shown <a href="http://www.open3d.org/docs/latest/tutorial/Advanced/surface_reconstruction.html" rel="noreferrer">here</a></p>
  <h3>Poisson Reconstruction</h3>
  <pre class="lang-py prettyprint-override"><code>point_cloud = np.genfromtxt('ct_prostate_contour_data.csv', delimiter=',')
  pcd = o3d.geometry.PointCloud()
  pcd.points = o3d.utility.Vector3dVector(point_cloud)
  pcd.compute_convex_hull()
  pcd.estimate_normals()
  pcd.orient_normals_consistent_tangent_plane(10)
  
  mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=10, width=0, scale=20, linear_fit=True)[0]
  mesh.compute_vertex_normals()
  mesh.paint_uniform_color([0.5, 0.5, 0.5])
  mesh.remove_degenerate_triangles()
  o3d.visualization.draw_geometries([pcd, mesh], mesh_show_back_face=True)
  </code></pre>
  <p>While this method seemingly leads to a watertight mesh to my eye, the result of mesh.is_watertight() is False, however for the Bladder data it returns True. Furthermore, the algorithm extends the mesh above and below the vertical limits of the data. Wile this isn't a deal breaking issue if there were a way to minimize it that would be great.</p>
  <p><strong>Poisson Mesh Image</strong>
  <img src="https://imgur.com/rh8O316.png" alt="Poisson Mesh Image" /></p>
  <h3>Ball Pivoting</h3>
  <pre><code>point_cloud = np.genfromtxt('ct_prostate_contour_data.csv', delimiter=',')
  pcd = o3d.geometry.PointCloud()
  pcd.points = o3d.utility.Vector3dVector(point_cloud)
  pcd.compute_convex_hull()
  pcd.estimate_normals()
  pcd.orient_normals_consistent_tangent_plane(30)
  
  distances = pcd.compute_nearest_neighbor_distance()
  avg_dist = np.mean(distances)
  radii = [0.1*avg_dist, 0.5*avg_dist, 1*avg_dist, 2*avg_dist] 
  r = o3d.utility.DoubleVector(radii)
  rec_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(pcd, r)
  o3d.visualization.draw_geometries([pcd, rec_mesh], mesh_show_back_face=True)
  </code></pre>
  <p>This would be my preferred method if I were able to fill the holes as it simply connects vertices without interpolation. Perhaps if I were able to get this into a state where the only remaining holes were large I could convert this mesh into a Pyvista compatible mesh and use Pymeshfix to patch the holes.</p>
  <p><strong>Ball Pivoting Mesh Image</strong>
  <img src="https://imgur.com/09e2xf1.png" alt="Ball Pivoting Mesh Image" /></p>
  <h3>Alpha Shapes</h3>
  <pre><code>point_cloud = np.genfromtxt('ct_prostate_contour_data.csv', delimiter=',')
  pcd = o3d.geometry.PointCloud()
  pcd.points = o3d.utility.Vector3dVector(point_cloud)
  alpha = 8
  tetra_mesh, pt_map = o3d.geometry.TetraMesh.create_from_point_cloud(pcd)
  mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd, alpha, tetra_mesh, pt_map)
  mesh.compute_vertex_normals()
  mesh.paint_uniform_color([0.5, 0.5, 0.5])
  mesh.remove_degenerate_triangles()
  o3d.visualization.draw_geometries([pcd, mesh])
  </code></pre>
  <p>The results from this are similar to ball pivoting but worse.</p>
  <p><strong>Alpha Shapes Mesh Image</strong>
  <img src="https://imgur.com/qmys6Tf.png" alt="Alpha Shapes Mesh Image" /></p>
  <h3>Sample Data</h3>
  <ul>
  <li><a href="https://github.com/isl-org/Open3D/files/6979880/ct_prostate_contour_data.csv" rel="noreferrer">ct_prostate_contour_data.csv</a></li>
  <li><a href="https://github.com/isl-org/Open3D/files/6979881/ct_rectum_contour_data.csv" rel="noreferrer">ct_rectum_contour_data.csv</a></li>
  <li><a href="https://github.com/isl-org/Open3D/files/6979882/ct_bladder_contour_data.csv" rel="noreferrer">ct_bladder_contour_data.csv</a></li>
  </ul>