Как объединить изображения в прозрачные слои? - PullRequest
1 голос
/ 25 марта 2019

Я работаю над видеоредактором для Raspberry Pi, и у меня проблема со скоростью размещения изображения поверх изображения.В настоящее время при использовании imagemagick для размещения одного изображения поверх другого требуется до 10 секунд, с использованием изображений 1080x1920 png на Raspberry Pi, и это слишком много.С увеличением количества изображений время также увеличивается.Есть идеи, как это ускорить?Код Imagemagick:

composite -blend 90 img1.png img2.png new.png

Видео редактор с поддержкой медленной непрозрачности здесь

-------- РЕДАКТИРОВАТЬ --------

чуть быстрее:

import numpy as np
from PIL import Image
size_X, size_Y = 1920, 1080#  put images resolution, else output may look wierd
image1 = np.resize(np.asarray(Image.open('img1.png').convert('RGB')), (size_X, size_Y, 3))
image2 = np.resize(np.asarray(Image.open('img2.png').convert('RGB')), (size_X, size_Y, 3))
output = image1*transparency+image2*(1-transparency)
Image.fromarray(np.uint8(output)).save('output.png')

Ответы [ 2 ]

3 голосов
/ 26 марта 2019

Мой Raspberry Pi в данный момент недоступен - все, что я хочу сказать, это то, что там было немного дыма, и я занимаюсь программным, а не аппаратным обеспечением! В результате я проверил это только на Mac. Используется Numba.

Сначала я использовал ваш код Numpy на этих 2 изображениях:

enter image description here

и

enter image description here

Затем я реализовал то же самое, используя Numba. Версия Numba на моем iMac работает в 5,5 раз быстрее. Поскольку Raspberry Pi имеет 4 ядра, вы можете попробовать поэкспериментировать с:

@jit(nopython=True,parallel=True)
def method2(image1,image2,transparency):
   ...

Вот код:

#!/usr/bin/env python3

import numpy as np
from PIL import Image

import numba
from numba import jit

def method1(image1,image2,transparency):
   result = image1*transparency+image2*(1-transparency)
   return result

@jit(nopython=True)
def method2(image1,image2,transparency):
   h, w, c = image1.shape
   for y in range(h):
      for x in range(w):
         for z in range(c):
            image1[y][x][z] = image1[y][x][z] * transparency + (image2[y][x][z]*(1-transparency))
   return image1

i1 = np.array(Image.open('image1.jpg').convert('RGB'))
i2 = np.array(Image.open('image2.jpg').convert('RGB'))

res = method1(i1,i2,0.4)
res = method2(i1,i2,0.4)

Image.fromarray(np.uint8(res)).save('result.png')

Результат:

enter image description here

Другие мысли ... Я сделал композит на месте, переписав ввод image1, чтобы попытаться сэкономить место в кеше. Это может помочь или помешать - пожалуйста, экспериментируйте. Возможно, я не обработал пиксели в оптимальном порядке - пожалуйста, поэкспериментируйте.

2 голосов
/ 27 марта 2019

Так же, как и другой вариант, я попробовал в pyvips (полное раскрытие: я сопровождающий pyvips, поэтому я не очень нейтрален):

#!/usr/bin/python3

import sys
import time
import pyvips

start = time.time()

a = pyvips.Image.new_from_file(sys.argv[1], access="sequential")
b = pyvips.Image.new_from_file(sys.argv[2], access="sequential")
out = a * 0.2 + b * 0.8
out.write_to_file(sys.argv[3])

print("pyvips took {} milliseconds".format(1000 * (time.time() - start)))

pyvips является«конвейерная» библиотека обработки изображений, так что код будет выполнять загрузку, обработку и сохранение всего параллельно.

На этом двухъядерном ноутбуке i5 с четырьмя потоками, используя два тестовых изображения Марка, которые я вижу:

$ ./overlay-vips.py blobs.jpg ships.jpg x.jpg
took 39.156198501586914 milliseconds

Итак, 39 мс для двух загрузок jpg, обработки и одного сохранения jpg.

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

a = pyvips.Image.new_from_file(sys.argv[1]).copy_memory()
b = pyvips.Image.new_from_file(sys.argv[2]).copy_memory()

start = time.time()
out = (a * 0.2 + b * 0.8).copy_memory()
print("pyvips between memory buffers took {} milliseconds"
        .format(1000 * (time.time() - start)))

Я вижу:

$ ./overlay-vips.py blobs.jpg ships.jpg x.jpg 
pyvips between memory buffers took 15.432596206665039 milliseconds

В этом же тесте numpy составляет около 60 мс.

Я попробовал небольшой вариант красивого примера Марка numba:

#!/usr/bin/python3

import sys
import time
import numpy as np
from PIL import Image

import numba
from numba import jit, prange

@jit(nopython=True, parallel=True)
def method2(image1, image2, transparency):
   h, w, c = image1.shape
   for y in prange(h):
      for x in range(w):
         for z in range(c):
            image1[y][x][z] = image1[y][x][z] * transparency \
                    + (image2[y][x][z] * (1 - transparency))
   return image1

# run once to force a compile
i1 = np.array(Image.open(sys.argv[1]).convert('RGB'))
i2 = np.array(Image.open(sys.argv[2]).convert('RGB'))
res = method2(i1, i2, 0.2)

# run again and time it
i1 = np.array(Image.open(sys.argv[1]).convert('RGB'))
i2 = np.array(Image.open(sys.argv[2]).convert('RGB'))

start = time.time()
res = method2(i1, i2, 0.2)
print("numba took {} milliseconds".format(1000 * (time.time() - start)))

Image.fromarray(np.uint8(res)).save(sys.argv[3])

И я вижу:

$ ./overlay-numba.py blobs.jpg ships.jpg x.jpg 
numba took 8.110523223876953 milliseconds

Итак, на этом ноутбуке numba примерно в 2 раза быстрее, чем pyvips.

Если вы также загружаете и сохраняете время, это немного медленнее:

$ ./overlay-numba.py blobs.jpg ships.jpg x.jpg 
numba plus load and save took 272.8157043457031 milliseconds

Но это кажется несправедливым, поскольку почти все это время загружается и сохраняется в PIL.

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