幻影坦克

幻影坦克应该很多人都见过,好像下面这张真·幻影坦克一样:

把上图保存下来查看就可以看到出现了新的图案。

这类图片基本上可以用于所有的聊天软件和社交平台,只要它们对于图片的展示方式都是缩略图用白色背景展示,点击进入大图的时候就会转换成黑色背景。

主要的实现方式有两种:
1. 通过棋盘格交错显示
2. 通过对黑白背景下的图片进行计算后合成新图片

这里使用了第二种实现方法,具体原理如下:
利用 PNG 图片中的 Alpha 通道,配合上背景的颜色就可以对原有的 RGB 通道进行滤波(又是这个罪恶的词语呢就),原本图片上的像素在黑白两色的背景下就可以显示出不同的颜色。为了操作的方便通常这些图都是转换成灰阶图,所以就剩下 Alpha 和 Gray 两个通道。

一个透明图片最后显示出来的效果是下面公式所示:

$$
Gray=Gray_{Front} \times Alpha \div 255 + Gray_{Back} \times (255 – Alpha)\div 255
$$

这样子如果需要已知两种显示模式下背景分别为:
$$
\begin{cases}
Gray_{Front} &= Gray_{White} \\
Gray_{Back} &=255
\end{cases}
$$

$$
\begin{cases}
Gray_{Front} &= Gray_{Black} \\
Gray_{Back} &=0
\end{cases}
$$

带入后解方程就可以得到:

$$
\begin{cases}
Alpha &= 255 + Gray_{Black} – Gray_{White} \\
Gray &=255 \times Gray_{Black}/Alpha
\end{cases}
$$

根据上面的公式,可以对两幅图进行计算然后生成最终的结果:

from PIL import Image
import sys
import numpy as np


def main(argv):
    if len(argv) != 4:
        print("Error")
        pass

    image_white = np.array(Image.open(argv[1]).convert("L"))
    image_black = np.array(Image.open(argv[2]).convert("L"))
    image_black = image_black * 0.3

    a = 255.0 + image_black - image_white
    g = 255.0 / a * image_black
    g[g == np.inf] = 255.0
    g.clip(0, 255)
    a.clip(0, 255)

    a = np.round(a, 0).astype("ubyte")
    g = np.round(g, 0).astype("ubyte")

    print("amax:%d gmax%d amin:%d gmin:%d" % (a.max(), g.max(), a.min(), g.min()))

    result = np.dstack([g, g, g, a])

    print(result.shape)

    im = Image.fromarray(result, "RGBA")

    im.save(argv[3], "PNG")
    im.show()


if __name__ == '__main__':
    main(sys.argv)

上面有修改的地方是对黑色背景下的图片进行了降低亮度的处理,可以避免最终计算结果超出 $0-255$ 的范围然最后的结果图变成下面的样子:

合成下面两幅图:

A

B

结果如下:

result

貌似效果一般,还需要进行一些修改。

可能会有后续更新的 Github 项目。

Reference

https://zhuanlan.zhihu.com/p/31164700
https://tieba.baidu.com/p/5299504995
https://github.com/Aloxaf/MirageTankGo

One thought on “幻影坦克

发表评论

电子邮件地址不会被公开。 必填项已用*标注