Python 多维阵列/准图像的连通分量标注 问题

Python 多维阵列/准图像的连通分量标注 问题,python,numpy,image-processing,scikit-image,connected-components,Python,Numpy,Image Processing,Scikit Image,Connected Components,我正在尝试对3维以上的数组执行此操作。我的意思是,我的布尔数组有一个.shape,比如(5,2,3,6,10),它是5维的 对于2D图像(而不是我的>3D问题),连接组件标签将是将标签放置到连接区域(在我的例子中是超卷)。如果两个(hpyer-)像素彼此相邻且在布尔数组中均为真,则两个(hpyer-)像素将连接起来 我已经试过了 对于2维和最多3维,这可以通过skimage.measure.label完成。然而,我不知道如何为我的案件解决这个问题 为感兴趣的读者提供更多资料(但对我的问题没

我正在尝试对3维以上的数组执行此操作。我的意思是,我的布尔数组有一个
.shape
,比如
(5,2,3,6,10)
,它是5维的

对于2D图像(而不是我的>3D问题),连接组件标签将是将标签放置到连接区域(在我的例子中是超卷)。如果两个(hpyer-)像素彼此相邻且在布尔数组中均为真,则两个(hpyer-)像素将连接起来

我已经试过了 对于2维和最多3维,这可以通过
skimage.measure.label
完成。然而,我不知道如何为我的案件解决这个问题


为感兴趣的读者提供更多资料(但对我的问题没有帮助):


如果2D中的4连接性足够,您可以使用最近邻树在n log n时间内获得同样位于前景的相邻像素。 然后是构造图和查找连接的组件(也就是n logn,IIRC)的问题

您直接想要什么:

[1]中的
:将numpy作为np导入
[2]中:arr=np.random.random((5,2,3,6,10))>0.5
在[3]中:从scipy导入ndi图像作为ndi
[4]中:带标签,n=ndi.标签(arr)
In[5]:n
Out[5]:11

您是否尝试过一种简单的迭代方法?迭代每个数据点,将未使用的标签设置为此数据点,检查此数据点的每个已连接邻居,如果已经有已标记邻居,则将标签设置为当前数据点,否则将当前数据点的标签设置为已连接邻居。这行得通吗?@YannickFunk:这是我的第一次实现。我使用了递归,没有联合查找数据结构,就像在所谓的。我的第一个实现非常缓慢。我直接用Python实现了这一点(而不是将实现推到C级),这并没有帮助。为什么它这么慢?数组有多大?@PaulBrodersen:每个维度y在15到50之间,我们有2到64个维度,数组中的y^x元素也是如此。正如你很容易看到的,x是有害的。(我知道:当它变成像64这样的数字时,内存甚至不足以容纳我的数组,所以我目前正在重新考虑整个方法。但是现在让我们假设x很小,比如4。)我认为它很慢,因为我用Python编写了循环等等,但我不确定。我没有使用经典算法,我进一步检查后发现。我从每个为真的单元格(“前景”)开始,看它是否有标签。对于跟踪标签,我使用一个单独的标签数组,该数组用0(=“背景”/“无标签”)初始化。如果它还没有标签,我就给它贴标签,然后递归地“进入”到每个相邻的没有标签的单元格,并用相同的标签给它贴标签。这样的标签是大于0的整数。已标记的单元格或错误的单元格(“背景”)不会进一步检查。您所说的“如果2D中的4连接性足够”是什么意思?你的意思是说你使用“4D中的4连接性,也就是2D中的2连接性”?我遵循的术语是。(我实际上通常使用1-连接性,但同时也很欣赏:-)我知道他们把1-连接性称为4-连接性,把2-连接性称为8-连接性。但是我的图像处理课已经上了一段时间了,所以我可能记错了。是的,这实现了1-连通性(根据scikit图像术语)。我刚刚想到,通过查找欧几里德距离严格小于的点,可以获得8-连通性(2-连通性),即
树。查询球树(树,r=1.5,p=2)
。此外,我更新了答案。有一个错误,第一个组件没有标记。我通读了你的代码,认为我理解了;-)。一点回顾(如果你不同意,请告诉我):1)它可能对稀疏数组(大量背景)很有效,但对密集数组很不有效。对于稀疏数组,它可能会很好地扩展许多维度(关于常数)。不幸的是,正如我昨天深夜注意到的那样,我的阵列非常密集(这是我起初没有预料到的)。然而,我有一个想法,我可以使他们稀疏,但我仍然要考虑这个想法。
#!/usr/bin/env python
"""
https://stackoverflow.com/questions/66724201/connected-component-labling-for-arrays-quasi-images-with-many-dimension
"""
import numpy as np
import networkx as nx

from scipy.spatial import cKDTree


def get_components(boolean_array):
    # find neighbours
    coordinates = list(zip(*np.where(boolean_array)))
    tree = cKDTree(coordinates)
    neighbours_by_pixel = tree.query_ball_tree(tree, r=1, p=1) # p=1 -> Manhatten distance; r=1 -> what would be 4-connectivity in 2D

    # create graph and find components
    G = nx.Graph()
    for ii, neighbours in enumerate(neighbours_by_pixel):
        if len(neighbours) > 1:
            G.add_edges_from([(ii, jj) for jj in neighbours[1:]]) # skip first neighbour as that is a self-loop
    components = nx.connected_components(G)

    # create output image
    output = np.zeros_like(data, dtype=np.int)
    for ii, component in enumerate(components):
        for idx in component:
            output[coordinates[idx]] = ii+1

    return output


if __name__ == '__main__':

    shape = (5, 2, 3, 6, 10)
    D = len(shape)
    data = np.random.rand(*shape) < 0.1
    output = get_components(data)
In [48]: %timeit output = get_components(data)
5.85 s ± 279 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)