def create_single_data(mesh_filaname): """ create input data for the network. The data is wrapped by Data structure in pytorch-geometric library :param mesh_filaname: name of the input mesh :return: wrapped data, voxelized mesh, and geodesic distance matrix of all vertices """ mesh = o3d.io.read_triangle_mesh(mesh_filaname) mesh.compute_triangle_normals() mesh_v = np.asarray(mesh.vertices) mesh_vn = np.asarray(mesh.vertex_normals) mesh_f = np.asarray(mesh.triangles) mesh_v, translation_normalize, scale_normalize = normalize_obj(mesh_v) mesh_normalized = o3d.geometry.TriangleMesh( vertices=o3d.utility.Vector3dVector(mesh_v), triangles=o3d.utility.Vector3iVector(mesh_f)) o3d.io.write_triangle_mesh( mesh_filename.replace("_remesh.obj", "_normalized.obj"), mesh_normalized) # vertices v = np.concatenate((mesh_v, mesh_vn), axis=1) v = torch.from_numpy(v).float() # topology edges print(" gathering topological edges.") tpl_e = get_tpl_edges(mesh_v, mesh_f).T tpl_e = torch.from_numpy(tpl_e).long() tpl_e, _ = add_self_loops(tpl_e, num_nodes=v.size(0)) # surface geodesic distance matrix print(" calculating surface geodesic matrix.") surface_geodesic = calc_surface_geodesic(mesh) # geodesic edges print(" gathering geodesic edges.") geo_e = get_geo_edges(surface_geodesic, mesh_v).T geo_e = torch.from_numpy(geo_e).long() geo_e, _ = add_self_loops(geo_e, num_nodes=v.size(0)) # batch batch = torch.zeros(len(v), dtype=torch.long) # voxel if not os.path.exists( mesh_filaname.replace('_remesh.obj', '_normalized.binvox')): os.system("./binvox -d 88 -pb " + mesh_filaname.replace("_remesh.obj", "_normalized.obj")) with open(mesh_filaname.replace('_remesh.obj', '_normalized.binvox'), 'rb') as fvox: vox = binvox_rw.read_as_3d_array(fvox) data = Data(x=v[:, 3:6], pos=v[:, 0:3], tpl_edge_index=tpl_e, geo_edge_index=geo_e, batch=batch) return data, vox, surface_geodesic, translation_normalize, scale_normalize
def create_single_data(mesh_obj): """ create input data for the network. The data is wrapped by Data structure in pytorch-geometric library :param mesh_filaname: name of the input mesh :return: wrapped data, voxelized mesh, and geodesic distance matrix of all vertices """ # triangulate first bm = bmesh.new() bm.from_mesh(mesh_obj.data) bmesh.ops.triangulate(bm, faces=bm.faces[:], quad_method='BEAUTY', ngon_method='BEAUTY') bm.verts.ensure_lookup_table() bm.faces.ensure_lookup_table() mesh_v = np.asarray([list(v.co) for v in bm.verts]) mesh_f = np.asarray([[v.index for v in f.verts] for f in bm.faces]) bm.free() mesh = o3d.geometry.TriangleMesh(o3d.utility.Vector3dVector(mesh_v), o3d.open3d.utility.Vector3iVector(mesh_f)) mesh.compute_vertex_normals() mesh.compute_triangle_normals() # renew mesh component list with o3d mesh, for consistency mesh_v = np.asarray(mesh.vertices) mesh_vn = np.asarray(mesh.vertex_normals) mesh_f = np.asarray(mesh.triangles) mesh_v, translation_normalize, scale_normalize = normalize_obj(mesh_v) mesh_normalized = o3d.geometry.TriangleMesh( vertices=o3d.utility.Vector3dVector(mesh_v), triangles=o3d.utility.Vector3iVector(mesh_f)) global MESH_NORMALIZED MESH_NORMALIZED = mesh_normalized # vertices v = np.concatenate((mesh_v, mesh_vn), axis=1) v = torch.from_numpy(v).float() # topology edges print(" gathering topological edges.") tpl_e = get_tpl_edges(mesh_v, mesh_f).T tpl_e = torch.from_numpy(tpl_e).long() tpl_e, _ = add_self_loops(tpl_e, num_nodes=v.size(0)) # surface geodesic distance matrix print(" calculating surface geodesic matrix.") surface_geodesic = calc_surface_geodesic(mesh) # geodesic edges print(" gathering geodesic edges.") geo_e = get_geo_edges(surface_geodesic, mesh_v).T geo_e = torch.from_numpy(geo_e).long() geo_e, _ = add_self_loops(geo_e, num_nodes=v.size(0)) # batch batch = torch.zeros(len(v), dtype=torch.long) # voxel fo_normalized = tempfile.NamedTemporaryFile(suffix='_normalized.obj') fo_normalized.close() o3d.io.write_triangle_mesh(fo_normalized.name, mesh_normalized) # TODO: we might cache the .binvox file somewhere, as in the RigNet quickstart example rignet_path = bpy.context.preferences.addons[ __package__].preferences.rignet_path binvox_exe = os.path.join(rignet_path, "binvox") if sys.platform.startswith("win"): binvox_exe += ".exe" if not os.path.isfile(binvox_exe): os.unlink(fo_normalized.name) clear() raise FileNotFoundError( "binvox executable not found in {0}, please check RigNet path in the addon preferences" ) os.system(binvox_exe + " -d 88 " + fo_normalized.name) with open(os.path.splitext(fo_normalized.name)[0] + '.binvox', 'rb') as fvox: vox = binvox_rw.read_as_3d_array(fvox) os.unlink(fo_normalized.name) data = Data(x=v[:, 3:6], pos=v[:, 0:3], tpl_edge_index=tpl_e, geo_edge_index=geo_e, batch=batch) return data, vox, surface_geodesic, translation_normalize, scale_normalize
def create_single_data(mesh, vox, surface_geodesic, pred_joints): """ create data used as input to networks, wrapped by Data structure in pytorch-gemetric library :param mesh: input mesh loaded by open3d :param vox: voxelized mesh :param surface_geodesic: geodesic distance matrix of all vertices :param pred_joints: predicted joints :return: wrapped data structure """ mesh_v = np.asarray(mesh.vertices) mesh_vn = np.asarray(mesh.vertex_normals) mesh_f = np.asarray(mesh.triangles) # vertices v = np.concatenate((mesh_v, mesh_vn), axis=1) v = torch.from_numpy(v).float() # topology edges print(" gathering topological edges.") tpl_e = get_tpl_edges(mesh_v, mesh_f).T tpl_e = torch.from_numpy(tpl_e).long() tpl_e, _ = add_self_loops(tpl_e, num_nodes=v.size(0)) # geodesic edges print(" gathering geodesic edges.") geo_e = get_geo_edges(surface_geodesic, mesh_v).T geo_e = torch.from_numpy(geo_e).long() geo_e, _ = add_self_loops(geo_e, num_nodes=v.size(0)) batch = np.zeros(len(v)) batch = torch.from_numpy(batch).long() pair_all = [] for joint1_id in range(len(pred_joints)): for joint2_id in range(joint1_id + 1, len(pred_joints)): dist = np.linalg.norm(pred_joints[joint1_id] - pred_joints[joint2_id]) bone_samples = sample_on_bone(pred_joints[joint1_id], pred_joints[joint2_id]) bone_samples_inside, _ = inside_check(bone_samples, vox) outside_proportion = len(bone_samples_inside) / ( len(bone_samples) + 1e-10) pair = np.array( [joint1_id, joint2_id, dist, outside_proportion, 1]) pair_all.append(pair) pair_all = np.array(pair_all) pair_all = torch.from_numpy(pair_all).float() num_pair = len(pair_all) num_joint = len(pred_joints) if len(pred_joints) < len(mesh_v): pred_joints = np.tile( pred_joints, (round(1.0 * len(mesh_v) / len(pred_joints) + 0.5), 1)) pred_joints = pred_joints[:len(mesh_v), :] elif len(pred_joints) > len(mesh_v): pred_joints = pred_joints[:len(mesh_v), :] pred_joints = torch.from_numpy(pred_joints).float() data = Data(x=torch.from_numpy(mesh_vn), pos=torch.from_numpy(mesh_v).float(), batch=batch, y=pred_joints, pairs=pair_all, num_pair=[num_pair], tpl_edge_index=tpl_e, geo_edge_index=geo_e, num_joint=[num_joint]).to(device) return data