Как эффективно использовать пиксельное голосование в векторизованной форме в 3D NumPy матрице для создания новой 2D матрицы? - PullRequest
1 голос
/ 04 мая 2020

У меня есть матрица NumPy формы (n, height, width), содержащая изображения в градациях серого в диапазоне uint8. Каждый слой (всего n) содержит прогноз из нейронной сети. Я хотел бы сравнить все n layers и для каждого пикселя получить второе наиболее распространенное значение и создать новую матрицу формы (height, width) с этим новым значением. Другими словами, я использую голосование за пиксель, чтобы создать новую 2D матрицу из всех матриц в многоуровневой. Я предпочитаю второе наиболее распространенное значение, поскольку самым распространенным является 3 по разным причинам, и я хотел бы игнорировать это; Вот почему я ищу второе наиболее распространенное значение с mode(vote[vote != 3], axis=None)[0][0]. Ниже приведено рабочее решение. Тем не менее, это не очень быстро, так как я должен медленно повторять. Я хотел бы использовать векторизованное решение для экономии времени.

import numpy
from scipy.stats import mode

n = 84
height = 1872
width = 3128

layered_image = numpy.ndarray(shape=(n, height , width), dtype=numpy.uint8)
image = numpy.ndarray(shape=(height , width), dtype=numpy.uint8)

for i in range(0, height):
    for j in range(0, width):
        vote = []
        for k in range(len(layered_image)):
            vote.append(layered_image[k][i][j])
        vote = numpy.asarray(vote, dtype=numpy.uint8)
        image[i][j] = mode(vote[vote != 3], axis=None)[0][0]

Спасибо за любые предложения.

Ответы [ 2 ]

0 голосов
/ 06 мая 2020

Благодаря Divakar , метод bincounting отлично работал для моих целей. Чтобы предотвратить чрезмерное использование оперативной памяти при работе с огромным количеством слоев, я добавил нарезку к этому методу. Это немного медленнее, но позволяет обрабатывать на машинах с меньшим объемом памяти; учитывая, что slice_coordinates является списком, содержащим координаты верхнего левого угла всех фрагментов изображения в кортежах (y, x), prediction_overlay многослойного изображения и prediction_mask нового 2D-изображения, нарезка работает следующим образом:

for i in range(len(slice_coordinates)):
    to_process = prediction_overlay [:, slice_coordinates[i][0] : slice_coordinates[i][0] + tile_height, slice_coordinates[i][1] : slice_coordinates[i][1] + tile_width]

    b = bincount2D_vectorized(to_process.reshape(to_process.shape[0],-1).T)
    processed = b[:,:-1].argmax(1).reshape(to_process.shape[1:])

    prediction_mask [slice_coordinates[i][0] : slice_coordinates[i][0] + tile_height, slice_coordinates[i][1] : slice_coordinates[i][1] + tile_width] = processed
0 голосов
/ 04 мая 2020

Один способ будет с равенством внешнего вещания -

np.equal.outer(layered_image,np.arange(3)).sum(0).argmax(-1)

Другой - с обработкой маски -

# a is the input layered_image
c0,c1,c2 = (a==0).sum(0), (a==1).sum(0), (a==2).sum(0)
out = np.where(np.maximum(c0,c1)>c2, np.where(c0>c1,0,1), 2)

Другой с 2D bincount -

# https://stackoverflow.com/a/46256361/ @Divakar
def bincount2D_vectorized(a):    
    N = a.max()+1
    a_offs = a + np.arange(a.shape[0])[:,None]*N
    return np.bincount(a_offs.ravel(), minlength=a.shape[0]*N).reshape(-1,N)

# a is the input layered_image
b = bincount2D_vectorized(a.reshape(a.shape[0],-1).T)
out = b[:,:-1].argmax(1).reshape(a.shape[1:])
...