Skip to content

Commit

Permalink
Sphere/vescicle picking (#179)
Browse files Browse the repository at this point in the history
Sphere picking using the same approach as surface and filament.
  • Loading branch information
brisvag authored Aug 7, 2024
1 parent fd1f7c5 commit 315f646
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 9 deletions.
17 changes: 11 additions & 6 deletions src/blik/napari.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ contributions:
- id: blik.main_widget
python_name: blik.widgets.main_widget:MainBlikWidget
title: "Open blik main widget"
- id: blik.filament_picking
python_name: blik.widgets.picking:FilamentWidget
title: "Open blik filament picking widget"
- id: blik.surface_picking
python_name: blik.widgets.picking:SurfaceWidget
title: "Open blik surface picking widget"
- id: blik.sphere_picking
python_name: blik.widgets.picking:SphereWidget
title: "Open sphere picking widget"
- id: blik.filament_picking
python_name: blik.widgets.picking:FilamentWidget
title: "Open blik filament picking widget"
- id: blik.file_reader_widget
python_name: blik.widgets.file_reader:file_reader
title: "Open blik file reader widget"
Expand All @@ -66,8 +69,8 @@ contributions:
- command: blik.power_spectrum
napari/layers/annotate:
- command: blik.main_widget
- command: blik.filament_picking
- command: blik.surface_picking
- command: blik.sphere_picking
- command: blik.filament_picking
napari/layers/filter:
- command: blik.bandpass_filter
Expand Down Expand Up @@ -127,10 +130,12 @@ contributions:
widgets:
- command: blik.main_widget
display_name: "Blik main widget"
- command: blik.filament_picking
display_name: "Filament picking"
- command: blik.surface_picking
display_name: "Surface picking"
- command: blik.sphere_picking
display_name: "Sphere picking"
- command: blik.filament_picking
display_name: "Filament picking"
- command: blik.file_reader_widget
display_name: "File reader"
- command: blik.bandpass_filter
Expand Down
22 changes: 21 additions & 1 deletion src/blik/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,13 @@ def add_to_exp(layer: napari.layers.Layer):
labels=False,
call_button="Create",
l_type={
"choices": ["segmentation", "particles", "surface_picking", "filament_picking"]
"choices": [
"segmentation",
"particles",
"surface_picking",
"sphere_picking",
"filament_picking",
]
},
)
def new(
Expand Down Expand Up @@ -221,6 +227,20 @@ def new(
units="angstrom",
)

return [pts]
elif l_type == "sphere_picking":
for lay in layers:
if isinstance(lay, Image) and lay.metadata["experiment_id"] == exp_id:
pts = Points(
name=f"{exp_id} - sphere picks",
size=20 / lay.scale[0],
scale=lay.scale,
metadata={"experiment_id": exp_id},
ndim=3,
# axis_labels=('z', 'y', 'x'),
units="angstrom",
)

return [pts]

show_info(f"cannot create a new {l_type}")
Expand Down
110 changes: 108 additions & 2 deletions src/blik/widgets/picking.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
from magicgui import magicgui
from magicgui.widgets import Container
from morphosamplers.helical_filament import HelicalFilament
from morphosamplers.models import Sphere
from morphosamplers.preprocess import get_label_paths_3d
from morphosamplers.sampler import (
sample_volume_along_spline,
sample_volume_around_surface,
)
from morphosamplers.samplers.sphere_samplers import PointSampler, PoseSampler
from morphosamplers.surface_spline import GriddedSplineSurface
from morphosamplers.preprocess import get_label_paths_3d
from scipy.spatial import ConvexHull
from scipy.spatial.transform import Rotation

from ..reader import construct_particle_layer_tuples
Expand Down Expand Up @@ -85,7 +88,9 @@ def _generate_surface_grids_from_labels_layer(
)

# doing this "custom" because we need to flip xyz
surfaces_lines = get_label_paths_3d(compute(surface_label.data)[0], axis=0, slicing_step=10, sampling_step=10)
surfaces_lines = get_label_paths_3d(
compute(surface_label.data)[0], axis=0, slicing_step=10, sampling_step=10
)

for lines in surfaces_lines:
lines = [invert_xyz(line.astype(float)) for line in lines]
Expand Down Expand Up @@ -393,6 +398,99 @@ def resample_filament(
)


@magicgui(
labels=True,
call_button="Generate",
)
def sphere(
point_picks: napari.layers.Points,
) -> napari.types.LayerDataTuple:
points = invert_xyz(point_picks.data)
vert_all = []
faces_all = []
spheres_all = []

exp_id = ""
faces_offset = 0
for i, (c, n) in enumerate(zip(points[::2], points[1::2])):
r = np.linalg.norm(n - c)

s = Sphere(center=c, radius=r)
ps = PointSampler(spacing=r / 10)
positions = ps.sample(s)

h = ConvexHull(positions)
tri = h.points[h.simplices]

# fix faces ordering
edges = tri - np.roll(tri, 1, axis=1)
cross = np.cross(edges[:, 0], edges[:, 1])
direction = np.einsum("...j,...j", cross, tri[:, 0] - (0, 0, 0))
faces = h.simplices.copy()
faces[direction < 0] = h.simplices[direction < 0][:, ::-1]
faces += i * faces_offset
faces_offset += len(positions)

exp_id = point_picks.metadata["experiment_id"]
vert_all.append(positions)
faces_all.append(faces)
spheres_all.append(s)

surface_layer_tuple = (
(invert_xyz(np.concatenate(vert_all)), np.concatenate(faces_all)),
{
"name": f"{exp_id} - surface",
"metadata": {
"experiment_id": exp_id,
"spheres": spheres_all,
},
"scale": point_picks.scale,
# smooth shading is bugged cause of some ordering issue
"shading": "flat",
},
"surface",
)
return [surface_layer_tuple]


@magicgui(
labels=True,
call_button="Generate",
spacing_A={"widget_type": "FloatSlider", "min": 0.01, "max": 10000},
)
def sphere_particles(
sphere_surf: napari.layers.Surface,
spacing_A=50,
) -> napari.types.LayerDataTuple:
spheres = sphere_surf.metadata.get("spheres", None)
if spheres is None:
raise ValueError("This surface layer contains no sphere objects.")

exp_id = sphere_surf.metadata["experiment_id"]

spacing_A /= sphere_surf.scale[0]

pos = []
ori = []
for s in spheres:
ps = PoseSampler(spacing=spacing_A)
poses = ps.sample(s)

features = pd.DataFrame(
{"orientation": np.asarray(Rotation.from_matrix(poses.orientations))}
)
pos.append(poses.positions)
ori.append(features)

return construct_particle_layer_tuples(
coords=np.concatenate(pos),
features=pd.concat(ori, axis=0),
scale=sphere_surf.scale[0],
exp_id=exp_id,
name_suffix="spheres picked",
)


class FilamentWidget(Container):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand All @@ -409,3 +507,11 @@ def __init__(self, *args, **kwargs):
self.append(surface)
self.append(surface_particles)
self.append(resample_surface)


class SphereWidget(Container):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.append(sphere)
self.append(sphere_particles)

0 comments on commit 315f646

Please sign in to comment.