def naive_approach(pathes1, pathes2, r=9): """ A naive approch at image warping. We justproject the vertices on both images and associate the corresponding pixels This methods only recover a small amount of pixels ---- input: pathes1, pathes2: tuple containing 4 strings corresponding, in this order, to the path to the image, the keypoints .txt file, the mesh .obj file and the camera calibration folder r: int -> radius of the patch of pixels we copy when we find a match ---- output: None """ path_img1, path_kpt1, path_mesh1, path_cameras1 = pathes1 path_img2, path_kpt2, path_mesh2, path_cameras2 = pathes2 db1 = "BEE10" if "BEE10" in path_img1 else "Emily" db2 = "BEE10" if "BEE10" in path_img2 else "Emily" img1 = io.imread(path_img1)[..., :3] img2 = io.imread(path_img2)[..., :3] kpt1 = io_keypoints.recover_keypoints(path_kpt1, have_indices=False) kpt2 = io_keypoints.recover_keypoints(path_kpt2, have_indices=False) *_, tform_2_1 = mesh_helper.procrustes(kpt1[:27], kpt2[:27]) v1, _ = igl.read_triangle_mesh(path_mesh1) v2, _ = igl.read_triangle_mesh(path_mesh2) cams1, *_ = tfm.get_info_cameras(path_cameras1, dataset=db1) cams2, *_ = tfm.get_info_cameras(path_cameras2, dataset=db2) cam1 = cams1[2] cam2 = cams2[5] M1, N1, _ = img1.shape M2, N2, _ = img2.shape new_img1 = np.zeros((M1, N1, 3), dtype=np.int) for k in range(len(v1)): pt1 = v1[k] pt2 = v2[k] y1, x1 = np.round(tfm.project_point(pt1, cam1)).astype(int) y2, x2 = np.round(tfm.project_point(pt2, cam2)).astype(int) if 0 <= x1 - r and x1 + r < M1 and 0 <= y1 - r and y1 + r < N1 and\ 0 <= x2 - r and x2 + r < M2 and 0 <= y2 - r and y2 + r < N2: new_img1[x1 - r: x1 + r + 1, y1 - r: y1 + r + 1] =\ img2[x2 - r: x2 + r + 1, y2 - r: y2 + r + 1] plt.figure() plt.imshow(new_img1 / new_img1.max()) plt.axis("off") plt.show()
def test_read_triangle_mesh(self): v, f = igl.read_triangle_mesh(self.test_path + "octopus-low.mesh") #print(v.shape, f.shape) v, f = igl.read_triangle_mesh(self.test_path + "face.obj") #print(v.shape, f.shape) v, f = igl.read_triangle_mesh(self.test_path + "bunny.off") #print(v.shape, f.shape) self.assertTrue(v.flags.c_contiguous) self.assertTrue(f.flags.c_contiguous)
def is_manifold(file=None, faces=None): if file is not None: _, faces = igl.read_triangle_mesh(file, np.float64) if faces is None: print("Specify at least one of the parameters.") assert faces is not None return igl.extract_manifold_patches(faces)[0] == 1
def exp1(W, pt_index, mvt, pathes): """ Moving one point with different weights ---- input: W: float list of length N -> the different weights pt_index: int -> the index of the vertex we want to move mvt: float list of length 3 -> the shift we want to apply to the vertex pathes: 3-tuple -> path to the surfacic mesh, the volumetric .obj and the volunetric .mesh, in this order ---- output: times: float array of shape (3, N) -> computation time for each mesh and for each weight """ times = [[], [], []] v, f = igl.read_triangle_mesh(pathes[0]) anchors = np.array([v[pt_index] + mvt], dtype=np.double) anchors_id = np.array([pt_index], dtype=np.int) for w in W: print("Experience 1, w = {}".format(w)) t1 = time() v, f = lp_ed.laplacian_editing(pathes[0], anchors, anchors_id, tetra=False, custom_weight=[w]) lp_ed.save_mesh("exp1_tri_w={}.obj".format(w), v, f) t2 = time() v, f = lp_ed.laplacian_editing(pathes[1], anchors, anchors_id, tetra=False, custom_weight=[w]) lp_ed.save_mesh("exp1_tet_tri_w={}.obj".format(w), v, f) t3 = time() v, f = lp_ed.laplacian_editing(pathes[2], anchors, anchors_id, tetra=True, custom_weight=[w]) lp_ed.save_mesh("exp1_tet_tet_w={}.obj".format(w), v, f) t4 = time() times[0].append(t2 - t1) times[1].append(t3 - t2) times[2].append(t4 - t3) dt1, dt2, dt3 = times[0][-1], times[1][-1], times[2][-1] print(f"tri: {dt1}s, tet_tri: {dt2}s, tet_tet: {dt3}s") print(times) print("Total time using tri:", sum(times[0])) print("Total time using tet_tri:", sum(times[1])) print("Total time using tet_tet:", sum(times[2])) return times
def transform(self, v: np.ndarray, f: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: # nv, nf, _, _, _ = igl.offset_surface(v, f, 0, 64, SIGNED_DISTANCE_TYPE_PSEUDONORMAL) igl.write_triangle_mesh("/home/zgong8/temp/mc_tmp_in.obj", v, f) subprocess.run(["/home/zgong8/libigl/tutorial/build/bin/705_MarchingCubes", "/home/zgong8/temp/mc_tmp_in.obj", "/home/zgong8/temp/mc_tmp_out_1.obj", "/home/zgong8/temp/mc_tmp_out_2.obj"]) nv, nf = igl.read_triangle_mesh("/home/zgong8/temp/mc_tmp_out_2.obj", np.float64) return nv, nf
def process_shape_file(self, in_file: str, out_file: str): assert self.is_full() vertices, faces = igl.read_triangle_mesh(in_file, np.float64) new_vertices, new_faces = self.process_shape_data(vertices, faces) if new_faces is not None: if len(new_faces) < max_output_faces: igl.write_triangle_mesh(out_file, new_vertices, new_faces) return True else: print("Too large, bad for connection, dropped in the end.") return False
def manifold_object(in_path, out_path): temp_path = temp_obj v, f = igl.read_triangle_mesh(in_path) size = len(f) multiplier = size * 5 subprocess.run(["./manifold", in_path, temp_path], cwd=refiner_path) subprocess.run([ "./simplify", "-i", temp_path, "-o", out_path, "-m", "-f", str(multiplier) ], cwd=refiner_path)
def __init__(self, meshPath=None, V=None, F=None, doNormalize=True): if V is None and F is None: if meshPath is not None: self.V, self.F = igl.read_triangle_mesh(meshPath) else: raise UserWarning( "Incorrect usage of Mesh class. Either path to existing mesh (meshPath) must be given, or array of vertices(V) and faces(F)." ) else: self.V = V self.F = F if doNormalize: self._normalizeMesh()
def count_shape_net_components(): total = 0 counter = 0 for in_file in iterate_shape_net(): v, f = igl.read_triangle_mesh(in_file, np.float64) tm = trimesh.Trimesh(v, f) components = trimesh.graph.connected_components(tm.edges, engine='scipy') num_of_components = len(components) if num_of_components > 1: counter += 1 total += 1 print(counter, "out of", total)
def inner_surface(in_path, out_path, depth=1, nsteps=1): '''compute inner surfaces from mesh at in_path, save results''' # load input mesh v, f = igl.read_triangle_mesh(in_path) v2array = inner_surface_mesh(v, f, depth=depth, nsteps=nsteps) if nsteps == 1: igl.write_triangle_mesh(out_path, v2array[0], f, force_ascii=False) else: split = out_path.split(".") for step in range(nsteps): step_str = "%03i" % (step + 1) out_path_step = ".".join([*(split[:-2]), step_str, split[-1]]) igl.write_triangle_mesh(out_path_step, v2array[step], f, force_ascii=False)
def init(file_name, env, **kwargs): def assign_neighbor_matrix(neighbors, v_id1, v_id2, v_id3): env.neighbors[v_id1, v_id2] = 1 env.neighbors[v_id2, v_id1] = 1 env.neighbors[v_id1, v_id3] = 1 env.neighbors[v_id3, v_id1] = 1 env.neighbors[v_id2, v_id3] = 1 env.neighbors[v_id3, v_id2] = 1 return neighbors if "V" in kwargs and "F" in kwargs: pass else: V, F = igl.read_triangle_mesh(file_name) #TODO env.n = len(V) env.vertice = V env.vertice_prime = copy.deepcopy(V) env.faces = F env.neighbors = np.zeros([env.n, env.n]) env.edge_matrix = np.zeros((env.n, env.n)) env.cell_rotaion = np.zeros((env.n, env.n, 3)) for i in range(env.n): env.verts_to_face.append([]) for i, face in enumerate(env.faces): env.verts_to_face[env.face[0]].append(i) env.verts_to_face[env.face[1]].append(i) env.verts_to_face[env.face[2]].append(i) env.neighbors = assign_neighbor_matrix( env.neighbors, face[0], face[1], face[2]) #NxN neighbor_matrix for row in range(env.n): env.edge_matrix[row][row] = env.neighbors[row].sum() return env
def poisson_recon(self, cloud, estimate_normals=True, depth=6, fulldepth=4, knn=10): pymeshlab = self.mlab temp_dir = os.path.expanduser('~/.temp/meshlab/') sysutil.mkdirs(temp_dir) cloud_path = os.path.join(temp_dir, "cloud.pts") recon_path = os.path.join(temp_dir, "recon.ply") np.savetxt(cloud_path, cloud) ms = pymeshlab.MeshSet() ms.load_new_mesh(cloud_path) ms.compute_normals_for_point_sets(k=20) ms.surface_reconstruction_screened_poisson(depth=depth, fulldepth=fulldepth) ms.save_current_mesh(recon_path) vert, face = igl.read_triangle_mesh(recon_path) return vert, face
def features_extractor(classes,DNA_size=50): """Extract the features from the samples in the dataset. The type of features is the ShapeDNA. :param classes: list list of the classes :param DNA_size: int size of the feature vector """ print("\nFeature extraction") for c in classes: print(c) for file in os.listdir(os.path.join('.', 'Dataset', c)): if file.endswith(".off"): print("\t", file, end=" ... ") # Load mesh v, f = igl.read_triangle_mesh(os.path.join('.', 'Dataset',c, file)) M = igl.massmatrix(v, f, igl.MASSMATRIX_TYPE_VORONOI) v = v / np.sqrt(M.sum()) # Compute Laplacian L = -igl.cotmatrix(v, f) M = igl.massmatrix(v, f, igl.MASSMATRIX_TYPE_VORONOI) # Compute EigenDecomposition try: evals, evecs = sp.sparse.linalg.eigsh(L, DNA_size+2, M, sigma=0.0, which='LM', maxiter=1e9, tol=1.e-15) except: evals, evecs = sp.sparse.linalg.eigsh(L + 1e-8 * sp.sparse.identity(v.shape[0]), DNA_size+2, M, sigma=0.0, which='LM', maxiter=1e9, tol=1.e-15) # Shape DNA descriptors = evals[2:] / evals[1] # Save descriptor np.save(os.path.join('.', 'Dataset', c, file[:-4] + "_DNA"), descriptors, allow_pickle=False) print("done.") print("Finished")
# Add the igl library to the modules search path import sys, os sys.path.insert(0, os.getcwd() + "/../") import igl V = igl.eigen.MatrixXd() F = igl.eigen.MatrixXi() igl.read_triangle_mesh("../../tutorial/shared/fertility.off", V, F) # Alternative discrete mean curvature HN = igl.eigen.MatrixXd() L = igl.eigen.SparseMatrixd() M = igl.eigen.SparseMatrixd() Minv = igl.eigen.SparseMatrixd() igl.cotmatrix(V, F, L) igl.massmatrix(V, F, igl.MASSMATRIX_TYPE_VORONOI, M) igl.invert_diag(M, Minv) # Laplace-Beltrami of position HN = -Minv * (L * V) # Extract magnitude as mean curvature H = HN.rowwiseNorm() # Compute curvature directions via quadric fitting PD1 = igl.eigen.MatrixXd() PD2 = igl.eigen.MatrixXd()
import igl import meshplot meshplot.offline() import numpy as np import os root_folder = os.getcwd() v, f = igl.read_triangle_mesh( os.path.join(root_folder, "data", "armadillo.obj")) #sample points on a 64x64x64 grid n = 64 K = np.linspace(-1.0, 1.0, n) pts = np.array([[x, y, z] for x in K for y in K for z in K]) S, _, _ = igl.signed_distance( pts, v, f, sign_type=igl.SIGNED_DISTANCE_TYPE_FAST_WINDING_NUMBER) nV, nF = igl.marching_cubes(S, pts, n, n, n, 0.0) meshplot.plot(nV, nF)
import igl V = igl.eigen.MatrixXd() U = igl.eigen.MatrixXd() F = igl.eigen.MatrixXi() c = 0 bbd = 1.0 twod = False if not igl.read_triangle_mesh("../tutorial/shared/beetle.off",V,F): print("failed to load mesh") twod = V.col(2).minCoeff() == V.col(2).maxCoeff() bbd = (V.colwiseMaxCoeff() - V.colwiseMinCoeff()).norm() L = igl.eigen.SparseMatrixd() M = igl.eigen.SparseMatrixd() igl.cotmatrix(V,F,L) L = -L igl.massmatrix(V,F,igl.MASSMATRIX_TYPE_DEFAULT,M) k = 5 D = igl.eigen.MatrixXd() if not igl.eigs(L,M,k+1,igl.EIGS_TYPE_SM,U,D): print("Eigs failed.") U = (U-U.minCoeff())/(U.maxCoeff()-U.minCoeff()); viewer = igl.viewer.Viewer()
def better_approach(pathes1, pathes2, view_indices, r=4, path_assoc_tri=None): """ A better approach to image warping using the following steps: 1) Each face is projected on the first image 2) We associate to each pixel the set of faces it is in 3) For every pixel having at least one matching face, we compute the ray passing through it and find the intersection point to the closest matching face. We the compute its barycentric coordinates 4) We find the point on the other mesh that has the same barycentric coordinates in the corresponding faces and project it onto its image plane 5) The color of the projected point will be the one used for the initial pixel It also saves the mask of the first image as mask.png and the associated_triangles matrix as a .npy file ---- input: pathes1, pathes2:tuple containing 4 strings corresponding, in this order, to the path to the image, the keypoints .txt file, the mesh .obj file and the camera calibration folder view_indices: two ints -> the indices of the views used r: int -> sampling ration on the image we want to tompute path_assoc_tri: str tuple of length 2 -> if the pixel-triangle association has already been computed for the two images, this is the path to the .npy files. If None, it is computed and saved ---- output: new_img: a float array with shape image1.shape / r -> The face on image2 warped on image1 """ path_img1, path_kpt1, path_mesh1, path_cameras1 = pathes1 path_img2, path_kpt2, path_mesh2, path_cameras2 = pathes2 db1 = "BEE10" if "BEE10" in path_img1 else "Emily" db2 = "BEE10" if "BEE10" in path_img2 else "Emily" view_index1, view_index2 = view_indices img1 = io.imread(path_img1)[..., :3] img2 = io.imread(path_img2)[..., :3] M1, N1, _ = img1.shape M2, N2, _ = img2.shape cams1, _, r_vectors1, t_vectors1, _ = tfm.get_info_cameras(path_cameras1, dataset=db1) cams2, _, r_vectors2, t_vectors2, _ = tfm.get_info_cameras(path_cameras2, dataset=db2) cam1 = cams1[view_index1] cam2 = cams2[view_index2] rvec1, tvec1 = r_vectors1[view_index1], t_vectors1[view_index1] rvec2, tvec2 = r_vectors2[view_index2], t_vectors2[view_index2] # Step 1: projecting the faces v1, f1 = igl.read_triangle_mesh(path_mesh1) v2, f2 = igl.read_triangle_mesh(path_mesh2) v1_proj, *_ = tfm.project_landmarks(v1, cam1) v2_proj, *_ = tfm.project_landmarks(v2, cam2) triangles_2d1 = v1_proj[f1] triangles_2d2 = v2_proj[f2] # Step 2: associating pixels and triangles if path_assoc_tri is None: assoc_tri1 = compute_association_pixels_triangles( triangles_2d1, (M1, N1), r) assoc_tri2 = compute_association_pixels_triangles( triangles_2d2, (M2, N2), 1) print("Saving the file") path_save1 = f"assoc_{db1}_view{view_index1}_r={r}.npy" path_save2 = f"assoc_{db2}_view{view_index2}_r={1}.npy" save_associated_triangles(assoc_tri1, path_save1) save_associated_triangles(assoc_tri2, path_save2) else: assoc_tri1 = get_association_from_file(path_assoc_tri[0]) assoc_tri2 = get_association_from_file(path_assoc_tri[1]) save_mask(assoc_tri1) # Step 3: intersecting point and local coordinate # Some pre-processing cam_square1 = np.vstack((cam1, [0, 0, 0, 1])) cam_square2 = np.vstack((cam2, [0, 0, 0, 1])) cam_square_inv1 = np.linalg.inv(cam_square1) cam_square_inv2 = np.linalg.inv(cam_square2) R1 = cv2.Rodrigues(rvec1)[0] R2 = cv2.Rodrigues(rvec2)[0] camera_pos1 = -R1.T @ tvec1 camera_pos2 = -R2.T @ tvec2 new_img = np.zeros_like(img1[::r, ::r]) print("Creating the warped image") for i in range(0, M1, r): if i % 500 == 0: print("Progress : {:.2f}%".format(i / M1 * 100)) for j in range(0, N1, r): tri_indices = assoc_tri1[i // r, j // r] if len(tri_indices) > 0: projected_point_h = np.array([j, i, 1, 1], dtype=np.double) unprojected_h = cam_square_inv1 @ projected_point_h unprojected = tfm.from_homogeneous(unprojected_h) dir = unprojected - camera_pos1 # Selecting the right face amongst the possible match triangle_index1, inter = find_the_right_face( v1, f1, tri_indices, camera_pos1, dir) # Barycentric coordinates # See https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/barycentric-coordinates p0, p1, p2 = v1[f1[triangle_index1]] denom = np.linalg.norm(np.cross(p1 - p0, p2 - p0)) u = np.linalg.norm(np.cross(inter - p0, inter - p2)) / denom v = np.linalg.norm(np.cross(inter - p0, inter - p1)) / denom # Step 4: projecting the corresponding point on the other # view/mesh onto its image plane p0_2, p1_2, p2_2 = v2[f2[triangle_index1]] inter_2 = p0_2 + u * (p1_2 - p0_2) + v * (p2_2 - p0_2) proj2 = np.round(tfm.project_point(inter_2, cam2)) y, x = proj2.astype(np.int) projected_point_h = np.array([y, x, 1, 1], dtype=np.double) unprojected_h = cam_square_inv2 @ projected_point_h unprojected = tfm.from_homogeneous(unprojected_h) dir = unprojected - camera_pos2 tri_indices = assoc_tri2[x, y] triangle_index2, _ = find_the_right_face( v2, f2, tri_indices, camera_pos2, dir) # Step 5: coloring :) if triangle_index1 == triangle_index2 and in_bound( proj2, (N2, M2)): new_img[i // r, j // r] = img2[x, y] return new_img
def load_mesh(self, obj_file): v, f = igl.read_triangle_mesh(str(obj_file)) return v, f
# Add the igl library to the modules search path import sys, os sys.path.insert(0, os.getcwd() + "/../") import igl V = igl.eigen.MatrixXd() U = igl.eigen.MatrixXd() F = igl.eigen.MatrixXi() c = 0 bbd = 1.0 twod = False if not igl.read_triangle_mesh("../../tutorial/shared/beetle.off", V, F): print("failed to load mesh") twod = V.col(2).minCoeff() == V.col(2).maxCoeff() bbd = (V.colwiseMaxCoeff() - V.colwiseMinCoeff()).norm() L = igl.eigen.SparseMatrixd() M = igl.eigen.SparseMatrixd() igl.cotmatrix(V, F, L) L = -L igl.massmatrix(V, F, igl.MASSMATRIX_TYPE_DEFAULT, M) k = 5 D = igl.eigen.MatrixXd() if not igl.eigs(L, M, k + 1, igl.EIGS_TYPE_SM, U, D): print("Eigs failed.")
import spheremesh as sh import igl import numpy as np filename = "data/cell.obj" l_max = 20 orig_v, faces = igl.read_triangle_mesh(filename) sphere_verts = sh.conformal_flow(orig_v, faces) sphere_verts = sh.mobius_center(orig_v,sphere_verts,faces) orig_v, sphere_verts = sh.canonical_rotation(orig_v, sphere_verts, faces) weights, Y_mat = sh.IRF(orig_v, sphere_verts, faces, l_max) reconstruct = Y_mat.dot(weights) ## construct icosphere mesh data ico_v, ico_f = igl.read_triangle_mesh("spheremesh/icosphere/icosphere.obj") ico_v = sh.project_sphere(ico_v) theta = np.arccos(ico_v[:,2]) phi = np.arctan2(ico_v[:,1],ico_v[:,0]) Y_mat2 = [] ## make sh matrix for l in range(0, l_max): for m in range(-l,l+1): y = sh.sph_real(l, m, phi, theta)
# Add the igl library to the modules search path import sys, os sys.path.insert(0, os.getcwd() + "/../") import igl V = igl.eigen.MatrixXd(); F = igl.eigen.MatrixXi(); igl.read_triangle_mesh("../../tutorial/shared/fertility.off", V, F); # Alternative discrete mean curvature HN = igl.eigen.MatrixXd() L = igl.eigen.SparseMatrixd() M = igl.eigen.SparseMatrixd() Minv = igl.eigen.SparseMatrixd() igl.cotmatrix(V,F,L) igl.massmatrix(V,F,igl.MASSMATRIX_TYPE_VORONOI,M) igl.invert_diag(M,Minv) # Laplace-Beltrami of position HN = -Minv*(L*V) # Extract magnitude as mean curvature H = HN.rowwiseNorm() # Compute curvature directions via quadric fitting PD1 = igl.eigen.MatrixXd() PD2 = igl.eigen.MatrixXd()
import igl import solver import constraint import transform import open3d as o3d import mesh as m cons = constraint.Constraint() cons.add_constraint(0, [0, 0, 0]) # slvr = solver.Sovler() if __name__ == "__main__": V, F = igl.read_triangle_mesh("cube.obj") mesh = m.Mesh(V, F) slvr = solver.Sovler(mesh, cons) slvr.precompute() V, F = slvr.solve() igl.write_obj("cube_remake", V, F)
# 1. Install miniconda (python 3.7 version, windows 64 bits) # 2. In a miniconda terminal run conda install igl # 3. Swap to this python compiler in pycharm import igl import numpy as np import os #Change this to point to your subject folder root_folder = '.' subject_id_usr = os.path.join(root_folder, 'subjects folder', 'subject_01') #Make sure you've at least simplified the mesh of the subject vertices = np.load(os.path.join(subject_id_usr, 'vertices_simple.npy')) faces = np.load(os.path.join(subject_id_usr, 'faces_simple.npy')) ret = igl.write_triangle_mesh(os.path.join(subject_id_usr, "bunny_out.obj"), vertices, faces) v, f = igl.read_triangle_mesh(os.path.join(subject_id_usr, "bunny_out.obj")) [pd1, pd2, pv1, pv2] = igl.principal_curvature(v, f, radius=5, use_k_ring=True) #Mean curvature is (pv1+pv2)/2 and Gaussian curvature is pv1*pv2 # k = igl.gaussian_curvature(v, f) np.save(os.path.join(subject_id_usr, 'mean_curv_simple.npy'), (pv1 + pv2) / 2) #Deletes temporary object os.remove(os.path.join(subject_id_usr, "bunny_out.obj"))
f_temp += np.ones_like(f_temp) * count_v count_v += len(v_temp) new_f[count_f:count_f + len(f_temp)] = f_temp new_fl[count_f:count_f + len(f_temp)] = np.ones( (len(f_temp), 1), dtype=int) * lb count_f += len(f_temp) return new_v, new_f, new_fl file_bench = "3/00000008_9b3d6a97e8de4aa193b81000_trimesh_000.obj" file_yml = "3/00000008_9b3d6a97e8de4aa193b81000_features_000.yml" file_root = os.path.dirname(file_bench) # wm.tetrahedralize("2/00000006_d4fe04f0f5f84b52bd4f10e4_trimesh_001.obj", file_root+"/"+"bench.mesh", stop_quality=7) fl_bench_file = parse_feat(file_yml) fl_bench = igl.read_dmat(fl_bench_file) v_bench, f_bench = igl.read_triangle_mesh(file_bench) v_ini, f_ini = igl.read_triangle_mesh("bench.mesh__sf.obj") prob_mat_ini, fl_ini_temp = pbc.project_face_labels(v_bench, f_bench.astype('int32'), fl_bench.astype('int32'), v_ini, f_ini.astype('int32')) fl_ini = pbc.refine_labels(v_ini, f_ini.astype('int32'), prob_mat_ini, fl_ini_temp.astype('int32'), 1) # mp.plot(v_ini, f_ini, fl_ini_temp[:,0]) # mp.plot(v_ini, f_ini, fl_ini[:,0]) eps = 0.1 # v_dict, f_dict =separate_surfaces(v_bench, f_bench, fl_bench) v_dict, f_dict = separate_surfaces(v_ini, f_ini, fl_ini[:, 0]) v_bad, f_bad, fl_bad = perturb_and_union(v_dict, f_dict, eps) # mp.plot(v_bad, f_bad, fl_bad[:,0], shading={"wireframe":True})
V_src_ = V_src/np.linalg.norm(V_src, axis=1)[:, np.newaxis] V_dst_ = V_dst/np.linalg.norm(V_dst, axis=1)[:, np.newaxis] dis, idx = KDTree(V_src_).query(V_dst_) if unique == False: return idx unique_idx, inverse_idx = np.unique(idx, return_inverse=True) Vs, Ws = np.zeros((len(unique_idx), 3)), np.zeros(len(unique_idx)) for i in range(len(V_dst)): Vs[inverse_idx[i]] += V_dst[i]/(0.001+dis[i]) Ws[inverse_idx[i]] += 1/(0.001+dis[i]) Vs /= Ws[:, np.newaxis] return unique_idx.astype(np.int), Vs sV3, sF3 = igl.read_triangle_mesh(__path__[0]+"/data/sphere3.obj") sV5, sF5 = igl.read_triangle_mesh(__path__[0]+"/data/sphere5.obj") def MinimalSurface(V, Nz, Iz, Al, Ar): Nz *= 1.05 V_borders = border_approximate(Nz, Iz, Al, Ar) V = np.row_stack([Nz, Iz, Al, Ar, V_borders, V]) b, bc = contrl_vertices(sV3, V) b, bc = contrl_vertices(sV5, bc) nilr_idx = contrl_vertices(sV5, np.row_stack([Nz, Iz, Al, Ar]), unique=False) V = igl.harmonic_weights(sV5, sF5, b, bc, 3) return V, sF5, bc, nilr_idx def calibrate_nilr(Nz, Iz, Al, Ar): R = np.eye(3)
print('Iteration: ', args.iteration) print('The pre-trained weights: ', args.weight) print('Source object: ', args.src) print('Target object: ', args.tgt) if args.if_nonrigid == 0: print('The translation is rigid.') else: print('The translation is non-rigid.') if __name__ == '__main__': if args.if_nonrigid == 1: rma_net = Net_PointNR_v2().cuda() # Load the pre-trained weights of RMA-Net rma_net.load_state_dict(torch.load(args.weight), True) # The testing samples source_points, _ = igl.read_triangle_mesh(args.src) target_points, _ = igl.read_triangle_mesh(args.tgt) source_points_tensor = torch.from_numpy( source_points).float().cuda().view(1, -1, 3) target_points_tensor = torch.from_numpy( target_points).float().cuda().view(1, -1, 3) print('Start to deform ' + args.src + ' to ' + args.tgt) with torch.no_grad(): phi_list, point_weight_list, deform_rigid_points_list, deformation_points_list, rigid_matrix_list = rma_net( source_points_tensor, target_points_tensor, iteration=args.iteration) results_path = args.src[:-4] + '_deform_results' if not os.path.exists(results_path): os.mkdir(results_path) for stage in range(args.iteration):
import spheremesh as sh import igl import numpy as np from numpy.linalg import norm filename = "data/cell.obj" l_max = 24 orig_v, faces = igl.read_triangle_mesh(filename) sphere_verts = sh.conformal_flow(orig_v, faces) sphere_verts = sh.mobius_center(orig_v, sphere_verts, faces) orig_v, sphere_verts = sh.canonical_rotation(orig_v, sphere_verts, faces) weights, Y_mat = sh.IRF(orig_v, sphere_verts, faces, l_max) reconstruct = Y_mat.dot(weights) p = sh.plot.new() sh.plot.mesh(p, orig_v, faces) def set_max(value): res = int(value)**2 res2 = int(value + 1)**2 ww = np.zeros(weights.shape[0]) ww[0:res] = 1 ww[res:res2] = 1
def test_read_triangle_mesh_type_issue(self): v, f = igl.read_triangle_mesh(self.test_path + "face.obj") vs = np.array([0], dtype = f.dtype) vt = np.arange(v.shape[0], dtype = f.dtype) d = igl.exact_geodesic(v, f, vs, vt)
def laplacian_editing(path, anchors, anchors_id, tetra=False, custom_weight=None): """ Applies laplacian mesh editing to a mesh using igl's cotangent weights ---- input: path: str -> path to the triangle mesh anchors: float array of shape (n, 3) -> position of the anchors anchors_id: float array of shape (n,) -> index of each anchor vertex tetra: bool -> if the mesh is tetraedral. If False, it should be with triangular faces custom_weight: float list of length n. If None, every weight is considered to be 1 ---- output: v_res: float array of shape (N, 3) -> the new vertices f: float array of shape (P, 3) -> the faces (same as before) """ nb_anchors = len(anchors) assert nb_anchors == len(anchors_id), "anchors and anchors_id have \ different size" extension = path.split('.')[-1] weight_anchors = 1.0 if extension == "mesh": v, vo, f = igl.read_mesh(path) f = f - 1 # When using read_mesh, vertex indices start at 1 instead of 0 # We could use read_triangle_mesh which returns vertices with indices # starting at 0 elif extension == "obj": v, f = igl.read_triangle_mesh(path) else: raise ValueError("Currently, only .obj and .mesh files are supported") if tetra: assert extension == "mesh", "Laplacian editing for tetraedral mesh is\ currently only supported for .mesh files" L = igl.cotmatrix(v, vo) else: L = igl.cotmatrix(v, f) M, N = L._shape # M should be equal to N delta = np.array(L.dot(v)) # The lines that will be appened to L and delta anchors_L = sparse.csc_matrix((nb_anchors, N)) anchors_delta = np.zeros((nb_anchors, 3), dtype=np.double) for k in range(nb_anchors): if custom_weight is None: anchors_L[k, anchors_id[k]] = weight_anchors anchors_delta[k] = weight_anchors * anchors[k] else: anchors_L[k, anchors_id[k]] = custom_weight[k] anchors_delta[k] = custom_weight[k] * anchors[k] L = sparse.vstack((L, anchors_L), format="coo") delta = np.vstack((delta, anchors_delta)) # Solving for least squares v_res = np.zeros((M, 3), dtype=np.double) for k in range(3): v_res[:, k] = lsqr(L, delta[:, k], x0=v[:, k])[0] return v_res, f
opacity=0.6) def draw_cpc_wireframe(p: pv.Plotter, V: np.ndarray, n=10): for i in np.linspace(0, 100, n + 1, dtype=np.int)[1:-1] - 1: p.add_mesh(polyline_from_points(V[i, :]), color=wireframe_color) for j in np.linspace(0, 100, n + 1, dtype=np.int)[1:-1] - 1: p.add_mesh(polyline_from_points(V[:, j]), color=wireframe_color) def draw_orient_definition(p: pv.Plotter, V: np.ndarray, N: np.ndarray): pass if __name__ == "__main__": V, F = igl.read_triangle_mesh("./data/12034_CPC.obj") N = igl.per_vertex_normals(V, F, igl.PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA) T, N, B = CPCScalpRecons.TNBFrame.TNB_frame(V, N, cpc_ratio=99) scalp = pv.PolyData() scalp.points, scalp.faces = V, np.column_stack( [np.full((len(F), 1), 3), F]) p = pv.Plotter() # p.add_text("Scalp TBN Frame", font_size=18) scalp_ = p.add_mesh(scalp, ambient=0.06, diffuse=0.75, opacity=1, color=(1., 0.8, 0.7)) #, scalars="yz_dot", cmap="jet")
import os import numpy as np import igl from PyQt5.QtWidgets import QApplication from PyIGL_viewer import Viewer script_folder = os.path.dirname(__file__) path_to_obj_file = os.path.join(script_folder, "assets", "cube.obj") vertices, faces = igl.read_triangle_mesh(path_to_obj_file) viewer_app = QApplication(["IGL viewer"]) viewer = Viewer() viewer.show() # The stretch values give the relative size of the different viewer widgets # By setting them all to 1, we make sure our widgets all have the same dimensions. viewer.set_column_stretch(0, 1) viewer.set_column_stretch(1, 1) viewer.set_row_stretch(0, 1) viewer.set_row_stretch(1, 1) def screenshot_function(): viewer.save_screenshot(os.path.join("screenshot.png")) # Linking all cameras means that all widgets will have the same point of view. def toggle_linking(): if viewer.linked_cameras: viewer.unlink_all_cameras() else:
def max_test(): v, f = igl.read_triangle_mesh(path, np.float64) df = SubdivisionDeformer({STEPS: 1}) for i in range(20): print(i, len(f)) v, f = df.transform(v, f)