示例#1
0
def compute_curvature(FV, VertexNormals, FaceNormals, Avertex, Acorner, up,
                      vp):
    """
    CalcFaceCurvature recives a list of vertices and faces in FV structure
    and the normal at each vertex and calculates the second fundemental
    matrix and the curvature using least squares
    :param FV: face-vertex data structure containing a list of vertices and a
    list of faces
    :param VertexNormals: n*3 matrix ( n = number of vertices ) containing the
    normal at each vertex
    :param FaceNormals: m*3 matrix ( m = number of faces ) containing the
    normal of each face
    :param Avertex:
    :param Acorner:
    :param up:
    :param vp:
    :return:
    FaceSFM - an m*1 cell matrix second fundemental
    VertexSFM - an n*w cell matrix second fundementel
    wfp - corner voronoi weights
    """
    print("Calculating curvature tensors ... Please wait")
    "Matrix of each face at each cell"
    FaceSFM, VertexSFM = list(), list()
    for i in range(FV.faces.shape[0]):
        FaceSFM.append([[0, 0], [0, 0]])
    for i in range(FV.vertices.shape[0]):
        VertexSFM.append([[0, 0], [0, 0]])
    Kn = np.zeros((1, FV.faces.shape[0]))

    " Get all the edge vectors "
    e0 = FV.vertices[FV.faces[:, 2], :] - FV.vertices[FV.faces[:, 1], :]
    e1 = FV.vertices[FV.faces[:, 0], :] - FV.vertices[FV.faces[:, 2], :]
    e2 = FV.vertices[FV.faces[:, 1], :] - FV.vertices[FV.faces[:, 0], :]

    " Normalize edge vectors "
    e0_norm = tut.unitize(e0)
    # e1_norm = normr(e1)
    # e2_norm = normr(e2)

    wfp = np.array(np.zeros((FV.faces.shape[0], 3)))
    for i in range(FV.faces.shape[0]):
        "Calculate Curvature Per Face"
        "set face coordinate frame"
        nf = FaceNormals[i, :]
        t = e0_norm[i, :]
        B = np.cross(nf, t)
        B = B / (np.linalg.norm(B))

        "extract relevant normals in face vertices"
        n0 = VertexNormals[FV.faces[i][0], :]
        n1 = VertexNormals[FV.faces[i][1], :]
        n2 = VertexNormals[FV.faces[i][2], :]

        " solve least squares problem of th form Ax=b "
        A = np.array([[np.dot(e0[i, :], t),
                       np.dot(e0[i, :], B), 0],
                      [0, np.dot(e0[i, :], t),
                       np.dot(e0[i, :], B)],
                      [np.dot(e1[i, :], t),
                       np.dot(e1[i, :], B), 0],
                      [0, np.dot(e1[i, :], t),
                       np.dot(e1[i, :], B)],
                      [np.dot(e2[i, :], t),
                       np.dot(e2[i, :], B), 0],
                      [0, np.dot(e2[i, :], t),
                       np.dot(e2[i, :], B)]])

        b = np.array([
            np.dot(n2 - n1, t),
            np.dot(n2 - n1, B),
            np.dot(n0 - n2, t),
            np.dot(n0 - n2, B),
            np.dot(n1 - n0, t),
            np.dot(n1 - n0, B)
        ])

        "Resolving by least mean square method because "
        "A is not a square matrix"

        x = np.linalg.lstsq(A, b, None)

        FaceSFM[i] = np.array([[x[0][0], x[0][1]], [x[0][1], x[0][2]]])
        Kn[0][i] = np.dot(np.array([1, 0]),
                          np.dot(FaceSFM[i], np.array([[1.], [0.]])))
        """
        Calculate curvature per vertex
        Calculate voronoi weights
        """
        wfp[i][0] = Acorner[i][0] / Avertex[FV.faces[i][0]]
        wfp[i][1] = Acorner[i][1] / Avertex[FV.faces[i][1]]
        wfp[i][2] = Acorner[i][2] / Avertex[FV.faces[i][2]]

        "Calculate new coordinate system and project the tensor"

        for j in range(3):
            new_ku, new_kuv, new_kv = \
                project_curvature_tensor(t, B, nf, x[0][0], x[0][1], x[0][2],
                                         up[FV.faces[i][j], :],
                                         vp[FV.faces[i][j], :])
            VertexSFM[FV.faces[i][j]] += np.dot(
                wfp[i][j], np.array([[new_ku, new_kuv], [new_kuv, new_kv]]))

    print('Finished Calculating curvature tensors')

    return FaceSFM, VertexSFM, wfp
示例#2
0
    def on_mouse_double_click(self, x, y):
        res = self._scene.camera.resolution
        fov_y = np.radians(self._scene.camera.fov[1] / 2.0)
        fov_x = fov_y * (res[0] / float(res[1]))
        half_fov = np.stack([fov_x, fov_y])

        right_top = np.tan(half_fov)
        right_top *= 1 - (1.0 / res)
        left_bottom = -right_top

        right, top = right_top
        left, bottom = left_bottom

        xy_vec = tu.grid_linspace(bounds=[[left, top], [right, bottom]], count=res).astype(np.float64)
        pixels = tu.grid_linspace(bounds=[[0, 0], [res[0] - 1, res[1] - 1]], count=res).astype(np.int64)
        assert xy_vec.shape == pixels.shape

        transform = self._scene.camera_transform
        vectors = tu.unitize(np.column_stack((xy_vec, -np.ones_like(xy_vec[:, :1]))))
        vectors = tf.transform_points(vectors, transform, translate=False)
        origins = (np.ones_like(vectors) * tf.translation_from_matrix(transform))

        indices = np.where(np.all(pixels == np.array([x, y]), axis=1))
        if len(indices) > 0 and len(indices[0]) > 0:
            pixel_id = indices[0][0]
            ray_origin = np.expand_dims(origins[pixel_id], 0)
            ray_direction = np.expand_dims(vectors[pixel_id], 0)
            # print(x, y, pixel_id, ray_origin, ray_direction)

            mesh = self._scene.geometry['geometry_0']

            locations, index_ray, index_tri = mesh.ray.intersects_location(
                ray_origins=ray_origin,
                ray_directions=ray_direction)

            if locations.size == 0:
                return

            ray_origins = np.tile(ray_origin, [locations.shape[0], 1])
            distances = np.linalg.norm(locations - ray_origins, axis=1)
            idx = np.argsort(distances)  # sort by disctances

            # color closest hit
            tri_color = mesh.visual.face_colors[index_tri[idx[0]]]
            if not np.alltrue(tri_color == [255, 0, 0, 255]):
                tri_color = [255, 0, 0, 255]
            else:
                # unselect triangle
                tri_color = [200, 200, 200, 255]

            mesh.visual.face_colors[index_tri[idx[0]]] = tri_color

            # collect clicked triangle ids
            tri_ids = np.where(np.all(mesh.visual.face_colors == [255, 0, 0, 255], axis=-1))[0]

            if len(tri_ids) >= self._settings_loader.min_triangles:
                # get center of triangles
                barycentric = mesh.triangles_center[tri_ids]
                joint_x = np.mean(barycentric[:, 0])
                joint_y = np.mean(barycentric[:, 1])
                joint_z = np.mean(barycentric[:, 2])
                joint = np.stack([joint_x, joint_y, joint_z])

                if 'joint_0' in self._scene.geometry:
                    self._scene.delete_geometry('joint_0')

                joint = np.expand_dims(joint, 0)
                joint = PointCloud(joint, process=False)
                self._scene.add_geometry(joint, geom_name='joint_0')

            if self.view['rays']:
                from trimesh import load_path
                ray_visualize = load_path(np.hstack((ray_origin, ray_origin + ray_direction)).reshape(-1, 2, 3))
                self._scene.add_geometry(ray_visualize, geom_name='cam_rays')

                # draw path where camera ray hits with mesh (only take 2 closest hits)
                path = np.hstack(locations[:2]).reshape(-1, 2, 3)
                ray_visualize = load_path(path)
                self._scene.add_geometry(ray_visualize, geom_name='cam_rays_hits')
示例#3
0
def calcvertex_normals(FV, N):
    """
    CalcVertexNormals calculates the normals and voronoi areas at each vertex
    INPUT:
    FV - triangle mesh in face vertex structure
    N - face normals
    OUTPUT -
    VertexNormals - [Nv X 3] matrix of normals at each vertex
    Avertex - [NvX1] voronoi area at each vertex
    Acorner - [NfX3] slice of the voronoi area at each face corner
    """

    print("Calculating vertex normals .... Please wait")

    "Get all the edge vectors"
    e0 = np.array(FV.vertices[FV.faces[:, 2], :] -
                  FV.vertices[FV.faces[:, 1], :])
    e1 = np.array(FV.vertices[FV.faces[:, 0], :] -
                  FV.vertices[FV.faces[:, 2], :])
    e2 = np.array(FV.vertices[FV.faces[:, 1], :] -
                  FV.vertices[FV.faces[:, 0], :])

    "Normalize edge vectors "
    e0_norm = tut.unitize(e0)
    e1_norm = tut.unitize(e1)
    e2_norm = tut.unitize(e2)

    de0 = np.sqrt((e0[:, 0])**2 + (e0[:, 1])**2 + (e0[:, 2])**2)
    de1 = np.sqrt((e1[:, 0])**2 + (e1[:, 1])**2 + (e1[:, 2])**2)
    de2 = np.sqrt((e2[:, 0])**2 + (e2[:, 1])**2 + (e2[:, 2])**2)
    l2 = np.array([de0**2, de1**2, de2**2])
    l2 = np.transpose(l2)
    """
    using ew to compute the cot of the angles for the voronoi area calculation
    ew is the triangle barycenter.
    We check later if it's inside or outside the triangle
    """
    ew = np.array([
        l2[:, 0] * (l2[:, 1] + l2[:, 2] - l2[:, 0]),
        l2[:, 1] * (l2[:, 2] + l2[:, 0] - l2[:, 1]),
        l2[:, 2] * (l2[:, 0] + l2[:, 1] - l2[:, 2])
    ])
    s = (de0 + de1 + de2) / 2

    "Af - face area vector"
    Af = np.sqrt(s * (s - de0) * (s - de1) * (s - de2))

    "herons formula for triangle area, "
    "could have also used  0.5 * norm(cross(e0,e1)) "
    "Calc weights"
    Acorner = np.zeros((np.shape(FV.faces)[0], 3))
    Avertex = np.zeros((np.shape(FV.vertices)[0], 1))

    "Compute vertex normals"
    VertexNormals, up, vp = \
        np.zeros((np.shape(FV.vertices)[0], 3)),\
        np.zeros((np.shape(FV.vertices)[0], 3)),\
        np.zeros((np.shape(FV.vertices)[0], 3))

    for i in range(np.shape(FV.faces)[0]):
        wfv1 = Af[i] / ((de1[i]**2) * (de2[i]**2))
        wfv2 = Af[i] / ((de0[i]**2) * (de2[i]**2))
        wfv3 = Af[i] / ((de1[i]**2) * (de0[i]**2))

        VertexNormals[FV.faces[i][0], :] += wfv1 * N[i, :]
        VertexNormals[FV.faces[i][1], :] += wfv2 * N[i, :]
        VertexNormals[FV.faces[i][2], :] += wfv3 * N[i, :]
        """
        Calculate areas for weights according to Mayar et al. [2002]
        Check if the triangle is obtuse, right or acute
        """
        "Changed shape for ew"

        if ew[0][i] <= 0:
            Acorner[i][1] = -0.25 * l2[i][2] * Af[i] / \
                (np.dot(e0[i, :], np.transpose(e2[i, :])))
            Acorner[i][2] = -0.25 * l2[i][1] * Af[i] / \
                (np.dot(e0[i, :], np.transpose(e1[i, :])))
            Acorner[i][0] = Af[i] - Acorner[i][2] - Acorner[i][1]
        elif ew[1][i] <= 0:
            Acorner[i][2] = -0.25 * l2[i][0] * Af[i] / \
                (np.dot(e1[i, :], np.transpose(e0[i, :])))
            Acorner[i][0] = -0.25 * l2[i][2] * Af[i] / \
                (np.dot(e1[i, :], np.transpose(e2[i, :])))
            Acorner[i][1] = Af[i] - Acorner[i][2] - Acorner[i][0]
        elif ew[2][i] <= 0:
            Acorner[i][0] = -0.25 * l2[i][1] * Af[i] / \
                (np.dot(e2[i, :], np.transpose(e1[i, :])))
            Acorner[i][1] = -0.25 * l2[i][0] * Af[i] / \
                (np.dot(e2[i, :], np.transpose(e0[i, :])))
            Acorner[i][2] = Af[i] - Acorner[i][1] - Acorner[i][0]
        else:
            ewscale = 0.5 * Af[i] / (ew[0][i] + ew[1][i] + ew[2][i])
            Acorner[i][0] = ewscale * (ew[1][i] + ew[2][i])
            Acorner[i][1] = ewscale * (ew[0][i] + ew[2][i])
            Acorner[i][2] = ewscale * (ew[1][i] + ew[0][i])

        Avertex[FV.faces[i][0]] += Acorner[i][0]
        Avertex[FV.faces[i][1]] += Acorner[i][1]
        Avertex[FV.faces[i][2]] += Acorner[i][2]

        " Calcul initial coordinate system "
        up[FV.faces[i][0], :] = e2_norm[i, :]
        up[FV.faces[i][1], :] = e0_norm[i, :]
        up[FV.faces[i][2], :] = e1_norm[i, :]

    VertexNormals = tut.unitize(VertexNormals)

    " Calcul initial vertex coordinate system"

    for i in range(np.shape(FV.vertices)[0]):
        up[i, :] = np.cross(up[i, :], VertexNormals[i, :])
        up[i, :] = up[i, :] / np.linalg.norm(up[i, :])
        vp[i, :] = np.cross(VertexNormals[i, :], up[i, :])

    print("Finished calculating vertex normals")
    return VertexNormals, Avertex, Acorner, up, vp