nvdiffrec
nvdiffrec copied to clipboard
Calculating Chamfer Loss
Hello, I was working to calculate Chamfer Loss results on NeRF realistic synthetic dataset. And In your paper, Table 8, You compared chamfer loss result to the meshs produced by PhySG. Can you share the code or library you used when you calculate chamfer loss?
Hello,
We used the https://github.com/otaheri/chamfer_distance package for chamfer distance, and trimesh to load meshes & sample point clouds. We used 2.5M points for the results in the paper, but you can reduce that value to improve performance when experimenting. I had to make local changes to the chamfer_distance package to make it run (on Windows), but unfortunately cannot share the modifications here. Optionally you can use Kaolin which has a similar chamfer function.
It's a good idea to sanity check the meshes in some 3D modeling program. Different projects use different coordinate system conventions leading to mismatch in rotation/scaling.
import argparse
import torch
import numpy as np
# pip install trimesh[all]
import trimesh
# https://github.com/otaheri/chamfer_distance
from chamfer_distance import ChamferDistance
def as_mesh(scene_or_mesh):
if isinstance(scene_or_mesh, trimesh.Scene):
assert len(scene_or_mesh.geometry) > 0
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
def sample_mesh(m, n):
vpos, _ = trimesh.sample.sample_surface(m, n)
return torch.tensor(vpos, dtype=torch.float32, device="cuda")
if __name__ == "__main__":
chamfer_dist = ChamferDistance()
parser = argparse.ArgumentParser(description='Chamfer loss')
parser.add_argument('-n', type=int, default=2500000)
parser.add_argument('mesh', type=str)
parser.add_argument('ref', type=str)
FLAGS = parser.parse_args()
mesh = as_mesh(trimesh.load(FLAGS.mesh))
ref = as_mesh(trimesh.load(FLAGS.ref))
# Make sure l=1.0 maps to 1/10th of the AABB. https://arxiv.org/pdf/1612.00603.pdf
scale = 10.0 / np.amax(np.amax(ref.vertices, axis=0) - np.amin(ref.vertices, axis=0))
ref.vertices = ref.vertices * scale
mesh.vertices = mesh.vertices * scale
# Sample mesh surfaces
vpos_mesh = sample_mesh(mesh, FLAGS.n)
vpos_ref = sample_mesh(ref, FLAGS.n)
dist1, dist2 = chamfer_dist(vpos_mesh[None, ...], vpos_ref[None, ...])
loss = (torch.mean(dist1) + torch.mean(dist2)).item()
print("[%7d tris]: %1.5f" % (mesh.faces.shape[0], loss))
Thank you for kindly replying !
Hello, thanks for your work! I was wondering how we can obtain the reference mesh
ref = as_mesh(trimesh.load(FLAGS.ref))
from the NeRF synthetic dataset, as I did not find that information from the paper.
Hi @weihan1,
The NeRF paper released their data files: https://drive.google.com/drive/folders/128yBriW1IG_3NJ5Rp7APSTZsJqdJdfc1
You can find the synthetic NeRF scenes in the blend_files.zip
file, and you'll manually have to export them as .obj
files from blender if you want to load them using the script.