图层混合简介
图层混合(blend)顾名思义,就是把两个图层混合成一个。
最基本的混合是alpha融合(alpha compositing),这是一个遵循光的反射与透射等(简化版)物理学原理的混合方式。
各个图像处理软件中,往往还提供很多具有一定艺术风格的混合方法,这是本文的主要讨论内容。但须注意,为了更深入地理解混合模式,alpha融合是必需要掌握的前提知识。
为了更好地理解本文内容,我们做如下约定:
- 所有色彩是归一化的,也就是值域在[0, 1]之间(而非[0, 255]),否则不仅公式不容易写,而且还不适配hdr的情况。
- 一般情况下,混合都是逐像素,大部分时候甚至逐通道计算。(在Photoshop中,仅有
深色
和浅色
不是逐通道计算) - 部分混合模式满足交换律,即交换两个图层的上下位置,结果不变。
- 一些混合模式的结果要求截断到[0, 1]之间,否则会发生不可预测的结果,这些混合模式仅能作用于int类型的数值;还有一些则不要求,这些则能作用于float类型的数值,其结果可以越过[0, 1]范围。
Photoshop中的混合模式
截止2022版本,Photoshop中有27个混合模式,分为六大类,各类别以及包含的混合模式为:
- 正常类别:
正常,溶解
- 变暗类别:
变暗,正片叠底,颜色加深,线性加深,深色
- 变亮类别:
变亮,滤色,颜色减淡,线性减淡(添加),浅色
- 复杂类别:
叠加,柔光,强光,亮光,线性光,点光,实色混合
- 差异类别:
差值,排除,减去,划分
- HSL类别:
色相,饱和度,颜色,明度
除了溶解(Dissolve)
模式以外,其他的混合都有明确的公式,溶解靠随机数实现,随着透明度降低,有越来越多的随机像素点的alpha通道会变成0,这样就会随机地显示出下方图层,表现得好像溶解了一样。本文主要讲有公式的那些混合模式,溶解不在此列,所以这里简单描述一下,后面就不再提了。
为了全面理解混合模式的公式,需要首先从RGB出发(即alpha通道恒等于1),在了解了RGB的混合之后,要基于此知识进一步推导RGBA的混合公式,也就是含透明度信息情况下的公式,真正写程序时候一般使用RGBA的公式即可,因为RGBA涵盖了RGB的情况。
部分混合模式在RGB情况下,交换前景与背景图后效果相同,此类混合模式有:变暗,正片叠底,线性加深,深色,变亮,滤色,线性减淡(添加),浅色,差值,排除,实色混合
公式符号约定
fg:foreground,表示前景,即处于上方的图层
bg:background,表示背景,即处于下方的图层
f
g
c
fg_c
fgc:表示前景的rgb部分,其中脚标_c是color的意思。背景的脚标含义同理,下面不再赘述。
f
g
α
fg_\alpha
fgα:表示前景的透明通道
f
g
c
α
fg_{c\alpha}
fgcα:表示前景rgb与alpha通道相乘的结果,即alpha预乘。
在写代码时,还需注意除法
的问题:所有的除法必需要考虑避免除以0的情况,因此碰到除法时应做如下保护:
a
b
=
a
m
a
x
(
b
,
e
p
s
)
\frac{a}{b} = \frac{a}{max(b, eps)}
ba=max(b,eps)a
接下来的公式中不会赘述这一点,但各位读者写代码时需自行注意。
RGB混合公式
正常(Normal)
仅显示上方图层。
N
o
r
m
a
l
(
f
g
c
,
b
g
c
)
=
f
g
c
Normal(fg_c,bg_c) = fg_c
Normal(fgc,bgc)=fgc
变暗(Darken)
取两图层中数值较小者。
D
a
r
k
e
n
(
f
g
c
,
b
g
c
)
=
m
i
n
(
f
g
c
,
b
g
c
)
Darken(fg_c, bg_c) = min(fg_c, bg_c)
Darken(fgc,bgc)=min(fgc,bgc)
正片叠底(Multiply)
上下两图层相乘。
M
u
l
t
i
p
l
y
(
f
g
c
,
b
g
c
)
=
f
g
c
∗
b
g
c
Multiply(fg_c, bg_c) = fg_c * bg_c
Multiply(fgc,bgc)=fgc∗bgc
前景与背景为同一个图片时,等同于如下曲线调节:
https://www.desmos.com/calculator/8blh2zzaqc
颜色加深(Color Burn)
让背景图层颜色变暗,变暗的程度由前景决定,前景越暗,背景变暗的程度就越强。
C
o
l
o
r
B
u
r
n
(
f
g
c
,
b
g
c
)
=
{
0
,
if:
f
g
c
=
=
0
1
−
m
i
n
(
1
−
b
g
c
f
g
c
,
1
)
,
if:
f
g
c
>
0
ColorBurn(fg_c, bg_c) = \begin{cases} 0, &\text{if: } fg_c == 0 \\[2ex] 1 - min(\frac{1 - bg_c}{fg_c}, 1), &\text {if: } fg_c>0 \end{cases}
ColorBurn(fgc,bgc)=⎩
⎨
⎧0,1−min(fgc1−bgc,1),if: fgc==0if: fgc>0
前景与背景为同一个图片时,等同于如下曲线调节:
https://www.desmos.com/calculator/5xdaojgl3p
线性加深(Linear Burn)
前景与背景相加后减1。效果类似颜色加深,只是变暗的曲线是线性的。
L i n e a r B u r n ( f g c , b g c ) = m a x ( f g c + b g c − 1 , 0 ) LinearBurn(fg_c, bg_c) =max(fg_c+bg_c-1, 0) LinearBurn(fgc,bgc)=max(fgc+bgc−1,0)
前景与背景为同一个图片时,等同于如下曲线调节:
https://www.desmos.com/calculator/akmwl8cert
深色(Darker Color)
计算上下两通道的灰度值,谁的灰度值小,结果颜色就取相应图层的rgb颜色。
注意该模式是少有的非逐通道
计算的混合模式。该模式不产生fg和bg以外的新的颜色。
变亮(Lighten)
取两图层中数值较大者。
L i g h t e n ( f g c , b g c ) = m a x ( f g c , b g c ) Lighten(fg_c, bg_c)=max(fg_c,bg_c) Lighten(fgc,bgc)=max(fgc,bgc)
滤色(Screen)
滤色是模拟光的反射与透射原理设计的混合模式。如果光照到图片后,我们把反射回来的记为我们看到的图像本身,那么透射过去的就是(1-image),也可以称之为负片
,光透过两个图层以后的负片就是(1-fg)(1-bg)
,对这个结果整体再来个负片,就是滤色的效果。光透过多个图层后一定是越来越暗的,所以最终再做一个整体的负片,就一定是变亮的,并且根据物理原理(或更简单一些,可以根据公式),如果各个输入图层在[0, 1]之间,那么结果就一定也在[0, 1]之间,不会产生数值截断,这是一个非常好的特性。
滤色是非常重要的一种混合模式,是各类发光效果最最常用的混合模式(bloom、glow等)。
S
c
r
e
e
n
(
f
g
c
,
b
g
c
)
=
1
−
(
1
−
f
g
c
)
∗
(
1
−
b
g
c
)
Screen(fg_c,bg_c)=1-(1-fg_c)*(1-bg_c)
Screen(fgc,bgc)=1−(1−fgc)∗(1−bgc)
前景与背景为同一个图片时,等同于如下曲线调节:
https://www.desmos.com/calculator/sa04opay5a
颜色减淡(Color Dodge)
让背景图层颜色变亮,变亮的程度由前景决定,前景越亮,背景变亮的程度就越强。
C o l o r D o d g e ( f g c , b g c ) = { 1 , if: f g c = = 1 m i n ( b g c 1 − f g c , 1 ) , otherwise ColorDodge(fg_c, bg_c) = \begin{cases} 1, &\text{if: } fg_c == 1 \\[2ex] min(\frac{bg_c}{1-fg_c}, 1), &\text {otherwise} \end{cases} ColorDodge(fgc,bgc)=⎩ ⎨ ⎧1,min