Эффективный режим наложения в Python максимально эффективно (Numpy, OpenCV) - PullRequest
0 голосов
/ 03 сентября 2018

Предположим, у меня есть два массива изображений a и b одинаковых размеров, 8-битный цвет, формат RGB. Теперь предположим, что я хочу создать новый массив NumPy, чьи значения пикселей совпадают со значениями двух предыдущих в сочетании с использованием режима наложения «Наложение».

Его определение, взятое из Википедии, выглядит следующим образом, где b - верхний слой, а a - нижний слой:

enter image description here

В формуле я считаю, что a и b представлены в терминах их "белизны" в том смысле, что полностью белый пиксель равен 1, а полностью черный пиксель равен 0. Я не уверен, как играет оттенок в это.

Я не уверен, есть ли более быстрый способ сделать это, кроме как перебирать два изображения попиксельно, что ДЕЙСТВИТЕЛЬНО медленно для изображений 1920x1080. Мне нужно быть в состоянии сделать это как можно быстрее.

Например, мне удалось реализовать режим смешивания Addition следующим образом:

import numpy as np
import cv2

a = cv2.imread("a.jpg", cv2.IMREAD_UNCHANGED)
b = cv2.imread("b.jpg", cv2.IMREAD_UNCHANGED)

a = a.astype(float)
b = b.astype(float)

ab = a
for i in range(len(ab)):
  ab[i] = a[i] + b[i]

cv2.imwrite('Out.png', ab)

Кажется, что это довольно быстро, и, конечно, гораздо быстрее, чем пытаться достичь того же, перебирая пиксель за пикселем. Но еще раз, это всего лишь режим наложения Addition, и мне нужен режим наложения Overlay.

Если вам известна какая-либо реализация Python режима наложения Overlay между двумя RGB-изображениями в форме очень маленьких массивов, который очень эффективен, пожалуйста, помогите мне найти его. Если нет, можете ли вы реализовать его максимально эффективно?

1 Ответ

0 голосов
/ 03 сентября 2018
import numpy as np
import cv2

a = cv2.imread("a.jpg", cv2.IMREAD_UNCHANGED)
b = cv2.imread("b.jpg", cv2.IMREAD_UNCHANGED)

a = a.astype(float)/255  
b = b.astype(float)/255 # make float on range 0-1

mask = a >= 0.5 # generate boolean mask of everywhere a > 0.5 
ab = np.zeros_like(a) # generate an output container for the blended image 

# now do the blending 
ab[~mask] = (2*a*b)[~mask] # 2ab everywhere a<0.5
ab[mask] = (1-2*(1-a)*(1-b))[mask] # else this 

Я думаю, что это должно сделать. Теперь ab является плавающим изображением на -1,2 и представляет собой смесь a и b. Это будет относительно быстро, потому что вместо цикла используется broadcasting и masking. Мне любопытно услышать разницу в скорости.


После материала, добавленного Марком Сетчеллом 16-NOV-2018, просто чтобы вы все знали, кто виноват: -)

Значения, рассчитанные по коду г-на Каякса, являются значениями с плавающей точкой в ​​диапазоне 0..1, тогда как imwrite() ожидает значения uint8s в диапазоне 0..255. Так что вам просто нужно добавить следующее в нижней части его кода:

# Scale to range 0..255 and save
x=(ab*255).astype(np.uint8) 
cv2.imwrite('result.png',x) 

Если затем взять эти два изображения как a.jpg и b.jpg:

enter image description here enter image description here

Слева вы получите результат - тот, что справа, вы получите в Photoshop, если выберете Наложение Режим наложения:

enter image description here enter image description here

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