Python中基于PIL实现LSB隐写后如何从二进制数据重建图像
我帮你分析下问题所在,以及怎么修复这个隐写术的图像重建问题:
你的核心问题出在处理后的二进制字符串没有转换回整数,也没有恢复成图像需要的像素结构。Image.fromarray()需要的是数值数组(比如0-255的uint8整数),而不是你保存的二进制字符串数组,这就是为什么生成的图像无效。
接下来一步步给你修正:
1. 核心问题拆解
- 你把每个RGB值转成了
'0bxxxxxxx'格式的二进制字符串,修改LSB后没有转回十进制整数 - 展平的RGB值列表没有重新组织成原始图像的像素元组结构(比如每个像素对应3个RGB值)
- 缺少将处理后的数据正确映射回图像格式的步骤
2. 修正后的完整代码
from PIL import Image import json def bincon(image_path): im = Image.open(image_path, 'r') pix_val = list(im.getdata()) # 获取每个像素的RGB元组 pix_val_flat = [x for sets in pix_val for x in sets] # 展平为单个RGB值的列表 # 直接遍历元素生成二进制字符串,简化代码 pixel_binaries = [bin(val) for val in pix_val_flat] # 返回图像尺寸和模式,方便后续重建时保持一致 return pixel_binaries, im.size, im.mode # 待嵌入的秘密信息二进制串 injection = '0111001101100101011000110111001001100101011101000010000001101101011001010111001101110011011000010110011101100101001000000110100101101110011010100110010101100011011101000110100101101111011011100010000001101101011011110110110101100101011011100111010000100000011010000110010101101000011001010110100001100101011010000110010101101000011001010110100001100101' injection_array = list(injection) # 直接转为字符列表,简化循环 # 1. 获取原始图像的二进制数据、尺寸和模式 pixel_bin, img_size, img_mode = bincon("input_image.png") # 替换为你的输入图像路径 modified_pixels = [] injectioncount = 0 # 2. 修改每个RGB值的LSB for bin_str in pixel_bin: if injectioncount < len(injection_array): # 剥离最低位并替换为秘密信息的位 new_bin_str = bin_str[:-1] + injection_array[injectioncount] injectioncount += 1 else: # 秘密信息位用完后,保留原像素的最低位 new_bin_str = bin_str # 将二进制字符串转回十进制整数(关键步骤) modified_val = int(new_bin_str, 2) modified_pixels.append(modified_val) # 保存对比用的二进制数据(可选) with open("comparison.json","w") as f: json.dump([bin(val) for val in modified_pixels], f, indent=2) # 3. 重建图像:将展平的RGB值重新分组为像素元组 # 例如RGB模式下,每3个连续值组成一个像素的RGB元组 pixel_tuples = [tuple(modified_pixels[i:i+3]) for i in range(0, len(modified_pixels), 3)] # 4. 创建并保存处理后的图像 im_out = Image.new(img_mode, img_size) im_out.putdata(pixel_tuples) im_out.save("output_image.png") print("处理后的图像已保存为output_image.png")
关键修改说明
- 增强
bincon函数:返回图像的尺寸和模式,确保重建的图像和原始图像格式一致 - 二进制转整数:用
int(new_bin_str, 2)将修改后的二进制字符串转回0-255的有效RGB值 - 恢复像素结构:把展平的RGB值重新分组为像素元组,再用
putdata()方法写入新图像,比fromarray更直观可靠 - 处理剩余像素:秘密信息位用完后,保留原始像素的LSB,避免破坏图像的其余部分
这样修改后,生成的output_image.png应该可以正常打开,肉眼几乎看不出变化,同时秘密信息已经嵌入到像素的最低有效位中了。
内容的提问来源于stack exchange,提问作者Nahum Thomas




