pymeshlab interface

Convert ObjMesh to pymeshlab’s mesh class to apply meshlab filters.

In this notebook, we define functions to convert our ObjMesh class to and from pymeshlab.


source

convert_to_pymeshlab

 convert_to_pymeshlab (mesh:blender_tissue_cartography.mesh.ObjMesh,
                       add_texture_info=None)

*Convert tcmesh.ObjMesh to pymeshlab.Mesh.

See https://pymeshlab.readthedocs.io/en/latest/classes/mesh.html Note: normal information is recalculated by pymeshlab. Discards any non-triangle faces.

The texture information is saved as a vertex attribute via v_tex_coords_matrix. Note that this discards information since a vertex can have multiple texture coordinates. For this reason, we also save it as wedge_tex_coord_matrix (i.e. per triangle).*

Type Default Details
mesh ObjMesh
add_texture_info NoneType None Whether to add texture info to the pymeshlab.Mesh. If None, texture is added if
available for at least one vertex.
Returns Mesh
mesh_fname_data = "datasets/registration_example/Drosophila_CAAX-mCherry_mesh_remeshed.obj"
mesh_fname_ref = "datasets/registration_example/Drosophila_reference.obj"

mesh_data = tcmesh.ObjMesh.read_obj(mesh_fname_data)
mesh_ref = tcmesh.ObjMesh.read_obj(mesh_fname_ref)
Warning: readOBJ() ignored non-comment line 4:
  o embryo_rect
pymesh_data = convert_to_pymeshlab(mesh_data)
pymesh_normals = pymesh_data.vertex_normal_matrix()
pymesh_normals = (pymesh_normals.T / np.linalg.norm(pymesh_normals, axis=-1)).T

mesh_normals = (mesh_data.normals.T / np.linalg.norm(mesh_data.normals, axis=-1)).T

np.einsum('vi,vi->v', mesh_normals, pymesh_normals)
array([0.99999487, 0.99997637, 0.99996542, ..., 0.99966711, 0.99984559,
       0.99975186])
np.allclose(mesh_data.vertices, pymesh_data.vertex_matrix())
True
### check correctness of wedge coords

mesh = tcmesh.ObjMesh.read_obj("datasets/movie_example/mesh_subdiv.obj")
converted = convert_to_pymeshlab(mesh)
ms = pymeshlab.MeshSet()
#ms.add_mesh(converted)
ms.load_new_mesh("datasets/movie_example/mesh_subdiv.obj")
np.allclose(np.nan_to_num(ms.current_mesh().wedge_tex_coord_matrix()),
            np.nan_to_num(converted.wedge_tex_coord_matrix()))
True

source

convert_from_pymeshlab

 convert_from_pymeshlab (mesh:pymeshlab.pmeshlab.Mesh,
                         reconstruct_texture_from_faces=True,
                         texture_vertex_decimals=10)

*Convert pymeshlab mesh to ObjMesh.

Texture vertices can be reconstructed from wedge_tex_coord_matrix (per face) or from the vertex attribute vertex_tex_coord_matrix. Reconstruction from face texture can accommodate multiple texture coordinates per vertex (e.g. for UV maps with seams).*

Type Default Details
mesh Mesh
reconstruct_texture_from_faces bool True Whether to reconstruct texture information from per-face data (True), or
per-vertex data (False)
texture_vertex_decimals int 10 Texture vertices are rounded to texture_vertex_decimals decimals.
Returns ObjMesh
pymesh_ref = convert_to_pymeshlab(mesh_ref)
pymesh_ref_converted = convert_from_pymeshlab(pymesh_ref)
np.allclose(mesh_ref.texture_vertices[mesh_ref.texture_tris],
 pymesh_ref_converted.texture_vertices[pymesh_ref_converted.texture_tris])
True
mesh_seams = tcmesh.ObjMesh.read_obj("datasets/drosophila_example/Drosophila_CAAX-mCherry_mesh_uv.obj")
pymesh_seams = convert_to_pymeshlab(mesh_seams,add_texture_info=True)
mesh_seams_reconverted = convert_from_pymeshlab(pymesh_seams, reconstruct_texture_from_faces=True)
mesh_seams_reconverted.write_obj("datasets/drosophila_example/Drosophila_CAAX-mCherry_mesh_uv_resaved.obj")
Warning: readOBJ() ignored non-comment line 4:
  o Drosophila_CAAX-mCherry_mesh_remeshed
Warning: readOBJ() ignored non-comment line 48073:
  l 2534 8160
/tmp/ipykernel_1942205/15752383.py:16: RuntimeWarning: invalid value encountered in divide
  normals = (normals.T / np.linalg.norm(normals, axis=-1)).T
mesh_seams.texture_vertices.shape, mesh_seams_reconverted.texture_vertices.shape
((8288, 2), (8288, 2))

You can now use MeshLab filters like in the following, and the face attributes will hopefully be correctly updated.

ms = pymeshlab.MeshSet()
ms.add_mesh(pymesh_seams)

ms.meshing_merge_close_vertices(threshold=pymeshlab.PercentageValue(100))
pymesh_seams_remeshed = ms.current_mesh()

convert_from_pymeshlab(pymesh_seams_remeshed, reconstruct_texture_from_faces=True,
                       texture_vertex_decimals=12)
<blender_tissue_cartography.mesh.ObjMesh>