这其实是作业所以写的会比较弱智(
我忏悔,我保证以后我的文章不会漏空格😢
我们经常在各种社交媒体上看到过这样的图片 : 在没点开之前是一张图片, 而我们点开这张图片准备保存或者细细观看的时候, 它又变成了另一张图片, 就像这张图片一样, 点开之前是一张笑脸, 点开了却变成了一张哭脸, 这究竟是怎么做到的呢 ? 今天,我们就从阐述图片组成的基本元素讲起, 揭开这种隐藏图片的秘密。
png 图片的基本组成部分
如果你对这些隐藏图片感兴趣并尝试下载这些图片并研究他们, 你应该会发现, 这些图片的格式, 无一例外, 都是 png 格式的, 在当下的网络世界,常见的位图图片格式主要有 jpg 和 png 两种, 其中 jpg 格式的图片经过了有损压缩, 占用的体积更小, 因此更加常见 ; 而 png 格式的图片是无损压缩,因此占用的体积更大, 出现的场合会更少。那为什么这些图片都是 png 格式呢 ?
这就要从图片的基本组成来讲了 : 我们都知道, 在jpg格式的图片中, 我们使用红黄蓝 ( RGB ) 三种颜色的值大小来代表一个像素点所对应的颜色是什么, 而在png格式的图片中, 为了实现图形的透明效果, 我们会在 RGB 的基础上再增加一个 Alpha 信道 ( Png Alpha Channel ) 来表示这个像素点对应的透明程度。看完这篇推文后, 你可以留意一下遇到的有透明背景的位图图片, 它们的格式应该都是 png 而不是 jpg , 因为只有 png 格式才在原理上支持这一点。正如下图所示, 我们平时生活中经常看到的网格图案背景其实就是代表这片区域是透明的。
那显示器是如何展示一张 ” 半透明 ” 或者 ” 透明 ” 的图片呢, 难道都像上面那样打上网格吗? 当然不是, 显示器在显示这些图片的时候, 会挑一个背景来展示这些图片, 而这些背景可以是纯白, 可以是纯黑, 灰色, 有时候也会是刚刚那样的网格。
在绝大部分社交平台或者相册中, 我们看到的略缩图会以白色背景展示, 在我们点击图片之后转换为用黑色背景来展示, 而正是因为存在这种背景切换, 才使得这类隐藏图片有了实现的可能。
我们的显示屏具体是如何展示图片的
为了简化计算, 我们将 RGB 三个通道简化为一个 \(A\) 来表示, Alpha 通道为 \(α\) , 而背景层为 \(B\) , 最终展示的图片 \(D\) 就是
\begin{equation} D=α·A+(1-α)·B \end{equation}
知道了计算过程, 我们就可以接下来对我们的图片进行隐写。
我们是如何在不同的背景展示不同的图片的
这里我们演示最常见的黑色和白色背景的图片隐写
在进行计算之前,我们需要先明确一点。在实际制作这类。图片时,由于涉及复杂的计算, 为了避免方程无解导致展示的效果过差, 我们通常会选用 RGB 值一样的照片进行隐写, 而这种图片在观感上就是灰色的图片。虽然损失了观感, 但是我们得以将 RGB 三个量简化为一个量灰度 \(C\) , 简化了计算。这也是我们看到大部分的隐写图都是灰色的原因。
我们首先计算图片在黑色背景和白色背景下显示的灰度。假设某个像素的灰度是 \(C\) , Alpha 通道是 \(α\) , 在黑色背景下显示的灰度是 \(C_1\) , 在白色背景下的灰度是 \(C_2\) , 其中每个数值的取值范围都是 \([0,1]\) , 则有
\begin{equation} \left\{ \begin{aligned} C_1=C\cdot α+0\cdot (1-α) \\C_2=C\cdot α+1\cdot (1-α) \end{aligned} \right.\end{equation}
由此解出 \(C\) 和 \(α\) , 我们就可以得到由两张原始图片颜色计算叠加图片颜色的公式
\begin{equation}\left\{ \begin{aligned} C=\frac {C_1} {1+C_1-C_2} \\α=1+C_1-C_2 \end{aligned} \right.\end{equation}
由 \(1−C_2≥0\) 和 \(C_1≥0\) 可知 \(C\) 一定在 \([0,1]\) 范围内。( 如果分子分母同时为零就取任意值, 对应的情况为黑色背景下为纯黑, 白色背景下为纯白, 此时让 \(α\) 为零即可 )
而正如上面所说, 我们并不能将相同的算法用于彩色图片。原因就是在处理彩色图片的 RGB 三个通道时, 得到的 Alpha 值可能不相同, 导致方程无解, 这样就无法同时准确还原三个通道的颜色了。
还有一些情况, 就是因为 \(A\) 不一定在 \([0,1]\) 范围内 ( 因为只有当 \(1+C_1–C_2≤1\) 即 \(C_1≤C_2\) 时才可以)。也就是在黑背景下图片的像素点要比白背景下图片对应的像素点亮的情况下, \(α\) 值就会被置为 \(1\) , 那这个像素点就 ” 失真 ” 了。在实际操作中, 也就意味着我们在选择白色背景下显示的图应该尽量选择一张亮色图, 而在黑背景下展示的图应该尽量选择一张暗色的图。这也解释了略缩图 ( 也就是没点开之前的图片往往偏亮, 而点开后的图往往偏暗的原因 )