Документация Engee

Комбинирование слоев

В этой демонстрации показано, как можно реализовать послойную альфа-композицию с помощью 10 строк кода с использованием OffsetArrays и PaddedViews. Если вам нужны более строго организованные средства, ColorBlendModes предоставляет определения и операции композиции для режимов наложения.

using Images
using OffsetArrays # предоставляем `OffsetArray`

1. Базовая операция смещения и дополнения

Предположим, у нас есть два объекта прозрачного цвета и мы хотим разместить их на холсте с частичным перекрытием.

red_patch = fill(RGBA(1., 0., 0., 1), 24, 24)
green_patch = fill(RGBA(0., 1., 0., 1), 32, 32)
mosaicview(red_patch, green_patch; npad=20, nrow=1, fillvalue=colorant"white")
fblbieu

Предположим, что оси холста начинаются с (1, 1); здесь мы оставляем красный участок без смещения, а зеленый участок смещаем на 6 пикселей вниз и на 16 пикселей вправо, после чего выполняем их дополнение до общих осей.

green_o = OffsetArray(green_patch, 6, 16)
r, g = paddedviews(Gray(0.2), red_patch, green_o)
mosaicview(r, g; npad=20, nrow=1, fillvalue=colorant"white")
smegeds

Обратите внимание, что их оси и размеры изменились после смещения и дополнения:

# Независимо от особенностей реализации `Base.OneTo(32)` практически эквивалентно `1:32`
println("before shifting -- size: ", size(green_patch), " axes: ", axes(green_patch))
println("after shifting  -- size: ", size(green_o), " axes: ", axes(green_o))
println("after padding   -- size: ", size(g), " axes: ", axes(g))
before shifting -- size: (32, 32) axes: (Base.OneTo(32), Base.OneTo(32))
after shifting  -- size: (32, 32) axes: (OffsetArrays.IdOffsetRange(values=7:38, indices=7:38), OffsetArrays.IdOffsetRange(values=17:48, indices=17:48))
after padding   -- size: (38, 48) axes: (Base.IdentityUnitRange(1:38), Base.IdentityUnitRange(1:48))

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

r[axes(red_patch)...]
g[axes(green_o)...]

Как описано в этой статье, существует несколько методов комбинирования:

# операция сложения
out_add = r .+ g

# операция очистки
out_clear = copy(r)
out_clear[axes(green_o)...] .= colorant"black"

# операция умножения
out_mul = copy(r)
# поканальное умножение
channelview(out_mul)[:, axes(green_o)...] .*= channelview(green_o)

# операция перекрытия
out_over = copy(r)
out_over[axes(green_o)...] .= green_o

# отображаем результаты этих операций
mosaicview(out_add, out_clear, out_mul, out_over;
           npad=20, nrow=1, fillvalue=colorant"white")
ouvjljq

2. Построение панели трех основных цветов

Теперь давайте воспользуемся тем же приемом, чтобы создать что-то более осмысленное. Сначала создадим три круга красного, зеленого и синего цветов.

using ImageDraw
function make_circle(sz, c::T) where T
    # заполняем прозрачным цветом, чтобы устранить черную область
    fillvalue = ARGB(c)
    img = fill(ARGB{eltype(T)}(0., 0., 0., 0.), sz...)
    origin = sz .÷ 2
    r = sz .÷ 4
    draw!(img, Ellipse(origin..., r...), fillvalue)
    img
end

# создаем три круга красного, зеленого и синего цветов
red_c   = make_circle((256, 256), ARGB(1., 0., 0., 1.))
green_c = make_circle((256, 256), ARGB(0., 1., 0., 1.))
blue_c  = make_circle((256, 256), ARGB(0., 0., 1., 1.))

mosaicview(red_c, green_c, blue_c; nrow=1)
snqheub

Затем сместим эти круги в соответствующие позиции, дополним их до общих осей и, наконец, скомбинируем с помощью операции сложения:

r = size(red_c, 1) ÷ 8
red_o   = OffsetArray(red_c,    r,  r)
green_o = OffsetArray(green_c, -r,  0)
blue_o  = OffsetArray(blue_c,   r, -r)

color_panel = sum(paddedviews(zero(eltype(red_o)), red_o, green_o, blue_o))
color_panel = color_panel[axes(red_c)...] # обрезаем пустую область
uimfbud

Эта страница была создана с помощью DemoCards.jl и Literate.jl.