【问题标题】:Using Python to Decode Steganography Images (example images at Wikipedia)使用 Python 解码隐写术图像(维基百科上的示例图像)
【发布时间】:2015-03-23 04:08:51
【问题描述】:

Wikipedia's Steganography Article 有一个带有隐藏图像数据的示例图像。

维基百科注释:

Image of a tree 带有隐写隐藏的图像。通过去除每个颜色分量的两个最低有效位以外的所有位和随后的归一化来显示隐藏的图像。隐藏的图片显示(here)

问题:我对“后续标准化”感到困惑;假设基于 PIL 模块工作的 Python 2.x 代码,规范化如何影响检索?

【问题讨论】:

  • 你真的有问题吗?
  • 鉴于以上信息,Python 代码将如何从树图像中解码猫图像? -- 我应该改写一下吗?
  • 这不是问题,这是一个 QA 网站,而不是“为我编写代码”服务。
  • 我知道 SE 是如何工作的,伙计。除了这个,你还有什么更高效的东西可以添加吗?我没有要求任何人为我编写代码。
  • “隐藏的图像是通过删除每个颜色分量的两个最低有效位以外的所有位和随后的归一化来显示的。”如果你不想要代码,你只需要解码图像,还有什么不够清楚吗?

标签: python image image-processing steganography


【解决方案1】:

后续的归一化是每个颜色分量的linear interpolation

比如说,像素 1,1 的红色分量是 234。

234的二进制表示是

In [1]: bin(234)
Out[1]: '0b11101010'

我们可以通过一些按位运算删除除了两个最低有效位之外的所有内容:

In [2]: bin(234 & 0b11)
Out[2]: '0b10'

8 位图像的范围是 8 位或 256 种可能的阴影。但是我们的颜色值范围只是 2 位或 4 种可能的色调。

规范化部分正在做linear interpolation来拉伸2位值以填充8位空间:

In [3]: (234 & 0b11) * (256/4)
Out[2]: 128

在每个颜色分量上都这样做,猫就会出现。

【讨论】:

  • 正确的换算系数是 255/3。如果将 [0,3] 范围内的值乘以 256/4 = 64,则得到 [0,192] 范围内的值。
【解决方案2】:

标准化是将一个范围的值更改为另一个范围的值的过程。

由于 00、01、10 和 11 的二进制值,您的范围为 [0,3]。您要将其标准化为 [0,255] 的原因是为了覆盖整个像素强度范围。如果你只是从数组中保存一张图像,其值在 [0,3] 范围内,它会显示为黑色,因为所有这些值都非常接近 0,而远离 255。

image normalization 上的维基百科页面为您提供了通用公式。它还显示了将范围 [50,180](称为范围 A)转换为 [0,255](范围 B)的示例。

首先,我们移动 A,使其从零开始。实际上,您减去最小值 (50),使 [50,180] 变为 [0,130](称为 C)。 C 的最大距离为 130-0 = 130,B 的最大距离为 255-0 = 255。因此您需要将 C 的所有值乘以 255/130。由于 C 中的最小值为 0,因此它将为 C * 255/130。但如果 B 不是从 0 开始,您只需添加必要的偏移量即可。

如果单词令人困惑,这里有一个将 [2,5] 转换为 [-4,4] 的可视化。

在您的情况下,标准化是从 [0,3] 到 [0,255]。由于两个范围都从 0 开始,因此您不需要任何偏移量,只需简单地乘以 255/3。此结果将 {0,1,2,3} 转换为 {0,85,170,255}。

这里要小心一点,255/3 是一个方便的整数。但是,如果您进行标准化,比如 [0,7],最准确的转换将需要浮点缩放因子 255/7。无论您将其保留为浮点数还是将其舍入为整数都超出了此答案的范围。

实现这一点的最简单代码是

import Image
import numpy as np

# The array will be of type `np.uint8`. For integer computations that exceed
# this range, use `np.asarray(Image.open(...), dtype=int)`.
stego = np.asarray(Image.open('Steganography_original.png'))
extracted = stego & 0b00000011
extracted *= (255 / 3)

# Compare result with the one from wikipedia
wiki_extracted = np.asarray(Image.open('Steganography_recovered.png').convert('RGB'))
if np.all(wiki_extracted == extracted):
    print 'All pixels match'

【讨论】:

  • 您是否将其保留为浮点数或将其舍入为整数超出了此答案的范围。:您能否推荐有关此主题的来源,我可以跟进?
  • 如果 255/7 = 36,则 {0,1,2,3,4,5,6,7} -> {0,36,72,108,144,180,216,252}。如果 255/7 = 36.4285...,您首先将范围 [0,7] 归一化,然后将值四舍五入为整数,然后是 {0,36,72,109,145,182,218,255}。我会选择后者,因为前者的累积精度误差。如果您使用的是像素强度存储为浮点数的图像格式,您还希望缩放因子为浮点数。
猜你喜欢
  • 2022-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-17
  • 1970-01-01
相关资源
最近更新 更多