Add skin surface computation tools (#149) #190
Merged
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.
Close #149
The goal of this PR is to add tooling to openlifu to create the skin surface interpolator needed for #147 (virtual fitting).
A useful bonus is that we will also get a skin surface model that can be used in transducer tracking.
Roughly the workflow from an MRI volume
arrayand associatedaffineis this:graph LR A[array] --> B{"(1) fg mask"} --> C[mask] --> E{"(2) meshify"} D[affine]-->E-->F[mesh]-->G{"(3)make<br>interpolator"} G-->H[interpolator] I[origin,<br>axes]-->H[interpolator]The goal of this PR is to introduce algorithms (1), (2), and (3).
(1)
compute_foreground_maskcompute_foreground_maskis a python implementation of the BRAINSTools foreground masking algorithm, with some simplifications and (hopefully) improvements(2)
create_closed_surface_from_labelmapcreate_closed_surface_from_labelmapis based on the closed surface representation functionality in Slicer's segmentation module.(3)
spherical_interpolator_from_meshHere a "spherical interpolator" is a function that maps angles from a spherical coordinate system to r values (radial spherical coordinate values) by interpolating over a set of known values. It's essentially a "spherical plotter."
Summary of the algorithm:
scipy.interpolate.LinearNDInterpolatorthat interpolates sphericalLinearNDInterpolatordoes not extrapolate, and so angles close to the "seams" of the spherical coordinate system (the boundaries of that square) generate NaNs through the interpolator. The solution used here is to first clone the gathered points with appropriate angular shifts so as to cover those seams, and then give that larger set of points to the interpolator.Example visualized
Here is a visualization of the whole pipeline on an example (this one is of a defaced MRI):
We start with a volume (shown as a slice), then we get a binary labelmap (shown as a slice), then we get a mesh (shown as a 3d render), and finally we get a spherical interpolator (shown applied to the vertices of a vtkSphereSource and then 3d rendered).