终端图像处理系列 - 图像混合模式的Shader实现
在图像处理应用中,将两张或者多张图片混合显示是非常常见的一种操作,应用场景包括但不限于:加水印、标签,插入画中画,遮盖等等。
最常见的图像混合模式是普通混合模式,比如加水印。对于叠加在原图上的水印图片,其中根据透明度来选择原图和水印图片像素所占的权重,从而可以形成一个半透明的水印。
除了普通混合模式外,还有多种图像混合模式,包括但不局限于:正片叠底(multiply)、滤色模式(screen)、叠加模式(overlay)、柔光模式(softlight)、强光模式(hardlight)、增加模式(add)、减去模式(subtract)等等。每一种混合模式都对应了一种函数T=F(S,D),其中,T是混合后的像素颜色,S表示用于混合的像素颜色,D表示底图的像素颜色(S,D,T的取值范围都是0~1)。
下面是各种混合模式的计算公式,这里选择最常见的12种混合模式作为例子。其它的混合模式可以类似实现。
混合模式 |
公式 |
条件、备注 |
---|---|---|
normal |
T=S |
|
multiply |
T=S*D |
|
screen |
T=1-(1-S)*(1-D) |
|
overlay |
T=2*S*D |
D<0.5 |
|
T=1-2*(1-S)*(1-D) |
D>=0.5 |
hardlight |
T= 2*S*D |
S<0.5 |
|
T=1-2*(1-S)*(1-D) |
S>=0.5 |
softlight |
T=2*S*D+D*D*(1-2*S) |
S<0.5 |
|
T=2*D*(1-S)+sqrt(D)*(2*S-1) |
S>=0.5 |
divide |
T=D/S |
D/S取0~1之间 |
add |
T=D+S |
D+S取0~1之间 |
subtract |
T=D-S |
D-S取0~1之间 |
diff |
T=|D-S| |
|
darken |
T=MIN(D,S) |
|
lighten |
T=MAX(D,S) |
|
另外,当融合图片是半透明的时候(α值不是1),融合后的像素值T’=T*α+(1-α)*D。从中可以看出,当α为0时(全透明),T’=D,即融合图片不影响结果;当α为1时(不透明),T’=T。
具体的效果如下图所示:
底图: |
融合图: |
---|
融合结果:
底图: |
融合图: |
---|
融合结果:
看完了效果,那么,怎么在GPUImage里实现呢?这里就要实现自定义的FragmentShader了。
这里的返回值是T和S的α值,后续会有一个跟底图的α融合过程。该融合过程可以放在shader中实现,也可以让OpenGL自动实现。
- 让OpenGL自动实现的方法如下:
1) 在render之前,设置:
这两句的含义是:让OpenGL根据α值自动融合结果;融合公式是:
T=S*α+(1-α)*D
2) glDrawArray
3) glDisable(GL_BLEND);
这样设置好之后,就可以实现原地多次增加贴图了(绘制在同一个frameBuffer上,不用两个frameBuffer来回倒腾),相当方便~
- 在shader里面手动实现的方法如下:
更多关于移动开发,图像处理的相关技术,请持续关注我们的公众号!
作者简介:dreamqian(钱梦仁),外号"大魔王",天天P图iOS工程师