Bir Numpy dizisine nasıl yeni boyutlar ekleyebilirim?


93

Uyuşmuş bir görüntü dizisi ile başlıyorum.

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

Şekil, 640x480 RGB görüntü için beklediğiniz şeydir.

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

Ancak sahip olduğum bu görüntü, 100 kare uzunluğunda bir video karesi. İdeal olarak, bu videodan img.shapegeri dönen tüm verileri içeren tek bir diziye sahip olmak istiyorum (480, 640, 3, 100).

Sonraki kareyi - yani bir sonraki görüntü verisi kümesini, başka bir 480 x 640 x 3 dizisini - ilk dizime eklemenin en iyi yolu nedir?

Yanıtlar:


105

Bir NumPy dizisine nasıl boyut ekleneceğini soruyorsunuz, böylece bu boyut daha sonra yeni verileri barındıracak şekilde büyütülebilir. Aşağıdaki şekilde bir boyut eklenebilir:

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

10
Şu anda, (dosyada ) numpy.newaxisolarak tanımlanmıştır , bu nedenle eşdeğer olarak `image = image [..., None] kullanabilirsiniz.Nonenumeric.py
Ray

60
Kullanmayın None. np.newaxisAçık, örtük olmaktan daha iyi olduğu için kullanın .
Neil G

7
Nasıl olabilir? Nonehiçbir şey ifade etmez. Açıktır. Öyle None. Açıkça ifade edildi. None olan bir şey python. Hiç şüphesiz. Noneson detay, daha derine inemezsiniz. Öte yandan, numpy.newaxisima ediyor None. Esasen öyle None. Öyle None. Ama Nonedolaylı olarak. Bu edilir Noneolsa da, doğrudan olarak ifade değildir None. Açıkça açıkça ve ayrıntılı olarak ifade edildi, kafa karışıklığına veya şüpheye yer bırakmadı. Örtülü olsa doğrudan ifade değil önerdi. API perspektifinden kullanmanın daha güvenli olduğunu eklemeliyim numpy.newaxis.
Pedro Rodrigues

3
Burada tahmin edin, açık olmak sözdizimsel / anlamsal netlikten çok "kodlayıcı amacına" atıfta bulunuyor.
Gabrer

JoshAdel'in cevabı bu durumda doğru cevap olarak seçilmelidir ve daha fazla oy gerektirir. Onun noktası, OP'nin ilerledikçe daha yüksek boyutlu parlaya katkıda bulunmaya çalışması açısından önemlidir. ndarray'ler oluşturulduktan sonra boyut olarak artırılamaz, bir kopya yapılmalıdır. Bu cevap yalnızca şekli (480, 640, 3, 1) oluşturacak ve her yeni çerçeve eklediğinizde başka bir kopya oluşturacaksınız. İyi değil.
Dan Boschen

61

Alternatif olarak

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

içinde @dbliss' cevabı , ayrıca kullanabilirsiniz numpy.expand_dimsgibi

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

Örneğin (yukarıdaki bağlantıdan alınmıştır):

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

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

Sonra

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

verim

array([[1, 2]])

ve

y.shape

verir

(1, 2)

yeni boyutta değerler nasıl eklenir? yaparsam y[1,0]sınır dışı hata verir. y[0,1]erişilebilir
weima

@weima: Neyin peşinde olduğunuzdan tam olarak emin değilim. İstediğiniz çıktı nedir?
Cleb

25

Baştan doğru boyutta bir dizi oluşturabilir ve onu doldurabilirsiniz:

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

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

çerçeveler belirli bir şekilde adlandırılmış ayrı bir jpg dosyasıysa (örnekte, çerçeve_0.jpg, çerçeve_1.jpg, vb.).

Sadece bir not (nframes, 480,640,3), bunun yerine şekilli bir dizi kullanmayı düşünebilirsiniz .


1
Sanırım gitmenin yolu bu. Birleştirmeyi kullanırsanız, her ekleme yaptığınızda diziyi bellekte taşımanız gerekecektir. hiç önemli olmamalı, ancak daha büyük videolara gitmek istiyorsanız 100 kare için. BTW, ben kare sayısını ilk boyut olarak kullanırdım, bu yüzden tek tek karelere erişebileceğiniz bir (100,480,640,3) diziye sahip olurdum (genellikle neye bakmak isteyeceksiniz, değil mi?) Daha kolay (F [1 ] yerine F [:,:,:, 1]). Elbette performans açısından hiç önemli olmamalı.
Magellan88

JoshAdel ve Magellan88'e katılıyorum, diğer cevaplar hafıza açısından çok verimsiz ve işlem süresi - ndarray'ler bir kez oluşturulduktan sonra boyut olarak artırılamaz, bu nedenle ekleme yaptığınızı düşünüyorsanız her zaman bir kopya alınacaktır.
Dan Boschen

12

Pythonic

X = X[:, :, None]

eşdeğer olan

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

Ancak görüntüleri istifleme hakkında açıkça sorduğunuz için , bir döngüde toplamış olabileceğiniz listgörüntüleri istiflemenizi tavsiye ederim np.stack([X1, X2, X3]).

Boyutların sırasını beğenmezseniz yeniden düzenleyebilirsiniz. np.transpose()


7

Aşağıdakileri kullanarak np.concatenate()hangisinin axisekleneceğini belirtebilirsiniz np.newaxis:

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

Birçok dosyadan okuyorsanız:

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

2

Numpy'de daha sonra daha fazla veri eklemenize izin veren bir yapı yoktur.

Bunun yerine, numpy, tüm verilerinizi bitişik bir sayı yığınına (temel olarak; bir C dizisi) koyar ve herhangi bir yeniden boyutlandırma, onu tutmak için yeni bir bellek parçası ayırmayı gerektirir. Numpy'nin hızı, tüm verileri uyuşmuş bir dizide aynı bellek yığınında tutabilmekten gelir; Örneğin matematiksel işlemler hız için paralelleştirilebilir ve daha az önbellek kaybı yaşarsınız .

Yani iki tür çözümünüz olacak:

  1. Belleği numpy dizisi için önceden ayırın ve JoshAdel'in cevabında olduğu gibi değerleri doldurun veya
  2. Verilerinizi, aslında hepsini bir araya getirmeniz gerekene kadar normal bir python listesinde tutun (aşağıya bakın)

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

Önce tek tek görüntü dizilerinin boyutlarını genişletmeniz gerekmediğini veya önceden kaç görüntü beklediğinizi bilmeniz gerekmediğini unutmayın.


2

Yeniden şekillendirme yöntemiyle Yaklaşım 1'i ve aynı sonucu üreten np.newaxis yöntemiyle Yaklaşım 2'yi düşünün:

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

Sonuç olarak elimizde:

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

Bu yaklaşımı takip ettim:

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).
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.