Note
Go to the end to download the full example code.
Example of sulcal graph in slam¶
# Authors:
# Lucile Hashimoto lucile-hashimoto
# Guillaume Auzias <guillaume.auzias@univ-amu.fr>
# License: MIT
# sphinx_gallery_thumbnail_number = 2
importation of slam modules
import numpy as np
import networkx as nx
import slam.io as sio
import slam.sulcal_graph as ssg
import slam.watershed as swat
import slam.remeshing as srem
loading an examplar mesh and corresponding texture
path_to_mesh = "../examples/data/example_mesh.gii"
path_to_texture = "../examples/data/example_texture.gii"
path_to_mask = None
mesh = sio.load_mesh(path_to_mesh)
side = "left"
texture = sio.load_texture(path_to_texture)
dpf = np.array(texture.darray[0])
# define the exclusion mask (cingular pole)
if path_to_mask is not None:
mask = sio.load_texture(path_to_mask).darray[0]
else:
mask = None
thresh_dist_perc=0
thresh_ridge=0
thresh_area_perc=0
extract the sulcal graph from a mesh
g = ssg.extract_sulcal_graph(mesh,
thresh_dist_perc=thresh_dist_perc,
thresh_ridge=thresh_ridge,
thresh_area_perc=thresh_area_perc,
mask=mask)
Computing the curvature
Calculating vertex normals .... Please wait
Finished calculating vertex normals
Calculating curvature tensors ... Please wait
Finished Calculating curvature tensors
Calculating Principal Components ... Please wait
Finished Calculating principal components
Computing the DPF
Computing Laplacian
Computing mesh weights of type conformal
-edge length threshold needed for 0 values = 0.0 %
-number of Nan in weights: 0 = 0.0 %
-number of Negative values in weights: 936 = 6.706792777300086 %
-nb Nan in Laplacian : 0
-nb Inf in Laplacian : 0
Computing Voronoi's vertex
-percent polygon with obtuse angle 29.4067067927773
Computing watershed by flooding...
Thresholds provided:
-Distance between 2 pits: 0 % <=> 0.0 mm
-Ridge height: 0
-Basin area: 0 % <=> 0.0 mm2
add an attribute to nodes
g = ssg.add_node_attribute_from_texture(g, dpf, attribute_name='pit_depth')
print("Node attributes:\n", g.nodes[0].keys())
print("First node:\n", g.nodes[0])
Node attributes:
dict_keys(['pit_index', 'basin_vertices', 'pit_depth', 'basin_area', 'basin_label'])
First node:
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float32(-0.050967123), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0}
add an attribute to edges
g = ssg.add_edge_attribute_from_texture(g, dpf, attribute_name='ridge_depth_bis')
print("Edge attributes:\n", g.edges[list(g.edges)[0]].keys())
print("First edge:\n", g.edges[list(g.edges)[0]])
Edge attributes:
dict_keys(['weight', 'ridge_vertices', 'ridge_length', 'ridge_index', 'ridge_depth', 'ridge_depth_diff_min', 'ridge_depth_diff_max', 'ridge_depth_bis'])
First edge:
{'weight': 1, 'ridge_vertices': array([ 444, 449, 480, 1997, 2045]), 'ridge_length': 5, 'ridge_index': np.int64(2045), 'ridge_depth': np.float64(-0.005626444880465831), 'ridge_depth_diff_min': np.float64(0.0022356885067722687), 'ridge_depth_diff_max': np.float64(0.007418748606375233), 'ridge_depth_bis': -0.01064499281346798}
add geodesic distances attribute to edges
g = ssg.add_geodesic_distances_to_edges(g, mesh)
add mean value to nodes attributes
g = ssg.add_mean_value_to_nodes(g, dpf, attribute_name='basin_mean_depth')
get textures from graph
atex_labels, atex_pits, atex_ridges = ssg.get_textures_from_graph(g, mesh)
- A more detailed computation of the sulcal graph
with explicit call to the watershed
mean_curvature, dpf, voronoi = swat.compute_mesh_features(mesh)
Computing the curvature
Calculating vertex normals .... Please wait
Finished calculating vertex normals
Calculating curvature tensors ... Please wait
Finished Calculating curvature tensors
Calculating Principal Components ... Please wait
Finished Calculating principal components
Computing the DPF
Computing Laplacian
Computing mesh weights of type conformal
-edge length threshold needed for 0 values = 0.0 %
-number of Nan in weights: 0 = 0.0 %
-number of Negative values in weights: 936 = 6.706792777300086 %
-nb Nan in Laplacian : 0
-nb Inf in Laplacian : 0
Computing Voronoi's vertex
-percent polygon with obtuse angle 29.4067067927773
extract sulcal pits and associated basins
basins, ridges, adjacency = swat.watershed(
mesh, voronoi, dpf, thresh_dist_perc, thresh_ridge, thresh_area_perc, mask)
# generate the sulcal graph
g = ssg.get_sulcal_graph(adjacency, basins, ridges)
Computing watershed by flooding...
Thresholds provided:
-Distance between 2 pits: 0 % <=> 0.0 mm
-Ridge height: 0
-Basin area: 0 % <=> 0.0 mm2
generate the textures from graph
atex_labels_graph, atex_pits_graph, atex_ridges_graph = (ssg.get_textures_from_graph
(g, mesh))
# compare the textures extracted from the watershed with the ones extarcted from the graph
# they should be identical
print("vertex-to-vertex difference between the texture extracted from the "
"watershed and the one extracted from the graph, should be strictly qual to 0")
print(np.max(atex_ridges-atex_ridges_graph))
vertex-to-vertex difference between the texture extracted from the watershed and the one extracted from the graph, should be strictly qual to 0
0.0
add as a new node attribute the 3D coordinates of the vertex corresponding to the pit in the mesh used to compute the watershed
g = ssg.add_coords_attribute(g, mesh,
attribute_vert_index='pit_index',
new_attribute_key='3dcoords')
print("First node:\n", g.nodes[0])
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float64(-0.013045193486841064), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0, '3dcoords': array([ 6.71122503, -2.44120479, 0.5532046 ])}
First node:
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float64(-0.013045193486841064), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0, '3dcoords': array([ 6.71122503, -2.44120479, 0.5532046 ])}
add as a new node attribute the 3D coordinates of the vertex corresponding to the pit in the spherical mesh obtained from the original mesh, so that ‘pit_index’ also gives the corresponding vertex in that mesh
source_spherical_mesh_file = "../examples/data/example_mesh_spherical.gii"
source_spherical_mesh = sio.load_mesh(source_spherical_mesh_file)
g = ssg.add_coords_attribute(g, source_spherical_mesh,
attribute_vert_index='pit_index',
new_attribute_key='sphere_3dcoords')
print("First node:\n", g.nodes[0])
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float64(-0.013045193486841064), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0, '3dcoords': array([ 6.71122503, -2.44120479, 0.5532046 ]), 'sphere_3dcoords': array([ 0.46400985, 0.88582945, -0.00102251])}
First node:
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float64(-0.013045193486841064), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0, '3dcoords': array([ 6.71122503, -2.44120479, 0.5532046 ]), 'sphere_3dcoords': array([ 0.46400985, 0.88582945, -0.00102251])}
Load another mesh and corresponding spherical version to be used as a target onto which the graph will be projected
target_mesh_file = "../examples/data/example_mesh_2.gii"
target_mesh = sio.load_mesh(target_mesh_file)
target_spherical_mesh_file = "../examples/data/example_mesh_2_spherical.gii"
target_spherical_mesh = sio.load_mesh(target_spherical_mesh_file)
Project the depth texture using resampling.texture_spherical_interpolation_nearest_neighbor for the visu
interpolated_dpf = srem.texture_spherical_interpolation_nearest_neighbor(
source_spherical_mesh, target_spherical_mesh, dpf)
Compute the ‘interpolated_pits_index’ corresponding to the index of the nearest neighbor of each pit in the target spherical mesh
g = ssg.vertex_index_interpolation(g, target_spherical_mesh,
graph_spherical_coords_attribute='sphere_3dcoords',
interpolated_attribute='interpolated_pits_index')
print("First node:\n", g.nodes[0])
First node:
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float64(-0.013045193486841064), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0, '3dcoords': array([ 6.71122503, -2.44120479, 0.5532046 ]), 'sphere_3dcoords': array([ 0.46400985, 0.88582945, -0.00102251]), 'interpolated_pits_index': 492}
Here is the way to get the list of ‘interpolated_pits_index’ for all nodes
interp_pits_inds = np.array(list(nx.get_node_attributes(g, 'interpolated_pits_index').values()))
add as a new node attribute the 3D coordinates of the vertex corresponding to # the inperpolated pit in the target spherical mesh
g = ssg.add_coords_attribute(g, target_spherical_mesh,
attribute_vert_index='interpolated_pits_index',
new_attribute_key='target_sphere_3dcoords')
print("First node:\n", g.nodes[0])
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float64(-0.013045193486841064), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0, '3dcoords': array([ 6.71122503, -2.44120479, 0.5532046 ]), 'sphere_3dcoords': array([ 0.46400985, 0.88582945, -0.00102251]), 'interpolated_pits_index': 492, 'target_sphere_3dcoords': array([0.45437539, 0.89028907, 0.03046896])}
First node:
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float64(-0.013045193486841064), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0, '3dcoords': array([ 6.71122503, -2.44120479, 0.5532046 ]), 'sphere_3dcoords': array([ 0.46400985, 0.88582945, -0.00102251]), 'interpolated_pits_index': 492, 'target_sphere_3dcoords': array([0.45437539, 0.89028907, 0.03046896])}
add as a new node attribute the 3D coordinates of the vertex corresponding to # the inperpolated pit in the target mesh
g = ssg.add_coords_attribute(g, target_mesh,
attribute_vert_index='interpolated_pits_index',
new_attribute_key='target_mesh_3dcoords')
print("First node:\n", g.nodes[0])
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float64(-0.013045193486841064), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0, '3dcoords': array([ 6.71122503, -2.44120479, 0.5532046 ]), 'sphere_3dcoords': array([ 0.46400985, 0.88582945, -0.00102251]), 'interpolated_pits_index': 492, 'target_sphere_3dcoords': array([0.45437539, 0.89028907, 0.03046896]), 'target_mesh_3dcoords': array([69.98622894, 68.32143402, 50.87675095])}
First node:
{'pit_index': 530, 'basin_vertices': [530, 535, 2172, 529, 524, 2131, 2173, 531, 947, 964, 941, 911, 2199, 2174, 559, 912, 2132, 2187, 2198, 910, 909, 2158, 546, 2091, 561, 513, 2074, 2200, 871, 948, 537, 927, 860, 2211, 2133, 2188, 894, 861, 895, 862, 2216, 863, 875, 846, 966, 2204, 2212, 2104, 496, 873, 514, 913, 2038, 560, 2218, 847, 2134, 819, 876, 965, 2135, 2159, 2213, 516, 967, 949, 462, 874, 503, 548, 794, 2161, 2138, 2215, 2136, 2205, 463, 497, 968, 806, 782, 929, 884, 2163, 2219, 356, 2217, 831, 486, 464, 2220, 2227, 450, 155, 553, 2214, 2230, 848, 440, 952, 795, 456, 2177, 2190, 878, 741, 2232, 2231, 781, 1925, 774, 547, 896, 2242, 747, 2191, 808, 2221, 914, 942, 566, 885, 2250, 536, 2264, 2235, 769, 797, 850, 915, 2251, 552, 578, 515, 2265, 743, 879, 851, 2233, 886, 2266, 621, 770, 596, 2234, 587, 880, 488, 605, 562, 615, 2222, 579, 809, 852, 629, 853, 604, 2244, 640, 489, 748, 2252, 2236, 641, 458, 2223, 2243, 639, 608, 2267, 2268, 427, 2280, 403, 411, 393, 382, 370, 1529], 'pit_depth': np.float64(-0.013045193486841064), 'basin_area': np.float64(445.9305499974789), 'basin_label': 0, '3dcoords': array([ 6.71122503, -2.44120479, 0.5532046 ]), 'sphere_3dcoords': array([ 0.46400985, 0.88582945, -0.00102251]), 'interpolated_pits_index': 492, 'target_sphere_3dcoords': array([0.45437539, 0.89028907, 0.03046896]), 'target_mesh_3dcoords': array([69.98622894, 68.32143402, 50.87675095])}
VISUALIZATION USING plotly¶
import slam.plot as splt
mesh_data = {
"vertices": mesh.vertices,
"faces": mesh.faces,
"opacity": 0.5,
"title": 'Source'
}
intensity_data = {
"values": dpf,
"mode": "vertex",
}
fig1 = splt.plot_mesh(
mesh_data=mesh_data,
intensity_data=intensity_data)
fig1 = splt.plot_graph(g, coords_attribute='3dcoords', fig=fig1,
marker={"size": 6, "color": "white", "line":{"color":"black", "width":2}},
)
fig1.show()
fig1
mesh_data = {
"vertices": source_spherical_mesh.vertices,
"faces": source_spherical_mesh.faces,
"title": 'Source spherical'
}
fig2 = splt.plot_mesh(
mesh_data=mesh_data,
intensity_data=intensity_data)
# add the pits to the plot
pits_coords = np.array(list(nx.get_node_attributes(g, 'sphere_3dcoords').values()))
trace_points = splt.plot_points(
pits_coords,
marker={"size": 6, "color": "white", "line":{"color":"black", "width":2}},
)
fig2.add_trace(trace_points)
fig2.show()
fig2
mesh_data = {
"vertices": target_spherical_mesh.vertices,
"faces": target_spherical_mesh.faces,
"title": 'Target sphere'
}
intensity_data = {
"values": interpolated_dpf,
"mode": "vertex",
}
fig3 = splt.plot_mesh(
mesh_data=mesh_data,
intensity_data=intensity_data)
# add the pits to the plot
pits_init = splt.plot_points(
pits_coords,
marker={"size": 6, "color": "white", "line":{"color":"black", "width":2}},
)
fig3.add_trace(pits_init)
# add the interpolated pits to the plot
interp_pits_coords_sphere = np.array(list(nx.get_node_attributes(g, 'target_sphere_3dcoords').values()))
pits_interpolated = splt.plot_points(
interp_pits_coords_sphere,
marker={"size": 6, "color": "red", "line":{"color":"black", "width":2}},
)
fig3.add_trace(pits_interpolated)
fig3.show()
fig3
mesh_data = {
"vertices": target_mesh.vertices,
"faces": target_mesh.faces,
"title": 'Target mesh'
}
intensity_data = {
"values": interpolated_dpf,
"mode": "vertex",
}
fig4 = splt.plot_mesh(
mesh_data=mesh_data,
intensity_data=intensity_data)
# add the interpolated pits to the plot
interp_pits_coords_mesh = np.array(list(nx.get_node_attributes(g, 'target_mesh_3dcoords').values()))
pits_interpolated = splt.plot_points(
interp_pits_coords_mesh,
marker={"size": 6, "color": "red", "line":{"color":"black", "width":2}}
)
fig4.add_trace(pits_interpolated)
fig4.show()
fig4
Total running time of the script: (0 minutes 18.263 seconds)