|
| 1 | +"""Tools to get a skin surface from an MRI. |
| 2 | +
|
| 3 | +Example workflow, starting from |
| 4 | +
|
| 5 | +- an MRI volume `vol_array`, as a numpy array |
| 6 | +- an associated 4x4 `affine` transform, as a numpy array |
| 7 | +- a desired spherical coordinate system `origin` location inside the volume (e.g. the sonication target) |
| 8 | +
|
| 9 | +foreground_mask_array = compute_foreground_mask(vol_array) |
| 10 | +foreground_mask_vtk_image = vtk_img_from_array_and_affine(foreground_mask_array, affine) |
| 11 | +skin_mesh = create_closed_surface_from_labelmap(foreground_mask_vtk_image) |
| 12 | +skin_interpolator = spherical_interpolator_from_mesh(skin_mesh, origin) |
| 13 | +""" |
| 14 | + |
1 | 15 | from typing import Callable, List, Optional, Tuple |
2 | 16 |
|
3 | 17 | import numpy as np |
@@ -265,6 +279,20 @@ def spherical_interpolator_from_mesh( |
265 | 279 | Returns: |
266 | 280 | A spherical interpolator, which is a callable that maps (theta,phi) pairs of spherical coordinates (phi being azimuthal) |
267 | 281 | to r values (radial spherical coordinate values). The angles are in radians. |
| 282 | +
|
| 283 | + Summary of the algorithm: |
| 284 | + - Transform the input mesh based on the desired origin and orientation of the spherical coordinate system. |
| 285 | + - We will gather some points into a set $S$. For each point $P$ on the mesh consider the ray $\\vec{OP}$ |
| 286 | + from the origin through $P$ and look at all the intersections of this ray $\\vec{OP}$ with the mesh. |
| 287 | + If none of those intersections are further out from the origin than $P$ is, then we put $P$ into our set $S$. |
| 288 | + - Using the spherical coordinates of the points in $S$, build a `scipy.interpolate.LinearNDInterpolator` |
| 289 | + that interpolates spherical $r$ values from the spherical $(\\theta,\\phi)$ values. |
| 290 | + - Problem: All the gathered $(\\theta,\\phi)$ values are likely strictly inside the square $[0,\\pi]\\times[-\\pi,\\pi]$, |
| 291 | + and `LinearNDInterpolator` does not _extrapolate_, and so angles close to the "seams" of the spherical coordinate |
| 292 | + system (the boundaries of that square) generate NaNs through the interpolator. The solution used here is to first |
| 293 | + clone the gathered points with appropriate angular shifts so as to cover those seams, and then give that larger set |
| 294 | + of points to the interpolator. |
| 295 | + - Return the interpolator. |
268 | 296 | """ |
269 | 297 |
|
270 | 298 | if xyz_direction_columns is None: |
|
0 commit comments