Làm cách nào để thêm thứ nguyên mới vào mảng Numpy?


85

Tôi bắt đầu với một mảng hình ảnh nhỏ.

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

Hình dạng là những gì bạn có thể mong đợi đối với hình ảnh RGB 640x480.

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

Tuy nhiên, hình ảnh mà tôi có là một khung hình của một video, dài 100 khung hình. Lý tưởng nhất, tôi muốn có một mảng duy nhất chứa tất cả dữ liệu từ video này img.shapesẽ trả về (480, 640, 3, 100).

Cách tốt nhất để thêm khung hình tiếp theo - tức là tập dữ liệu hình ảnh tiếp theo, một mảng 480 x 640 x 3 khác - vào mảng ban đầu của tôi là gì?

Câu trả lời:


98

Bạn đang hỏi cách thêm thứ nguyên vào mảng NumPy, để sau đó thứ nguyên đó có thể được phát triển để chứa dữ liệu mới. Một thứ nguyên có thể được thêm vào như sau:

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

10
Hiện tại, numpy.newaxisđược định nghĩa là None(trong tệp numeric.py), vì vậy tương đương bạn có thể sử dụng `image = image [..., None].
Ray

58
Không sử dụng None. Sử dụng np.newaxisbởi vì rõ ràng tốt hơn là ẩn.
Neil G

7
Làm thế nào mà có thể được? Nonekhông ám chỉ bất cứ điều gì. Nó là rõ ràng. Đó là None. Nói rõ ràng. None một thứ trong python. Không có nghi ngờ gì. Nonelà chi tiết cuối cùng, bạn không thể đi sâu hơn. Mặt khác, numpy.newaxisngụ ý None. Về cơ bản, nó là None. Đó là None. Nhưng là Nonengầm. Nó Nonemặc dù không được thể hiện trực tiếp bằng None. Rõ ràng được nêu rõ ràng và chi tiết, không có chỗ cho sự nhầm lẫn hoặc nghi ngờ. Gợi ý ngầm mặc dù không được thể hiện trực tiếp. Tôi phải nói thêm rằng, từ góc độ API, nó an toàn hơn khi sử dụng numpy.newaxis.
Pedro Rodrigues

2
Đoán ở đây, rõ ràng đề cập đến "ý định của người viết mã" hơn là sự rõ ràng về cú pháp / ngữ nghĩa.
Gabrer

Câu trả lời của JoshAdel nên được chọn là câu trả lời đúng trong trường hợp này và cần nhiều phiếu bầu hơn. Quan điểm của anh ấy rất quan trọng ở chỗ OP đang tìm cách thêm vào nparray có kích thước cao hơn khi anh ấy đi. ndarray's không thể tăng kích thước sau khi được tạo, phải tạo một bản sao. Câu trả lời này sẽ chỉ tạo ra hình dạng (480, 640, 3, 1) và mỗi khi bạn thêm một khung hình mới, bạn sẽ tạo một bản sao khác. Không tốt.
Dan Boschen

59

Ngoài ra

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

trong câu trả lời @dbliss ' , bạn cũng có thể sử dụng numpy.expand_dimsnhư

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

Ví dụ (lấy từ liên kết trên):

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

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

Sau đó

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

hoa lợi

array([[1, 2]])

y.shape

cho

(1, 2)

làm thế nào để thêm các giá trị trong dimention mới? nếu tôi làm điều y[1,0]đó sẽ đưa ra lỗi chỉ mục nằm ngoài giới hạn. y[0,1]có thể truy cập
weima

@weima: Không hoàn toàn chắc chắn bạn đang theo đuổi điều gì. Đầu ra mong muốn của bạn là gì?
Cleb

24

Bạn chỉ có thể tạo một mảng có kích thước chính xác từ trước và điền vào đó:

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

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

nếu các khung là tệp jpg riêng lẻ được đặt tên theo một số cách cụ thể (trong ví dụ: frame_0.jpg, frame_1.jpg, v.v.).

Chỉ cần một lưu ý (nframes, 480,640,3), thay vào đó bạn có thể cân nhắc sử dụng một mảng hình.


1
Tôi nghĩ đây là cách để đi. nếu bạn sử dụng nối, bạn sẽ cần phải di chuyển mảng trong bộ nhớ mỗi khi bạn thêm vào nó. cho 100 khung hình không quan trọng chút nào, nhưng nếu bạn muốn chuyển sang video lớn hơn. BTW, tôi sẽ sử dụng số lượng khung làm thứ nguyên đầu tiên để có một mảng (100.480.640,3) theo cách đó bạn có thể truy cập các khung riêng lẻ (thông thường bạn sẽ muốn nhìn vào điều gì, phải không?) Dễ dàng hơn (F [1 ] thay vì F [:,:,:, 1]). Tất nhiên hiệu suất khôn ngoan nó sẽ không có vấn đề gì cả.
Magellan88

Tôi đồng ý với JoshAdel và Magellan88, các câu trả lời khác là bộ nhớ khôn ngoan và thời gian xử lý rất kém hiệu quả - ndarrays không thể tăng kích thước sau khi được tạo, vì vậy, một bản sao sẽ luôn được tạo nếu bạn nghĩ rằng bạn đang gắn vào nó.
Dan Boschen

10

Pythonic

X = X[:, :, None]

tương đương với

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

Nhưng vì bạn đang hỏi rõ ràng về việc xếp chồng các hình ảnh, tôi khuyên bạn nên xếp chồng các listhình ảnh np.stack([X1, X2, X3])mà bạn có thể đã thu thập trong một vòng lặp.

Nếu bạn không thích thứ tự của các kích thước, bạn có thể sắp xếp lại với np.transpose()


6

Bạn có thể sử dụng np.concatenate()chỉ định cái nào axisđể nối thêm, bằng cách sử dụng np.newaxis:

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

Nếu bạn đang đọc từ nhiều tệp:

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

2

Không có cấu trúc nào trong numpy cho phép bạn nối thêm dữ liệu sau này.

Thay vào đó, numpy đặt tất cả dữ liệu của bạn vào một nhóm số liền nhau (về cơ bản; một mảng C) và bất kỳ thay đổi kích thước nào cũng yêu cầu phân bổ một phần bộ nhớ mới để chứa nó. Tốc độ của Numpy đến từ việc có thể giữ tất cả dữ liệu trong một mảng phức tạp trong cùng một đoạn bộ nhớ; Ví dụ: các phép toán có thể được thực hiện song song để tăng tốc độ và bạn ít bị lỗi bộ nhớ cache hơn .

Vì vậy, bạn sẽ có hai loại giải pháp:

  1. Phân bổ trước bộ nhớ cho mảng numpy và điền vào các giá trị, như trong câu trả lời của JoshAdel hoặc
  2. Giữ dữ liệu của bạn trong danh sách python bình thường cho đến khi thực sự cần thiết để gộp tất cả chúng lại với nhau (xem bên dưới)

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

Lưu ý rằng trước tiên không cần phải mở rộng kích thước của từng mảng hình ảnh riêng lẻ, cũng như không cần biết trước bao nhiêu hình ảnh bạn mong đợi.


2

Hãy xem xét Cách tiếp cận 1 với phương pháp định hình lại và Cách tiếp cận 2 với phương pháp np.newaxis tạo ra cùng một kết quả:

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

Chúng tôi có kết quả như sau:

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

Tôi đã làm theo cách tiếp cận này:

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).
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.