# 幻影坦克
# 1. 介绍
有些图片在 qq 或者贴吧等平台上,正常情况是一张图片,但是打开放大变成了另一种图片,因为其表现形式像红色警戒的幻影坦克,因此将这类图片称作幻影坦克。其实这类图片是 png 图片,众所周知 png 图片有透明度,正是因为这个特性就可以让图片在不同背景下显示出不同图片成为可能。接下来介绍如何制作这类图片。
# 2. 图像混合
在调用 canvas 的 context 的 getImageData 方法后,会返回一个对象,其中 data 属性包含这个图片的像素颜色信息。每个像素有四个数据分别是 rgba,其中第四个数据是不透明度。这四个数据的取值范围均为 0-255。a 的数值越大越不透明,255 为完全不透明,0 为完全透明。那如果取值在这个中间图片会是什么样子的呢。
其中 mix 下标图像混合后的色值,1 下标为上面的图片色值,2 下标为下面的图片或者说背景色值。
可以做个实验,左边是色值改为混合后的色值,其中背景是白色,右边是改变不透明度,其背景是白色,每隔 100ms 改变一次,最后的效果一致。
有了上面的公式一切都好办了。根据这个公式,我们可以得出一张 png 图片在不同的背景下的色值。如果把在白色背景下呈现的图片叫做表图,在黑色背景下呈现的图片叫做里图。在知道了表图以及里图的色值,就可以根据这个公式计算出这张 png 图片的色值以及透明度。这样就可以让这张图片在黑白不同的背景下呈现出不同的图片。
# 3. 从隐藏一个阿卡林开始
如果我想让表图是白色的图片,让里图是阿卡林的话,代入公式可得,下标为表代表表图的色值,下标为里代表里图的色值。白色的 rgb 为 255,黑色的 rgb 为 0。
可以发现要想完美实现需求的话,需要里图与表图的 rgb 差值相同才行,这也是为啥大部分的幻影坦克用的基本是灰度图的原因,当 rgb 相同的时候颜色就是灰色的,数值越大越白,越小越黑。另外表图是白色也是不可能完成的需求,如果要求表图为白色就要求混合后的图片要么 rgb 都为 255,要么不透明度为零。但是可以降低要求让表图的 rgb 尽可能大,尽可能偏白。如果将表图 rgb 设置为 250 灰白,一般人看不出会认为是白色。同时将阿卡林的图片变成灰度图。灰度的公式如下
avg =0.299 * r +0.587 * g +0.114 * b 将 rgb 都设置成 avg 就行,至于这三个系数是怎么来的,老实说我也不清楚,但是效果挺好的。于是就得到了如下的公式。
可以发现效果非常的 amazing 啊,另外在背景颜色为白色的情况下,表图其实不是白色,看的出来有点灰准确的讲是 rgb 为 250 的灰白色,不细看还看不出来。
那如果就是要里图是有颜色的,而不是灰色图的话要怎么办。可以尝试一下让表图的 rgb 不相同,试着让其尽量大偏白,这就相当于让一个不透明度变小,或者说选择里图中 rgb 最小的值进行计算不透明度,从而计算表图的 rgb。
最终的效果,只能说在黑色背景下图片是完美显示,只是在白色背景下隐藏不了,加一层灰色的遮罩都隐藏不了,因为表图的 rgb 值不同所以会表现出彩色,图片隐藏不住。换句话说,如果想在黑色背景下完美展示,并在白色背景下完美隐藏的彩色图片理论上是不存在的。
# 4. 制作一个真正的幻影坦克
如果有一张图片想要在白色背景下展示叫做表图,另一张图片想要在黑色背景下展示加做里图。代入公式可得。
可以发现,要想完美实现一个幻影坦克就要表图的色值大于里图的色值,不然的话 α 会大于一,出现异样,具体表现就是在白色背景下会显示出里图。为了更好的隐藏里图可以让里图更暗一些,具体的做法就是将里图的色值等比例的缩小,不过缩的太小,里图会变的很暗,在黑色背景就不太好显示。在选择里图的时候可以考虑色值比较小的图片。
相关资料
[『整活』幻影坦克 基础版_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1kV411v7fR/
幻影坦克架构指南 (一) - 知乎 (zhihu.com)
http://182.92.185.149/2021/02/07 / 幻影坦克图片的原理和任意两张图片合成幻影坦克图的完备性讨论