【问题标题】:How can I add new dimensions to a Numpy array?如何向 Numpy 数组添加新维度?
【发布时间】:2013-06-28 00:11:46
【问题描述】:

我从一个图像的 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 阵列)添加到我的初始阵列的最佳方法是什么?

【问题讨论】:

    标签: python arrays opencv numpy


    【解决方案1】:

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

    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) 形状的数组。

    【讨论】:

    • 我认为这是要走的路。如果您使用串联,则每次添加时都需要在内存中移动数组。对于 100 帧,这根本不重要,但如果您想观看更大的视频。顺便说一句,我会使用帧数作为第一个维度,所以有一个 (100,480,640,3) 数组,这样您就可以访问单个帧(您通常想要查看的是什么,对吧?)更容易(F[1 ] 而不是 F[:,:,:,1])。当然,性能方面它根本不重要。
    • 我同意 JoshAdel 和 Magellan88 的观点,其他答案在内存和处理时间方面效率非常低——ndarrays 一旦创建就不能增加大小,所以如果你认为你正在追加,总是会制作一个副本给它。
    【解决方案2】:

    您可以使用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)
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 目前,numpy.newaxis 被定义为 None(在文件 numeric.py 中),因此您可以使用 `image = image[..., None]。
      • 不要使用None。使用np.newaxis,因为显式优于隐式。
      • 怎么可能? None 没有任何暗示。这是明确的。它是None。说清楚了。None is 在 python 中是一个 thing。毫无疑问。 None 是最后一个细节,你不能再深入了。另一方面,numpy.newaxis 暗示 None。它本质上是None。它是None。但隐含的是None。它是None,但不直接表示为None显式 清楚而详细地说明,没有混淆或怀疑的余地。 隐式 建议但未直接表达。我必须补充一点,从 API 的角度来看,使用numpy.newaxis 更安全。
      • 在这里猜一猜,明确指的是“编码意图”而不是句法/语义清晰度。
      • 由于标题询问添加(多)维度s,我想添加一个添加n维度的方法:a[(..., *([np.newaxis] * n))]。构造tuple 的括号是解包n 乘以np.newaxislist 所必需的
      【解决方案4】:

      我遵循了这种方法:

      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).
      

      【讨论】:

        【解决方案5】:

        替代

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

        @dbliss' answer,也可以用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:不完全确定你在追求什么。你想要的输出是什么?
        • “你想要的维度”的值去哪儿了?我只能看到值 1
        【解决方案6】:

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

        相反,numpy 将所有数据放入一个连续的数字块中(基本上是一个 C 数组),并且任何调整大小都需要分配一个新的内存块来保存它。 Numpy 的速度来自于能够将 numpy 数组中的所有数据保存在同一块内存中;例如数学运算可以是parallelized for speed,你得到的更少cache misses

        所以你会有两种解决方案:

        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)
        

        请注意,无需先扩展单个图像数组的维度,也无需提前知道预期的图像数量。

        【讨论】:

          【解决方案7】:

          考虑使用 reshape 方法的方法 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]]]]
          

          【讨论】:

            【解决方案8】:

            Python 风格

            X = X[:, :, None]

            相当于

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

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

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

            【讨论】:

              【解决方案9】:

              这对我有用:

              image = image[..., None]
              

              【讨论】:

              • 请问这里的参考文献在哪里?
              猜你喜欢
              • 2017-01-18
              • 2020-06-24
              • 2017-08-19
              • 2021-12-30
              • 1970-01-01
              • 2017-06-10
              相关资源
              最近更新 更多