3-мерный массив в numpy

Новое на Python и Numpy, пытаясь создать 3-мерные массивы. Моя проблема в том, что порядок размеров отключен по сравнению с Matlab. На самом деле порядок не имеет смысла.

Создание матрицы:

x = np.zeros((2,3,4))

В моем мире это должно привести к 2 строкам, 3 столбцам и 4 глубинам и должно быть представлено как:

[0 0 0      [0 0 0      [0 0 0      [0 0 0
 0 0 0]      0 0 0]      0 0 0]      0 0 0] 

Разделение по каждой глубине. Вместо этого он представлен как

[0 0 0 0      [0 0 0 0
 0 0 0 0       0 0 0 0
 0 0 0 0]      0 0 0 0]

То есть, 3 строки, 4 столбца и 2 глубины. То есть, первым измерением является "глубина". Чтобы добавить к этой проблеме, импортирование изображения с помощью OpenCV - это измерение размера, то есть я вижу информацию о цвете как измерение глубины. Это усложняет ситуацию, если все, что я хочу сделать, это попробовать что-то в известном меньшем 3-мерном массиве.

Я что-то неправильно понял? Если нет, то почему heck numpy использует такой неинтуитивный способ работы с 3D-мерными массивами?

Ответ 1

У вас есть усеченное представление массива. Давайте посмотрим на полный пример:

>>> a = np.zeros((2, 3, 4))
>>> a
array([[[ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.]]])

Массивы в NumPy печатаются как array слов с последующей структурой, аналогично встроенным спискам Python. Давайте создадим аналогичный список:

>>> l = [[[ 0.,  0.,  0.,  0.],
          [ 0.,  0.,  0.,  0.],
          [ 0.,  0.,  0.,  0.]],

          [[ 0.,  0.,  0.,  0.],
          [ 0.,  0.,  0.,  0.],
          [ 0.,  0.,  0.,  0.]]]

>>> l
[[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], 
 [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]]]

Первый уровень этого составного списка l содержит ровно 2 элемента, так же как и первое измерение массива a (количество строк). Каждый из этих элементов сам по себе список с 3 -х элементов, который является равным второму измерению a (# столбцов). И, наконец, наиболее вложенные списки имеют 4 элементов, каждый же, как в третьем измерении a (глубина/# цветов).

Таким образом, у вас точно такая же структура (с точки зрения размеров), как в Matlab, просто напечатанная другим способом.

Некоторые предостережения:

  1. Matlab хранит данные столбец за столбцом ("порядок Фортрана"), в то время как NumPy по умолчанию сохраняет их построчно ("порядок С"). Это не влияет на индексирование, но может повлиять на производительность. Например, в Matlab эффективный цикл будет проходить по столбцам (например, for n = 1:10 a(:, n) end), тогда как в NumPy предпочтительнее выполнять итерацию по строкам (например, for n in range(10): a[n, :] - примечание n в первом положении, не последний).

  2. Если вы работаете с цветными изображениями в OpenCV, помните, что:

    2.1. Он хранит изображения в формате BGR, а не в RGB, как это делают большинство библиотек Python.

    2.2. Большинство функций работают с координатами изображения (x, y), которые противоположны координатам матрицы (i, j).

Ответ 2

Вы правы, вы создаете матрицу с 2 строками, 3 столбцами и 4 глубинами. Матрица печатает Numpy отличается от Matlab:

Numpy:

>>> import numpy as np
>>> np.zeros((2,3,2))
 array([[[ 0.,  0.],
    [ 0.,  0.],
    [ 0.,  0.]],

   [[ 0.,  0.],
    [ 0.,  0.],
    [ 0.,  0.]]])

Matlab

>> zeros(2, 3, 2)
 ans(:,:,1) =
     0     0     0
     0     0     0
 ans(:,:,2) =
     0     0     0
     0     0     0

Однако вы рассчитываете ту же матрицу. Посмотрите на Numpy для пользователей Matlab, он поможет вам преобразовать код Matlab в Numpy.


Например, если вы используете OpenCV, вы можете создать образ, используя numpy, учитывая, что OpenCV использует представление BGR:

import cv2
import numpy as np

a = np.zeros((100, 100,3))
a[:,:,0] = 255

b = np.zeros((100, 100,3))
b[:,:,1] = 255

c = np.zeros((100, 200,3)) 
c[:,:,2] = 255

img = np.vstack((c, np.hstack((a, b))))

cv2.imshow('image', img)
cv2.waitKey(0)

enter image description here

Если вы посмотрите на матрицу c то увидите, что это матрица 100x200x3, которая в точности соответствует изображению на рисунке (красным, поскольку мы установили координату R на 255, а две другие остались на 0).

Ответ 3

Как бы ни говорили люди: "порядок не имеет значения, это просто соглашение", это ломается при входе в междоменные интерфейсы, переход IE из C-порядка в Fortran или какую-то другую схему упорядочения. Там очень важно, как именно выкладываются ваши данные и как фигура представлена в виде numpy.

По умолчанию numpy использует порядок C, что означает, что смежные элементы в памяти - это элементы, хранящиеся в строках. Вы также можете выполнить упорядочение FORTRAN ("F"), вместо этого элементы упорядочиваются по столбцам, индексируя смежные элементы.

Numpy shape также имеет свой собственный порядок, в котором она отображает форму. В numpy форма имеет наибольший шаг вперед, т.е. В трехмерном векторе это будет наименее непрерывное измерение, Z или страницы, 3-е затемнение и т.д. Так что при выполнении:

np.zeros((2,3,4)).shape

ты получишь

(2,3,4)

что на самом деле (frames, rows, columns). выполнение np.zeros((2,2,3,4)).shape вместо этого будет означать (metaframs, frames, rows, columns). Это имеет больше смысла, когда вы думаете о создании многомерных массивов в C, таких как языки. Для C++ создание несмежно определенного 4D массива приводит к array [ of arrays [ of arrays [ of elements ]]]. Это вынуждает вас ссылаться на первый массив, который содержит все другие массивы (4-е измерение), а затем одинаковые до конца (3-й, 2-й, 1-й), что приводит к синтаксису, например:

double element = array4d[w][z][y][x];

В Фортране этот порядок меняется на обратный (вместо x - первый array4d[x][y][z][w]), наиболее смежный с наименее смежным, а в matlab он становится все странным.

Matlab пытался сохранить как математическое упорядочение по умолчанию (строка, столбец), так и внутреннее использование столбцов для библиотек, и не следовать С соглашению о размерном упорядочении. В Matlab вы заказываете так:

double element = array4d[y][x][z][w];

который ограничивает все соглашения и создает странные ситуации, когда вы иногда индексируете, как если бы упорядочивались строки, а иногда упорядочивались столбцы (например, при создании матрицы).

На самом деле, Матлаб - не интуитивный, а не Нампи.