Python 给定一组三角形顶点和面,分离对象并形成单独的网格
编辑:我已经为这个问题写了一个更简洁的版本,但我保留这篇文章,因为它是一个完整的解释 给定一个3D numpy数组,可以围绕某个阈值形成3DPython 给定一组三角形顶点和面,分离对象并形成单独的网格,python,networkx,mesh,mplot3d,marching-cubes,Python,Networkx,Mesh,Mplot3d,Marching Cubes,编辑:我已经为这个问题写了一个更简洁的版本,但我保留这篇文章,因为它是一个完整的解释 给定一个3D numpy数组,可以围绕某个阈值形成3D import numpy as np from skimage import measure A = np.zeros((12,12,12)) #A[A<1] = -1 for i in np.arange(1,2): for j in np.arange(1,2): for k in np.arange(1,2):
import numpy as np
from skimage import measure
A = np.zeros((12,12,12))
#A[A<1] = -1
for i in np.arange(1,2):
for j in np.arange(1,2):
for k in np.arange(1,2):
A[i,j,k] = 10
for i in np.arange(8,9):
for j in np.arange(8,9):
for k in np.arange(8,9):
A[i,j,k] = 10
verts, faces, normals, values = measure.marching_cubes_lewiner(A,1)
# which returns
verts = [[0.1, 1., 1. ] [1., 1., 0.1] [1., 0.1, 1. ] [1., 1., 1.9] [1., 1.9, 1. ]
[1.9, 1., 1. ] [7.1, 8., 8. ] [8., 8., 7.1] [8., 7.1, 8. ] [8., 8., 8.9]
[8., 8.9, 8. ] [8.9, 8., 8. ]]
faces = [[ 2, 1, 0] [ 0, 3, 2] [ 1, 4, 0] [ 0, 4, 3] [ 5, 1, 2] [ 3, 5, 2]
[ 5, 4, 1] [ 4, 5, 3] [ 8, 7, 6] [ 6, 9, 8] [ 7, 10, 6] [ 6, 10, 9]
[11, 7, 8] [ 9, 11, 8] [11, 10, 7] [10, 11, 9]]
返回此可爱的3D图像:
我使用自己的代码(见下文)使用算法分离这些对象,并获得:
现在的问题是,尽管我已经找到了构成每个图形的顶点,但我不再有简单的方法为每个对象创建单独的3D网格。以前,使用verts[faces]
创建网格,但不清楚如何将每个图形
与面
关联以创建三角形网格。我试图解决这个问题,但没有成功。例如:
verts1 = verts[0:6]
faces1 = faces[0:6]
mesh = Poly3DCollection(verts1[faces1])
这是行不通的。我认为关键是找到每个物体对应的面。如果这样做了,它可能会起作用。例如,我们的第一个图仅包括顶点1到6。因此,我们只需要引用这些顶点的面
。作为演示,第一个图形,graph1
可以使用以下方法复制(不使用graph2):
如果我不仅可以记录顶点,还可以记录它们的索引,那么我就可以对引用该对象的面进行排序。我会解释的。第一个问题,我没有索引。这是我排序对象的方法。我们首先创建一个线列表(或edgelist),然后对它们创建元组,然后使用networkx查找连接的组件
# create linelist
linelist = []
for idx, vert in enumerate(faces):
for i,x in enumerate(vert):
l = [np.ndarray.tolist(verts[faces[idx][i]]), np.ndarray.tolist(verts[faces[idx][(i+1)%len(vert)]])] # connect the verts of the triangle
linelist.append(l) # add to the line list
# Creates graph
tmp = [tuple(tuple(j) for j in i) for i in linelist]
graph = nx.Graph(tmp)
graphs = []
i=0
for idx, graph in enumerate(sorted(nx.connected_components(graph),key = len, reverse = True)):
graphs.append((graph))
print("Graph ",idx," corresponds to vertices: ",graph,'\n\n',file=open("output.txt","a"))
i+=1
我不明白networkx如何也能记录每个顶点的索引
其次,引用每个对象的面
可能是不相交的,即它可能是面[0:4]+面[66]+面[100:110]
。然而,这可能是可以克服的
假设我们可以为每个图生成一个索引列表,主要问题是找到一种有效的方法来发现哪些面引用了这些顶点。我的解决方案适用于这组对象,但不适用于更复杂的排列(我可以提供)。它也异常缓慢。不过,这是:
objects = []
obj = []
i = 0
for idx, face in enumerate(M):
if i == 0:
obj.append(face)
i = i + 1
else:
if np.isin(face,obj).any():
obj.append(face)
else:
objects.append(obj.copy())
obj = []
obj.append(face)
i = 0
if idx == len(M)-1:
objects.append(obj.copy())
如果你读到这里,我真的对社区印象深刻。我认为也许有一种有效的方法可以通过networkx实现这一点,但我还没有找到
所需输出:我希望像对顶点排序一样,将面排序为连接的组件<代码>图形1=面[x1]+面[x2]+…+面[xn]
编辑:如果有人能帮我编码,我确实有个主意(部分要感谢@Ehsan)。在分离成连接的组件并找到图之后,可以对每个组件的顶点进行散列以找到原始索引。然后,可以搜索至少包含其中一个索引的
面
(因为如果它包含一个顶点,那么它必须是图
的面)。我不确定这会有多有效。我希望有一个快速的networkx解决方案。@Paul Broderson回答了这个问题
我把它放在这里只是为了美观:
#!/usr/bin/env python
"""
Given a list of triangles, find the connected components.
https://stackoverflow.com/q/61584283/2912349
"""
import itertools
import networkx as nx
faces = [[ 2, 1, 0], [ 0, 3, 2], [ 1, 4, 0], [ 0, 4, 3], [ 5, 1, 2], [ 3, 5, 2],
[ 5, 4, 1], [ 4, 5, 3], [ 8, 7, 6], [ 6, 9, 8], [ 7, 10, 6], [ 6, 10, 9],
[11, 7, 8], [ 9, 11, 8], [11, 10, 7], [10, 11, 9]]
#create graph
edges = []
for face in faces:
edges.extend(list(itertools.combinations(face, 2)))
g = nx.from_edgelist(edges)
# compute connected components and print results
components = list(nx.algorithms.components.connected_components(g))
for component in components:
print(component)
# {0, 1, 2, 3, 4, 5}
# {6, 7, 8, 9, 10, 11}
# separate faces by component
component_to_faces = dict()
for component in components:
component_to_faces[tuple(component)] = [face for face in faces if set(face) <= component] # <= operator tests for subset relation
for component, component_faces in component_to_faces.items():
print(component, component_faces)
# (0, 1, 2, 3, 4, 5) [[2, 1, 0], [0, 3, 2], [1, 4, 0], [0, 4, 3], [5, 1, 2], [3, 5, 2], [5, 4, 1], [4, 5, 3]]
# (6, 7, 8, 9, 10, 11) [[8, 7, 6], [6, 9, 8], [7, 10, 6], [6, 10, 9], [11, 7, 8], [9, 11, 8], [11, 10, 7], [10, 11, 9]]
#/usr/bin/env python
"""
给定三角形列表,查找连接的组件。
https://stackoverflow.com/q/61584283/2912349
"""
进口itertools
将networkx导入为nx
面=[[2,1,0],[0,3,2],[1,4,0],[0,4,3],[5,1,2],[3,5,2],
[ 5, 4, 1], [ 4, 5, 3], [ 8, 7, 6], [ 6, 9, 8], [ 7, 10, 6], [ 6, 10, 9],
[11, 7, 8], [ 9, 11, 8], [11, 10, 7], [10, 11, 9]]
#创建图形
边=[]
对于面中的面:
扩展(列表(itertools.组合(面,2)))
g=nx.从边缘列表(边缘)
#计算连接的组件并打印结果
组件=列表(nx.algorithms.components.connected_components(g))
对于组件中的组件:
打印(组件)
# {0, 1, 2, 3, 4, 5}
# {6, 7, 8, 9, 10, 11}
#按组件分离面
组件到面=dict()
对于组件中的组件:
组件到面[元组(组件)]=[面对面如果设置(面)您能否以正确的格式(即设置了所有逗号)添加面
和顶点
)?因此,我们可以在代码中直接使用您的数据。此外,我不确定您的答案是否正确。您想将面和顶点拆分为属于连接对象的相同样式的列表吗?也许添加一种形式的所需输出有助于澄清这一点。当然,更新了面和顶点s、 基本上,我想将面分类为对象,就像将顶点分类为对象一样,每个顶点的集合都连接在一起。使用顶点更容易,因为它们可以以边列表的形式放置。我不知道如何使用面。我将用忘记放置的更多代码更新帖子。@Sparky05我创建了一个更简洁的问题,并提出了更明确的期望:
# create linelist
linelist = []
for idx, vert in enumerate(faces):
for i,x in enumerate(vert):
l = [np.ndarray.tolist(verts[faces[idx][i]]), np.ndarray.tolist(verts[faces[idx][(i+1)%len(vert)]])] # connect the verts of the triangle
linelist.append(l) # add to the line list
# Creates graph
tmp = [tuple(tuple(j) for j in i) for i in linelist]
graph = nx.Graph(tmp)
graphs = []
i=0
for idx, graph in enumerate(sorted(nx.connected_components(graph),key = len, reverse = True)):
graphs.append((graph))
print("Graph ",idx," corresponds to vertices: ",graph,'\n\n',file=open("output.txt","a"))
i+=1
objects = []
obj = []
i = 0
for idx, face in enumerate(M):
if i == 0:
obj.append(face)
i = i + 1
else:
if np.isin(face,obj).any():
obj.append(face)
else:
objects.append(obj.copy())
obj = []
obj.append(face)
i = 0
if idx == len(M)-1:
objects.append(obj.copy())
#!/usr/bin/env python
"""
Given a list of triangles, find the connected components.
https://stackoverflow.com/q/61584283/2912349
"""
import itertools
import networkx as nx
faces = [[ 2, 1, 0], [ 0, 3, 2], [ 1, 4, 0], [ 0, 4, 3], [ 5, 1, 2], [ 3, 5, 2],
[ 5, 4, 1], [ 4, 5, 3], [ 8, 7, 6], [ 6, 9, 8], [ 7, 10, 6], [ 6, 10, 9],
[11, 7, 8], [ 9, 11, 8], [11, 10, 7], [10, 11, 9]]
#create graph
edges = []
for face in faces:
edges.extend(list(itertools.combinations(face, 2)))
g = nx.from_edgelist(edges)
# compute connected components and print results
components = list(nx.algorithms.components.connected_components(g))
for component in components:
print(component)
# {0, 1, 2, 3, 4, 5}
# {6, 7, 8, 9, 10, 11}
# separate faces by component
component_to_faces = dict()
for component in components:
component_to_faces[tuple(component)] = [face for face in faces if set(face) <= component] # <= operator tests for subset relation
for component, component_faces in component_to_faces.items():
print(component, component_faces)
# (0, 1, 2, 3, 4, 5) [[2, 1, 0], [0, 3, 2], [1, 4, 0], [0, 4, 3], [5, 1, 2], [3, 5, 2], [5, 4, 1], [4, 5, 3]]
# (6, 7, 8, 9, 10, 11) [[8, 7, 6], [6, 9, 8], [7, 10, 6], [6, 10, 9], [11, 7, 8], [9, 11, 8], [11, 10, 7], [10, 11, 9]]