Python 如何通过相邻值分割矩阵?

Python 如何通过相邻值分割矩阵?,python,matrix,grouping,image-segmentation,Python,Matrix,Grouping,Image Segmentation,假设我有这样一个矩阵: m = [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1] r = [[[0,0]], [[0,1], [0,2], [1,0], [1,1]], [[0,3], [1,2], [1,3], [2,0], [2,1], [2,2]] [[2,3]]] 我需要得到相同相邻值的坐标(但不是对角线): 结果是“矩阵”列表中的坐标列表,从[0,0]

假设我有这样一个矩阵:

     m = [0, 1, 1, 0,
          1, 1, 0, 0,
          0, 0, 0, 1]
r = [[[0,0]],   
     [[0,1], [0,2], [1,0], [1,1]],   
     [[0,3], [1,2], [1,3], [2,0], [2,1], [2,2]]   
     [[2,3]]]    
我需要得到相同相邻值的坐标(但不是对角线):


结果是“矩阵”列表中的坐标列表,从[0,0]开始,如下所示:

     m = [0, 1, 1, 0,
          1, 1, 0, 0,
          0, 0, 0, 1]
r = [[[0,0]],   
     [[0,1], [0,2], [1,0], [1,1]],   
     [[0,3], [1,2], [1,3], [2,0], [2,1], [2,2]]   
     [[2,3]]]    

一定有办法做到这一点,但我真的被卡住了;dr:我们取一个由0和1组成的数组,并使用它将其转换为一个由0和[1,2,3,…]组成的数组。然后,我们使用
np.where
来查找值大于0的每个元素的坐标。具有相同值的元素最终位于相同的列表中

将矩阵的非零元素解释为特征并对其进行标记。输入中的每个唯一特征都会被指定一个唯一的标签。特征是例如具有相同值的相邻元素(或像素)组

import numpy as np
from scipy.ndimage import label

# make dummy data
arr = np.array([[0,1,1,0], [1,1,0,0], [0,0,0,1]])

#initialise list of features
r = []
由于OP需要所有功能,即零像素和非零像素组,因此我们使用
标签
两次:第一次在原始阵列上,第二次在
1-原始阵列上
。(对于0和1的数组,
1-array
只是翻转值)

现在,
label
返回一个元组,其中包含带标签的数组(我们感兴趣)和在该数组中找到的功能的数量(我们可以使用,但当我对其进行编码时,我选择忽略它)。因此,我们感兴趣的是
label
返回的元组的第一个元素,我们使用
[0]访问它

a = label(arr)[0]
b = label(1-arr)[0]
现在我们检查指定了哪些唯一的像素值
标签
。因此我们需要a和b的
集合,分别
。为了使
set()
工作,我们需要对两个数组进行线性化,这是我们使用
.ravel()
所做的。我们必须减去
{0}
在这两种情况下,因为对于
a
b
而言,我们只对非零值感兴趣

因此,找到唯一的标签后,我们循环遍历这些值,并使用
np.where
查找给定值在数组上的位置。
np.where
返回数组的元组。该元组的第一个元素是满足条件的所有行坐标,第二个元素是列坐标。 因此,我们可以使用
zip(*
将两个长度为n的容器解包为长度为2的n个容器。这意味着我们可以从
所有行坐标列表+所有列坐标列表
到满足条件的所有行-列坐标对的
列表。最后在python 3中,zip是一个生成器,我们可以通过调用
列表()来计算它
在它上面。然后,生成的列表被附加到坐标列表中,
r

for x in set(a.ravel())-{0}:
    r.append(list(zip(*np.where(a==x))))
for x in set(b.ravel())-{0}:
    r.append(list(zip(*np.where(b==x))))

print(r)

[[(0, 1), (0, 2), (1, 0), (1, 1)],
 [(2, 3)],
 [(0, 0)],
 [(0, 3), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2)]]
这就是说,我们可以利用
label
返回其分配的功能数量这一事实,稍微加快此代码的速度。这允许我们避免使用
set
命令,这在大型阵列上可能需要时间:

a, num_a = label(arr)

for x in range(1, num_a+1): # range from 1 to the highest label
    r.append(list(zip(*np.where(a==x))))

只有标准库的解决方案:

from pprint import pprint

m = [0, 1, 1, 0,
     1, 1, 0, 0,
     0, 0, 0, 1]

def is_neighbour(x1, y1, x2, y2):
    return (x1 in (x2-1, x2+1) and y1 == y2) or \
           (x1 == x2 and y1 in (y2+1, y2-1))

def is_value_touching_group(val, groups, x, y):
    for d in groups:
        if d['color'] == val and any(is_neighbour(x, y, *cell) for cell in d['cells']):
            return d

def check(m, w, h):
    groups = []

    for i in range(h):
        for j in range(w):
            val = m[i*w + j]
            touching_group = is_value_touching_group(val, groups, i, j)
            if touching_group:
                touching_group['cells'].append( (i, j) )
            else:
                groups.append({'color':val, 'cells':[(i, j)]})

    final_groups = []
    while groups:
        current_group = groups.pop()
        for c in current_group['cells']:
            touching_group = is_value_touching_group(current_group['color'], groups, *c)
            if touching_group:
                touching_group['cells'].extend(current_group['cells'])
                break
        else:
            final_groups.append(current_group['cells'])

    return final_groups

pprint( check(m, 4, 3) )
印刷品:

[[(2, 3)],
 [(0, 3), (1, 3), (1, 2), (2, 2), (2, 0), (2, 1)],
 [(0, 1), (0, 2), (1, 1), (1, 0)],
 [(0, 0)]]

作为值键下的组列表返回

将numpy导入为np
输入数学
def获取密钥(旧命令):
new_dict={}
对于键,旧目录项()中的值:
如果值不在新的目录键()中:
新记录[值]=[]
新建目录[值]。追加(键)
其他:
新建目录[值]。追加(键)
返回新命令
def是_邻居(a,b):
如果a==b:
返回真值
其他:
距离=abs(a[0]-b[0]),abs(a[1]-b[1])
返回距离==(0,1)或距离==(1,0)
def对照(arr):
arr2=arr.copy()
ret=[]
对于arr中的a:
对于枚举中的i,b(arr2):
如果设置(a)。交叉点(设置(b)):
a=列表(集合(a+b))
ret.append(a)
对于ret中的clist:
clist.sort()
返回[list(y)表示集合中的y([tuple(x)表示集合中的x])]
def get_组(d):
对于d.项()中的k,v:
ret=[]
对于v点:
匹配=[a表示v中的a,如果是_邻居(点,a)]
ret.append(匹配项)
d[k]=对比(ret)
返回d
a=np.数组([[0,1,1,0],
[1,1,0,0],
[0,0,1,1]])
d=主语(名词,名词,名词)(a))
d=获取密钥(d)
d=获取组(d)
印刷品(d)
结果:

{
  0: [[(0, 3), (1, 2), (1, 3)], [(0, 0)], [(2, 0), (2, 1)]], 
  1: [[(2, 2), (2, 3)], [(0, 1), (0, 2), (1, 0), (1, 1)]]
}

只是为了澄清一下,矩阵是一维数组还是二维数组?它不是固定的,可以更改,但是更方便。你能解释一下这个代码是如何工作的吗?它很短!