在数字列表中隐藏二进制值
Hiding binary values in a number list
我试图在数字列表中隐藏二进制值(颜色值,因此它们可以稍微改变并保持相同的含义),但我觉得这个方法有点不雅。具体来说,由于我决定将 NULL
字符 (00000000
) 与无信息区分开来,所以我对数字列表的更改比我想要的要多。因此,如果二进制字符串为 0,我将列表中的数字更改为 1。如果它有 1,我将其更改为 2。
它有效,但我想问一下是否有人能想到仍然符合该标准的改进。这就是看似显而易见的 xor 解决方案失败的条件。以下是我正在做的事情的简化版本:
def encode(pic_data, file_data):
"""encode pic_data with the information stored in file_data"""
# file data is shorter than pic_data, I test for it in the real code
new_pic_data = pic_data.copy()
for i in range(len(file_data)):
# I add 1 to the value of 0 or 1, because I need to be able to
# distinguish 0 from nothing
data_value = int(file_data[i]) + 1
# rgb max value is 255, data_value can be 1 or 2
if new_pic_data[i] >= 253:
data_value *= -1
new_pic_data[i] += data_value
return new_pic_data
def decode(pic_data_original, pic_data_modified):
"""
extract a binary string from the differences between the input
data sets
"""
# both data sets have to be the same length
new_file_data = [abs(pic_data_original[i] - pic_data_modified[i]) - 1
for i in range(len(pic_data_original))]
# the test at the end of this makes sure we do not use locations
# where no data was stored
return ''.join(str(i) for i in new_file_data if i >= 0)
binary_string = '01100001' # the data to be hidden
flat_rgb_data = [18, 15, 222, 69, 151, 222, 254, 199, 21] # the picture
# [19, 17, 224, 70, 152, 223, 253, 201, 21]
encoded_rgb_data = encode(flat_rgb_data, binary_string)
# getting binary_string back, '01100001'
decoded_data = decode(flat_rgb_data, encoded_rgb_data)
print(decoded_data)
背景,有兴趣者:
我在这里真正做的是一些图像隐写术,其中我可以将任意文件隐藏到图片中。基本思想是图片是一系列 [(R1, G1, B1), (R2, G2, B2), ...]
形式的 RGB 值。我将其拼合成一个列表并得到 [R1, G1, B1, R2, G2, B2, ...]
。这就是上面的flat_rgb_data
。
然后我读取任何类型的文件,并将字节字符串转换为二进制字符串。如果其中一个字符是 '0x61'
,则在上面的 binary_string
中变为 '01100001'
。
来自 encode()
的列表被重新组合(因为缺少更好的术语)并保存为图像。即使并排放置,它与原件之间的颜色差异也很难区分。没有原图,我什至想不出图像已经被修改过。
显然,每张图片都必须在视觉上很忙,并且被视为一次性垫,这样才能正常工作。此外,您不能使用互联网上的图片 =).
我需要能够区分 NULL
字符 (00000000
) 和没有信息的原因,正如我在上面提到的一个关键标准,是一些文件格式使用NULL
个有意义的字符。通常人们在涉及文本时会忽略这一点,因为您可以安全地删除所有 NULL
。但举个例子,如果您从 MS Word 文档中删除 NULL
s,Word 将无法再打开它。
无论如何,谢谢你的帮助。
解决方案:永远不要使用 MS Word,反正都是废话! :)
更严重的是,如果我很了解你的情况,如果你不使用你的想法,你面临的唯一问题是你不知道可能有多少尾随 NULL。 (你仍然检测到它们 'inside' 文档。)一个肮脏的解决方案(如果烦人的格式对额外的 NULL 感到满意)是假设所有尾随 0 实际上是为 NULL 编码。
更好的解决方案:您能否以某种方式在代码开头对尾随 NULL 的数量进行编码?例如,如果你知道你永远不会有超过 256 个尾随 NULL,你分配第一个字节来编码那个数字?
感谢 Julien Bernu 的创意;我希望他能充实这个想法并 post 作为答案,但已经有一段时间了,所以我决定实施它,以便其他人可以从这个想法中受益。
我不认为这是比我的原始算法更好的策略,但它确实解决了我的具体问题,因此值得考虑。
优点:
- 将每个颜色值最多修改 +/- 1(而不是 +/- 2)
- 保留区分
NULL
和 00000000
的能力
缺点:
- 打破算法对称性(现在必须跟踪哪个图像是原始图像,或在修改后的图像中标记它)
- 无法使用具有最大或最小颜色值(0 或 255)的图像部分,具体取决于与该颜色值对齐的位
以下是修改后的简化示例。请注意,由于某些 0 和 255 值,我必须向图像数据添加另一个像素才能存储信息。
def encode(pic_data, file_data):
"""encode pic_data with the information stored in file_data"""
# file data is shorter than pic_data, I test for it in the real code
# would also need to make sure that the length of pic_data is greater than
# the length of file_data by the number of 0s and 255s in it, to be safe
new_pic_data = pic_data.copy()
offset = 0
for i in range(len(file_data)):
# Now, 1 is 1 and 0 is -1, which still allows us to
# distinguish 0 from nothing
data_value = 1 if file_data[i] == '1' else -1
# rgb max value is between 0 and 255
while pic_data[i + offset] == 0 and data_value == -1:
offset += 1
while pic_data[i + offset] == 255 and data_value == 1:
offset += 1
new_pic_data[i + offset] += data_value
return new_pic_data
def decode(pic_data_original, pic_data_modified):
"""
extract a binary string from the differences between the input
data sets
"""
# both data sets have to be the same length
new_file_data = ['1' if (pic_data_modified[i] - pic_data_original[i] == 1)
else '0' if (pic_data_modified[i] - pic_data_original[i] == -1)
else ''
for i in range(len(pic_data_original))]
return ''.join(i for i in new_file_data)
binary_string = '01100001' # the data to be hidden
flat_rgb_data = [18, 15, 255, 0, 151, 0, 254, 199, 21, 180, 105, 205] # the picture
# [17, 16, 255, 1, 150, 0, 253, 198, 20, 181, 105, 205]
encoded_rgb_data = encode(flat_rgb_data, binary_string)
# getting binary_string back, '01100001'
decoded_data = decode(flat_rgb_data, encoded_rgb_data)
print(decoded_data)
我试图在数字列表中隐藏二进制值(颜色值,因此它们可以稍微改变并保持相同的含义),但我觉得这个方法有点不雅。具体来说,由于我决定将 NULL
字符 (00000000
) 与无信息区分开来,所以我对数字列表的更改比我想要的要多。因此,如果二进制字符串为 0,我将列表中的数字更改为 1。如果它有 1,我将其更改为 2。
它有效,但我想问一下是否有人能想到仍然符合该标准的改进。这就是看似显而易见的 xor 解决方案失败的条件。以下是我正在做的事情的简化版本:
def encode(pic_data, file_data):
"""encode pic_data with the information stored in file_data"""
# file data is shorter than pic_data, I test for it in the real code
new_pic_data = pic_data.copy()
for i in range(len(file_data)):
# I add 1 to the value of 0 or 1, because I need to be able to
# distinguish 0 from nothing
data_value = int(file_data[i]) + 1
# rgb max value is 255, data_value can be 1 or 2
if new_pic_data[i] >= 253:
data_value *= -1
new_pic_data[i] += data_value
return new_pic_data
def decode(pic_data_original, pic_data_modified):
"""
extract a binary string from the differences between the input
data sets
"""
# both data sets have to be the same length
new_file_data = [abs(pic_data_original[i] - pic_data_modified[i]) - 1
for i in range(len(pic_data_original))]
# the test at the end of this makes sure we do not use locations
# where no data was stored
return ''.join(str(i) for i in new_file_data if i >= 0)
binary_string = '01100001' # the data to be hidden
flat_rgb_data = [18, 15, 222, 69, 151, 222, 254, 199, 21] # the picture
# [19, 17, 224, 70, 152, 223, 253, 201, 21]
encoded_rgb_data = encode(flat_rgb_data, binary_string)
# getting binary_string back, '01100001'
decoded_data = decode(flat_rgb_data, encoded_rgb_data)
print(decoded_data)
背景,有兴趣者:
我在这里真正做的是一些图像隐写术,其中我可以将任意文件隐藏到图片中。基本思想是图片是一系列 [(R1, G1, B1), (R2, G2, B2), ...]
形式的 RGB 值。我将其拼合成一个列表并得到 [R1, G1, B1, R2, G2, B2, ...]
。这就是上面的flat_rgb_data
。
然后我读取任何类型的文件,并将字节字符串转换为二进制字符串。如果其中一个字符是 '0x61'
,则在上面的 binary_string
中变为 '01100001'
。
来自 encode()
的列表被重新组合(因为缺少更好的术语)并保存为图像。即使并排放置,它与原件之间的颜色差异也很难区分。没有原图,我什至想不出图像已经被修改过。
显然,每张图片都必须在视觉上很忙,并且被视为一次性垫,这样才能正常工作。此外,您不能使用互联网上的图片 =).
我需要能够区分 NULL
字符 (00000000
) 和没有信息的原因,正如我在上面提到的一个关键标准,是一些文件格式使用NULL
个有意义的字符。通常人们在涉及文本时会忽略这一点,因为您可以安全地删除所有 NULL
。但举个例子,如果您从 MS Word 文档中删除 NULL
s,Word 将无法再打开它。
无论如何,谢谢你的帮助。
解决方案:永远不要使用 MS Word,反正都是废话! :)
更严重的是,如果我很了解你的情况,如果你不使用你的想法,你面临的唯一问题是你不知道可能有多少尾随 NULL。 (你仍然检测到它们 'inside' 文档。)一个肮脏的解决方案(如果烦人的格式对额外的 NULL 感到满意)是假设所有尾随 0 实际上是为 NULL 编码。
更好的解决方案:您能否以某种方式在代码开头对尾随 NULL 的数量进行编码?例如,如果你知道你永远不会有超过 256 个尾随 NULL,你分配第一个字节来编码那个数字?
感谢 Julien Bernu 的创意;我希望他能充实这个想法并 post 作为答案,但已经有一段时间了,所以我决定实施它,以便其他人可以从这个想法中受益。
我不认为这是比我的原始算法更好的策略,但它确实解决了我的具体问题,因此值得考虑。
优点:
- 将每个颜色值最多修改 +/- 1(而不是 +/- 2)
- 保留区分
NULL
和00000000
的能力
缺点:
- 打破算法对称性(现在必须跟踪哪个图像是原始图像,或在修改后的图像中标记它)
- 无法使用具有最大或最小颜色值(0 或 255)的图像部分,具体取决于与该颜色值对齐的位
以下是修改后的简化示例。请注意,由于某些 0 和 255 值,我必须向图像数据添加另一个像素才能存储信息。
def encode(pic_data, file_data):
"""encode pic_data with the information stored in file_data"""
# file data is shorter than pic_data, I test for it in the real code
# would also need to make sure that the length of pic_data is greater than
# the length of file_data by the number of 0s and 255s in it, to be safe
new_pic_data = pic_data.copy()
offset = 0
for i in range(len(file_data)):
# Now, 1 is 1 and 0 is -1, which still allows us to
# distinguish 0 from nothing
data_value = 1 if file_data[i] == '1' else -1
# rgb max value is between 0 and 255
while pic_data[i + offset] == 0 and data_value == -1:
offset += 1
while pic_data[i + offset] == 255 and data_value == 1:
offset += 1
new_pic_data[i + offset] += data_value
return new_pic_data
def decode(pic_data_original, pic_data_modified):
"""
extract a binary string from the differences between the input
data sets
"""
# both data sets have to be the same length
new_file_data = ['1' if (pic_data_modified[i] - pic_data_original[i] == 1)
else '0' if (pic_data_modified[i] - pic_data_original[i] == -1)
else ''
for i in range(len(pic_data_original))]
return ''.join(i for i in new_file_data)
binary_string = '01100001' # the data to be hidden
flat_rgb_data = [18, 15, 255, 0, 151, 0, 254, 199, 21, 180, 105, 205] # the picture
# [17, 16, 255, 1, 150, 0, 253, 198, 20, 181, 105, 205]
encoded_rgb_data = encode(flat_rgb_data, binary_string)
# getting binary_string back, '01100001'
decoded_data = decode(flat_rgb_data, encoded_rgb_data)
print(decoded_data)