Как сделать альфа-композицию со списком данных RGBA в массивах numpy? - PullRequest
1 голос
/ 25 февраля 2020

Следуя этой формуле для альфа-смешения двух значений цвета, я буду sh применять ее к n numpy массивам данных изображения rgba (хотя ожидаемый вариант использования на практике будет иметь очень низкую верхнюю границу массивов, вероятно,> 5). В контексте, этот процесс будет ограничен массивами одинаковой формы.

Теоретически я мог бы добиться этого путем итерации, но ожидать, что это будет интенсивно в вычислительном отношении и ужасно неэффективным.

Какой самый эффективный способ применить функцию между двумя элементами в одной позиции между двумя массивами по всему массиву ?

Свободный пример:

# in context, the numpy arrays come from here, as either numpy data in the 
# first place or a path
def import_data(source):
    # first test for an extant numpy array
    try:
        assert(type(source) is np.ndarray)
        data = source
    except AssertionError:
        try:
            exists(source)
            data = add_alpha_channel(np.array(Image.open(source)))
        except IOError:
            raise IOError("Cannot identify image data in file '{0}'".format(source))
        except TypeError:
                raise TypeError("Cannot identify image data from source.")

    return data

# and here is the in-progress method that will, in theory composite the stack of 
# arrays; it context this is a bit more elaborate; self.width & height are just what  
# they appear to be—-the final size of the composited output of all layers

def render(self):
        render_surface = np.zeros((self.height, self.width, 4))
        for l in self.__layers:  
            foreground = l.render() # basically this just returns an np array
            # the next four lines just find the regions between two layers to 
            # be composited
            l_x1, l_y1 = l.origin
            l_x2 = l_x1 + foreground.shape[1]
            l_y2 = l_y1 + foreground.shape[0]
            background = render_surface[l_y1: l_y2, l_x1: l_x2]

            # at this point, foreground & background contain two identically shaped 
            # arrays to be composited; next line is where the function i'm seeking 
            # ought to go
            render_surface[l_y1: l_y2, l_x1: l_x2] = ?

1 Ответ

1 голос
/ 25 февраля 2020

Начиная с этих двух изображений RGBA:

enter image description here

enter image description here

Я реализовал формулу Вы связались с этим и придумали это:

#!/usr/local/bin/python3
from PIL import Image
import numpy as np

# Open input images, and make Numpy array versions
src  = Image.open("a.png")
dst  = Image.open("b.png")
nsrc = np.array(src, dtype=np.float)
ndst = np.array(dst, dtype=np.float)

# Extract the RGB channels
srcRGB = nsrc[...,:3]
dstRGB = ndst[...,:3]

# Extract the alpha channels and normalise to range 0..1
srcA = nsrc[...,3]/255.0
dstA = ndst[...,3]/255.0

# Work out resultant alpha channel
outA = srcA + dstA*(1-srcA)

# Work out resultant RGB
outRGB = (srcRGB*srcA[...,np.newaxis] + dstRGB*dstA[...,np.newaxis]*(1-srcA[...,np.newaxis])) / outA[...,np.newaxis]

# Merge RGB and alpha (scaled back up to 0..255) back into single image
outRGBA = np.dstack((outRGB,outA*255)).astype(np.uint8)

# Make into a PIL Image, just to save it
Image.fromarray(outRGBA).save('result.png')

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

enter image description here

...