jianglongye / gifs

GIFS: Neural Implicit Function for General Shape Representation, CVPR 2022
https://jianglongye.com/gifs
MIT License
76 stars 4 forks source link

Calculate GT UDF #1

Closed rsy6318 closed 2 years ago

rsy6318 commented 2 years ago

Hi, during prepare dataset, I use point-cloud-utils to calculate the udf while you use igl to do this. At some points, I get different result.

[0.00067592 0.01747461 0.00339326 0.00423185 0.04085864 0.00293247 0.03736376 0.01696323 0.00475346 0.01318494] [0.00067592 0.01747461 0.00339326 0.00423185 0.04085864 0.00293247 0.03736376 0.01696323 0.00475346 0.01318494] [0.00064281 0.05099245 0.01015422 0.012562 0.04038997 0.00293696 0.03715294 0.08596424 0.01266249 0.01308912]

This is 10 results of the sampling points. Top is the result of point-cloud-utils, middle is the distance from sampled points to their closest points on the mesh according to the point-cloud-utils. The bottom is the result of igl. It can be seem that most results are similar but there is few that very different. I wonder if it would influence the results?

jianglongye commented 2 years ago

I believe it's basically fine since I haven't heard of any well-known issues with igl SDF calculation function.

I also do a quick test to compare the SDF calculation between igl, trimesh and point-cloud-utils.

Here is the script:

import numpy as np
import trimesh
import igl
import point_cloud_utils as pcu

np.random.seed(0)

sphere = trimesh.creation.icosphere()
pts = np.random.uniform(-1, 1, (10, 3))

dist = np.abs(pcu.signed_distance_to_mesh(pts, sphere.vertices, sphere.faces)[0])
print("point_cloud_utils:", dist)

dist = np.abs(igl.signed_distance(pts, sphere.vertices, sphere.faces)[0])
print("igl:", dist)

dist = np.abs(trimesh.proximity.signed_distance(sphere, pts))
print("trimesh:", dist)

Here is the result:

point_cloud_utils: [0.51017601 0.65703507 0.2223707  0.36690731 0.21883344 0.43236254
 0.33405032 0.1727736  0.08369474 0.08968811]
igl: [0.50929385 0.65575071 0.22238655 0.36632363 0.21883836 0.43257203
 0.33420322 0.17259464 0.08370056 0.08990478]
trimesh: [0.50929385 0.65575071 0.22238655 0.36632363 0.21883836 0.43257203
 0.33420322 0.17259464 0.08370056 0.08990478]

It looks like that igl's result is consistent with trimesh.

By the way, NDF also uses igl to calculate UDF.

rsy6318 commented 2 years ago

Thanks for your reply! For point-cloud-utils, I use 'closest_points_on_mesh' to calculate the distance from query point to mesh. I think the car dataset is multi-layers and SDF would be unsuitable.

jianglongye commented 2 years ago

It's a good point.

I conjecture that the logic of igl's SDF calculation is that it first calculates the distance to the closest point on mesh, i.e. UDF, and then determines the sign. By checking the code here, we can also confirm that it is indeed the case. Since we only need UDF, the incorrect signs do not affect the results.

I do not know why igl and point-cloud-utils give different results, more detailed experiments are needed.

rsy6318 commented 2 years ago

Thanks for your reply! We like your work very much!

I use the 'scaled_off' file of shapenet car, the file name is 1005ca47e516495512da0dbf3c68e847, and the query points are

[[ 0.26664394 -0.08880997 0.18735304] [ 0.36330735 -0.03190491 0.10032159] [ 0.1362305 -0.09429415 -0.13514743] [ 0.42728582 -0.05826093 0.03475667] [-0.38879484 -0.1295442 0.07898633] [ 0.15233493 -0.07547763 0.1961531 ] [-0.4601973 0.08014096 -0.15493135] [ 0.2970031 -0.06503728 -0.01160855] [ 0.42649888 -0.06867809 0.07881794] [ 0.19822311 -0.00238855 -0.21956048]]

The UDF of point-cloud-utils are:

[0.00067592 0.01747461 0.00339326 0.00423185 0.04085864 0.00293247 0.03736376 0.01696323 0.00475346 0.01318494]

The igl results are:

[0.00064281 0.05099245 0.01015422 0.012562 0.04038997 0.00293696 0.03715294 0.08596424 0.01266249 0.01308912]

It is obvious that some UDF are different and the difference is beyond the voxel size sometimes.

Thanks for your reply again !

jianglongye commented 2 years ago

I have done a detailed experiment, and the conclusion is that: igl and point_cloud_utils find the same closest points but igl somehow provides the wrong distances.

Here is the testing script:

import igl
import numpy as np
import point_cloud_utils as pcu
import trimesh

def as_mesh(scene_or_mesh):
    if isinstance(scene_or_mesh, trimesh.Scene):
        if len(scene_or_mesh.geometry) == 0:
            mesh = None
        else:
            mesh = trimesh.util.concatenate(
                tuple(trimesh.Trimesh(vertices=g.vertices, faces=g.faces) for g in scene_or_mesh.geometry.values())
            )
    else:
        assert isinstance(scene_or_mesh, trimesh.Trimesh)
        mesh = scene_or_mesh
    return mesh

mesh = as_mesh(trimesh.load("./1005ca47e516495512da0dbf3c68e847/model.obj"))

total_size = (mesh.bounds[1] - mesh.bounds[0]).max()
centers = (mesh.bounds[1] + mesh.bounds[0]) / 2

mesh.apply_translation(-centers)
mesh.apply_scale(1 / total_size)
_ = mesh.export("scaled.obj")

query_pts = np.array(
    [
        [0.26664394, -0.08880997, 0.18735304],
        [0.36330735, -0.03190491, 0.10032159],
        [0.1362305, -0.09429415, -0.13514743],
        [0.42728582, -0.05826093, 0.03475667],
        [-0.38879484, -0.1295442, 0.07898633],
        [0.15233493, -0.07547763, 0.1961531],
        [-0.4601973, 0.08014096, -0.15493135],
        [0.2970031, -0.06503728, -0.01160855],
        [0.42649888, -0.06867809, 0.07881794],
        [0.19822311, -0.00238855, -0.21956048],
    ]
)
_ = trimesh.Trimesh(query_pts[1:2]).export("query_pts.ply")

dist, fi, bc = pcu.closest_points_on_mesh(query_pts, mesh.vertices, mesh.faces)
closest_pts = pcu.interpolate_barycentric_coords(mesh.faces, fi, bc, mesh.vertices)
_ = trimesh.Trimesh(closest_pts[1:2]).export("pcu_closest_points.ply")
print(dist)
print(closest_pts)
print(np.linalg.norm(query_pts - closest_pts, axis=-1))
print("-----------------")

dist, fi, cloest_pts = igl.signed_distance(query_pts, mesh.vertices, mesh.faces)
_ = trimesh.Trimesh(closest_pts[1:2]).export("igl_closest_points.ply")
print(np.abs(dist))
print(closest_pts)
print(np.linalg.norm(query_pts - closest_pts, axis=-1))

Here is the result:

[0.00067592 0.01747461 0.00339326 0.00423185 0.04085864 0.00293248
 0.03736376 0.01696324 0.00475347 0.01318494]
[[ 0.26688435 -0.08846666  0.18788333]
 [ 0.3643326  -0.02522869  0.08420517]
 [ 0.13627684 -0.09765719 -0.13469793]
 [ 0.42305397 -0.05826093  0.03475667]
 [-0.38466255 -0.08891272  0.08018442]
 [ 0.15262244 -0.07559658  0.19323718]
 [-0.4468213   0.04988579 -0.13756016]
 [ 0.2970031  -0.06503728 -0.02857179]
 [ 0.42193782 -0.06867809  0.07747922]
 [ 0.19913701 -0.0040874  -0.20651742]]
[0.00067592 0.01747461 0.00339326 0.00423185 0.04085864 0.00293248
 0.03736376 0.01696324 0.00475347 0.01318494]
-----------------
[0.0006428  0.05099245 0.01015423 0.012562   0.04038997 0.00293697
 0.03715294 0.08596426 0.01266249 0.01308912]
[[ 0.26688435 -0.08846666  0.18788333]
 [ 0.3643326  -0.02522869  0.08420517]
 [ 0.13627684 -0.09765719 -0.13469793]
 [ 0.42305397 -0.05826093  0.03475667]
 [-0.38466255 -0.08891272  0.08018442]
 [ 0.15262244 -0.07559658  0.19323718]
 [-0.4468213   0.04988579 -0.13756016]
 [ 0.2970031  -0.06503728 -0.02857179]
 [ 0.42193782 -0.06867809  0.07747922]
 [ 0.19913701 -0.0040874  -0.20651742]]
[0.00067592 0.01747461 0.00339326 0.00423185 0.04085864 0.00293248
 0.03736376 0.01696324 0.00475347 0.01318494]

It's a good idea to redo experiments with point_cloud_utils's function. I will do this in the near future. Stay tuned!

Here is the link of the testing data and script.

jianglongye commented 2 years ago

I have rerun the main experiment and the results were similar. I have also updated the code with functions from point_cloud_utils.