Как мне эффективно создать изображение импульсного шума, используя numpy? - PullRequest
1 голос
/ 30 мая 2020

Я пытался создать зашумленное изображение, используя следующий фрагмент кода:

def toImpulse(img, coef=1.2): # img - > 3dim numpy array, returns impulse image
    bmp = np.zeros(shape=(img.shape[0], img.shape[1], 1), dtype=np.float)
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            bmp[i][j] = sum(img[i][j]) / 3

Здесь я суммирую по каналу RGB и делаю изображение одноканальным? Я предполагаю, что это можно записать как numpy .sum ()

    sum_ = 0
    max_ = np.amax(bmp)
    final = np.zeros(img.shape)
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            sum_ += bmp[i][j]
            if sum_ >= coef * max_:
                final[i][j] = 1
                sum_ -= coef * max_
            else:
                final[i][j] = 0

    return final

Но это оказалось очень медленным при обработке видео в реальном времени. Как я могу сделать его более эффективным, используя NumPy? Вот пример работы функции Исходное изображение Шумное изображение

Ответы [ 2 ]

2 голосов
/ 01 июня 2020

Ваш код занимает 539 мсек на моей машине. Если я использую Numpy для вычисления среднего значения трех цветовых каналов и избегаю записи нулей в выходное изображение, потому что оно уже инициализировано нулем следующим образом:

def metoImpulse(img, coef=1.2):
    # Get mean of the 3 colour channels
    bmp = np.mean(img, axis=-1, dtype=np.float32)
    sum_ = 0
    max_ = np.amax(bmp)
    final = np.zeros_like(img[...,0])
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            sum_ += bmp[i][j]
            if sum_ >= coef * max_:
                final[i][j] = 1
                sum_ -= coef * max_
    return final

Время уменьшится с 539 мс до 257 мс . Если я затем использую Numba, добавив декоратор перед моей функцией:

@jit(parallel=True)
def metoImpulse(img, coef=1.2):
   # Get mean of the 3 colour channels
   bmp = np.mean(img, axis=-1, dtype=np.float32)
   sum_ = 0
   max_ = np.amax(bmp)
   final = np.zeros_like(img[...,0])
   for i in range(img.shape[0]):
      for j in range(img.shape[1]):
         sum_ += bmp[i][j]
         if sum_ >= coef * max_:
            final[i][j] = 1
            sum_ -= coef * max_
   return final

Время уменьшится с 257 мс до 1,11 мс.

Входное изображение:

enter image description here

Выходное изображение:

enter image description here

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

Второй для l oop можно заменить на np.searchsorted в cumsum вашего массива.

def toImpulse2(img, coef=1.2): # img - > 3dim numpy array, returns impulse image
    bmp = img.sum(axis=2)
    max_ = bmp.max() * coef
    cumsum = np.cumsum(bmp)
    repeats = int(cumsum[-1] / max_)
    final = np.zeros((img.shape[0] * img.shape[1], img.shape[2]))
    final[np.searchsorted(cumsum, np.arange(1, repeats + 1) * max_)] = 1
    return final.reshape(img.shape)

Я использую img.sum() вместо img.mean(), чтобы все вычисления были целочисленными для точность. Для больших изображений разница между этим кодом и вашим кодом небольшая, потому что он работает с типом float.

...