背景
从computerphile的视频中,我想到了与Least Significant Bit Steganography一起玩的想法。 现在,我尝试使用Numpy提取并连接图像的所有RGB值以位格式。最终,我只需要数组的第7位和第8位。
设置
我用Pillow
加载图像,并通过以下方式提取位:
from PIL import Image
import numpy as np
img = Image.open('test.png')
arr = np.array(img)
bits = np.unpackbits(arr, axis=2)
问题
bits
数组的形状现在为(1600、1200、24)以获得1600x1200像素的图像。我现在需要的是
到目前为止的方法
我试图将{2}沿第二轴的3d数组分成3组。然后,我可以遍历1200个包含3个列表的列表,并提取最后2位,如下所示:
sp = np.split(bits, 3, axis=2)
for i in range(0, 1200):
for j in range(0, 3):
print(sp[j][0][i][-2:])
问题
尽管我上面的方法行得通,但我觉得必须仅使用Numpy Magic®
才能有更有效的解决方案。你知道更好的方法吗?
答案 0 :(得分:1)
这是XY problem。您无需使用显式方法将像素转换为二进制图像或提取任何特定位,因为那样您就必须再次将其全部缝合起来。您可以直接使用bitwise operations进行所需的操作,因为“二进制”和十进制是相同数字的两个表示形式。 AND
和SHIFT
的组合将使您可以将整数的任何部分归零,或隔离特定范围的位
例如,
>> (107 >> 3) & 7
5
因为
Decimal: 107 >> 3 = 13 & 7 = 5
Binary : 01101011 >> 3 = 00001101 & 00000111 = 00000101
|-| |-|
we want
these 3
现在,假设您的信息是世界“你好”。您可以像这样方便地将字节分成四个部分。
secret = b'hello'
bits = []
for byte in secret:
for i in range(6, -1, -2):
bits.append((byte >> i) & 3)
bits = np.array(bits)
由于每个bits
元素都包含两位,因此值的范围可以在0到3之间。如果您想到二进制中的字母“ h”,即“ 01 | 10 | 10 | 00”,则可以了解bits
的前几个值是1、2、2、0等。
要利用numpy中的矢量化操作,我们应该展平图像数组,我认为图像数组的形状为(height,width,3)。
np.random.seed(0)
img = np.random.randint(0, 255, (1600, 1200, 3)).astype(np.uint8)
shape = img.shape
# this specific type of flattening puts the pixels in your desired order, i.e.,
# pixel (0, 0) red-green-blue, pixel (0, 1) red-green-blue, etc
flat_img = img.reshape(-1).copy()
现在嵌入很简单
length = len(bits)
flat_img[:length] = (flat_img[:length] & 252) + bits
stego_img = flat_img.reshape(shape)