Fix [0,0,0] "bullet hole" artefact in spherical barycentric resampling#77
Merged
jnolan14 merged 1 commit intoMay 22, 2026
Conversation
barycentric_spherical_map() could leave some target vertices unmapped, collapsing their interpolated value to exactly [0, 0, 0]. Two fixes: - Increase the default centroid search neighbourhood from 10 to 30. Registration can distort triangle areas enough that a target point's true containing triangle falls outside the nearest 10 centroids. - Guard the nearest-face fallback on the actual unmatched mask (intersecting_faces == -1) rather than the leftover loop mask, so the fallback always runs and no point is left with face == -1 and zero weights (which produced the [0, 0, 0] sample).
8d24891 to
bc523b6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
barycentric_spherical_map()can leave a few target vertices unmapped, whichcollapses their interpolated value to exactly
[0, 0, 0]. When the map isused to resample mesh coordinates (e.g. white/pial surfaces onto a canonical
topology), the affected vertices are teleported to the origin and their 1-ring
neighbours are stretched by tens of millimetres — a "bullet hole" in the surface.
Root cause (two compounding bugs)
neighborhood(=10) nearestsource-triangle centroids are searched per target point. Registration
(e.g.
mris_register) can distort triangle areas by >200× on the sphere,pushing a target point's true containing triangle past the nearest 10
centroids (observed rank 11–12), so it is never found.
nearest face" fallback was guarded by
np.count_nonzero(remaining), whereremainingis the leftover mask from the final loop iteration, not "are anypoints still unassigned". When the last iteration matched nothing, the
fallback was skipped and those points kept
face == -1with zero weights.SphericalResamplingBarycentricthen doessource.faces[faces]with
faces == -1, so NumPy negative-indexes the last face, and the zeroweights make
sample()return exactly[0, 0, 0].Fix
barycentric_spherical_mapdefaultneighborhood10 → 30 (negligible cost; thecorrect containing triangle is found, giving exact barycentric weights).
intersecting_faces == -1mask so it alwaysruns — no point can be left with a
-1face / zero weights.