Применение функции отображения к каждому члену ndarray с индексами в качестве аргументов - PullRequest
0 голосов
/ 17 декабря 2018

У меня есть ndarray, представляющий RGB-изображение с формой (ширина, высота, 3), и я хочу заменить каждое значение результатом какой-либо функции, его положения и цветового канала, к которому оно принадлежит.Делать это в трех вложенных циклах for очень медленно, есть ли способ выразить это как собственную операцию с массивом?

Редактировать: искать решение на месте - такое, которое не требует создания другой O (width)x height) ndarray (если только numpy не обладает магией, которая может помешать выделению такого ndarray)

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Обратите внимание на квалификацию во многих комментариях, непосредственное использование математической арифметики часто будет проще и быстрее.

import numpy as np

def test(item, ix0, ix1, ix2):
    # A function with the required signature. This you customise to suit.
    return item*(ix0+ix1+ix2)//202

def make_function_for(arr, f):
''' where arr is a 3D numpy array and f is a function taking four arguments.
        item : the item from the array
        ix0 ... ix2 : the three indices
    it returns the required result from these 4 arguments. 
'''
    def user_f(ix0, ix1, ix2):
        # np.fromfunction requires only the three indices as arguments.
        ix0=ix0.astype(np.int32)
        ix1=ix1.astype(np.int32)
        ix2=ix2.astype(np.int32)
        return f(arr[ix0, ix1, ix2], ix0, ix1, ix2)
    return user_f
    # user_f is a function suitable for calling in np.fromfunction

a=np.arange(100*100*3)
a.shape=100,100,3
a[...]=np.fromfunction(make_function_for(a, test), a.shape)

Моя тестовая функция довольно проста, поэтому я могу сделать это просто.

Использование fromfunction:

%timeit np.fromfunction(make_function_for(a, test), a.shape)
5.7 ms ± 346 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Использование арифметики numy:

def alt_func(arr):
    temp=np.add.outer(np.arange(arr.shape[0]), np.arange(arr.shape[1]))
    temp=np.add.outer(temp,np.arange(arr.shape[2]))
    return arr*temp//202

%timeit alt_func(a)
967 µs ± 4.94 µs per loop  (mean ± std. dev. of 7 runs, 1000 loops each)

Так что арифметика numpy почти в 6 раз быстрее на моем компьютере для этого случая.

Отредактировано, чтобы исправить мои, казалось бы, неизбежные опечатки!

0 голосов
/ 18 декабря 2018

Я не уверен, правильно ли я понял ваш вопрос!Насколько я понял, вы хотите применить сопоставление для каждого канала вашего изображения RGB на основе соответствующих им индексов, если да, то приведенный ниже код MIGHT поможет, поскольку в вашем вопросе нет подробностей.

import numpy as np

bit_depth = 8
patch_size = 32    

def lut_generator(constant_multiplier):
    x = np.arange(2 ** bit_depth)
    y = constant_multiplier * x
    return dict(zip(x, y))


rgb = np.random.randint(0, (2**bit_depth), (patch_size, patch_size, 3))
# Considering a simple lookup table without using indices.
lut = lut_generator(5)

# splitting three channels followed and their respective indices.
# You can use indexes wherever you need them.
r, g, b = np.dsplit(rgb, rgb.shape[-1])
indexes = np.arange(rgb.size).reshape(rgb.shape)
r_idx, g_idx, b_idx = np.dsplit(indexes, indexes.shape[-1])

# Apply transformation on each channel.
transformed_r = np.vectorize(lut.get)(r)
transformed_g = np.vectorize(lut.get)(g)
transformed_b = np.vectorize(lut.get)(b)

Удачи!

...