Numpy坐标矩阵

时间:2014-06-26 16:48:22

标签: python arrays numpy matrix coordinates

我试图获得一个坐标数组矩阵。这与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

6 个答案:

答案 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