Индексирование и маскирование массива Python Numpy - PullRequest
0 голосов
/ 07 января 2019

Мне нужна помощь в индексации 3-мерного массива (изображения RGB / BGR) с использованием 2-мерного массива индексов. Все значения равны 0, 1 или 2 для разных цветовых каналов. Результатом должен быть двумерный массив значений цвета. Если кто-нибудь может сказать мне синтаксис этого в python, это было бы здорово!

Для контекста того, что я пытаюсь сделать (также прочитайте TLDR ниже):

Я, по сути, пытаюсь преобразовать следующий код из обычного для синтаксиса цикла, который очень и очень медленный, в более эффективный синтаксис python / numpy:

colorIndices = np.zeros((height,width));       # an array which has the index of the outstanding color
colorIndices -= 1;           # all -1's

for x in range(0,width):
    for y in range(0,height):

        pix = img[y,x];        # get the pixel, a 1D array of length 3
        colorID = np.argmax(pix);           #get which index has max value (candidate for outstanding color)

        if(pix[colorID]>np.average(pix)+np.std(pix)):      # if that value is more than one std dev away from the overall pixel's value, the pixel has an outstanding color
            colorIndices[y,x] = colorID;

Затем я хотел бы получить доступ к цветным каналам в каждом пикселе, используя что-то вроде:

img[:,:,:]=0;
img[colorIndices] = 255;

TLDR: Я хочу установить пиксель на чистый синий, зеленый или красный, если это оттенок этого цвета. Я определяю, является ли пиксель оттенком красного, если значение R пикселя более чем на одно стандартное значение выше среднего общего распределения {R, G, B}.

Неработающий код, который у меня пока есть:

  colorIDs = np.argmax(img, axis=2);

  averages = np.average(img, axis=2);
  stds = np.std(img, axis=2);
  cutoffs = averages + stds;

  print(img[colorIDs]);

Here is an example of the image I am using

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Вы можете преобразовать числовой индекс по заданной оси в значения, вы можете использовать np.take_along_axis или Необычное индексирование . При использовании причудливого индекса необходимо индексировать по всем осям массивы, формы которых соответствуют размеру конечного результата. np.ogrid помогает в этом. Для массива MxNx3 img (M, N, _ = img.shape), если бы у вас было ix = np.argmax(img, axis=2), индекс выглядел бы так:

r, c = np.ogrid[:M, :N]
maxes = img[r, c, ix]

Использование take_along_axis экономит вам шаг и несколько временных массивов:

maxes = np.take_along_axis(img, ix, 2)

Теперь создайте свою маску:

significant = np.abs(maxes - img.mean(axis=2) > img.std(axis=2))

На данный момент у вас есть двумерная логическая маска и целочисленный индекс в третьем измерении. Самое простое, наверное, превратить все в линейный индекс:

r, c = np.where(significant)

Теперь вы можете построить вывод:

color_index = np.zeros_like(img)
color_index[r, c, ix[significant]] = 255

Несмотря на соблазн, np.put_along_axis не может использоваться здесь прямым способом. Проблема в том, что маскировка ix с significant сделает недействительным сходство форм. Однако вы можете создать промежуточный 2D-массив, содержащий 255 в местах, отмеченных significant, и использовать его с put_along_axis:

values = np.zeros(significant.shape, dtype=img.dtype)
values[significant] = 255
color_index = np.zeros_like(img)
np.put_along_axis(color_index, ix, values, 2)

Все вместе:

ix = np.argmax(img, axis=2)
significant = np.abs(np.take_along_axis(img, ix, 2) - img.mean(axis=2)) > img.std(axis=2)
color_index = np.zeros_like(img)
color_index[(*np.where(significant), ix[significant])] = 255
0 голосов
/ 07 января 2019

Я думаю, что вы хотите применить 2d индексную маску от argmax ко 2-й оси:

In [38]: img=np.random.randint(0,10,(16,16,3))
In [39]: ids = np.argmax(img, axis=2)
In [40]: ids
Out[40]: 
array([[0, 1, 2, 1, 2, 0, 0, 0, 2, 2, 1, 0, 1, 2, 1, 0],
       [0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1],
       [1, 1, 0, 0, 0, 0, 1, 2, 0, 2, 2, 1, 2, 1, 1, 0],
       [2, 0, 1, 2, 0, 0, 1, 1, 0, 2, 2, 1, 1, 1, 1, 2],
       [2, 2, 1, 1, 0, 1, 0, 2, 1, 0, 0, 2, 2, 0, 1, 2],
       [1, 0, 2, 1, 0, 2, 0, 1, 0, 1, 1, 2, 1, 1, 0, 2],
       [1, 0, 0, 0, 1, 2, 1, 0, 1, 2, 1, 1, 1, 2, 0, 0],
       [1, 2, 2, 2, 0, 0, 1, 1, 0, 1, 0, 2, 2, 1, 1, 0],
       [0, 2, 2, 1, 0, 0, 1, 0, 2, 1, 1, 0, 2, 1, 1, 0],
       [1, 0, 2, 1, 2, 0, 1, 1, 0, 2, 2, 2, 1, 1, 0, 1],
       [1, 1, 1, 1, 1, 2, 1, 1, 0, 2, 1, 0, 0, 1, 0, 0],
       [1, 2, 1, 0, 2, 2, 2, 1, 0, 1, 2, 1, 2, 0, 2, 1],
       [2, 0, 2, 1, 2, 0, 1, 1, 2, 2, 2, 2, 1, 0, 2, 1],
       [0, 1, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 0, 2, 0, 1],
       [0, 1, 2, 1, 1, 0, 1, 2, 0, 1, 0, 0, 2, 1, 0, 2],
       [0, 0, 2, 2, 2, 2, 2, 1, 0, 0, 0, 2, 0, 0, 1, 1]])
In [41]: I,J = np.ix_(np.arange(16), np.arange(16))
In [42]: img[I,J,ids]
Out[42]: 
array([[5, 9, 9, 8, 8, 8, 5, 7, 1, 9, 9, 5, 5, 9, 6, 8],
       [6, 7, 5, 8, 5, 6, 9, 6, 7, 7, 7, 8, 3, 7, 9, 5],
       [7, 6, 8, 7, 6, 9, 6, 8, 9, 5, 8, 8, 9, 7, 9, 6],
       [8, 9, 3, 4, 7, 5, 8, 4, 4, 9, 1, 4, 9, 9, 9, 7],
       [9, 8, 9, 7, 9, 8, 7, 5, 8, 9, 9, 6, 9, 5, 8, 8],
       [7, 9, 8, 8, 9, 3, 6, 9, 8, 6, 8, 7, 7, 7, 7, 7],
       [8, 8, 5, 8, 9, 8, 8, 2, 8, 7, 8, 9, 5, 5, 6, 7],
       [9, 6, 6, 9, 5, 3, 6, 4, 7, 6, 8, 8, 6, 3, 9, 9],
       [7, 8, 9, 7, 5, 7, 5, 9, 6, 4, 7, 7, 8, 5, 7, 8],
       [9, 7, 6, 4, 8, 9, 3, 8, 9, 2, 6, 9, 6, 7, 9, 7],
       [9, 8, 6, 6, 5, 9, 3, 9, 2, 4, 9, 5, 9, 9, 6, 9],
       [8, 7, 8, 3, 8, 8, 9, 7, 9, 5, 9, 8, 6, 9, 7, 8],
       [8, 2, 7, 7, 4, 5, 9, 8, 8, 8, 6, 5, 3, 9, 9, 6],
       [6, 8, 8, 5, 8, 8, 8, 9, 3, 7, 7, 8, 5, 4, 2, 9],
       [3, 7, 9, 9, 8, 5, 9, 8, 9, 7, 3, 3, 9, 5, 5, 9],
       [8, 4, 3, 6, 4, 9, 9, 9, 9, 9, 9, 7, 9, 7, 5, 8]])

В последних версиях NumPy есть функция, которая делает это для нас

np.take_along_axis(img, ids[:,:,None], 2)[:,:,0]

и для установки значений np.put_along_axis.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...