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