Issue when computing skeleton (with non-watertight mesh)
yvanblanchard opened this issue · 6 comments
Hello,
I have a non-watertight mesh (OBJ) and the output skeleton is KO (very few points).
Here is my input file:
MeshToSkeletonize.zip
Hi! Two separate issues here.
- The skeleton:
I quickly loaded your mesh into Blender to look at the structure. Not sure if you're familiar with that software but in the screenshot you can see the vertices and the edges/faces between them. The highlighted on is a face that I selected and then moved a little to the side. As you can see it's disconnected by which I mean your mesh consists of faces that each have their entirely independent set of vertices. This is an issue since skeletor
uses the mesh's connectivity to generate skeletons.
Fortunately, we can fix this issue using trimesh
:
>>> import trimesh as tm
>>># Load mesh and forbid trimesh run fixes
>>> m = tm.load('MeshToSkeletonize.obj', process=False)
>>> # Inspect - note the number of vertices
>>> m
<trimesh.Trimesh(vertices.shape=(1635, 3), faces.shape=(545, 3))>
>>> # Check the number of connected components
>>> # (i.e. how many disconnected pieces your mesh consists of)
>>> import networkx as nx
>>> len(list(nx.connected_components(m.vertex_adjacency_graph)))
545
>>> # As expected: 545 = the number of faces in your mesh
>>> # Now let's see if we can tell trimesh to merge vertices and generate one continuous mesh
>>> m.merge_vertices(merge_tex=True, merge_norm=True)
>>> # Note the reduction in vertices:
>>> m
<trimesh.Trimesh(vertices.shape=(473, 3), faces.shape=(545, 3))>
>>> # Check connected components again
>>> len(list(nx.connected_components(m.vertex_adjacency_graph)))
2
>>> # Looking at your mesh this makes sense since there is a small corner that is
>>> # entirely disconnected
OK, with the mesh fixed we can try to skeletonise your mesh. I had a really quick crack at it and this is the best I could come up with:
>>> # Let's try skeletonizing the fixed mesh
>>> import skeletor as sk
>>> s = sk.skeletonize.by_teasar(m, inv_dist=10)
>>> s
<Skeleton(vertices=(244, 3), edges=(242, 2), method=teasar)>
As you can see it did something but probably not what you were hoping for. Some notes:
skeletor
is designed to generate tree-like (acyclic) skeletons (i.e. each vertex has exactly one or no parent) which is why you get the breaks in your honeycomb structure. This is a limitation of the output format (SWC) but in theory I could rewrite the code to optionally not break-up cycles. Alternatively: you could use the skeleton --> mesh vertex map (s.skel_map
) to heal the breaks by re-introducing edges according to the original mesh.- Your mesh has a fairly low vertex count. That's perfect for visualisation but some of the skeletonization methods (e.g. mesh contraction or the wavefront method) don't work well on low-polygon, geometric meshes.
- The visualisation issue:
skeletor
usestrimesh
's visualisation functions and from the backtrace in your screenshot it looks like the issue is withpyglet
, notskeletor
ortrimesh
directly. I would recommend you check the issues in thepyglet
Github repository and open one there if you don't find a solution to your problem.
Hope this is at least somewhat helpful!
Thank you for your detailed reply .
I followed your advice, and remesh my model for having a much finer mesh, and also check again for disconnected faces (merge_vertices).
File:
MeshToSkeletonizeRemeshedFiner2.zip
I also tried your skeleton method (by_teasar, with inv_dist of 10mm).
But it leads to this bad/unexpected result:
Notice that it does not matter is skeleton lines are not fully connected (zero or one parent max), but I need the skeleton to be perfeclty at medial position of 'branches' shapes of course.
The TEASAR method doesn't produce centred lines unfortunately.
With the higher res mesh you could try the wavefront method though:
>>> m = tm.load('/Users/philipps/Downloads/MeshToSkeletonizeRemeshedFiner.obj')
>>> m.merge_vertices(merge_tex=True, merge_norm=True, digits_vertex=5)
>>> s = sk.skeletonize.by_wavefront(m, waves=1)