def calc_geodesic_matrix(bones, mesh_v, surface_geodesic, mesh_filename, subsampling=False): """ calculate volumetric geodesic distance from vertices to each bones :param bones: B*6 numpy array where each row stores the starting and ending joint position of a bone :param mesh_v: V*3 mesh vertices :param surface_geodesic: geodesic distance matrix of all vertices :param mesh_filename: mesh filename :return: an approaximate volumetric geodesic distance matrix V*B, were (v,b) is the distance from vertex v to bone b """ if subsampling: mesh0 = o3d.io.read_triangle_mesh(mesh_filename) mesh0 = mesh0.simplify_quadric_decimation(3000) o3d.io.write_triangle_mesh(mesh_filename.replace(".obj", "_simplified.obj"), mesh0) mesh_trimesh = trimesh.load(mesh_filename.replace(".obj", "_simplified.obj")) subsamples_ids = np.random.choice(len(mesh_v), np.min((len(mesh_v), 1500)), replace=False) subsamples = mesh_v[subsamples_ids, :] surface_geodesic = surface_geodesic[subsamples_ids, :][:, subsamples_ids] else: mesh_trimesh = trimesh.load(mesh_filename) subsamples = mesh_v origins, ends, pts_bone_dist = pts2line(subsamples, bones) pts_bone_visibility = calc_pts2bone_visible_mat(mesh_trimesh, origins, ends) pts_bone_visibility = pts_bone_visibility.reshape(len(bones), len(subsamples)).transpose() pts_bone_dist = pts_bone_dist.reshape(len(bones), len(subsamples)).transpose() # remove visible points which are too far for b in range(pts_bone_visibility.shape[1]): visible_pts = np.argwhere(pts_bone_visibility[:, b] == 1).squeeze(1) if len(visible_pts) == 0: continue threshold_b = np.percentile(pts_bone_dist[visible_pts, b], 15) pts_bone_visibility[pts_bone_dist[:, b] > 1.3 * threshold_b, b] = False visible_matrix = np.zeros(pts_bone_visibility.shape) visible_matrix[np.where(pts_bone_visibility == 1)] = pts_bone_dist[np.where(pts_bone_visibility == 1)] for c in range(visible_matrix.shape[1]): unvisible_pts = np.argwhere(pts_bone_visibility[:, c] == 0).squeeze(1) visible_pts = np.argwhere(pts_bone_visibility[:, c] == 1).squeeze(1) if len(visible_pts) == 0: visible_matrix[:, c] = pts_bone_dist[:, c] continue for r in unvisible_pts: dist1 = np.min(surface_geodesic[r, visible_pts]) nn_visible = visible_pts[np.argmin(surface_geodesic[r, visible_pts])] if np.isinf(dist1): visible_matrix[r, c] = 8.0 + pts_bone_dist[r, c] else: visible_matrix[r, c] = dist1 + visible_matrix[nn_visible, c] if subsampling: nn_dist = np.sum((mesh_v[:, np.newaxis, :] - subsamples[np.newaxis, ...])**2, axis=2) nn_ind = np.argmin(nn_dist, axis=1) visible_matrix = visible_matrix[nn_ind, :] os.remove(mesh_filename.replace(".obj", "_simplified.obj")) return visible_matrix
def calc_geodesic_matrix(bones, mesh_v, surface_geodesic, mesh_filename): """ calculate volumetric geodesic distance from vertices to each bones :param bones: B*6 numpy array where each row stores the starting and ending joint position of a bone :param mesh_v: V*3 mesh vertices :param surface_geodesic: geodesic distance matrix of all vertices :param mesh_filename: mesh filename :return: an approaximate volumetric geodesic distance matrix V*B, were (v,b) is the distance from vertex v to bone b """ mesh_trimesh = trimesh.load(mesh_filename) origins, ends, pts_bone_dist = pts2line(mesh_v, bones) pts_bone_visibility = calc_pts2bone_visible_mat(mesh_trimesh, origins, ends) pts_bone_visibility = pts_bone_visibility.reshape(len(bones), len(mesh_v)).transpose() pts_bone_dist = pts_bone_dist.reshape(len(bones), len(mesh_v)).transpose() # remove visible points which are too far for b in range(pts_bone_visibility.shape[1]): visible_pts = np.argwhere(pts_bone_visibility[:, b] == 1).squeeze(1) if len(visible_pts) == 0: continue threshold_b = np.percentile(pts_bone_dist[visible_pts, b], 15) pts_bone_visibility[pts_bone_dist[:, b] > 1.3 * threshold_b, b] = False visible_matrix = np.zeros(pts_bone_visibility.shape) visible_matrix[np.where( pts_bone_visibility == 1)] = pts_bone_dist[np.where( pts_bone_visibility == 1)] for c in range(visible_matrix.shape[1]): unvisible_pts = np.argwhere(pts_bone_visibility[:, c] == 0).squeeze(1) visible_pts = np.argwhere(pts_bone_visibility[:, c] == 1).squeeze(1) if len(visible_pts) == 0: visible_matrix[:, c] = pts_bone_dist[:, c] continue for r in unvisible_pts: dist1 = np.min(surface_geodesic[r, visible_pts]) nn_visible = visible_pts[np.argmin(surface_geodesic[r, visible_pts])] if np.isinf(dist1): visible_matrix[r, c] = 8.0 + pts_bone_dist[r, c] else: visible_matrix[r, c] = dist1 + visible_matrix[nn_visible, c] return visible_matrix