Numpy配列に新しい次元を追加するにはどうすればよいですか?


93

私は画像のずんぐりした配列から始めています。

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

形状は、640x480RGB画像に期待できるものです。

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

しかし、私が持っているこの画像は、100フレームの長さのビデオのフレームです。理想的には、をimg.shape返すようなこのビデオからのすべてのデータを含む単一の配列が必要(480, 640, 3, 100)です。

次のフレーム(つまり、次の画像データのセット、別の480 x 640 x 3配列)を最初の配列に追加する最良の方法は何ですか?

回答:


105

NumPy配列にディメンションを追加して、そのディメンションを拡張して新しいデータに対応できるようにする方法を尋ねています。ディメンションは次のように追加できます。

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

10
現在、numpy.newaxisNone(ファイル内でnumeric.py)と定義されているため、同等に `image = image [...、None]を使用できます。
レイ

60
使用しないでくださいNonenp.newaxis明示的は暗黙的よりも優れているため、使用します。
ニールG

7
どうしてそれができるのでしょうか?None何も意味しません。それは明白です。ですNone。明確に述べた。None あるもののpythonインチ は間違いありません。None最後の詳細です、あなたは深く行くことはできません。一方、はをnumpy.newaxis意味しNoneます。本質的にはNoneです。ですNone。しかし、None暗黙のうちにです。それはNone直接として表現されていないがNone明示的に 明確かつ詳細に述べられており、混乱や疑いの余地はありません。 直接表現されていませんが、暗黙的に 提案されています。APIの観点からは、を使用する方が安全であることを付け加えなければなりませんnumpy.newaxis
ペドロロドリゲス

3
ここで推測すると、明示的であるということは、構文的/意味的な明確さではなく、「コーダーの意図」を指します。
Gabrer

この場合、JoshAdelの回答を正しい回答として選択する必要があり、さらに多くの票が必要です。彼の主張は、OPが彼が進むにつれてより高次元のnparrayに追加しようとしているという点で重要です。ndarrayは、一度作成するとサイズを大きくすることはできません。コピーを作成する必要があります。この答えは形(480、640、3、1)のみを作成し、新しいフレームを追加するたびに別のコピーを作成します。良くない。
DanBoschen20年

61

代わりに

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 2017

@weima:あなたが何を求めているのか完全にはわかりません。あなたの望む出力は何ですか?
クレブ2017

25

正しいサイズの配列を事前に作成して、それを埋めることができます。

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

JoshAdelとMagellan88に同意します。他の答えは、メモリと処理時間が非常に非効率的です。一度作成するとndarrayのサイズを大きくすることはできないため、追加すると思われる場合は常にコピーが作成されます。
DanBoschen20年

12

Pythonic

X = X[:, :, None]

これは

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

しかし、あなたは画像の積み重ねについて明確に質問しているので、私はlist画像の積み重ねに行くことをお勧めしますnp.stack([X1, X2, X3])ているので、ループで収集した可能性のします。

寸法の順序が気に入らない場合は、次のように並べ替えることができます np.transpose()


7

を使用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配列内のすべてのデータを同じメモリチャンクに保持できることから生まれます。たとえば、数学演算を並列化して速度を上げることができ、キャッシュミスが少なくなります。

したがって、2種類のソリューションがあります。

  1. JoshAdelの回答のように、numpy配列にメモリを事前に割り当て、値を入力するか、
  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

同じ結果をもたらす、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]]]]

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).
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.