예제 #1
0
def vis_verts(mean_shape, verts, face, mvs=None, textures=None):
    """
    mean_shape: N x 3
    verts: B x N x 3
    face: numpy F x 3
    textures: B x F x T x T (x T) x 3
    """
    from psbody.mesh.mesh import Mesh
    from psbody.mesh.meshviewer import MeshViewers
    if mvs is None:
        mvs = MeshViewers((2, 3))

    num_row = len(mvs)
    num_col = len(mvs[0])

    mean_shape = convert2np(mean_shape)
    verts = convert2np(verts)

    num_show = min(num_row * num_col, verts.shape[0] + 1)

    mvs[0][0].set_dynamic_meshes([Mesh(mean_shape, face)])
    # 0th is mean shape:

    if textures is not None:
        tex = convert2np(textures)
    for k in np.arange(1, num_show):
        vert_here = verts[k - 1]
        if textures is not None:
            tex_here = tex[k - 1]
            fc = tex_here.reshape(tex_here.shape[0], -1, 3).mean(axis=1)
            mesh = Mesh(vert_here, face, fc=fc)
        else:
            mesh = Mesh(vert_here, face)
        mvs[int(k % num_row)][int(k / num_row)].set_dynamic_meshes([mesh])
예제 #2
0
    def test_aabb_tree(self):
        v_src = np.array([[-36, 37, 8], [5, -36, 35], [12, -15, 1],
                          [-10, -42, -26], [-38, -32, -26], [-8, -45, 40],
                          [44, -1, -1], [-16, 40, -13], [-39, 28, -11],
                          [-26, -10, -40], [-37, 44, 46], [8, -44, -27],
                          [-15, 32, -48], [-46, -33, 15], [23, 15, -5],
                          [5, -20, 24], [-31, 19, -32], [-13, 13, 28],
                          [-42, 43, 28], [-1, -6, -5]])
        f_src = np.array([[12, 16, 17], [5, 10, 1], [13, 19, 7], [13, 1, 5],
                          [14, 8, 16], [9, 2, 8], [1, 19, 18], [4, 0, 3],
                          [18, 15, 5], [3, 16, 2]])

        m = Mesh(v=v_src, f=f_src)
        t = m.compute_aabb_tree()

        v_query = np.array([[-19, 1, 1], [32, 29, 14], [-12, 31, 3],
                            [-15, 44, 38], [5, 12, 9]])

        v_expected = np.array([[-19.678178, 0.364208, -1.384218],
                               [23.000000, 15.000000, -5.000000],
                               [-13.729523, 19.930467, 0.278131],
                               [-31.869765, 34.228123, 44.656367],
                               [7.794764, 18.188195, -6.471474]])
        f_expected = np.array([2, 4, 0, 1, 4])

        f_est, v_est = t.nearest(v_query)

        diff1 = abs(f_est - f_expected)
        diff2 = abs(v_est - v_expected)

        self.assertTrue(max(diff1.flatten()) < 1e-6)
        self.assertTrue(max(diff2.flatten()) < 1e-6)
예제 #3
0
 def test_estimate_vertex_normals(self):
     # normals of a sphere should be scaled versions of the vertices
     m = Mesh(filename=self.test_sphere_path)
     m.v -= np.mean(m.v, axis=0)
     rad = np.linalg.norm(m.v[0])
     vn = np.array(m.estimate_vertex_normals())
     mse = np.mean(np.sqrt(np.sum((vn - m.v / rad)**2, axis=1)))
     self.assertTrue(mse < 0.05)
예제 #4
0
 def test_writing_bin_ply(self):
     m = Mesh(filename=self.test_ply_path)
     (_, tempname) = tempfile.mkstemp()
     m.write_ply(tempname)
     with open(tempname, 'rb') as f:
         candidate = f.read()
     os.remove(tempname)
     with open(self.test_bin_ply_path, 'rb') as f:
         truth = f.read()
     self.assertEqual(candidate, truth)
예제 #5
0
    def test_vert_normals(self):
        from psbody.mesh.geometry.vert_normals import VertNormals
        from psbody.mesh.mesh import Mesh
        mesh = Mesh(filename=os.path.join(test_data_folder, 'sphere.ply'))
        pred = VertNormals(mesh.v, mesh.f)

        vn_obs = mesh.estimate_vertex_normals().reshape((-1, 3))
        vn_pred = pred.reshape((-1, 3))

        self.assertTrue(np.max(np.abs(vn_pred.flatten() - vn_obs.flatten())) < 1e-15)
예제 #6
0
 def setUp(self):
     simpleobjpath = os.path.join(test_data_folder, 'test_doublebox.obj')
     self.simple_m = Mesh(filename=simpleobjpath)
     cylinderpath = os.path.join(test_data_folder, 'cylinder.obj')
     self.cylinder_m = Mesh(filename=cylinderpath)
     cylinder_trans_path = os.path.join(test_data_folder,
                                        'cylinder_trans.obj')
     self.cylinder_trans_m = Mesh(filename=cylinder_trans_path)
     self_int_cyl_path = os.path.join(test_data_folder,
                                      'self_intersecting_cyl.obj')
     self.self_int_cyl_m = Mesh(filename=self_int_cyl_path)
예제 #7
0
    def test_ascii_bad_ply(self):
        """Ensure that the proper exception is raised when a file fails to be read."""
        with self.assertRaisesRegex(SerializationError, 'Unable to open file'):
            Mesh(filename=self.test_bad_ply_path)

        # The next two tests are unnecessary,
        # just demonstrating the exception hierarchy:
        with self.assertRaises(MeshError):
            Mesh(filename=self.test_bad_ply_path)

        with self.assertRaises(Exception):
            Mesh(filename=self.test_bad_ply_path)
예제 #8
0
    def test_qslim_smoke_test(self):
        from psbody.mesh.mesh import Mesh
        from psbody.mesh.topology.decimation import qslim_decimator
        from psbody.mesh.geometry.triangle_area import triangle_area

        m = Mesh(
            filename=os.path.join(test_data_folder, 'female_template.ply'))

        ta = triangle_area(m.v, m.f)
        m.set_face_colors(ta / np.max(ta))

        qslimmer = qslim_decimator(m, factor=0.1)
        m2 = qslimmer(m)
        ta = triangle_area(m2.v, m2.f)
        m2.set_face_colors(ta / np.max(ta))
예제 #9
0
 def test_load_obj(self):
     m = Mesh(filename=self.test_obj_path)
     self.assertTrue((m.v == self.box_v).all())
     self.assertTrue((m.f == self.box_f).all())
     self.assertDictOfArraysEqual(m.segm, self.box_segm)
     self.assertEqual(m.landm, self.landm)
     self.assertDictOfArraysEqual(m.landm_xyz, self.landm_xyz)
def setup_silhouette_obj(silhs, rends, f):
    n_model = [ch.sum(rend[:, :, 0] > 0) for rend in rends]
    dist_tsf = [cv2.distanceTransform(np.uint8(1 - silh), cv2.DIST_L2, cv2.DIST_MASK_PRECISE) for silh in silhs]

    # Make sigma proportional to image area.
    # This gives radius 400 for 960 x 1920 image.
    sigma_ratio = 0.2727
    sigma = [np.sqrt(sigma_ratio * (silh.shape[0] * silh.shape[1]) / np.pi) for silh in silhs]
    # Model2silhouette ==> Consistency (contraction)

    def obj_m2s(w, i):
        return w * (GMOf(rends[i][:, :, 0] * dist_tsf[i], sigma[i]) / np.sqrt(n_model[i]))

    # silhouette error term (scan-to-model) ==> Coverage (expansion)
    coords = [np.fliplr(np.array(np.where(silh > 0)).T) + 0.5  for silh in silhs]# is this offset needed?
    scan_flat_v = [np.hstack((coord, ch.zeros(len(coord)).reshape((-1, 1)))) for coord in coords]
    scan_flat = [Mesh(v=sflat_v, f=[]) for sflat_v in scan_flat_v]
    # 2d + all 0.
    sv_flat = [ch.hstack((rend.camera, ch.zeros(len(rend.v)).reshape((-1, 1)))) for rend in rends]
    for i in range(len(rends)):
        sv_flat[i].f = f

    def obj_s2m(w, i):
        from sbody.mesh_distance import ScanToMesh
        return w * ch.sqrt(GMOf(ScanToMesh(scan_flat[i], sv_flat[i], f), sigma[i]))
       
    # For vis
    for i in range(len(rends)):
        scan_flat[i].vc = np.tile(np.array([0, 0, 1]), (len(scan_flat[i].v), 1))

    return obj_m2s, obj_s2m, dist_tsf
 def render_and_show(sv):
     for i in range(len(rends)):
         img = imgs[i]
         img_res = render_mesh(Mesh(sv[i].r, sv[i].model.f), img.shape[1], img.shape[0], kp_camera[i], near=0.5, far=20)
         plt.figure()
         plt.imshow(img[:, :, ::-1])
         plt.imshow(img_res)
         plt.axis('off')    
예제 #12
0
    def test_connectivity_smoke_test(self):

        from psbody.mesh import Mesh
        from psbody.mesh.topology.connectivity import get_vert_connectivity, get_faces_per_edge
        m = Mesh(
            filename=os.path.join(test_data_folder, 'female_template.ply'))
        vconn = get_vert_connectivity(m)
        fpe = get_faces_per_edge(m)

        self.assertIsNotNone(vconn)
        self.assertIsNotNone(fpe)
        def on_step(_):
            global c
            mesh = [None] * len(rends)
            for i in range(len(rends)):
                rend = rends[i]
                img = imgs[i]
                edges = cv2.Canny(np.uint8(rend[:, :, 0].r * 255), 100, 200)
                coords = np.array(np.where(edges > 0)).T
                plt.figure(200 + i, facecolor='w')
                plt.clf()
                plt.subplot(2, 2, 1)
                plt.imshow(dist_tsf[i])
                plt.plot(coords[:, 1], coords[:, 0], 'w.')
                plt.axis('off')
                plt.subplot(2, 2, 2)
                plt.imshow(rend[:, :, 0].r)
                plt.title('fitted silhouette')
                plt.draw()
                plt.axis('off')
                if img is not None and kp_camera is not None and j2d is not None:
                    plt.subplot(2, 2, 3)
                    plt.imshow(img[:, :, ::-1])
                    plt.scatter(kp_camera[i].r[:, 0], kp_camera[i].r[:, 1])
                    plt.scatter(j2d[i][:, 0], j2d[i][:, 1], c='w')
                    plt.axis('off')
                plt.subplot(2, 2, 4)
                plt.imshow((silhs[i] + rend[:, :, 0].r) / 2.0)
                plt.axis('off')
                plt.draw()
                plt.show(block=False)
                plt.pause(1e-5)
                #mv[i].set_static_meshes([Mesh(shape_model[i].r, shape_model[i].f)])

                if False:  #vc is not None:
                    vc1 = vc[i].r.copy()
                    vc1[:, 0] = vc[i].r.copy()[:, 2]
                    vc1[:, 2] = vc[i].r.copy()[:, 0]
                    mv[i].set_dynamic_meshes(
                        [Mesh(shape_model[i].r, shape_model[i].f, vc=vc1)])
                    vc2 = vc[i].r.copy()[symIdx, :]
                    vc2[:, 0] = vc[i].r.copy()[symIdx, 2]
                    vc2[:, 2] = vc[i].r.copy()[symIdx, 0]
                    mv2[i].set_dynamic_meshes(
                        [Mesh(shape_model[i].r, shape_model[i].f, vc=vc2)])
                else:
                    vc[:, 0] = 0.8
                    vc[:, 1] = 0.76
                    vc[:, 2] = 0.77
                    mesh[i] = Mesh(shape_model[i].r, shape_model[i].f, vc=vc)
                    v = mesh[i].v.copy()
                    mesh[i].v[:, 1] = -v[:, 1]
                    mesh[i].v[:, 2] = -v[:, 2]

                    #mv[i].set_static_meshes([mesh])
                mv2[0][i].set_static_meshes([mesh[i]])
                #if c==0:
                #    import pdb; pdb.set_trace()

                #mv2[0][i].save_snapshot('tmp_%.4d.png' % (c))
            c = c + 1
 def on_step(_):
     for i in range(len(rends)):
         rend = rends[i]
         img = imgs[i]
         edges = cv2.Canny(np.uint8(rend[:, :, 0].r * 255), 100, 200)
         coords = np.array(np.where(edges > 0)).T
         plt.figure(200+i, facecolor='w')
         plt.clf()
         plt.subplot(2, 2, 1)
         plt.imshow(dist_tsf[i])
         plt.plot(coords[:, 1], coords[:, 0], 'w.')
         plt.axis('off')
         plt.subplot(2, 2, 2)
         plt.imshow(rend[:, :, 0].r)
         plt.title('fitted silhouette')
         plt.draw()
         plt.axis('off')
         if img is not None and kp_camera is not None:
             plt.subplot(2, 2, 3)
             plt.imshow(img[:, :, ::-1])
             plt.scatter(kp_camera[i].r[:, 0], kp_camera[i].r[:, 1])
             plt.axis('off')
         plt.subplot(2, 2, 4)
         plt.imshow((silhs[i]+rend[:, :, 0].r)/2.0)
         plt.axis('off')
         plt.draw()
         plt.show(block=False)
         plt.pause(1e-5)
         if vc is not None:
             vc1 = vc[i].r.copy()
             vc1[:,0] = vc[i].r.copy()[:,2]
             vc1[:,2] = vc[i].r.copy()[:,0]
             mv[i].set_dynamic_meshes([Mesh(sv[i].r, sv[i].model.f, vc=vc1)])
             vc2 = vc[i].r.copy()[symIdx,:]
             vc2[:,0] = vc[i].r.copy()[symIdx,2]
             vc2[:,2] = vc[i].r.copy()[symIdx,0]
             mv2[i].set_dynamic_meshes([Mesh(sv[i].r, sv[i].model.f, vc=vc2)])
         else:
             mv[i].set_dynamic_meshes([Mesh(sv[i].r, sv[i].f)])
예제 #15
0
    def test_launch_smoke_test(self):
        """this test just opens a mesh window, waits, and kills the window"""

        sphere = Mesh(filename=os.path.join(test_data_folder, 'sphere.ply'))
        sphere.v = sphere.v / 10.

        print('keeping MeshViewer alive for 10 seconds..')
        time.sleep(10)
        print('killing MeshViewer and exiting...')

        if 0:
            # this cannot be unit tested
            from psbody.mesh.utils import row
            click = self.mvs[0][0].get_mouseclick()
            subwin_row = click['which_subwindow'][0]
            subwin_col = click['which_subwindow'][1]
            sphere.v = sphere.v - row(np.mean(sphere.v, axis=0)) + row(
                np.array([click['x'], click['y'], click['z']]))
            self.mvs[subwin_row][subwin_col].set_dynamic_meshes([sphere])

            print('items in mouseclick dict are as follows:')
            print(click)
예제 #16
0
    def setUp(self):
        fnames = [
            os.path.join(test_data_folder, i)
            for i in os.listdir(test_data_folder)
            if os.path.splitext(i)[1].lower() == '.ply'
        ]

        self.meshes = [Mesh(filename=fname) for fname in fnames]

        self.mvs = MeshViewers(shape=[2, 2])
        self.mvs[0][0].set_static_meshes([self.meshes[0]])
        self.mvs[0][1].set_static_meshes([self.meshes[1]])
        self.mvs[1][0].set_static_meshes([self.meshes[2]])
        self.mvs[1][1].set_static_meshes(
            [self.meshes[0]])  # only 2 .ply files left in the GitHub version
예제 #17
0
def vis_vert2kp(verts, vert2kp, face, mvs=None):
    """
    verts: N x 3
    vert2kp: K x N

    For each keypoint, visualize its weights on each vertex.
    Base color is white, pick a color for each kp.
    Using the weights, interpolate between base and color.

    """
    from psbody.mesh.mesh import Mesh
    from psbody.mesh.meshviewer import MeshViewer, MeshViewers
    from psbody.mesh.sphere import Sphere

    num_kp = vert2kp.shape[0]
    if mvs is None:
        mvs = MeshViewers((4, 4))
    # mv = MeshViewer()
    # Generate colors
    import pylab
    cm = pylab.get_cmap('gist_rainbow')
    cms = 255 * np.array([cm(1. * i / num_kp)[:3] for i in range(num_kp)])
    base = np.zeros((1, 3)) * 255
    # base = np.ones((1, 3)) * 255

    verts = convert2np(verts)
    vert2kp = convert2np(vert2kp)

    num_row = len(mvs)
    num_col = len(mvs[0])

    colors = []
    for k in range(num_kp):
        # Nx1 for this kp.
        weights = vert2kp[k].reshape(-1, 1)
        # So we can see it,,
        weights = weights / weights.max()
        cm = cms[k, None]
        # Simple linear interpolation,,
        # cs = np.uint8((1-weights) * base + weights * cm)
        # In [0, 1]
        cs = ((1 - weights) * base + weights * cm) / 255.
        colors.append(cs)

        # sph = [Sphere(center=jc, radius=.03).to_mesh(c/255.) for jc, c in zip(vert,cs)]
        # mvs[int(k/4)][k%4].set_dynamic_meshes(sph)
        mvs[int(k % num_row)][int(k / num_row)].set_dynamic_meshes(
            [Mesh(verts, face, vc=cs)])
예제 #18
0
    def setUp(self):

        fnames = [
            os.path.join(test_data_folder, i)
            for i in os.listdir(test_data_folder)
            if os.path.splitext(i)[1].lower() == '.ply'
        ]

        # We build a cycle to make sure we have enough meshes
        self.meshes = itertools.cycle(Mesh(filename=fname) for fname in fnames)

        self.mvs = MeshViewers(shape=[2, 2])
        self.mvs[0][0].set_static_meshes([next(self.meshes)])
        self.mvs[0][1].set_static_meshes([next(self.meshes)])
        self.mvs[1][0].set_static_meshes([next(self.meshes)])
        self.mvs[1][1].set_static_meshes([next(self.meshes)])
예제 #19
0
    def test_trinormal(self):

        from psbody.mesh.mesh import Mesh
        from psbody.mesh.geometry.tri_normals import TriNormals, TriToScaledNormal, TriNormalsScaled, NormalizeRows

        m = Mesh(
            filename=os.path.join(test_data_folder, 'female_template.ply'))

        # Raffi: I do not know what this thing is supposed to test, maybe stability over some noise...
        tn = TriNormals(m.v, m.f)
        tn2 = NormalizeRows(TriToScaledNormal(m.v, m.f))

        eps = 1e-8
        mvc = m.v.copy()
        mvc[0] += eps
        tn_b = TriNormals(mvc, m.f)
        tn2_b = NormalizeRows(TriToScaledNormal(mvc, m.f))
        # our TriNormals empirical: sp.csc_matrix(tn_b.flatten() - tn.flatten()) / eps
        # old TriToScaledNormals empirical': sp.csc_matrix(tn2_b.flatten() - tn2.flatten()) / eps

        # apparently just for printing sparsly
        # import scipy.sparse as sp
        # print sp.csc_matrix(tn_b.flatten() - tn.flatten()) / eps
        np.testing.assert_almost_equal(tn_b.flatten() - tn.flatten(),
                                       tn2_b.flatten() - tn2.flatten())

        tn = TriNormalsScaled(m.v, m.f)
        tn2 = TriToScaledNormal(m.v, m.f)
        eps = 1e-8
        mvc = m.v.copy()
        mvc[0] += eps

        tn_b = TriNormalsScaled(mvc, m.f)
        tn2_b = TriToScaledNormal(mvc, m.f)

        np.testing.assert_almost_equal(tn_b.flatten() - tn.flatten(),
                                       tn2_b.flatten() - tn2.flatten())
예제 #20
0
 def test_raw_initialization(self):
     m = Mesh(v=self.box_v, f=self.box_f)
     self.assertTrue((m.v == self.box_v).all())
     self.assertTrue((m.f == self.box_f).all())
예제 #21
0
    def test_loop_subdivision_smoke_test(self):
        from psbody.mesh import Mesh
        from psbody.mesh.topology.subdivision import loop_subdivider

        m1 = Mesh(
            filename=os.path.join(test_data_folder, 'female_template.ply'))
        sdv = loop_subdivider(m1)

        self.assertIsNotNone(sdv)
        self.assertTrue(hasattr(sdv, "faces"))

        f_new = sdv.faces

        v_new = sdv(m1.v)
        self.assertIsNotNone(v_new)
        v_new = v_new.reshape((-1, 3))

        v_new_want_edge = sdv(m1.v, want_edges=True)
        self.assertIsNotNone(v_new_want_edge)
        v_new_want_edge = v_new_want_edge.reshape((-1, 3))

        m2 = Mesh(v=v_new, f=f_new)

        m1.reset_normals()
        m2.reset_normals()

        m1.write_ply(os.path.join(temporary_files_folder, 'lowres.ply'))
        m2.write_ply(os.path.join(temporary_files_folder, 'highres.ply'))

        if 0:
            from psbody.mesh import MeshViewers
            mvs = MeshViewers(shape=(2, 2))
            mvs[0][0].set_static_meshes([m1])
            m1.f = []
            mvs[0][1].set_static_meshes([m1])
            mvs[1][0].set_static_meshes([m2])
            m2.f = []
            mvs[1][1].set_static_meshes([m2])
예제 #22
0
    def test_landmark_loader(self):
        scan_fname = pjoin(test_data_folder, 'csr0001a.ply')
        scan_lmrk = pjoin(test_data_folder, 'csr0001a.lmrk')
        template_fname = pjoin(test_data_folder,
                               'textured_mean_scape_female.obj')
        template_pp = pjoin(test_data_folder,
                            'template_caesar_picked_points.pp')
        scan = Mesh(filename=scan_fname, lmrkfilename=scan_lmrk)
        template = Mesh(filename=template_fname, ppfilename=template_pp)

        # Detecting CAESAR lmrk files:
        m = Mesh(filename=scan_fname, landmarks=scan_lmrk)
        self.assertEqual(m.landm, scan.landm)
        self.assertDictOfArraysEqual(m.landm_xyz, scan.landm_xyz)

        # Detecting Meshlab pp file
        m = Mesh(filename=template_fname, landmarks=template_pp)
        self.assertEqual(m.landm, template.landm)
        self.assertDictOfArraysAlmostEqual(m.landm_xyz, template.landm_xyz)

        del template.landm_regressors

        def test(landmarks):
            m = Mesh(filename=template_fname, landmarks=landmarks)
            self.assertEqual(m.landm, template.landm)
            self.assertDictOfArraysAlmostEqual(m.landm_xyz, template.landm_xyz)

        import json
        import yaml
        import pickle
        tmp_dir = tempfile.mkdtemp('bodylabs-test')
        test_files = [
            (yaml, os.path.join(tmp_dir, 'landmarks.yaml'), 'w'),
            (yaml, os.path.join(tmp_dir, 'landmarks.yml'), 'w'),
            (json, os.path.join(tmp_dir, 'landmarks.json'), 'w'),
            (pickle, os.path.join(tmp_dir, 'landmarks.pkl'), 'wb'),
        ]
        test_data_ind = dict((n, int(v)) for n, v in template.landm.items())
        test_data_xyz = dict(
            (n, v.tolist()) for n, v in template.landm_xyz.items())
        for loader, filename, mode in test_files:
            with open(filename, mode) as fd:
                loader.dump(test_data_ind, fd)
            test(filename)
            with open(filename, mode) as fd:
                loader.dump(test_data_xyz, fd)
            test(filename)

        shutil.rmtree(tmp_dir, ignore_errors=True)

        test(template.landm)
        test(template.landm_xyz)

        m = Mesh(filename=template_fname, landmarks=[0, 1, 2])
        self.assertEqual(m.landm, {'0': 0, '1': 1, '2': 2})

        m = Mesh(filename=template_fname,
                 landmarks=[template.v[0], template.v[7]])
        self.assertDictOfArraysAlmostEqual(m.landm_xyz, {
            '0': template.v[0],
            '1': template.v[7]
        })

        m = Mesh(filename=template_fname,
                 landmarks=[template.v[0].tolist(), template.v[7].tolist()])
        self.assertDictOfArraysAlmostEqual(m.landm_xyz, {
            '0': template.v[0],
            '1': template.v[7]
        })
예제 #23
0
 def test(landmarks):
     m = Mesh(filename=template_fname, landmarks=landmarks)
     self.assertEqual(m.landm, template.landm)
     self.assertDictOfArraysAlmostEqual(m.landm_xyz, template.landm_xyz)
예제 #24
0
 def test_load_ply(self):
     m = Mesh(filename=self.test_ply_path, ppfilename=self.test_pp_path)
     self.assertTrue((m.v == self.box_v).all())
     self.assertTrue((m.f == self.box_f).all())
     self.assertTrue(m.landm == self.landm)