什么是颜色迁移
简单的讲,就是将一张图片A的颜色分布转移到另一张图片B上,其中B称为原图片,A称为目标图片。例如下面的例子,b是原图片,a是目标图片,c是做迁移之后生成的图片。算法很多人都讲过,可以参考这篇https://zhuanlan.zhihu.com/p/37018069。
图片来自论文:https://www.cs.tau.ac.il/~turkel/imagepapers/ColorTransfer.pdf
为什么要在Unity中实现
离线的版本很多人都实现过,那么实时的颜色迁移会怎么样呢,每帧之间怎么变化呢,不做实验不知道,所以就在后处理中用Compute Shader实现了,流程如下:
其中颜色迁移公式如下:
k指的是lab(三通道分别计算),S为原图像,T为目标图像,μ为图像均值,σ为图像标准差。至于rgb和lab的转换,论文里讲的很详细,不再赘述。
遇到的坑
在计算均值和标准差时,GPU内的数据同步问题,要么用原子计算,要么用barrier。barrier用了DeviceMemoryBarrierWithGroupSync没使成功,只是用了原子加法,但是原子加法只支持整型,只好牺牲精度了。
还有,如果对整张图片求均值和标准差是很耗性能的,所以做了下采样再计算的。
感觉GPU和CPU的数据同步,以及GPU内部的数据同步,对实时图像处理造成不小的困难。
结果如何
还不错,对一个场景使用了不同目标图片的话,会产生有趣的效果。
原场景如下,来自Unity的3D Game Kit。
原场景
用了吉卜力风格的图片做迁移:
吉卜力风格的图片
结果图片
用了赛博朋克风格的图片做迁移:
赛博朋克风格的图片
结果图片
用了新海诚风格的图片做迁移:
新海诚风格的图片
结果图片
代码
代码还是GitHub:
alpacasking/PostProcessingLibgithub.com
有两个问题待解决:
- 每帧之间的颜色迁移不是连续的
- lab颜色空间的精度不够高