mkazhdan / PoissonRecon

Poisson Surface Reconstruction
MIT License
1.59k stars 431 forks source link

Is --width parameter really ignored if --depth parameter is given in PoissonRecon? #251

Closed chanyeong-jeong closed 1 year ago

chanyeong-jeong commented 1 year ago

I have been running PoissonRecon ported into open3d as create_from_point_cloud_poisson. README.md file says:

[--width ] This floating point value specifies the target width of the finest level octree cells. This parameter is ignored if the --depth is also specified.

However, it seems that create_from_point_cloud_poisson of open3d===0.16.0 version generates triangle mesh depending on the parameter width. I tried with parameter:

"DEPTH": 7,
"WIDTH": 11, # or 0
"SCALE": 1,
"LINEAR_FIT": True,

and the two meshes created yield different results.

Moreover, consider the following error-reproducible example.

def test_min_num_points(depth, width, scale):
    for i in range(10, 0, -1):
        sampled_pcl = o3d.geometry.PointCloud()
        sampled_pcl.points = o3d.utility.Vector3dVector(np.arange(3 * i).reshape((-1, 3)))
        sampled_pcl.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(
            radius=50, max_nn=100))
        try:
            (
                poisson_mesh,
                densities,
            ) = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
                sampled_pcl,
                depth=depth,
                width=width,
                scale=scale,
                linear_fit=True,
                n_threads=-1)
        except Exception as e:
            print("Exception message:", e)
            print("Number of input points:", i)
            return

>>> test_min_num_points(7, 5, 1)
Exception message: [Open3D Error] (void open3d::geometry::poisson::Execute(const open3d::geometry::PointCloud&, std::shared_ptr<open3d::geometry::TriangleMesh>&, std::vector<double>&, int, float, float, bool, UIntPack<CSignatures ...>) [with Real = float; SampleData = {}; unsigned int ...FEMSigs = {5, 5, 5}]) /root/Open3D/cpp/open3d/geometry/SurfaceReconstructionPoisson.cpp:519: depth (=1) has to be >= 2

Number of input points: 4

>>> test_min_num_points(7, 0, 1)
[WARNING] /root/Open3D/build/poisson/src/ext_poisson/PoissonRecon/Src/FEMTree.Initialize.inl (Line 192)
          Initialize
          Found out-of-bound points: 1
[WARNING] /root/Open3D/build/poisson/src/ext_poisson/PoissonRecon/Src/FEMTree.Initialize.inl (Line 192)
          Initialize
          Found out-of-bound points: 1
[WARNING] /root/Open3D/build/poisson/src/ext_poisson/PoissonRecon/Src/FEMTree.Initialize.inl (Line 192)
          Initialize
          Found out-of-bound points: 1
[WARNING] /root/Open3D/build/poisson/src/ext_poisson/PoissonRecon/Src/FEMTree.Initialize.inl (Line 192)
          Initialize
          Found out-of-bound points: 1
Segmentation fault (core dumped)
[Python interpreter crashes]

In this case, the width parameter value determines the behavior(how the program handles exception) of the code, which is confusing again. I expect the program to not crash by segmentation fault so that it prints a proper error message. Could it be the problem of PoissonRecon or the problem of open3d-ported version? Thank you in advance!

mkazhdan commented 1 year ago

I'm assuming with the port. Though you could try and download the PoissonRecon code directly and try yourself.

chanyeong-jeong commented 1 year ago

I did clone and run the code directly to confirm that PoissonRecon produces two identical triangle mesh for depth=8 width=0 and depth=8 width=1. So I'm pretty sure that open3d-ported version is to blame. Perhaps I should make an issue there. Thank you for your reply!

By the way, I came up with some curiosity as I have been testing the following testcases (1.ply is a point cloud file containing only one point):

$ ./PoissonRecon --width 0 --in ./pcd/1.ply --out ./pcd/1-w0.ply
[WARNING] Src/FEMTree.Initialize.inl (Line 199)
          Initialize
          Found bad data: 1
[ERROR] Src/FEMTree.System.inl (Line 2641)
        solveSystem
        Solver depth cannot exceed maximum depth: 8 <= 0

$ ./PoissonRecon --width 1 --in ./pcd/1.ply --out ./pcd/1-w1.ply
[WARNING] Src/PoissonRecon.cpp (Line 623)
          Execute
          Full depth cannot exceed system depth: 5 <= 0
Segmentation fault (core dumped)

What does it mean to set width=0 (with depth value not provided) when the width of the finest cell cannot be 0? I assume width=0 is the default setting according to this line, but how is the octree constructed then? Also, why does the program make segmentation fault when there are few points, but a different error message when --width 0?

mkazhdan commented 1 year ago

I believe that the code crashes in the case of a single point because the bounding box has max side lengths equal to zero, resulting in a division by zero when trying to estimate the mapping from world coordinates to the unit cube.

In terms of what width does -- I believe the code tries to find the combination of scale value and depth value so that the width of a leaf node is exactly equal to the prescribed depth. (Which won't make much sense when the width is zero.) Newer code will be a little more lax in this regard, only ensuring that the width is at least as small as the prescribed width. (Though things still won't make sense when the prescribed width is zero.)

chanyeong-jeong commented 1 year ago

I see. Then it would be inappropriate to set width as 0 as long as I want the code to not crash. Thanks for your clarification.