如何为Numpy数组添加新尺寸?


85

我从一个图像的numpy数组开始。

In[1]:img = cv2.imread('test.jpg')

形状是您可能期望的640x480 RGB图像。

In[2]:img.shape
Out[2]: (480, 640, 3)

但是,我拥有的这张图像是一帧视频,长度为100帧。理想情况下,我希望有一个数组,其中包含该视频中的所有数据,从而img.shape返回(480, 640, 3, 100)

将下一帧(即另一组图像数据,另一个480 x 640 x 3数组)添加到我的初始数组的最佳方法是什么?

Answers:


97

您在问如何向NumPy数组添加维度,以便可以扩展该维度以容纳新数据。可以如下添加维:

image = image[..., np.newaxis]

10
当前,numpy.newaxis被定义为None(在文件中numeric.py),因此等效地可以使用`image = image [...,None]。

58
不要使用None。使用np.newaxis是因为显式比隐式好。
Neil G

7
怎么可能?None并不暗示任何东西。这是明确的。是的None。陈述清楚。None python中的东西。毫无疑问。None是最后一个细节,您无法深入。另一方面,numpy.newaxis暗含None。本质上是None。是的None。但是是None隐含的。它None虽然不能直接表示None明确 明确,详细地陈述,不容混淆或怀疑。 提示虽然没有直接表达。我必须补充一点,从API角度来看,它使用起来更安全numpy.newaxis
Pedro Rodrigues

2
猜测在这里,明确是指“编码意图”,而不是句法/语义上的清晰。
加布里尔

在这种情况下,应选择JoshAdel的答案作为正确答案,并且需要更多投票。他的观点很重要,因为OP希望在他使用时添加到更高尺寸的nparray。ndarray的大小一旦创建就无法增加,必须进行复制。该答案只会形成形状(480、640、3、1),并且每次添加新框架时,您都将制作另一个副本。不好。
Dan Boschen

58

替代

image = image[..., np.newaxis]

@dbliss的回答,您还可以使用numpy.expand_dims

image = np.expand_dims(image, <your desired dimension>)

例如(摘自上面的链接):

x = np.array([1, 2])

print(x.shape)  # prints (2,)

然后

y = np.expand_dims(x, axis=0)

产量

array([[1, 2]])

y.shape

(1, 2)

如何在新尺寸中添加值?如果我这样做y[1,0]给索引超出范围错误。y[0,1]可访问
weima

@weima:不太清楚你要做什么。您想要的输出是什么?
克莱布(Cleb)'17年

24

您可以预先创建一个正确大小的数组并填充它:

frames = np.empty((480, 640, 3, 100))

for k in xrange(nframes):
    frames[:,:,:,k] = cv2.imread('frame_{}.jpg'.format(k))

如果帧是以某种特定方式命名的单个jpg文件(在示例中为frame_0.jpg,frame_1.jpg等)。

仅需注意,您可以考虑使用(nframes, 480,640,3)形状数组。


1
我认为这是要走的路。如果使用串联,则每次添加阵列时都需要在内存中移动该阵列。100帧根本不重要,但是如果您想观看更大的视频。顺便说一句,我本来会以帧数作为第一个维度,所以有一个(100,480,640,3)数组,这样您就可以更容易地访问单个帧(通常想要看的是吧?)[F [1 ]代替F [:,:,:,1])。当然,就性能而言,这根本不重要。
Magellan88 2014年

我同意JoshAdel和Magellan88的观点,其他答案都是非常低效的存储方式和处理时间-创建后ndarray的大小无法增加,因此如果您认为要附加到ndarray,将始终进行复制。
Dan Boschen

10

Pythonic

X = X[:, :, None]

相当于

X = X[:, :, numpy.newaxis]X = numpy.expand_dims(X, axis=-1)

但是,当您明确询问要堆叠图像时,我建议您将您可能已经循环收集list的图像堆叠起来np.stack([X1, X2, X3])

如果您不喜欢尺寸的顺序,可以重新排列 np.transpose()


6

您可以使用np.concatenate()指定axis要追加的内容np.newaxis

import numpy as np
movie = np.concatenate((img1[:,np.newaxis], img2[:,np.newaxis]), axis=3)

如果要读取许多文件:

import glob
movie = np.concatenate([cv2.imread(p)[:,np.newaxis] for p in glob.glob('*.jpg')], axis=3)

2

numpy中没有允许您以后追加更多数据的结构。

相反,numpy将所有数据放入连续的数字块(基本上是C数组),并且任何大小调整都需要分配新的内存块来容纳它。Numpy的速度来自能够将所有数据保存在同一内存块中的numpy数组中。例如,可以并行进行数学运算以提高速度,并且减少缓存丢失

因此,您将有两种解决方案:

  1. 为numpy数组预先分配内存并填写值,例如JoshAdel的答案,或者
  2. 将数据保存在普通的python列表中,直到真正需要将它们放在一起为止(请参见下文)

images = []
for i in range(100):
    new_image = # pull image from somewhere
    images.append(new_image)
images = np.stack(images, axis=3)

请注意,无需先扩展单个图像阵列的尺寸,也不需要知道您希望提前多少张图像。


2

考虑使用重塑方法的方法1和使用np.newaxis方法的方法2,它们会产生相同的结果:

#Lets suppose, we have:
x = [1,2,3,4,5,6,7,8,9]
print('I. x',x)

xNpArr = np.array(x)
print('II. xNpArr',xNpArr)
print('III. xNpArr', xNpArr.shape)

xNpArr_3x3 = xNpArr.reshape((3,3))
print('IV. xNpArr_3x3.shape', xNpArr_3x3.shape)
print('V. xNpArr_3x3', xNpArr_3x3)

#Approach 1 with reshape method
xNpArrRs_1x3x3x1 = xNpArr_3x3.reshape((1,3,3,1))
print('VI. xNpArrRs_1x3x3x1.shape', xNpArrRs_1x3x3x1.shape)
print('VII. xNpArrRs_1x3x3x1', xNpArrRs_1x3x3x1)

#Approach 2 with np.newaxis method
xNpArrNa_1x3x3x1 = xNpArr_3x3[np.newaxis, ..., np.newaxis]
print('VIII. xNpArrNa_1x3x3x1.shape', xNpArrNa_1x3x3x1.shape)
print('IX. xNpArrNa_1x3x3x1', xNpArrNa_1x3x3x1)

结果如下:

I. x [1, 2, 3, 4, 5, 6, 7, 8, 9]

II. xNpArr [1 2 3 4 5 6 7 8 9]

III. xNpArr (9,)

IV. xNpArr_3x3.shape (3, 3)

V. xNpArr_3x3 [[1 2 3]
 [4 5 6]
 [7 8 9]]

VI. xNpArrRs_1x3x3x1.shape (1, 3, 3, 1)

VII. xNpArrRs_1x3x3x1 [[[[1]
   [2]
   [3]]

  [[4]
   [5]
   [6]]

  [[7]
   [8]
   [9]]]]

VIII. xNpArrNa_1x3x3x1.shape (1, 3, 3, 1)

IX. xNpArrNa_1x3x3x1 [[[[1]
   [2]
   [3]]

  [[4]
   [5]
   [6]]

  [[7]
   [8]
   [9]]]]

1

我遵循这种方法:

import numpy as np
import cv2

ls = []

for image in image_paths:
    ls.append(cv2.imread('test.jpg'))

img_np = np.array(ls) # shape (100, 480, 640, 3)
img_np = np.rollaxis(img_np, 0, 4) # shape (480, 640, 3, 100).
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.