Skip to content

Commit 48b0435

Browse files
Mesh updates (#63)
* Refactor mesh smoothing function to the mesh header and module * Implement mesh simplification
1 parent 234c5af commit 48b0435

13 files changed

Lines changed: 1680 additions & 242 deletions

File tree

MIGRATION_GUIDE.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,47 @@ Important details:
19331933
See `development/mesh/check_marching_cubes.py` for reference comparisons and
19341934
`development/mesh/benchmark_marching_cubes.py` for reproducible timings.
19351935

1936+
### Mesh Smoothing
1937+
1938+
Laplacian mesh smoothing is available as `bic.mesh.smooth_mesh`. It was moved
1939+
from `bic.utils.smooth_mesh`; the old location is no longer available. The C++
1940+
API likewise moved from `#include "bioimage_cpp/mesh_smoothing.hxx"` and
1941+
`bioimage_cpp::smooth_mesh` to `#include "bioimage_cpp/mesh/smoothing.hxx"`
1942+
and `bioimage_cpp::mesh::smooth_mesh`.
1943+
1944+
### Mesh Simplification
1945+
1946+
Topology-preserving triangle-mesh simplification is available as
1947+
`bic.mesh.simplify_mesh`. It uses quadric-error edge collapses, preserves
1948+
manifold topology and open boundaries, and applies configurable soft penalties
1949+
to sharp features:
1950+
1951+
vertices, faces, _, values = bic.mesh.marching_cubes(
1952+
volume, level=0.5, allow_degenerate=False
1953+
)
1954+
vertices, faces, normals, values = bic.mesh.simplify_mesh(
1955+
vertices,
1956+
faces,
1957+
reduction=0.8,
1958+
values=values,
1959+
feature_angle=45.0,
1960+
feature_weight=10.0,
1961+
)
1962+
1963+
`reduction` is the approximate fraction of input faces to remove. A mesh can
1964+
stop above its target if no topology- and boundary-safe collapse remains.
1965+
Normals are recomputed from the final face geometry. Optional scalar values are
1966+
interpolated along collapsed edges; the fourth return item is `None` when
1967+
values are omitted. Vertices and values preserve float32/float64 input dtypes,
1968+
while returned faces are int64.
1969+
1970+
The input must be a non-empty, consistently oriented triangle 2-manifold with
1971+
no duplicate, zero-area, or unreferenced geometry. Use
1972+
`marching_cubes(..., allow_degenerate=False)` before simplification; invalid
1973+
meshes are rejected rather than silently repaired.
1974+
1975+
1976+
19361977
### Anti-Aliased Resampling
19371978

19381979
`affine_transform` itself never pre-smooths the input; downsampling without

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
Image processing and segmentation functionality in C++ with light-weight python bindings through nanobind and minimal dependencies to enable distribution via pip.
99

1010
The package includes dependency-free triangle-mesh extraction from 3D volumes
11-
and segmentation masks under `bioimage_cpp.mesh`.
11+
and segmentation masks, plus Laplacian mesh smoothing, under `bioimage_cpp.mesh`.
1212

1313
The `bioimage_cpp` python library can be installed via pip:
1414
```bash
File renamed without changes.

development/utils/benchmark_mesh_smoothing.py renamed to development/mesh/benchmark_mesh_smoothing.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
99
Run::
1010
11-
python development/utils/benchmark_mesh_smoothing.py --n-vertices 5000 --iterations 5 --repeats 3
12-
python development/utils/benchmark_mesh_smoothing.py --n-vertices 20000 --threads 1,2,4,0
11+
python development/mesh/benchmark_mesh_smoothing.py --n-vertices 5000 --iterations 5 --repeats 3
12+
python development/mesh/benchmark_mesh_smoothing.py --n-vertices 20000 --threads 1,2,4,0
1313
1414
Notes
1515
-----
@@ -117,7 +117,7 @@ def main() -> int:
117117
label = f"bioimage_cpp[n_threads={n_threads}]"
118118

119119
def run(verts=mesh.verts, normals=mesh.normals, faces=mesh.faces, n=n_threads):
120-
bic.utils.smooth_mesh(verts, normals, faces, iterations=args.iterations, n_threads=n)
120+
bic.mesh.smooth_mesh(verts, normals, faces, iterations=args.iterations, n_threads=n)
121121

122122
times = time_call(run, args.repeats, args.warmup)
123123
rows.append(
@@ -141,7 +141,7 @@ def run_ref():
141141
# exact agreement; see module docstring).
142142
if reference is not None:
143143
ref_v, ref_n = reference(mesh.verts, mesh.normals, mesh.faces, 1)
144-
ours_v, ours_n = bic.utils.smooth_mesh(mesh.verts, mesh.normals, mesh.faces, iterations=1)
144+
ours_v, ours_n = bic.mesh.smooth_mesh(mesh.verts, mesh.normals, mesh.faces, iterations=1)
145145
v_max_diff = float(np.max(np.abs(ours_v - ref_v)))
146146
n_max_diff = float(np.max(np.abs(ours_n - ref_n)))
147147
print(f"Correctness vs reference (iterations=1): "

0 commit comments

Comments
 (0)