|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
import time
|
|
|
import open3d as o3d
|
|
|
from scipy.sparse import lil_matrix
|
|
|
from scipy.sparse.csgraph import dijkstra
|
|
|
|
|
|
|
|
|
def get_bones(skel):
|
|
|
"""
|
|
|
extract bones from skeleton struction
|
|
|
:param skel: input skeleton
|
|
|
:return: bones are B*6 array where each row consists starting and ending points of a bone
|
|
|
bone_name are a list of B elements, where each element consists starting and ending joint name
|
|
|
leaf_bones indicate if this bone is a virtual "leaf" bone.
|
|
|
We add virtual "leaf" bones to the leaf joints since they always have skinning weights as well
|
|
|
"""
|
|
|
bones = []
|
|
|
bone_name = []
|
|
|
leaf_bones = []
|
|
|
this_level = [skel.root]
|
|
|
while this_level:
|
|
|
next_level = []
|
|
|
for p_node in this_level:
|
|
|
p_pos = np.array(p_node.pos)
|
|
|
next_level += p_node.children
|
|
|
for c_node in p_node.children:
|
|
|
c_pos = np.array(c_node.pos)
|
|
|
bones.append(np.concatenate((p_pos, c_pos))[np.newaxis, :])
|
|
|
bone_name.append([p_node.name, c_node.name])
|
|
|
leaf_bones.append(False)
|
|
|
if len(c_node.children) == 0:
|
|
|
bones.append(np.concatenate((c_pos, c_pos))[np.newaxis, :])
|
|
|
bone_name.append([c_node.name, c_node.name+'_leaf'])
|
|
|
leaf_bones.append(True)
|
|
|
this_level = next_level
|
|
|
bones = np.concatenate(bones, axis=0)
|
|
|
return bones, bone_name, leaf_bones
|
|
|
|
|
|
|
|
|
def calc_surface_geodesic(mesh):
|
|
|
|
|
|
samples = mesh.sample_points_poisson_disk(number_of_points=4000)
|
|
|
pts = np.asarray(samples.points)
|
|
|
pts_normal = np.asarray(samples.normals)
|
|
|
|
|
|
time1 = time.time()
|
|
|
N = len(pts)
|
|
|
verts_dist = np.sqrt(np.sum((pts[np.newaxis, ...] - pts[:, np.newaxis, :]) ** 2, axis=2))
|
|
|
verts_nn = np.argsort(verts_dist, axis=1)
|
|
|
conn_matrix = lil_matrix((N, N), dtype=np.float32)
|
|
|
|
|
|
for p in range(N):
|
|
|
nn_p = verts_nn[p, 1:6]
|
|
|
norm_nn_p = np.linalg.norm(pts_normal[nn_p], axis=1)
|
|
|
norm_p = np.linalg.norm(pts_normal[p])
|
|
|
cos_similar = np.dot(pts_normal[nn_p], pts_normal[p]) / (norm_nn_p * norm_p + 1e-10)
|
|
|
nn_p = nn_p[cos_similar > -0.5]
|
|
|
conn_matrix[p, nn_p] = verts_dist[p, nn_p]
|
|
|
[dist, predecessors] = dijkstra(conn_matrix, directed=False, indices=range(N),
|
|
|
return_predecessors=True, unweighted=False)
|
|
|
|
|
|
|
|
|
|
|
|
inf_pos = np.argwhere(np.isinf(dist))
|
|
|
if len(inf_pos) > 0:
|
|
|
euc_distance = np.sqrt(np.sum((pts[np.newaxis, ...] - pts[:, np.newaxis, :]) ** 2, axis=2))
|
|
|
dist[inf_pos[:, 0], inf_pos[:, 1]] = 8.0 + euc_distance[inf_pos[:, 0], inf_pos[:, 1]]
|
|
|
|
|
|
verts = np.array(mesh.vertices)
|
|
|
vert_pts_distance = np.sqrt(np.sum((verts[np.newaxis, ...] - pts[:, np.newaxis, :]) ** 2, axis=2))
|
|
|
vert_pts_nn = np.argmin(vert_pts_distance, axis=0)
|
|
|
surface_geodesic = dist[vert_pts_nn, :][:, vert_pts_nn]
|
|
|
time2 = time.time()
|
|
|
print('surface geodesic calculation: {} seconds'.format((time2 - time1)))
|
|
|
return surface_geodesic
|
|
|
|