Views
No views yet
.ply or .pcd point cloud in → get a watertight, high-quality triangle mesh out.| Innovation | Why it matters |
|---|---|
| Compactly-supported kernel functions | The implicit field is built from local kernel basis functions that have finite support. This makes the linear system sparse, so it can be solved with fast sparse PCG solvers instead of dense matrix inversion. Result: room-scale reconstruction in seconds. |
| Gradient fitting solve | Instead of only fitting point positions (SDF ≈ 0), NKSR also fits surface normals as gradients of the field. This makes the reconstruction dramatically more robust to noise and outliers. |
| Minimal training, maximum generalisation | The model is trained once on a mixture of synthetic and real data (the "kitchen-sink" config) and then works out-of-the-box on new scans without any fine-tuning. |
1# 1. Clone the original NKSR repo and install it
2# (see https://github.com/nv-tlabs/NKSR for the latest instructions)
3git clone https://github.com/nv-tlabs/NKSR.git
4cd NKSR
5pip install -r requirements.txt
6pip install --no-build-isolation package/
7
8# 2. Install this wrapper
9pip install -e .1from nksr_wrapper import NKSRMeshReconstructor, load_point_cloud, save_mesh
2
3points, normals = load_point_cloud("scan.ply")
4recon = NKSRMeshReconstructor(device="cuda:0")
5mesh = recon.reconstruct(points, normals, detail_level=1.0)
6save_mesh("mesh.ply", mesh.vertices, mesh.faces)python scripts/reconstruct.py scan.ply mesh.ply --detail 1.0 --mise-iter 1reconstruct().xyz — (N, 3) point positionsnormal — (N, 3) oriented normals (optional but strongly recommended)sensor — (N, 3) sensor/camera positions (optional; used for normal orientation when normals are missing)voxel_size (default ≈ 0.1 in the pretrained config). One voxel_size unit = one spatial unit in your point-cloud coordinate system.x, the implicit function is evaluated as a weighted sum of compact kernel functions centred on nearby voxels:f(x) = Σ_i w_i · φ_i(x)φ_i is a compact kernel (e.g. Wendland or similar) and w_i are learned weights. Because the kernels have finite support, the sum only involves neighbours within a small radius → sparse linear system.w by fitting two constraints:f(x_j) ≈ 0 on every input point (the surface is the zero level-set).∇f(x_j) ≈ n_j on voxel centres (the gradient of the field matches the surface normal).mise_iter doubles the effective resolution in those cells, giving you a crisp mesh without wasting polygons on empty space.mesh.v (V×3 vertices) and mesh.f (F×3 face indices).NKSRMeshReconstructor1class NKSRMeshReconstructor(
2 device="cuda:0",
3 config="ks",
4 chunk_tmp_device="cpu",
5)device — PyTorch device (CUDA strongly recommended).config — Pretrained model name:
"ks" — Kitchen-sink (recommended default). Trained on a mixture of synthetic and real scans; generalises to objects, indoor rooms, and outdoor scenes."snet" — ShapeNet objects with normals."snet-wonormal" — ShapeNet objects without normals.chunk_tmp_device — Where to stash finished chunks when reconstructing huge scenes. "cpu" offloads to system RAM..reconstruct(...)1mesh = recon.reconstruct(
2 points, # (N, 3) required
3 normals=None, # (N, 3) optional, strongly recommended
4 sensor_positions=None, # (N, 3) optional, helps orient normals
5 colors=None, # (N, 3) optional, for colored mesh output
6
7 # Quality / resolution
8 detail_level=1.0, # 0.0 = smooth, 1.0 = max detail
9 voxel_size=None, # override resolution explicitly
10 mise_iter=1, # 0 = base, 1 = 2× in subdivided cells, 2 = 4×
11
12 # Large-scene settings
13 chunk_size=-1.0, # >0 enables out-of-core chunking
14 overlap_ratio=0.05,
15
16 # Solver tuning
17 solver_max_iter=2000,
18 solver_tol=1e-5,
19 approx_kernel_grad=False,
20
21 # Normal estimation fallback
22 estimate_normals_if_missing=True,
23 normal_knn=64,
24 normal_drop_threshold_deg=85.0,
25)MeshResult dataclass with:.vertices — (V, 3) float array.faces — (F, 3) int array.vertex_colors — (V, 3) float array, if colors was provided.save(path) — convenience method to write PLY/OBJ/GLB via Trimeshnksr-wrapper/
├── nksr_wrapper/
│ ├── __init__.py # public API
│ ├── reconstructor.py # NKSRMeshReconstructor + MeshResult
│ └── io.py # load_point_cloud, save_mesh
├── scripts/
│ └── reconstruct.py # CLI entry point
├── examples/
│ ├── quickstart.py # minimal script
│ └── chunked_reconstruction.py # large-scene example
├── setup.py
├── requirements.txt
└── README.md1# Basic reconstruction
2python scripts/reconstruct.py scan.ply mesh.ply --detail 1.0
3
4# Large scene (chunked)
5python scripts/reconstruct.py huge_scan.ply mesh.ply --chunk-size 50.0
6
7# No normals in file — estimate on-the-fly
8python scripts/reconstruct.py scan.ply mesh.ply --estimate-normals
9
10# With per-point colors → colored mesh
11python scripts/reconstruct.py scan.ply mesh.ply --colors colors.npy --mise-iter 2| Problem | Solution |
|---|---|
| Mesh is too noisy / has spikes | Lower detail_level (try 0.3) or increase voxel_size |
| Mesh is too smooth / missing fine detail | Raise detail_level (try 1.0) or set mise_iter=2 |
| Out-of-memory on large scans | Use chunk_size=50.0 and chunk_tmp_device="cpu" |
| Mesh is inside-out | Normals are unoriented. Provide sensor_positions or pre-orient normals with Open3D |
| Reconstruction is very slow | You are probably on CPU. NKSR requires CUDA for the custom sparse kernels. |
| PLY file has no normals | Use --estimate-normals or pass sensor_positions to the reconstructor |
1@inproceedings{huang2023nksr,
2 title={Neural Kernel Surface Reconstruction},
3 author={Huang, Jiahui and Gojcic, Zan and Atzmon, Matan and
4 Litany, Or and Fidler, Sanja and Williams, Francis},
5 booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)},
6 year={2023}
7}