Search code examples
meshlabpymeshlab

How to use PyMeshLab to reduce vertex number to a certain number


I have a batch of triangle meshes and each one has different vertices and faces. I want to reduce the vertex numbers of all the meshes to the same number, 10000.

I know I can use simplification_quadric_edge_collapse_decimation to reduce the face number which means the vertex number will be reduced accordingly. But the problem is that I have to use the method several times in order to get the vertex number exactly down to 10000.

Therefore, I'm wondering if there is another way to reduce the vertex number to 10000 directly?


Solution

  • Meshlab, and to my knowledge any other libraries able to simplify, use the face number as the parameter to guide simplification process.

    The good news are that both values are related by the Euler characteristic of the mesh, which roughly says that the number of vertex is half the number of faces for a surface without holes. Decimating your mesh to 20000 faces will produce a mesh of about 10000 vertex, but you can also fall under 9999 easily. As you have the advantage of being programming in python, you can design a process to slowly converge to the desired number of vertex.

    The idea is to simplify your mesh to a face number slightly above of 20000, and then slowly refine your solution until you get exactly 10000 vertex. I propose you to reduce the number of faces in each step using the excess of vertex on current step (vertex_number - 10000).

    import pymeshlab as ml
    ms = ml.MeshSet()
    ms.load_new_mesh('input.ply')
    m = ms.current_mesh()
    print('input mesh has', m.vertex_number(), 'vertex and', m.face_number(), 'faces')
    
    #Target number of vertex
    TARGET=10000
    
    #Estimate number of faces to have 100+10000 vertex using Euler
    numFaces = 100 + 2*TARGET
    
    #Simplify the mesh. Only first simplification will be agressive
    while (ms.current_mesh().vertex_number() > TARGET):
        ms.apply_filter('simplification_quadric_edge_collapse_decimation', targetfacenum=numFaces, preservenormal=True)
        print("Decimated to", numFaces, "faces mesh has", ms.current_mesh().vertex_number(), "vertex")
        #Refine our estimation to slowly converge to TARGET vertex number
        numFaces = numFaces - (ms.current_mesh().vertex_number() - TARGET)
    
    m = ms.current_mesh()
    print('output mesh has', m.vertex_number(), 'vertex and', m.face_number(), 'faces')
    ms.save_current_mesh('output.ply')
    

    Pythagore model courtesy of Geoffrey Marchal

    Please, note that:

    • Sometimes you just can't reduce exactly to 10000 vertex, and will end with 9999 vertex.
    • With this formula, each step (after first one) will remove about half of the vertices exceeding 10000, giving a "soft landing" into your desired number of vertices. A typical execution should reduce to about 10050 vertices, then 10025, 10012, 10006, 10003, 10001, and finally 10000 vertices. The final number of faces depends of the said Euler Characteristic of the input model.
    • Only the first simplification step will take significant execution time (depending of number of triangles in the input mesh), and next simplification steps will be very fast.
    • If you still want to speed-up the method you can do numFaces = numFaces - int(1.5*(ms.current_mesh().vertex_number() - 10000)), but this increases the chances of ending under 9999 vertex and execution time won't be affected much.
    • This method should work with any decimation algorithm based on faces, it is not exclusive for quadric edge collapse.