non-void/VirtualBones

Issue with Extracting Low-Frequency Mesh for "dress02"

Closed this issue · 2 comments

Thanks for releasing such an great work. I am currently working on a project similar to yours and am interested in comparing it with your work. To do this, I need to use the data you have shared.

I noticed that you have shared two type of clothes, "dress02" and "dress03". In another issue, you mentioned the use of the diffusion_smoothing method from TailorNet to extract low-frequency meshes from the original mesh. Following this method, I successfully extracted the low-frequency mesh for "dress03". However, I encountered a problem while processing "dress02".

The error message states, 'The boundary edges are not closed loops!'. The code requires np.sum(edge_mat == v) == 2, meaning each edge vertex should exactly connect to two boundary edges. But in the case of "dress02", some vertices are connected to one boundary edge and some are connected to three.

Could you please guide me on how to resolve this issue? Any advice or suggestions would be greatly appreciated.

Here is my code to extract the low-frequency meshes

import copy
from src.obj_parser import Mesh_obj
if __name__ == "__main__":
    for dress in ['dress02']:
#         obj_template_path = f"assets/{dress}/garment.obj"
        obj_template_path = f"assets/{dress}/SSDR/u.obj"
        garment_template = Mesh_obj(obj_template_path)
        for sequnce_idx in range(89):
            test_path = f"{dress}/{sequnce_idx}.npz"
            test = np.load(test_path)
            for frame_idx in range(len(test['sim_res'])):
                ms = copy.deepcopy(garment_template)
                ms.v = test['sim_res'][frame_idx]
                smoothing = DiffusionSmoothing(ms.v, ms.f)

                verts_smooth = ms.v.copy()
                for i in range(20):
                    verts_smooth = smoothing.smooth_uniform(verts_smooth)
                ms_smooth = Mesh(v=verts_smooth, f=ms.f)

                os.makedirs(f"out_GT/{dress}/seq_{sequnce_idx:02d}", exist_ok=True)
                ms_smooth.write_obj(f"out_GT/{dress}/seq_{sequnce_idx:02d}/{frame_idx:04d}_coarse.obj")

hi,can you share the checkpoint files? It seems that the checkpoints of this project can not download now. Thanks a lot!

check these

https://github.com/MPI-IS/mesh


import os.path

import numpy as np
import scipy
import scipy.sparse as sp
from psbody.mesh import Mesh, MeshViewer
from obj_parser import Mesh_obj


def numpy_laplacian_uniform(v, f):
    """Computes uniform laplacian operator on mesh."""
    import scipy.sparse as sp
    from sklearn.preprocessing import normalize
    from psbody.mesh.topology.connectivity import get_vert_connectivity

    connectivity = get_vert_connectivity(Mesh(v=v, f=f))
    # connectivity is a sparse matrix, and np.clip can not applied directly on
    # a sparse matrix.
    connectivity.data = np.clip(connectivity.data, 0, 1)
    lap = normalize(connectivity, norm='l1', axis=1)
    lap = lap - sp.eye(connectivity.shape[0])

    return lap


def numpy_laplacian_cot(v, f):
    """Computes cotangent laplacian operator on mesh."""
    n = len(v)

    v_a = f[:, 0]
    v_b = f[:, 1]
    v_c = f[:, 2]

    ab = v[v_a] - v[v_b]
    bc = v[v_b] - v[v_c]
    ca = v[v_c] - v[v_a]

    cot_a = -1 * (ab * ca).sum(axis=1) / (np.sqrt(np.sum(np.cross(ab, ca) ** 2, axis=-1)) + 1.e-10)
    cot_b = -1 * (bc * ab).sum(axis=1) / (np.sqrt(np.sum(np.cross(bc, ab) ** 2, axis=-1)) + 1.e-10)
    cot_c = -1 * (ca * bc).sum(axis=1) / (np.sqrt(np.sum(np.cross(ca, bc) ** 2, axis=-1)) + 1.e-10)

    I = np.concatenate((v_a, v_c, v_a, v_b, v_b, v_c))
    J = np.concatenate((v_c, v_a, v_b, v_a, v_c, v_b))
    W = 0.5 * np.concatenate((cot_b, cot_b, cot_c, cot_c, cot_a, cot_a))

    L = sp.csr_matrix((W, (I, J)), shape=(n, n))
    L = L - sp.spdiags(L * np.ones(n), 0, n, n)

    return L


def direct_smoothing(v, f, smoothness=0.1, Ltype='cotangent'):
    """Apply direct smoothing on mesh."""
    if Ltype == 'cotangent':
        L = numpy_laplacian_cot(v, f)
    elif Ltype == 'uniform':
        L = numpy_laplacian_uniform(v, f)
    else:
        raise AttributeError
    new_v = v + smoothness * L.dot(v)
    return new_v


class DiffusionSmoothing(object):
    """A class useful to apply smoothing repeatedly in efficient manner on the same-topology meshes."""

    def __init__(self, v, f):
        """Computes and stores necessary variables.

        v is only used for getting total number of vertices. f defines the topology.
        """
        self.num_v = v.shape[0]
        self.v = v
        self.f = f
        try:
            self.set_boundary_ids_and_mats(v, f)
        except:
            pass
        self.uniL = None

    def get_uniform_lap_smoothing(self):
        """Computes uniform laplacian for smoothing.

        Boundary vertices are smoothed not by all neighbors but only neighboring
        boundary vertices in order to prevent boundary shrinking.
        """
        L = numpy_laplacian_uniform(self.v, self.f)

        # remove rows corresponding to boundary vertices
        for row in self.b_ids:
            L.data[L.indptr[row]:L.indptr[row + 1]] = 0
        L.eliminate_zeros()

        num_b = self.b_ids.shape[0]
        I = np.tile(self.b_ids, 3)
        J = np.hstack((
            self.b_ids,
            self.b_ids[self.l_ids],
            self.b_ids[self.r_ids],
        ))
        W = np.hstack((
            -1 * np.ones(num_b),
            0.5 * np.ones(num_b),
            0.5 * np.ones(num_b),
        ))
        mat = sp.csr_matrix((W, (I, J)), shape=(self.num_v, self.num_v))
        L = L + mat
        return L

    def set_boundary_ids_and_mats(self, v, f):
        from util.geometry import get_boundary_verts
        _, b_rings = get_boundary_verts(v, f)

        def shift_left(ls, k):
            return ls[k:] + ls[:k]

        b_ids = []
        l_ids = []
        r_ids = []
        for rg in b_rings:
            tmp = list(range(len(b_ids), len(b_ids) + len(rg)))
            ltmp = shift_left(tmp, 1)
            rtmp = shift_left(tmp, -1)
            l_ids.extend(ltmp)
            r_ids.extend(rtmp)
            b_ids.extend(rg)

        b_ids = np.asarray(b_ids, dtype=np.int64)
        num_b = b_ids.shape[0]
        m_ids = np.arange(num_b, dtype=np.int64)
        l_ids = np.asarray(l_ids, dtype=np.int64)
        r_ids = np.asarray(r_ids, dtype=np.int64)

        self.right_edge_mat = sp.csr_matrix((
            np.hstack((-1 * np.ones(num_b), np.ones(num_b))),
            (np.hstack((m_ids, m_ids)), np.hstack((m_ids, r_ids)))
        ), shape=(num_b, num_b)
        )

        self.left_edge_mat = sp.csr_matrix((
            np.hstack((-1 * np.ones(num_b), np.ones(num_b))),
            (np.hstack((m_ids, m_ids)), np.hstack((m_ids, l_ids)))
        ), shape=(num_b, num_b)
        )

        # boundary vertex ids
        self.b_ids = b_ids
        # left and right boundary neighbour vertex ids
        self.l_ids = l_ids
        self.r_ids = r_ids

    def smooth_cotlap(self, verts, smoothness=0.03):
        """Smooth using cotangent laplacian.

        Boundary vertices are smoothed only by neighboring boundary vertices
        in order to prevent boundary shrinking.
        """
        L = numpy_laplacian_cot(verts, self.f)
        new_verts = verts + smoothness * L.dot(verts)

        b_verts = verts[self.b_ids]
        le = 1. / (np.linalg.norm(self.left_edge_mat.dot(b_verts), axis=-1) + 1.0e-10)
        ri = 1. / (np.linalg.norm(self.right_edge_mat.dot(b_verts), axis=-1) + 1.0e-10)

        num_b = b_verts.shape[0]
        I = np.tile(np.arange(num_b), 3)
        J = np.hstack((
            np.arange(num_b),
            self.l_ids,
            self.r_ids,
        ))
        W = np.hstack((
            -1 * np.ones(num_b),
            le / (le + ri),
            ri / (le + ri),
        ))
        mat = sp.csr_matrix((W, (I, J)), shape=(num_b, num_b))
        new_verts[self.b_ids] = verts[self.b_ids] + smoothness * mat.dot(verts[self.b_ids])
        return new_verts

    def smooth_uniform(self, verts, smoothness=0.03):
        """Smooth using uniform laplacian.

        Boundary vertices are smoothed only by neighboring boundary vertices
        in order to prevent boundary shrinking.
        """
        if self.uniL is None:
            self.uniL = self.get_uniform_lap_smoothing()
        new_verts = verts + smoothness * self.uniL.dot(verts)
        return new_verts

    def smooth_naive(self, verts, smoothness=0.03):
        L = numpy_laplacian_cot(verts, self.f)
        new_verts = verts + smoothness * L.dot(verts)

        return new_verts

    def smooth(self, verts, smoothness=0.03, n=1, Ltype="cotangent"):
        assert (Ltype in ["cotangent", "uniform", "naive"])
        for i in range(n):
            if Ltype == 'uniform':
                verts = self.smooth_uniform(verts, smoothness)
            elif Ltype == "cotangent":
                verts = self.smooth_cotlap(verts, smoothness)
            else:
                verts = self.smooth_naive(verts, smoothness)
        return verts


if __name__ == "__main__":
    root_dir = "/home/panxiaoyu/Garments/Garment/ClothDataGeneration/SimScenes"
    input_file_path = "dress01.obj"

    input_mesh = Mesh(filename=os.path.join(root_dir, input_file_path))
    smoothing = DiffusionSmoothing(input_mesh.v, input_mesh.f)
    verts_smooth = input_mesh.v.copy()
    for i in range(20):
        verts_smooth = smoothing.smooth(verts_smooth, smoothness=0.1, Ltype="naive")
    smoothed_mesh = Mesh(v=verts_smooth, f=input_mesh.f)
    smoothed_mesh.write_obj(os.path.join(root_dir, "dress01_smoothed.obj"))