From 1b046b833a8895be303a22b0f8f2cf6dc184bba3 Mon Sep 17 00:00:00 2001 From: Robert Haase Date: Wed, 12 Apr 2023 13:39:51 +0200 Subject: [PATCH 1/4] allow creating labeled surface from label images --- napari_process_points_and_surfaces/__init__.py | 16 ++++++++++++++-- .../_quantification.py | 2 ++ .../_tests/test_function.py | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/napari_process_points_and_surfaces/__init__.py b/napari_process_points_and_surfaces/__init__.py index f97f276..d8994e4 100644 --- a/napari_process_points_and_surfaces/__init__.py +++ b/napari_process_points_and_surfaces/__init__.py @@ -263,13 +263,15 @@ def invert_faces(surface: "napari.types.SurfaceData", viewer: "napari.Viewer" = @register_function(menu="Surfaces > Create surface from all labels (marching cubes, scikit-image, nppas)") @time_slicer -def all_labels_to_surface(labels: "napari.types.LabelsData", viewer: "napari.Viewer" = None) -> "napari.types.SurfaceData": +def all_labels_to_surface(labels: "napari.types.LabelsData", add_label_id_as_value:bool = False, viewer: "napari.Viewer" = None) -> "napari.types.SurfaceData": """ Turn a set of labels into a surface using the marching cubes algorithm Parameters ---------- labels_data:napari.types.LabelsData + add_label_id_as_value: bool, optional + if True, will give the same label value to the surface vertices it had in the label image """ import vedo from skimage.measure import marching_cubes @@ -281,15 +283,25 @@ def all_labels_to_surface(labels: "napari.types.LabelsData", viewer: "napari.Vie # Create a surface for every label mesh_list = [] + all_values = [] for label in np.unique(labels)[:-1]: + print("label", label) verts, faces, normals, values = marching_cubes(labels==label) + if add_label_id_as_value: + all_values = all_values + (np.ones_like(verts[:,0]) * label).tolist() + print("unique labels:", np.unique(all_values)) mesh = vedo.mesh.Mesh((verts, faces)) mesh_list.append(mesh) # merge the meshes; label is stored in `mesh.pointdata['OriginalMeshID']` mesh = vedo.merge(mesh_list, flag=True) - return to_napari_surface_data(mesh) + surface = to_napari_surface_data(mesh) + + if add_label_id_as_value: + surface = set_vertex_values(surface, all_values) + + return surface #(mesh.points(), np.asarray(mesh.faces()), mesh.pointdata['OriginalMeshID']) # alias diff --git a/napari_process_points_and_surfaces/_quantification.py b/napari_process_points_and_surfaces/_quantification.py index 53f21fc..61e98f1 100644 --- a/napari_process_points_and_surfaces/_quantification.py +++ b/napari_process_points_and_surfaces/_quantification.py @@ -360,6 +360,8 @@ def set_vertex_values(surface: "napari.types.SurfaceData", values) -> "napari.ty """ from ._vedo import SurfaceTuple + values = np.asarray(values) + num_vertices = len(surface[0]) num_values = len(values) if num_vertices != num_values: diff --git a/napari_process_points_and_surfaces/_tests/test_function.py b/napari_process_points_and_surfaces/_tests/test_function.py index 137a0fb..b72ad58 100644 --- a/napari_process_points_and_surfaces/_tests/test_function.py +++ b/napari_process_points_and_surfaces/_tests/test_function.py @@ -35,6 +35,8 @@ def test_something(): labels = label(nuclei > 20000) surface = all_labels_to_surface(labels) + surface = all_labels_to_surface(labels, add_label_id_as_value=False) + surface = all_labels_to_surface(labels, add_label_id_as_value=True) surface = label_to_surface(labels, 3) surface = largest_label_to_surface(labels) From f966fc338a356a69f5ee330eebfd3db1381c7637 Mon Sep 17 00:00:00 2001 From: Robert Haase Date: Wed, 12 Apr 2023 13:40:00 +0200 Subject: [PATCH 2/4] bugfix: invert vertices for visualization purposes --- napari_process_points_and_surfaces/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/napari_process_points_and_surfaces/__init__.py b/napari_process_points_and_surfaces/__init__.py index d8994e4..3a6ed52 100644 --- a/napari_process_points_and_surfaces/__init__.py +++ b/napari_process_points_and_surfaces/__init__.py @@ -297,6 +297,7 @@ def all_labels_to_surface(labels: "napari.types.LabelsData", add_label_id_as_val mesh = vedo.merge(mesh_list, flag=True) surface = to_napari_surface_data(mesh) + surface = invert_faces(surface) if add_label_id_as_value: surface = set_vertex_values(surface, all_values) From 98e22bcbfefd56105f44d523e42421f7b9ac7ee5 Mon Sep 17 00:00:00 2001 From: Robert Haase Date: Wed, 12 Apr 2023 13:43:48 +0200 Subject: [PATCH 3/4] bugfix: the last surface was missing --- napari_process_points_and_surfaces/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napari_process_points_and_surfaces/__init__.py b/napari_process_points_and_surfaces/__init__.py index 3a6ed52..1135cfa 100644 --- a/napari_process_points_and_surfaces/__init__.py +++ b/napari_process_points_and_surfaces/__init__.py @@ -284,7 +284,7 @@ def all_labels_to_surface(labels: "napari.types.LabelsData", add_label_id_as_val # Create a surface for every label mesh_list = [] all_values = [] - for label in np.unique(labels)[:-1]: + for label in np.unique(labels)[1:]: print("label", label) verts, faces, normals, values = marching_cubes(labels==label) if add_label_id_as_value: From 779a6f73886eaa30fe5a22b7750225ee171db989 Mon Sep 17 00:00:00 2001 From: Robert Haase Date: Wed, 12 Apr 2023 14:29:26 +0200 Subject: [PATCH 4/4] corrected test result --- .../_tests/test_vedo_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napari_process_points_and_surfaces/_tests/test_vedo_functions.py b/napari_process_points_and_surfaces/_tests/test_vedo_functions.py index 2128be7..9dd568c 100644 --- a/napari_process_points_and_surfaces/_tests/test_vedo_functions.py +++ b/napari_process_points_and_surfaces/_tests/test_vedo_functions.py @@ -34,7 +34,7 @@ def test_connected_components(): surface = nppas.all_labels_to_surface(image) connected_components = nppas.connected_component_labeling(surface) - assert len(np.unique(connected_components[2])) == 3 + assert len(np.unique(connected_components[2])) == 2 def test_decimate(): import napari_process_points_and_surfaces as nppas