LSB图像隐写术编码后像素值异常变更问题求助
LSB图像隐写中像素值莫名变更的问题解决办法
你遇到的这个像素值诡异变更的问题,核心原因其实很直白:你用错了图像格式。JPEG是有损压缩格式,它天生和LSB隐写的需求冲突——LSB隐写依赖精确保留像素的最低位修改,但JPEG在保存时会自动丢弃视觉上“不重要”的信息,直接篡改你辛苦修改的像素数据,导致解码时看到的图像和你内存中修改后的完全不一样。
具体问题拆解
- JPEG压缩的致命影响:你在
encode函数里修改完像素后,保存为temp2.JPG时,JPEG的压缩算法会重新编码图像,不仅会改变你修改的LSB位,甚至会调整整个像素值,这就是为什么你在decode里打开图像后,像素值完全变了样。 - 额外的冗余压缩操作:你的
encode里有一行多余的enc_img.save("OUT.JPG"),这会在你还没修改像素时就先做一次有损压缩,进一步干扰后续的隐写操作。 - 像素坐标的逻辑错误:PIL的
Image.size返回的是(width, height),但你写了height, width = enc_img.size,把宽高搞反了,导致你遍历像素的顺序完全错误,这也会让隐写的数据乱掉。
解决方案
1. 改用无损图像格式
把所有涉及的图像文件换成PNG格式(比如temp.png),保存时明确指定PNG格式,确保像素数据被精确保存:
# 打开图像时用PNG img = Image.open("temp.png") # 保存时明确指定PNG格式,避免默认压缩 enc_img.save('temp2.png', format='PNG')
2. 修正encode函数的核心逻辑
删掉冗余的保存操作,修正宽高顺序,同时简化LSB修改的逻辑(原来的条件判断太绕,容易出错):
def encode(): data = "This is a data" img = Image.open("temp.png") data = preprocess_data(data) data.append(list('11111111')) print(data) i = 0 j = 0 enc_img = img.copy() width, height = enc_img.size # 修正:size返回(width, height) pixels = enc_img.load() finished = False for h in range(height): for w in range(width): pixel = list(enc_img.getpixel((w, h))) # 坐标修正为(w, h) newpixel = [] for k in range(3): # 简化LSB修改逻辑:清除原LSB,再设置目标位 target_bit = int(data[i][j]) # 先把原像素的LSB置0,再按目标位设置 modified_pixel = (pixel[k] & ~1) | target_bit newpixel.append(modified_pixel) # 更新数据指针 j = (j + 1) % 8 if j == 0: i += 1 # 检查是否写完所有数据(包括终止符) if i == len(data): enc_img.save('temp2.png', format='PNG') print("Saved") finished = True break if finished: break pixels[w, h] = tuple(newpixel) # 坐标修正 if finished: break print("Encoding done!!")
3. 修正decode函数的逻辑
同样修正坐标问题,优化数据收集的逻辑:
def decode(): img = Image.open("temp2.png") width, height = img.size data = "" current_byte = "" bit_count = 0 pixels = img.load() for h in range(height): for w in range(width): pixel = pixels[w, h] for k in range(3): current_byte += str(pixel[k] & 1) bit_count += 1 if bit_count == 8: if current_byte == "11111111": return data # 转成ASCII字符 data += chr(int(current_byte, 2)) current_byte = "" bit_count = 0 break return data
总结
- 永远记住:LSB隐写只能用无损压缩格式(PNG、BMP等),JPEG这类有损格式会直接破坏隐写数据。
- 仔细核对PIL的坐标和尺寸逻辑,避免因宽高搞反导致的遍历错误。
- 简化LSB修改的逻辑,用位运算直接操作比复杂的条件判断更可靠。
内容的提问来源于stack exchange,提问作者Dharmender Lodhi
相关产品推荐
相关产品推荐

