我试图获得一个坐标数组矩阵。这与numpy.meshgrid不同。例如,对于2x2尺寸,我想要2x2x2输出
[[[0,0],[0,1]],
[[1,0],[1,1]]]
作为一个numpy数组。这可能看起来更清晰,是一个2x2的元组矩阵:
[[(0,0),(0,1)],
[(1,0),(1,1)]]
(除了我不认为你可以在一个numpy数组中有元组,这不是重点)
这个简单的例子可以通过切换numpy-meshgrid输出的轴来完成(具体来说,将第一个轴移动到最后):
np.array(np.meshgrid([0,1],[0,1])).transpose([1,2,0])
这可以很容易地推广到任意维度,除了meshgrid没有像我期望的那样超过2个输入。具体来说,返回的矩阵具有沿奇数顺序的轴变化的坐标值:
In [627]: np.meshgrid([0,1],[0,1],[0,1])
Out[627]:
[array([[[0, 0],
[1, 1]],
[[0, 0],
[1, 1]]]),
array([[[0, 0],
[0, 0]],
[[1, 1],
[1, 1]]]),
array([[[0, 1],
[0, 1]],
[[0, 1],
[0, 1]]])]
请注意,此输出的元素分别沿轴1,0和2变化。这将构建一个不正确的坐标矩阵;我需要输出按顺序沿轴0,1和2变化。所以我可以做到
In [642]: np.array(np.meshgrid([0,1],[0,1],[0,1])).swapaxes(1,2)
Out[642]:
array([[[[0, 0],
[0, 0]],
[[1, 1],
[1, 1]]],
[[[0, 0],
[1, 1]],
[[0, 0],
[1, 1]]],
[[[0, 1],
[0, 1]],
[[0, 1],
[0, 1]]]])
但是这开始变得非常hacky并且我不知道我是否可以在更高维度的网格网格输出中依赖此顺序。 numpy.mgrid给出正确的顺序,但似乎不允许任意值,我将需要。所以这归结为两个问题:
1)是否有一种更清洁的方式,也许有一些功能在我没有丢失,这将生成如上所述的坐标向量矩阵? 2)这个奇怪的排序真的是我们对meshgrid的期望吗?这一点是否有我可以指望的规范?
[编辑]跟进Jaime的解决方案,这里有一个更为通用的功能,可以为任何感兴趣的人更明确地构建它:[编辑2,修复了一个错误,可能是另一个,可以&#39现在花更多的时间在这上面,这真的需要一个更常见的功能...]
def build_coords(*vecs):
coords = numpy.empty(map(len,vecs)+[len(vecs)])
for ii in xrange(len(vecs)):
s = np.hstack((len(vecs[ii]), np.ones(len(vecs)-ii-1)))
v = vecs[ii].reshape(s)
coords[...,ii] = v
return coords
答案 0 :(得分:8)
鉴于1D coords:
rows = np.arange(2)
cols = np.arange(3)
我希望这可以解决问题:
np.dstack((rows[:, None, None], cols[:, None]))
但显然dstack
等需要完全匹配的尺寸,他们不会广播它们,我认为这是一种耻辱。
所以这个替代方案有点长,但显式优于隐式,你可以将它全部包装成一个小函数:
>>> coords = np.empty((len(rows), len(cols), 2), dtype=np.intp)
>>> coords[..., 0] = rows[:, None]
>>> coords[..., 1] = cols
>>> coords
array([[[0, 0],
[0, 1],
[0, 2]],
[[1, 0],
[1, 1],
[1, 2]]])
答案 1 :(得分:5)
numpy函数indices
也可用于此效果,其功能也可从其名称中清楚显示。
>>> import numpy as np
>>> np.indices((2,3))
array([[[0, 0, 0],
[1, 1, 1]],
[[0, 1, 2],
[0, 1, 2]]])
可以被认为是y坐标的2乘3矩阵和x坐标的2乘3矩阵(y,x = np.indices((2,3))
)。它可以通过转置轴来重铸为Jaime提出的形式:
>>> np.indices((2,3)).transpose((1,2,0))
它在功能上等同于the meshgrid
solution,使用indexing='ij'
,但不要求您提供坐标数组,当您有多个维度时,这可能是一个好处。
>>> def f1(shape):
... return np.array(np.meshgrid(*(np.arange(s) for s in shape), indexing='ij'))
...
>>> shape = (200, 31, 15, 4)
>>> np.all(f1(shape) == np.indices(shape))
True
时间方面,这些解决方案类似,当您考虑生成meshgrid
运行的1-D阵列所需的时间,但meshgrid
返回列表(数组),而不是像indices
这样的数组。通过在上面的np.array
中添加对f1
的额外调用,indices
明显优于meshgrid
:
In [14]: %timeit f1(shape)
100 loops, best of 3: 14 ms per loop
In [15]: %timeit np.indices(shape)
100 loops, best of 3: 5.77 ms per loop
无需额外拨打array
:
In [16]: def f2(shape):
return np.meshgrid(*(np.arange(s) for s in shape), indexing='ij')
.....:
In [17]: %timeit f2(shape)
100 loops, best of 3: 5.78 ms per loop
但是要小心解释时间。这可能不会成为你解决的任何问题的瓶颈。
在任何情况下,meshgrid
都可以执行比indices
更多的操作,例如生成更通用的rectilinear grid而不是笛卡尔网格,因此请在适当的时候使用它们。在这种情况下,我会使用更具描述性的命名indices
。
答案 2 :(得分:1)
试试np.meshgrid([0, 1], [0, 1], [0, 1], indexing="ij")
。与非默认meshgrid
相比,indexing="xy"
文档实际上非常清楚默认indexing="ij"
如何产生有趣的轴排序,因此您可以查看更多详细信息。 (他们对为什么以这种方式运作不太清楚,唉......)
答案 3 :(得分:0)
我使用的一种简单方法是 -
x,y = np.mgrid[-10:10:0.1, -10:10:0.1]
pos = np.empty(x.shape + (2,))
pos[:, :, 0] = x; pos[:, :, 1] = y
pos = np.reshape(pos, (x.shape[0]*x.shape[1], 2))
pos
是必需的坐标数组。
答案 4 :(得分:0)
最初的问题发布于6年前,但我发现自己反复寻找解决此问题的好的方法,并多次来到这里。通过查看Numpy文档,我最近将一种直观而动态的方法用于生成n维坐标,并希望将其发布在此处,以供仍满足此答案的人使用。
我们使用numpy.ndindex()
,其中:
鉴于数组的形状,ndindex实例遍历数组的N维索引。每次迭代都返回一个索引元组,最后一个维在第一个维上迭代。
理解的最好方法是看一个例子:
In [100]: for index in np.ndindex(2,2,2):
print(index)
(0, 0, 0)
(0, 0, 1)
(0, 1, 0)
(0, 1, 1)
(1, 0, 0)
(1, 0, 1)
(1, 1, 0)
(1, 1, 1)
这正是我们要寻找的,那么如何将其转换为numpy数组格式或列表形式?
如果我们希望将坐标作为列表,则可以使用:
In [103]: coordList = [x for x in np.ndindex(2,2,2)]
In [104]: print(coordList)
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
如果我们希望将坐标作为一个numpy数组,则可以使用:
In [105]: coordArray = np.stack([x for x in np.ndindex(2,2,2)])
In [106]: print(coordArray)
[[0 0 0]
[0 0 1]
[0 1 0]
[0 1 1]
[1 0 0]
[1 0 1]
[1 1 0]
[1 1 1]]
这种方法可以轻松地缩放以改变尺寸和大小,并且使用numpy.reshape()
,我们可以准确地得到OP正在寻找的格式:
In [117]: answer = np.stack([x for x in np.ndindex(2,2)]).reshape(2,2,2)
In [118]: print(answer)
[[[0 0]
[0 1]]
[[1 0]
[1 1]]]
再一次,它很容易扩展到更大的尺寸:
In [120]: example = np.stack([x for x in np.ndindex(3,3,3)]).reshape(3,3,3,3)
In [121]: print(example)
[[[[0 0 0]
[0 0 1]
[0 0 2]]
[[0 1 0]
[0 1 1]
[0 1 2]]
[[0 2 0]
[0 2 1]
[0 2 2]]]
[[[1 0 0]
[1 0 1]
[1 0 2]]
[[1 1 0]
[1 1 1]
[1 1 2]]
[[1 2 0]
[1 2 1]
[1 2 2]]]
[[[2 0 0]
[2 0 1]
[2 0 2]]
[[2 1 0]
[2 1 1]
[2 1 2]]
[[2 2 0]
[2 2 1]
[2 2 2]]]]
答案 5 :(得分:0)
目前我找到的最简单的方法:
height = 2
width = 4
t = np.mgrid[:height, :width]
t = np.stack((t[0], t[1]), axis=2)
>>> t
array([
[[0, 0], [0, 1], [0, 2], [0, 3]],
[[1, 0], [1, 1], [1, 2], [1, 3]]
])
如果你想在 tensorflow 中做同样的事情:
rows = tf.range(0, img0.shape[1]) # generate row numbers
cols = tf.range(0, img0.shape[2]) # generate col numbers
cols, rows = tf.meshgrid(cols, rows) # expend them to a grid
z = tf.stack((cols, rows), axis=2) # stack them together
z = tf.stack([z]*img0.shape[0], axis=0) # stack up to number of batches