def test_mean_pointcloud_type(): points = np.array([[1, 2, 3], [1, 1, 1]]) trilist = np.array([0, 1, 2]) pcs = [TriMesh(points, trilist), TriMesh(points + 2, trilist)] mean_pc = mean_pointcloud(pcs) assert isinstance(mean_pc, TriMesh) assert_allclose(mean_pc.points, points + 1)
def grid_view(daams, fitter, final_shape, image=None, angle=0, indexes=None, trilist=None): t = fitter.algorithms[-1] t = t.transform t.set_target(final_shape) sub, sampled = subsample_dense_pointclouds([ PointCloud(daams.reference_frame.landmarks['source'].lms. points[daams.n_landmarks:]) ], daams.reference_frame.shape, mask=daams.reference_frame.mask) index = [] for p in sub[0].points: for i, pp in enumerate( daams.reference_frame.landmarks['source'].lms.points): if np.all(p == pp): index.append(i) if indexes: index = indexes + index else: index = range(daams.n_landmarks) + index tm = TriMesh(daams.reference_frame.landmarks['source'].lms.points[index]) if not trilist is None: tm_fit = TriMesh(t.target.points[index], trilist) else: tm_fit = TriMesh(t.target.points[index], tm.trilist) if image: image = build_reference_frame(final_shape) image.landmarks['DENSE'] = t.target img = image img.landmarks['trim'] = tm_fit img = img.rotate_ccw_about_centre(angle - 360) img = img.crop_to_landmarks_proportion(1, group='trim') img.view_widget() else: tm_fit.view() return tm_fit, t.target
def test_chain_pwa_before_tps(): a_tm = TriMesh(np.random.random([10, 2])) b = PointCloud(np.random.random([10, 2])) pwa = PiecewiseAffine(a_tm, b) tps = ThinPlateSplines(b, a_tm) chain = pwa.compose_before(tps) assert (isinstance(chain, TransformChain))
def duplicate_vertices(mesh): # generate a new mesh with unique vertices per triangle # (i.e. duplicate verts so that each triangle is unique) old_to_new = mesh.trilist.ravel() old_to_new = mesh.trilist.ravel() new_trilist = np.arange(old_to_new.shape[0]).reshape([-1, 3]) new_points = mesh.points[old_to_new] return TriMesh(new_points, trilist=new_trilist), old_to_new
def _construct_shape_type(points, trilist, tcoords, texture, colour_per_vertex): # Four different outcomes - either we have a textured mesh, a coloured # mesh or just a plain mesh or we fall back to a plain pointcloud. if trilist is None: obj = PointCloud(points, copy=False) elif tcoords is not None and texture is not None: obj = TexturedTriMesh(points, tcoords, texture, trilist=trilist, copy=False) elif colour_per_vertex is not None: obj = ColouredTriMesh(points, trilist=trilist, colours=colour_per_vertex, copy=False) else: # TriMesh fall through obj = TriMesh(points, trilist=trilist, copy=False) if tcoords is not None and texture is None: warnings.warn('tcoords were found, but no texture was recovered, ' 'reverting to an untextured mesh.') if texture is not None and tcoords is None: warnings.warn('texture was found, but no tcoords were recovered, ' 'reverting to an untextured mesh.') return obj
def getTriMeshfromPly(path): data = [] with open(path) as csv_file: csv_reader = csv.reader(csv_file, delimiter=' ') for row in csv_reader: data.append(row) flag = False points = [] trilist = [] count = 0 for row in range(len(data)): if (data[row][0] == 'element') and (data[row][1] == 'vertex'): numOfVertices = int(data[row][2]) if flag and count < numOfVertices: data[row][0] = "{0:.6f}".format(float(data[row][0])) data[row][1] = "{0:.6f}".format(float(data[row][1])) data[row][2] = "{0:.6f}".format(float(data[row][2])) points.append([ float(data[row][0]), float(data[row][1]), float(data[row][2]) ]) count = count + 1 elif flag and count >= numOfVertices: if data[row][0] == '3': trilist.append( [int(data[row][1]), int(data[row][2]), int(data[row][3])]) if (data[row][0] == 'end_header'): flag = True points_np = np.array(points) trilist_np = np.array(trilist) return TriMesh(points_np, trilist_np)
def face_ibug_68_to_face_ibug_68_trimesh(pcloud): r""" Apply the IBUG 68-point semantic labels, with trimesh connectivity. The semantic labels applied are as follows: - tri References ---------- .. [1] http://www.multipie.org/ .. [2] http://ibug.doc.ic.ac.uk/resources/300-W/ """ from menpo.shape import TriMesh n_expected_points = 68 validate_input(pcloud, n_expected_points) tri_list = np.array([[47, 29, 28], [44, 43, 23], [38, 20, 21], [47, 28, 42], [49, 61, 60], [40, 41, 37], [37, 19, 20], [28, 40, 39], [38, 21, 39], [36, 1, 0], [48, 59, 4], [49, 60, 48], [67, 59, 60], [13, 53, 14], [61, 51, 62], [57, 8, 7], [52, 51, 33], [61, 67, 60], [52, 63, 51], [66, 56, 57], [35, 30, 29], [53, 52, 35], [37, 36, 17], [18, 37, 17], [37, 38, 40], [38, 37, 20], [19, 37, 18], [38, 39, 40], [28, 29, 40], [41, 36, 37], [27, 39, 21], [41, 31, 1], [30, 32, 31], [33, 51, 50], [33, 30, 34], [31, 40, 29], [36, 0, 17], [31, 2, 1], [31, 41, 40], [ 1, 36, 41], [31, 49, 2], [ 2, 49, 3], [60, 59, 48], [ 3, 49, 48], [31, 32, 50], [48, 4, 3], [59, 5, 4], [58, 67, 66], [ 5, 59, 58], [58, 59, 67], [ 7, 6, 58], [66, 57, 58], [13, 54, 53], [ 7, 58, 57], [ 6, 5, 58], [50, 61, 49], [62, 67, 61], [31, 50, 49], [32, 33, 50], [30, 33, 32], [34, 52, 33], [35, 52, 34], [53, 63, 52], [62, 63, 65], [62, 51, 63], [66, 65, 56], [63, 53, 64], [62, 66, 67], [62, 65, 66], [57, 56, 9], [65, 63, 64], [ 8, 57, 9], [ 9, 56, 10], [10, 56, 11], [11, 56, 55], [11, 55, 12], [56, 65, 55], [55, 64, 54], [55, 65, 64], [55, 54, 12], [64, 53, 54], [12, 54, 13], [45, 46, 44], [35, 34, 30], [14, 53, 35], [15, 46, 45], [27, 28, 39], [27, 42, 28], [35, 29, 47], [30, 31, 29], [15, 35, 46], [15, 14, 35], [43, 22, 23], [27, 21, 22], [24, 44, 23], [44, 47, 43], [43, 47, 42], [46, 35, 47], [26, 45, 44], [46, 47, 44], [25, 44, 24], [25, 26, 44], [16, 15, 45], [16, 45, 26], [22, 42, 43], [50, 51, 61], [27, 22, 42]]) new_pcloud = TriMesh(pcloud.points, tri_list) mapping = OrderedDict() mapping['tri'] = np.arange(new_pcloud.n_points) return new_pcloud, mapping
def eye_ibug_close_17_to_eye_ibug_close_17_trimesh(pcloud): r""" Apply the IBUG 17-point close eye semantic labels, with trimesh connectivity. The semantic labels applied are as follows: - tri """ from menpo.shape import TriMesh n_expected_points = 17 validate_input(pcloud, n_expected_points) tri_list = np.array([[10, 11, 13], [ 3, 13, 2], [ 4, 14, 3], [15, 5, 16], [12, 11, 0], [13, 14, 10], [13, 12, 2], [14, 13, 3], [ 0, 1, 12], [ 2, 12, 1], [13, 11, 12], [ 9, 10, 14], [15, 9, 14], [ 7, 8, 15], [ 5, 6, 16], [15, 14, 4], [ 7, 15, 16], [ 8, 9, 15], [15, 4, 5], [16, 6, 7]]) new_pcloud = TriMesh(pcloud.points, tri_list, copy=False) mapping = OrderedDict() mapping['tri'] = np.arange(new_pcloud.n_points) return new_pcloud, mapping
def chain_tps_after_pwa_test(): a_tm = TriMesh(np.random.random([10, 2])) b = PointCloud(np.random.random([10, 2])) pwa = PiecewiseAffine(a_tm, b) tps = ThinPlateSplines(b, a_tm) chain = tps.compose_after(pwa) assert(isinstance(chain, TransformChain))
def test_trimesh_creation_copy_warning(): points = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]]) trilist = np.array([[0, 1, 3], [1, 2, 3]], order='F') with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") TriMesh(points, trilist=trilist, copy=False) assert len(w) == 1
def constrain_to_pointcloud(self, pointcloud, trilist=None): r""" Restricts this mask to be equal to the convex hull around a point cloud Parameters ---------- pointcloud : :map:`PointCloud` The pointcloud of points that should be constrained to trilist: (t, 3) ndarray, Optional Triangle list to be used on the points in selecting the mask region. If None defaults to performing Delaunay triangulation on the points. Default: None """ from menpo.transform.piecewiseaffine import PiecewiseAffine from menpo.transform.piecewiseaffine import TriangleContainmentError if self.n_dims != 2: raise ValueError("can only constrain mask on 2D images.") if trilist is not None: from menpo.shape import TriMesh pointcloud = TriMesh(pointcloud.points, trilist) pwa = PiecewiseAffine(pointcloud, pointcloud) try: pwa.apply(self.indices) except TriangleContainmentError as e: self.from_vector_inplace(~e.points_outside_source_domain)
def __init__(self, source, target): from menpo.shape import TriMesh # to avoid circular import if not isinstance(source, TriMesh): source = TriMesh(source.points) Alignment.__init__(self, source, target) if self.n_dims != 2: raise ValueError("source and target must be 2 " "dimensional")
def test_trimesh_creation(): points = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]]) trilist = np.array([[0, 1, 3], [1, 2, 3]]) TriMesh(points, trilist)
def calculate_errors_4DMaja_real(path_fits, path_gt, model): # Parameters: # -------------- # path_fits: 'string' of the directory that contains your reconstructed meshes. # Meshes' filenames should be the same with the # corresponding ground truth meshes filenames + the suffix of # the mesh type (e.g <frame_number>.obj, <frame_number>.ply) # path_gt : 'string' of the full path of the ground truth mesh. # model : 'string' of the model template you are using. Should be one of the # following: 'LSFM', 'Basel', 'Surrey' # Returns: # -------------- # errors : python list that contains the error per vertex between the ground # truth mesh and a mean mesh calculated from your reconstructed meshes path_fits = Path(path_fits) path_gt = Path(path_gt) # load meshes' filenames filenames = [p.name for p in path_fits.glob('*')] filenames.sort() # load gt_mesh (it is olny one, maja's neautral face) gt_mesh = m3io.import_mesh(path_gt, texture_resolver=None) gt_mesh.landmarks['ibug49'] = PointCloud(gt_mesh.points[lms_indexes][19:]) errors = [0] # accumulate fits acc_points = np.zeros((gt_mesh.n_points, 3)) for i, filename in enumerate(print_progress(filenames)): fit_3d = m3io.import_mesh(path_fits / filename, texture_resolver=None) if model == 'Surrey': lms = face_ibug_49_to_face_ibug_49( PointCloud(fit_3d.points[eos.load_eos_low_res_lm_index()])) fit_3d = eos.upsample_eos_low_res_to_fw_no_texture(fit_3d) fit_3d.landmarks['ibug49'] = lms elif model == 'LSFM' or model == 'Basel': fit_3d.landmarks['ibug49'] = PointCloud( fit_3d.points[lms_indexes][19:]) else: print('Error: Not supported model template') return acc_points += fit_3d.points # create mean_fit_3d mean_fit_3d = TriMesh(acc_points / len(filenames), gt_mesh.trilist) mean_fit_3d.landmarks['ibug49'] = PointCloud( mean_fit_3d.points[lms_indexes][19:]) # calculate per vertex errors between the neutral gt_mesh and the mean_fit_3d gt_mesh, eval_mask = landmark_and_mask_gt_mesh(gt_mesh, distance=1) errors[0], _, _ = mask_align_and_calculate_dense_error( mean_fit_3d, gt_mesh, eval_mask) return errors
def test_trimesh_from_tri_mask(): points = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]]) trilist = np.array([[0, 1, 3], [1, 2, 3]]) mask = np.zeros(2, dtype=np.bool) mask[0] = True trimesh = TriMesh(points, trilist=trilist).from_tri_mask(mask) assert (trimesh.n_tris == 1) assert (trimesh.n_points == 3) assert_allclose(trimesh.points, points[trilist[0]])
def test_trimesh_n_tris(): points = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]]) trilist = np.array([[0, 1, 3], [1, 2, 3]]) trimesh = TriMesh(points, trilist) assert(trimesh.n_tris == 2)
def test_trimesh_face_normals(): points = np.array([[0.0, 0.0, -1.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]]) trilist = np.array([[0, 1, 3], [1, 2, 3]]) expected_normals = np.array( [[-np.sqrt(3) / 3, -np.sqrt(3) / 3, np.sqrt(3) / 3], [-0, -0, 1]]) trimesh = TriMesh(points, trilist) face_normals = trimesh.tri_normals() assert_allclose(face_normals, expected_normals)
def test_trimesh_creation_copy_false(): points = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]]) trilist = np.array([[0, 1, 3], [1, 2, 3]]) tm = TriMesh(points, trilist, copy=False) assert (is_same_array(tm.points, points)) assert (is_same_array(tm.trilist, trilist))
def load_tassos_lsfm_combined_model(path): m = loadmat(str(path)) mean = TriMesh(m['mean'].reshape([-1, 3]), trilist=m['trilist']) return { 'shape_model': PCAModel.init_from_components( m['components'].T, m['eigenvalues'].ravel(), mean, 8888, True), 'n_id_comps': int(m['n_trunc_ids'][0][0]), 'n_exp_comps': int(m['n_trunc_expressions'][0][0]) }
def generative_construct(DB, fitter, trilist, label=None, fit_group='mean', train_group='final', feature=igo, diagonal=200, scales=(0.5, 1.0), n_processes=24, model_class=HolisticAAM, increament_model=None, original_shape_model=None, shape_forgetting_factor=1.0, appearance_forgetting_factor=1.0, max_iters=10, ): # fix appearance optimize shape error = [] # Multi Processs Computation frs = mp_fit(DB, fitter, group=fit_group, n_processes=n_processes, max_iters=max_iters) for fr, img in zip(frs, DB): img.landmarks[train_group] = TriMesh(fr.final_shape.points, trilist=trilist) error.append(fr.final_error(alignment_error)) if label: img.landmarks[label] = TriMesh(fr.final_shape.points, trilist=trilist) del fitter if increament_model: pdm = copy.deepcopy(increament_model) pdm.increment(DB, verbose=True, group=train_group, shape_forgetting_factor=shape_forgetting_factor, appearance_forgetting_factor=appearance_forgetting_factor) else: pdm = model_class(DB, holistic_features=feature, diagonal=diagonal, scales=scales, verbose=True, group=train_group) if original_shape_model: pdm.shape_models = original_shape_model if increament_model: del increament_model return pdm, np.mean(error)
def _construct_shape_type(points, trilist, tcoords, texture, colour_per_vertex): r""" Construct the correct Shape subclass given the inputs. TexturedTriMesh can only be created when tcoords and texture are available. ColouredTriMesh can only be created when colour_per_vertex is non None and TriMesh can only be created when trilist is non None. Worst case fall back is PointCloud. Parameters ---------- points : ``(N, D)`` `ndarray` The N-D points. trilist : ``(N, 3)`` `ndarray`` or ``None`` Triangle list or None. tcoords : ``(N, 2)`` `ndarray` or ``None`` Texture coordinates. texture : :map:`Image` or ``None`` Texture. colour_per_vertex : ``(N, 1)`` or ``(N, 3)`` `ndarray` or ``None`` The colour per vertex. Returns ------- shape : :map:`PointCloud` or subclass The correct shape for the given inputs. """ # Four different outcomes - either we have a textured mesh, a coloured # mesh or just a plain mesh or we fall back to a plain pointcloud. if trilist is None: obj = PointCloud(points, copy=False) elif tcoords is not None and texture is not None: obj = TexturedTriMesh(points, tcoords, texture, trilist=trilist, copy=False) elif colour_per_vertex is not None: obj = ColouredTriMesh(points, trilist=trilist, colours=colour_per_vertex, copy=False) else: # TriMesh fall through obj = TriMesh(points, trilist=trilist, copy=False) if tcoords is not None and texture is None: warnings.warn('tcoords were found, but no texture was recovered, ' 'reverting to an untextured mesh.') if texture is not None and tcoords is None: warnings.warn('texture was found, but no tcoords were recovered, ' 'reverting to an untextured mesh.') return obj
def test_trimesh_boundary_tri_index(): points = np.array([[0.0, 0.0, 0.0], [0.5, 0.5, 0.0], [0.0, 0.5, 0.0], [-0.5, 0.5, 0.0], [-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [0.0, -1.0, 0.0]]) trilist = np.array([[0, 2, 3], [2, 0, 1], [4, 0, 3], [0, 5, 1], [4, 5, 0], [5, 4, 6]]) trimesh = TriMesh(points, trilist) boundary_tri_index = trimesh.boundary_tri_index() # The "middle" triangle is [4, 5, 0] which is surrounded on all sides # [5, 4, 6] has two edges that have no neighbours assert_allclose(boundary_tri_index, [True, True, True, True, False, True])
def from_UV_2_3D(uv, uv_layout='oval', topology='full', plot=False): res = uv.shape[0] info_dict = import_uv_info(uv, res, uv_layout=uv_layout, topology=topology) tmask = info_dict['tmask'] tc_ps = info_dict['tcoords_pixel_scaled'] tmask_im = info_dict['tmask_image'] trilist = info_dict['trilist'] #uv = interpolaton_of_uv_xyz(uv,tmask).as_unmasked() x = uv.pixels[0][(tc_ps.points.astype(int).T[0, :], tc_ps.points.astype(int).T[1, :])] y = uv.pixels[1][(tc_ps.points.astype(int).T[0, :], tc_ps.points.astype(int).T[1, :])] z = uv.pixels[2][(tc_ps.points.astype(int).T[0, :], tc_ps.points.astype(int).T[1, :])] points = np.hstack((x.T[:, None], y.T[:, None], z.T[:, None])) if plot is True: TriMesh(points, trilist).view() return TriMesh(points, trilist)
def face_ibug_68_to_face_ibug_51_trimesh(pcloud): r""" Apply the IBUG 51-point semantic labels, with trimesh connectivity.. The semantic labels applied are as follows: - tri References ---------- .. [1] http://www.multipie.org/ .. [2] http://ibug.doc.ic.ac.uk/resources/300-W/ """ from menpo.shape import TriMesh # Apply face_ibug_68_to_face_ibug_51 new_pcloud = face_ibug_68_to_face_ibug_51(pcloud) # This is in terms of the 51 points tri_list = np.array([[30, 12, 11], [27, 26, 6], [21, 3, 4], [30, 11, 25], [32, 44, 43], [23, 24, 20], [20, 2, 3], [11, 23, 22], [21, 4, 22], [32, 43, 31], [50, 42, 43], [44, 34, 45], [35, 34, 16], [44, 50, 43], [35, 46, 34], [49, 39, 40], [18, 13, 12], [36, 35, 18], [20, 19, 0], [1, 20, 0], [20, 21, 23], [21, 20, 3], [2, 20, 1], [21, 22, 23], [11, 12, 23], [24, 19, 20], [10, 22, 4], [13, 15, 14], [16, 34, 33], [16, 13, 17], [14, 23, 12], [14, 24, 23], [43, 42, 31], [14, 15, 33], [41, 50, 49], [41, 42, 50], [49, 40, 41], [33, 44, 32], [45, 50, 44], [14, 33, 32], [15, 16, 33], [13, 16, 15], [17, 35, 16], [18, 35, 17], [36, 46, 35], [45, 46, 48], [45, 34, 46], [49, 48, 39], [46, 36, 47], [45, 49, 50], [45, 48, 49], [48, 46, 47], [39, 48, 38], [38, 47, 37], [38, 48, 47], [47, 36, 37], [28, 29, 27], [18, 17, 13], [10, 11, 22], [10, 25, 11], [18, 12, 30], [13, 14, 12], [26, 5, 6], [10, 4, 5], [7, 27, 6], [27, 30, 26], [26, 30, 25], [29, 18, 30], [9, 28, 27], [29, 30, 27], [8, 27, 7], [8, 9, 27], [5, 25, 26], [33, 34, 44], [10, 5, 25]]) new_pcloud = TriMesh(new_pcloud.points, trilist=tri_list, copy=False) mapping = OrderedDict() mapping['tri'] = np.arange(new_pcloud.n_points) return new_pcloud, mapping
def _get_mean_model(model): """ Get mean BFM mesh. Parameters: model (BFM dict model): BFM model Returns: mean_mesh (menpo.shape.mesh.base.TriMesh): mean mesh model """ return TriMesh(points=np.reshape(model['shapeMU'], (-1, 3)), trilist=model['tri'])
def pseudoinverse(self): r""" The pseudoinverse of the transform - that is, the transform that results from swapping `source` and `target`, or more formally, negating the transforms parameters. If the transform has a true inverse this is returned instead. :type: ``type(self)`` """ from menpo.shape import PointCloud, TriMesh # to avoid circular import new_source = TriMesh(self.target.points, self.source.trilist) new_target = PointCloud(self.source.points) return type(self)(new_source, new_target)
def test_trimesh_copy(): points = np.ones([10, 3]) trilist = np.ones([10, 3]) landmarks = PointCloud(np.ones([3, 3]), copy=False) tmesh = TriMesh(points, trilist=trilist, copy=False) tmesh.landmarks['test'] = landmarks tmesh_copy = tmesh.copy() assert (not is_same_array(tmesh_copy.points, tmesh.points)) assert (not is_same_array(tmesh_copy.trilist, tmesh.trilist)) assert (not is_same_array(tmesh_copy.landmarks['test'].lms.points, tmesh.landmarks['test'].lms.points))
def test_trimesh_vertex_normals(): points = np.array([[0.0, 0.0, -1.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]]) trilist = np.array([[0, 1, 3], [1, 2, 3]]) # 0 and 2 are the corner of the triangles and so the maintain the # face normals. The other two are the re-normalised vertices: # normalise(n0 + n2) expected_normals = np.array( [[-np.sqrt(3) / 3, -np.sqrt(3) / 3, np.sqrt(3) / 3], [-0.32505758, -0.32505758, 0.88807383], [0, 0, 1], [-0.32505758, -0.32505758, 0.88807383]]) trimesh = TriMesh(points, trilist) vertex_normals = trimesh.vertex_normals() assert_allclose(vertex_normals, expected_normals)
def ibug_close_eye_trimesh(landmark_group): """ Apply the ibug's "standard" close eye semantic labels to the landmarks in the given landmark group. The group label will be 'ibug_close_eye_trimesh'. The semantic labels applied are as follows: - tri Parameters ---------- landmark_group : :map:`LandmarkGroup` The landmark group to apply semantic labels to. Returns ------- group_label : `str` The group label: 'ibug_close_eye_trimesh' landmark_group : :map:`LandmarkGroup` New landmark group. Raises ------ :class:`menpo.landmark.exceptions.LabellingError` If the given landmark group contains less than 38 points """ from menpo.shape import TriMesh group_label = 'ibug_close_eye_trimesh' n_expected_points = 17 n_points = landmark_group.lms.n_points _validate_input(landmark_group, n_expected_points, group_label) tri_list = np.array([[10, 11, 13], [ 3, 13, 2], [ 4, 14, 3], [15, 5, 16], [12, 11, 0], [13, 14, 10], [13, 12, 2], [14, 13, 3], [ 0, 1, 12], [ 2, 12, 1], [13, 11, 12], [ 9, 10, 14], [15, 9, 14], [ 7, 8, 15], [ 5, 6, 16], [15, 14, 4], [ 7, 15, 16], [ 8, 9, 15], [15, 4, 5], [16, 6, 7]]) new_landmark_group = LandmarkGroup( TriMesh(landmark_group.lms.points, tri_list, copy=False), OrderedDict([('tri', np.ones(n_points, dtype=np.bool))])) return group_label, new_landmark_group
def FastNICP(sources, target): aligned = [] corrs = [] for source in sources: pts, _ = icp(source.points, target.points) mesh = TriMesh(pts) try: a_s, corr = nicp(mesh, target, us=2001, ls=1, step=100) except: print('Failed Fast NICP') nicp_result = SNICP([PointCloud(pts)], target) corr = nicp_result.point_correspondence[0] a_s = nicp_result.aligned_shapes[0] aligned.append(a_s) corrs.append(corr) return aligned, corrs