def getMeshCurvature(mesh, gaussian_curvature=True, mean_curvature=True, shape_index=True, remove_outliers=True): try: import igl except ModuleNotFoundError: raise ModuleNotFoundError("The dependency 'igl' is required for this functionality!") v1, v2, k1, k2 = igl.principal_curvature(mesh.vertices, mesh.faces) k1 = clipOutliers(k1) k2 = clipOutliers(k2) feature_names = [] features = [] if gaussian_curvature: feature_names.append('gaussian_curvature') mesh.vertex_attributes['gaussian_curvature'] = k1*k2 if mean_curvature: feature_names.append('mean_curvature') mesh.vertex_attributes['mean_curvature'] = (k1 + k2)/2 if shape_index: shape_index = -2*np.arctan( (k1 + k2)/(k1 - k2) )/np.pi feature_names.append('shape_index') mesh.vertex_attributes['shape_index'] = shape_index return feature_names
def test_principal_curvature(self): pd1, pd2, pv1, pv2 = igl.principal_curvature(self.v, self.f) qd1, qd2, qv1, qv2 = igl.principal_curvature(self.v, self.f, radius=7, use_k_ring=False) self.assertTrue(pd1.shape == qd1.shape == pd2.shape == qd2.shape == self.v.shape) self.assertTrue(pv1.shape == qv1.shape == pv2.shape == qv2.shape == (self.v.shape[0],)) self.assertTrue(pd1.dtype == pd2.dtype == pv1.dtype == pv2.dtype == np.float64) v = self.v.copy() #v = v.astype(np.float32) pd1, pd2, pv1, pv2 = igl.principal_curvature(v, self.f) #self.assertTrue(pd1.dtype == pd2.dtype == pv1.dtype == pv2.dtype == np.float32) self.assertTrue(type(pd1) == type(pd2) == type(pv1) == type(pv2) == np.ndarray) self.assertTrue(pd1.flags.c_contiguous) self.assertTrue(pd2.flags.c_contiguous) self.assertTrue(pv1.flags.c_contiguous) self.assertTrue(pv2.flags.c_contiguous) self.assertTrue(qd1.flags.c_contiguous) self.assertTrue(qd2.flags.c_contiguous) self.assertTrue(qv1.flags.c_contiguous) self.assertTrue(qv2.flags.c_contiguous)
def calc_curvatures(self, max_radius: int = 5, min_radius: int = 2) -> np.ndarray: """ Calculating Principal and Gaussian curvature features of each mesh face Parameters: vertices: np.ndarray - (x, y, z) coordinates of the mesh vertices faces: np.ndarray - indices of the mesh vertices forming faces areas: np.ndarray - surface areas of the mesh faces max_radius: int - controls the size of the neighbourhood used min_radius: int - minimum value of radius used in calculation of principal curvatures Returns: curvatures: np.ndarray - curvature statistics """ curvatures = [] for radius in range(min_radius, min_radius + max_radius): pd1, pd2, pv1, pv2 = igl.principal_curvature(v=self.vertices, f=self.faces, radius=radius, use_k_ring=True) pv1 = pv1[self.faces] pv2 = pv2[self.faces] curv_vals = [ pv1.mean(axis=1), np.abs(pv1).mean(axis=1), pv2.mean(axis=1), np.abs(pv2).mean(axis=1), (pv1 * pv2).mean(axis=1), np.abs(pv1 * pv2).mean(axis=1), ((pv1 + pv2) / 2).mean(axis=1), np.abs((pv1 + pv2) / 2).mean(axis=1), (pv1 - pv2).mean(axis=1) ] curv_vals = np.swapaxes(curv_vals, 0, 1) curv_dirs = [ pd1[self.faces].mean(axis=1), pd2[self.faces].mean(axis=1) ] curv_dirs = np.hstack(curv_dirs) curvatures.append(np.hstack((curv_vals, curv_dirs))) curvatures = np.hstack(curvatures) gauss_curv = igl.gaussian_curvature(self.vertices, self.faces) gauss_curv = np.expand_dims(gauss_curv[self.faces].mean(axis=1), axis=1) return np.hstack((curvatures, gauss_curv)) * self.areas[:, None]
def getMeshCurvature(mesh, gaussian_curvature=True, mean_curvature=True, shape_index=True, remove_outliers=True): v1, v2, k1, k2 = igl.principal_curvature(mesh.vertices, mesh.faces) k1 = clipOutliers(k1) k2 = clipOutliers(k2) feature_names = [] features = [] if gaussian_curvature: feature_names.append('gaussian_curvature') mesh.vertex_attributes['gaussian_curvature'] = k1*k2 if mean_curvature: feature_names.append('mean_curvature') mesh.vertex_attributes['mean_curvature'] = (k1 + k2)/2 if shape_index: shape_index = -2*np.arctan( (k1 + k2)/(k1 - k2) )/np.pi feature_names.append('shape_index') mesh.vertex_attributes['shape_index'] = shape_index return feature_names
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() PV1 = igl.eigen.MatrixXd() PV2 = igl.eigen.MatrixXd() igl.principal_curvature(V, F, PD1, PD2, PV1, PV2) # Mean curvature H = 0.5 * (PV1 + PV2) viewer = igl.viewer.Viewer() viewer.data.set_mesh(V, F) # Compute pseudocolor C = igl.eigen.MatrixXd() igl.parula(H, True, C) viewer.data.set_colors(C) # Average edge length for sizing avg = igl.avg_edge_length(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"))
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() PV1 = igl.eigen.MatrixXd() PV2 = igl.eigen.MatrixXd() igl.principal_curvature(V,F,PD1,PD2,PV1,PV2) # Mean curvature H = 0.5*(PV1+PV2) viewer = igl.viewer.Viewer() viewer.data.set_mesh(V, F) # Compute pseudocolor C = igl.eigen.MatrixXd() igl.parula(H,True,C) viewer.data.set_colors(C) # Average edge length for sizing avg = igl.avg_edge_length(V,F)
def getGaussCurv(self): vertices = np.row_stack([vertex.coords for vertex in self.vertices]) faces = np.row_stack([face.vertex_ids for face in self.faces]) self.gaussian_curvature = igl.principal_curvature(vertices, faces, radius=6)