编辑:我把这个问题写了一个更简洁的版本。此处 但我保留这个帖子是因为它是一个完整的解释。
给定一个3D numpy数组。方阵 可以形成一个三维 对象 在某个临界点附近。
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]]
这就可以绘制了。
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from mpl_toolkits.mplot3d import Axes3D
mesh = Poly3DCollection(verts[faces])
mesh.set_edgecolor('k')
mesh.set_facecolor('b')
ax.set_xlim(0,10)
ax.set_ylim(0,10)
ax.set_zlim(0,12)
返回这个可爱的3D图像。
我用一个算法来分离这些对象 用我自己的代码(见下文),并得到。
graph1 = {(1.0, 1.0, 0.10000000149011612), (1.899999976158142, 1.0, 1.0), (0.10000000149011612, 1.0, 1.0), (1.0, 1.899999976158142, 1.0), (1.0, 0.10000000149011612, 1.0), (1.0, 1.0, 1.899999976158142)}
graph2 = {(8.899999618530273, 8.0, 8.0), (8.0, 8.899999618530273, 8.0), (7.099999904632568, 8.0, 8.0), (8.0, 8.0, 7.099999904632568), (8.0, 7.099999904632568, 8.0), (8.0, 8.0, 8.899999618530273)}
现在,问题是,即使我已经找到了组成每个图形的顶点,我不再有简单的方法为每个对象创建单独的3D网格。而之前。verts[faces]
是用来创建网格的,但如何将每一个 graph
到 faces
来创建三角形网格。我曾试图解决这个问题,但一直没有成功。比如说
verts1 = verts[0:6]
faces1 = faces[0:6]
mesh = Poly3DCollection(verts1[faces1])
这样做是行不通的 我想关键是要找到每个对象对应的面。如果这样做,可能就会成功。例如,我们的第一个图只包括顶点1到6。所以我们只需要 faces
指向这些顶点的图。作为示范,第一个图。graph1
可以重现(不需要 graph2)使用。
faces1 = faces[0:8]
mesh = Poly3DCollection(verts[faces1])
# and plot like above
如果我不仅记录了顶点,还记录了它们的索引 那我就可以对它们进行排序了 faces
对于那些指代该对象的。我将解释一下。第一个问题,我没有索引。这是我对对象进行排序的方式。我们首先创建一个lineelist(或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如何也能记录每个顶点的索引。
其次,有可能是 faces
指向每个对象的是不相干的,即可能是 faces[0:4] + faces[66] + faces[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有一个有效的方法可以做到这一点,但我还没有找到。
希望的输出: 我想把面孔整理成连接的组件,就像整理顶点一样。graph1 = faces[x1] + faces[x2] + ... + faces[xn]
.
编辑:如果有人能帮助我编写代码,我确实有一个想法(部分感谢@Ehsan)。在分离成连接的组件并找到图之后,每个组件的顶点可以被哈希以找到原始索引。然后,就可以搜索 faces
其中至少包含其中的一个索引(因为如果它包含一个顶点,它必须是一个面的 graph
). 我不知道这样做的效率如何。如果有一个快速的networkx变通方法我就好了。
@Paul Broderson 回答了这个问题 https:/stackoverflow.coma6159034812919727。
我把它放在这里只是为了美观。
#!/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]]