Exemple #1
0
 def test_writing_obj_locally_using_mesh_write_obj(self):
     local_file = os.path.join(
         self.tmp_dir,
         "test_writing_ascii_obj_locally_using_mesh_write_ply.obj")
     m = Mesh(filename=self.test_obj_path)
     m.write_obj(local_file)
     self.assertFilesEqual(local_file, self.test_obj_path)
Exemple #2
0
 def test_writing_ascii_ply_locally_using_mesh_write_ply(self):
     local_file = os.path.join(
         self.tmp_dir,
         "test_writing_ascii_ply_locally_using_mesh_write_ply.ply")
     m = Mesh(filename=self.test_ply_path)
     m.write_ply(local_file, ascii=True)
     self.assertFilesEqual(local_file, self.test_ply_path)
Exemple #3
0
 def test_scale_vertex_colors(self):
     m = Mesh(v=np.ones((4, 3)), vc='red')
     m.scale_vertex_colors(np.array([2.0, 1.0, 0.5, 0.0]))
     expected_c = np.array([[1.0, 0.0, 0.0], [0.5, 0.0, 0.0],
                            [0.25, 0.0, 0.0], [0.0, 0.0, 0.0]])
     np.testing.assert_array_equal(expected_c, m.vc)
     self.assertEqual(m.vc.dtype, np.float64)
Exemple #4
0
def main():
    import argparse
    from lace.mesh import Mesh

    parser = argparse.ArgumentParser()
    parser.add_argument('-p', '--path', help='filepath to mesh', required=True)
    parser.add_argument('-c', '--cloud', help='display point cloud', required=False, default=False, action='store_true')
    parser.add_argument('-d', '--direction', help='direction of connected component',
                        choices=['N', 'S', 'E', 'W'], default=None, required=False)
    args = parser.parse_args()

    path_to_mesh = args.path
    mesh = Mesh(filename=path_to_mesh, vc='SteelBlue')

    point_on_plane = np.array([0., 1., 0.])

    n1 = np.array([0., 1., 0.])
    p1 = Plane(point_on_plane, n1)

    n2 = np.array([1., 0., 0.])
    p2 = Plane(point_on_plane, n2)

    n3 = np.array([1., 1., 0.])
    n3 /= np.linalg.norm(n3)
    p3 = Plane(point_on_plane, n3)

    n4 = np.array([-1., 1., 0.])
    n4 /= np.linalg.norm(n4)
    p4 = Plane(point_on_plane, n4)

    dirmap = {
        'N': [0., +100., 0.],
        'S': [0., -100., 0.],
        'E': [+100., 0., 0.],
        'W': [-100., 0., 0.],
        None: None,
    }

    neighborhood = dirmap[args.direction]
    if neighborhood != None:
        neighborhood = np.array([neighborhood])

    xs1 = p1.mesh_xsection(mesh, neighborhood=neighborhood)
    xs2 = p2.mesh_xsection(mesh, neighborhood=neighborhood)
    xs3 = p3.mesh_xsection(mesh, neighborhood=neighborhood)
    xs4 = p4.mesh_xsection(mesh, neighborhood=neighborhood)

    lines = [
        polyline.as_lines()
        for polyline in [xs1, xs2, xs3, xs4]
    ]

    if args.cloud:
        mesh.f = []

    from lace.meshviewer import MeshViewer
    mv = MeshViewer(keepalive=True)
    mv.set_dynamic_meshes([mesh], blocking=True)
    mv.set_dynamic_lines(lines)
Exemple #5
0
    def test_recenter_over_floor_raises_expected_on_empty_mesh(self):
        mesh = Mesh()

        with self.assertRaises(ValueError) as ctx:
            mesh.recenter_over_floor()

        self.assertEqual(str(ctx.exception),
                         'Mesh has no vertices; centroid is not defined')
Exemple #6
0
def find_rigid_transform(a, b, visualize=False):
    """
    Args:
        a: a 3xN array of vertex locations
        b: a 3xN array of vertex locations

    Returns: (R,T) such that R.dot(a)+T ~= b
    Based on Arun et al, "Least-squares fitting of two 3-D point sets," 1987.
    See also Eggert et al, "Estimating 3-D rigid body transformations: a
    comparison of four major algorithms," 1997.
    """
    import numpy as np
    import scipy.linalg

    if a.shape[0] != 3:
        if a.shape[1] == 3:
            a = a.T
    if b.shape[0] != 3:
        if b.shape[1] == 3:
            b = b.T
    assert a.shape[0] == 3
    assert b.shape[0] == 3

    a_mean = np.mean(a, axis=1)
    b_mean = np.mean(b, axis=1)
    a_centered = a - a_mean.reshape(-1, 1)
    b_centered = b - b_mean.reshape(-1, 1)

    c = a_centered.dot(b_centered.T)
    u, s, v = np.linalg.svd(c, full_matrices=False)
    v = v.T
    R = v.dot(u.T)

    if scipy.linalg.det(R) < 0:
        if np.any(s == 0
                  ):  # This is only valid in the noiseless case; see the paper
            v[:, 2] = -v[:, 2]
            R = v.dot(u.T)
        else:
            raise ValueError(
                "find_rigid_transform found a reflection that it cannot recover from. Try RANSAC or something..."
            )

    T = (b_mean - R.dot(a_mean)).reshape(-1, 1)

    if visualize != False:
        from lace.mesh import Mesh
        from lace.meshviewer import MeshViewer

        mv = MeshViewer() if visualize is True else visualize
        a_T = R.dot(a) + T
        mv.set_dynamic_meshes([
            Mesh(v=a.T, f=[]).set_vertex_colors("red"),
            Mesh(v=b.T, f=[]).set_vertex_colors("green"),
            Mesh(v=a_T.T, f=[]).set_vertex_colors("orange"),
        ])

    return R, T
Exemple #7
0
def _load(f, mesh=None):
    import numpy as np
    from lace.mesh import Mesh
    if not mesh:
        mesh = Mesh()
    faces = []
    facenormals = []
    verts = []

    head = f.readline().strip()
    if head.startswith("solid"):  # ascii STL format
        #name = head[6:]
        current_face = []
        for line in f:
            line = line.split()
            if line[0] == "endsolid":
                break
            elif line[0] == "facet":
                current_face = []
                if line[1] == "normal":
                    try:
                        facenormals.append([float(x) for x in line[2:]])
                    except:  # pylint: disable=bare-except
                        facenormals.append([np.nan, np.nan, np.nan])
                else:
                    facenormals.append([np.nan, np.nan, np.nan])
            elif line[0] == "endfacet":
                faces.append(current_face)
                current_face = []
            elif line[0:2] == ["outer", "loop"]:
                pass
            elif line[0] == "endloop":
                pass
            elif line[0] == "vertex":
                current_face.append(len(verts))
                try:
                    verts.append([float(x) for x in line[1:]])
                except:  # pylint: disable=bare-except
                    verts.append([np.nan, np.nan, np.nan])
            else:
                raise ValueError(
                    "Badly formatted STL file. I don't understand the line %s"
                    % line)
    else:
        raise Exception(
            "Looks like this is a binary STL file; you're going to have to implement that"
        )
        # format docs are here: http://en.wikipedia.org/wiki/STL_(file_format)

    mesh.v = np.array(verts, dtype=np.float64).copy()
    mesh.f = np.array(faces, dtype=np.uint32).copy()
    mesh.fn = np.array(facenormals, dtype=np.float64).copy()
    return mesh
Exemple #8
0
 def test_estimate_vertex_normals(self):
     # normals of a sphere should be scaled versions of the vertices
     test_sphere_path = sc(
         's3://bodylabs-korper-assets/is/ps/shared/data/body/'
         'korper_testdata/sphere.ply'
     )
     m = Mesh(filename=test_sphere_path)
     m.v -= np.mean(m.v, axis=0)
     rad = np.linalg.norm(m.v[0])
     m.estimate_vertex_normals()
     mse = np.mean(np.sqrt(np.sum((m.vn - m.v/rad)**2, axis=1)))
     self.assertTrue(mse < 0.05)
Exemple #9
0
 def test_explicit_landmark_indexes_from_another_mesh(self):
     m = Mesh(filename=self.template_fname, landmarks=self.template.landm)
     np.testing.assert_array_equal(self.template.v, m.v)
     self.assertEqual(m.landm, self.template.landm)
     # The following are _not_ expected to pass, as the initial load of template is
     # loading points that are slightly off from the actual vertex locations,
     # so the regressors are going to be subtly different.
     #   self.assertDictOfArraysAlmostEqual(m.landm_xyz, self.template.landm_xyz)
     #   self.assertDictOfArraysAlmostEqual(m.landm_regressors, self.template.landm_regressors)
     # But if we disable the regressors and just use the landmark verts:
     m.landm_regressors = {}
     self.assertDictOfArraysAlmostEqual(
         m.landm_xyz, self.template_without_regressors.landm_xyz)
Exemple #10
0
 def test_mesh_copy(self):
     m = Mesh(
         v=np.random.randn(10, 3),
         f=np.random.randn(10, 3),
         vc=np.random.randn(10, 3),
         vn=np.random.randn(10, 3),
     )
     m2 = m.copy()
     np.testing.assert_array_equal(m.v, m2.v)
     np.testing.assert_array_equal(m.f, m2.f)
     np.testing.assert_array_equal(m.vc, m2.vc)
     np.testing.assert_array_equal(m.vn, m2.vn)
     self.assertNotEqual(id(m.v), id(m2.v))
Exemple #11
0
 def test_mesh_copy_light(self):
     m = Mesh(
         v=np.random.randn(10, 3),
         f=np.random.randn(10, 3),
         vc=np.random.randn(10, 3),
         vn=np.random.randn(10, 3),
     )
     m2 = m.copy(only=['f', 'v'])
     np.testing.assert_array_equal(m.v, m2.v)
     np.testing.assert_array_equal(m.f, m2.f)
     self.assertIsNone(m2.vc)
     self.assertIsNone(m2.vn)
     self.assertNotEqual(id(m.v), id(m2.v))
Exemple #12
0
 def load_texture(self, texture_version):
     '''
     Expect a texture version number as an integer, load the texture version from /is/ps/shared/data/body/template/texture_coordinates/.
     Currently there are versions [0, 1, 2, 3] availiable.
     '''
     import numpy as np
     lowres_tex_template = 's3://bodylabs-korper-assets/is/ps/shared/data/body/template/texture_coordinates/textured_template_low_v%d.obj' % texture_version
     highres_tex_template = 's3://bodylabs-korper-assets/is/ps/shared/data/body/template/texture_coordinates/textured_template_high_v%d.obj' % texture_version
     from lace.mesh import Mesh
     from lace.cache import sc
     mesh_with_texture = Mesh(filename=sc(lowres_tex_template))
     if not np.all(mesh_with_texture.f.shape == self.f.shape):
         mesh_with_texture = Mesh(filename=sc(highres_tex_template))
     self.transfer_texture(mesh_with_texture)
Exemple #13
0
    def uniquified_mesh(self):
        """This function returns a copy of the mesh in which vertices are copied such that
        each vertex appears in only one face, and hence has only one texture"""
        import numpy as np
        from lace.mesh import Mesh
        new_mesh = Mesh(v=self.v[self.f.flatten()], f=np.array(range(len(self.f.flatten()))).reshape(-1, 3))

        if self.vn is None:
            self.reset_normals()
        new_mesh.vn = self.vn[self.f.flatten()]

        if self.vt is not None:
            new_mesh.vt = self.vt[self.ft.flatten()]
            new_mesh.ft = new_mesh.f.copy()
        return new_mesh
def load_front_torso_mesh():
    from lace.mesh import Mesh

    mesh = Mesh(filename="/Users/pnm/code/tape/examples/anonymized_female.obj")
    mesh.cut_across_axis(1, minval=100.0, maxval=120.0)
    mesh.cut_across_axis(0, minval=-19.0, maxval=19.0)
    mesh.cut_across_axis(2, minval=0)
    return mesh
Exemple #15
0
 def test_writing_obj_locally_using_serializer(self):
     local_file = os.path.join(
         self.tmp_dir,
         "test_writing_ascii_obj_locally_using_serializer.obj")
     m = Mesh(filename=self.test_obj_path)
     obj.dump(m, local_file)
     self.assertFilesEqual(local_file, self.test_obj_path)
Exemple #16
0
    def test_concatenate_vertices_only(self):
        v1 = np.array([
            [0., 0., 0.],
            [5., 5., 5.],
            [5., 0., 5.],
        ])
        m1 = Mesh(v=v1)

        v2 = np.array([
            [0., 0., 0.],
            [5., -5., 5.],
            [5., 0., 5.],
        ])
        m2 = Mesh(v=v2)

        self.assertEqual(Mesh.concatenate(m1, m2).v.shape[0], 6)
Exemple #17
0
    def test_writing_empty_mesh(self):
        m = Mesh()

        local_file = os.path.join(self.tmp_dir, 'test_writing_empty_mesh.obj')
        obj.dump(m, local_file)

        self.assertEqual(os.stat(local_file).st_size, 0)
Exemple #18
0
 def test_writing_binary_ply_locally_using_serializer(self):
     local_file = os.path.join(
         self.tmp_dir,
         "test_writing_binary_ply_locally_using_serializer.ply")
     m = Mesh(filename=self.test_ply_path)
     ply.dump(m, local_file)
     self.assertFilesEqual(local_file, self.test_bin_ply_path)
Exemple #19
0
 def test_json_index(self):
     from baiji.serialization import json
     path = self.make_index_data(json, '.json')
     m = Mesh(filename=self.template_fname, landmarks=path)
     self.assertEqual(m.landm, self.template.landm)
     self.assertDictOfArraysAlmostEqual(
         m.landm_xyz, self.template_without_regressors.landm_xyz)
Exemple #20
0
def create_rectangular_prism(origin, size):
    '''
    Return a Mesh which is an axis-aligned rectangular prism. One vertex is
    `origin`; the diametrically opposite vertex is `origin + size`.

    size: 3x1 array.

    '''
    from lace.topology import quads_to_tris

    lower_base_plane = np.array([
        # Lower base plane
        origin,
        origin + np.array([size[0], 0, 0]),
        origin + np.array([size[0], 0, size[2]]),
        origin + np.array([0, 0, size[2]]),
    ])
    upper_base_plane = lower_base_plane + np.array([0, size[1], 0])

    vertices = np.vstack([lower_base_plane, upper_base_plane])

    faces = quads_to_tris(np.array([
        [0, 1, 2, 3],  # lower base (-y)
        [7, 6, 5, 4],  # upper base (+y)
        [4, 5, 1, 0],  # +z face
        [5, 6, 2, 1],  # +x face
        [6, 7, 3, 2],  # -z face
        [3, 7, 4, 0],  # -x face
    ]))

    return Mesh(v=vertices, f=faces)
Exemple #21
0
 def test_explicit_landmarks_as_array_of_indexes(self):
     m = Mesh(filename=self.template_fname, landmarks=np.array([0, 7]))
     self.assertEqual(m.landm, {'0': 0, '1': 7})
     self.assertDictOfArraysAlmostEqual(m.landm_xyz, {
         '0': self.template.v[0],
         '1': self.template.v[7]
     })
Exemple #22
0
 def test_yml_points(self):
     from baiji.serialization import yaml
     path = self.make_point_data(yaml, '.yml')
     m = Mesh(filename=self.template_fname, landmarks=path)
     self.assertEqual(m.landm, self.template.landm)
     self.assertDictOfArraysAlmostEqual(m.landm_xyz,
                                        self.template.landm_xyz)
Exemple #23
0
 def test_explicit_landmarks_as_dict_of_indexes(self):
     m = Mesh(filename=self.template_fname, landmarks={'foo': 0, 'bar': 7})
     self.assertEqual(m.landm, {'foo': 0, 'bar': 7})
     self.assertDictOfArraysAlmostEqual(m.landm_xyz, {
         'foo': self.template.v[0],
         'bar': self.template.v[7]
     })
Exemple #24
0
 def test_flip_faces(self):
     raw_box = Mesh(vc('/unittest/serialization/obj/test_box_simple.obj'))
     box = Mesh(v=raw_box.v, f=raw_box.f)
     box.reset_normals()
     original_vn = box.vn.copy()
     original_f = box.f.copy()
     box.flip_faces()
     box.reset_normals()
     self.assertEqual(box.f.shape, original_f.shape)
     for face, orig_face in zip(box.f, original_f):
         self.assertNotEqual(list(face), list(orig_face))
         self.assertEqual(set(face), set(orig_face))
     np.testing.assert_array_almost_equal(box.vn, np.negative(original_vn))
Exemple #25
0
 def test_explicit_landmarks_as_array_of_points(self):
     m = Mesh(filename=self.template_fname,
              landmarks=[self.template.v[0], self.template.v[7]])
     self.assertEqual(m.landm, {'0': 0, '1': 7})
     self.assertDictOfArraysAlmostEqual(m.landm_xyz, {
         '0': self.template.v[0],
         '1': self.template.v[7]
     })
Exemple #26
0
    def test_cut_across_axis_by_percentile(self):
        original_mesh = Mesh(filename=sc(
            's3://bodylabs-assets/example_meshes/average_female.obj'))

        # Set up
        mesh = original_mesh.copy()
        # Sanity check
        np.testing.assert_almost_equal(mesh.v[:, 0].min(), -0.3668)
        np.testing.assert_almost_equal(mesh.v[:, 0].max(), 0.673871)
        # Act
        mesh.cut_across_axis_by_percentile(0, 25, 40)
        # Test
        np.testing.assert_almost_equal(mesh.v[:, 0].min(), 0.03, decimal=1)
        np.testing.assert_almost_equal(mesh.v[:, 0].max(), 0.10, decimal=1)
        # Visualize
        if self.debug:
            mesh.show()
Exemple #27
0
    def test_bounding_box_is_undefined_on_empty_mesh(self):
        mesh = Mesh()

        with self.assertRaises(ValueError) as ctx:
            mesh.bounding_box  # pylint: disable=pointless-statement

        self.assertEqual(str(ctx.exception),
                         'Mesh has no vertices; bounding box is not defined')
Exemple #28
0
 def test_loads_from_local_path_using_constructor_with_landmarks(self):
     skip_on_import_error('lace-search')
     m = Mesh(filename=self.test_obj_with_landmarks_path,
              ppfilename=self.test_pp_path)
     self.assertTrue((m.v == self.truth['box_v']).all())
     self.assertTrue((m.f == self.truth['box_f']).all())
     self.assertEqual(m.landm, self.truth['landm'])
     self.assertDictOfArraysEqual(m.landm_xyz, self.truth['landm_xyz'])
     self.assertDictOfArraysEqual(m.segm, self.truth['box_segm'])
Exemple #29
0
def _load(f, existing_mesh=None):
    import numpy as np
    from lace.mesh import Mesh
    v = np.loadtxt(f.name)
    if existing_mesh is None:
        return Mesh(v=v)
    else:
        existing_mesh.v = v
        return existing_mesh
Exemple #30
0
def _load(f, existing_mesh=None):
    from lace.mesh import Mesh
    parser = BSFParser(f)
    if existing_mesh is None:
        return Mesh(v=parser.v, f=parser.f, vc=parser.vc)
    else:
        existing_mesh.v = parser.v
        existing_mesh.f = parser.f
        existing_mesh.vc = parser.vc
        return existing_mesh