LSB介绍
LSB全称为 Least Significant Bit(最低有效位),是一种常被用做图片隐写的算法。LSB属于空域算法中的一种,是将信息嵌入到图像点中像素位的最低位,以保证嵌入的信息是不可见的(无法被肉眼察觉),但是由于使用了图像不重要的像素位,算法的鲁棒性差,水印信息很容易为滤波、图像量化、几何变形的操作破坏。
原理示意图
由图可见其像素值改变极小。
秘密信息: 101 | ||
242 243 | 11110010 | 11110011 |
213212 | 11010101 | 11010100 |
120121 | 01111000 | 01111001 |
隐藏代码
from skimage import io
import matplotlib.pyplot as plt
# 秘密信息编码
def encode(s):
value = ''
for c in s:
#先将对应的字符转换为对应的ascll码然后通过bin方法将其转换为二进制的形式
ascll = ord(c)
bin_result = bin(ascll)
bin_result = bin_result.replace('0b', '')
bin_result = ''.join([i for i in ['0'] * (16 - len(bin_result))]) + bin_result
value = value + bin_result
return value
# 信息隐藏
def hide():
img = io.imread("./Test.jpg")
width, height, c = img.shape
# 此处仅仅利用了RGB三通道中的第一个通道像素值的最后一位,每个字符占用16位
print("此图片可以隐藏:", width * height // 16, "个字符")
message = input("请输入要隐藏的信息:")
length = len(message)
binLength = bin(length).replace('0b', '')
binLength = ''.join(['0'] * (16 - len(binLength))) + binLength
binMsg = encode(message)
#将消息长度的16位二进制数与消息的二进制数进行连接
binMsg = binLength + binMsg
print(binMsg)
total = len(binMsg)
index = 0
#隐藏
for i in range(width):
for j in range(height):
#只将消息的一个比特位与RGB三通道的一个通道的像素最低位进行替换
#求与操作可以将该通道对应的像素值的二进制数最低位置为0
img[i, j, 0] = img[i, j, 0] & 254
img[i, j, 0] = img[i, j, 0] + int(binMsg[index])
index += 1
if index >= total:
break
if index >= total:
break
#保存结果
fname = "./result.png"
io.imsave(fname, img)
print("图片已保存为" + fname)
mod_img = io.imread(fname)
# 构造对比图
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体
plt.rcParams['axes.unicode_minus'] = False
plt.subplot(121)
plt.title("原始图像")
plt.imshow(img)
plt.subplot(122)
plt.title("嵌有秘密信息的图像")
plt.imshow(mod_img)
plt.show()
if __name__ == '__main__':
hide()
提取代码
from skimage import io
import matplotlib.pyplot as plt
# 消息解码
def decode(s,length):
msg = ""
s = [s[i:i + 16] for i in range(0, len(s), 16)]
for ch in s:
msg = msg + chr(int(ch,2))
print(msg)
# 消息提取
def extract():
img = io.imread("./result.png")
width, height, c = img.shape
msg = ""
length = 0
for i in range(width):
for j in range(height):
# 获取当前像素的最低位,将其添加到消息字符串中
a = bin(int(img[i, j, 0]))[2:].zfill(8)
msg += a[-1]
# 如果已经提取了前16位,则解析出消息长度
if len(msg) == 16:
length = int(msg, 2)
# 如果消息字符串的长度达到消息长度,则提取全部隐藏消息并解码
if len(msg) == (length + 1) * 16:
hidden_msg = msg[16:]
decode(hidden_msg, length)
break
if len(msg) == (length + 1) * 16:
break
if __name__ == '__main__':
extract()