文章目录
- 摘要
- 1. 方法
- 1.1 步骤
- 1.2 代码
- 1.3 embed_bit=3(低3位嵌入) 实验现象
- 1.3 实验现象分析
- 1.4 所有实验现象
- 2. 更新-彩色水印嵌入与提取
- 参考资料
摘要
数字水印技术是一种保护图像版权的方式。LSB(Least Significant Bits, 最低有效位)技术是空域水印嵌入的一种方式。本文以灰度图像为对象,使用Python实现了任意长度位平面的水印嵌入方式,并且可以提取出水印对应的灰度图像。
1. 方法
1.1 步骤
- 读取图像(background、watermark)
- 对读取的图像进行嵌入
2.1 划分对应的位平面
2.2 将background的低位位平面替换为watermark的高位位平面
2.3 合成图像(synthesis) ,实现嵌入 - 进行提取并绘制结果
本实验选择的嵌入位数是3
1.2 代码
喜欢的东西都在码里,可以不用本地配置环境,使用百度的飞浆平台进行在线运行。
开源这个代码不求赞,只求你们可以注册帮我拿点算力,或者fork一下项目,我真的很需要算力,所以希望我劝各位年轻人,要讲武德,耗子尾汁,不要白嫖。好卑微的博主呜呜呜。下面第一个Link给的算力多,注册之后点第二个link可以在线运行
百度飞浆邀请注册地址
import numpy as np
import matplotlib.pyplot as plt
import cv2
class LSB_Embed():
def __init__(self):
pass
@staticmethod
def get_bitPlane(img):
"""
获取灰度图像的8个位平面
:param img: 灰度图像
:return: 8个位平面的矩阵
"""
h, w = img.shape
flag = 0b00000001
bitPlane = np.zeros(shape=(h, w, 8))
for i in range(bitPlane.shape[-1]):
bitplane = img & flag # 获取图像的某一位,从最后一位开始处理
bitplane[bitplane != 0] = 1 # 阈值处理 非0即1
bitPlane[..., i] = bitplane # 处理后的数据载入到某个位平面
flag <<= 1 # 获取下一个位的信息
return bitPlane.astype(np.uint8)
@staticmethod
def lsb_embed(background, watermark, embed_bit=3):
"""
在background的低三位进行嵌入水印,具体为将watermark的高三位信息替换掉background的低三位信息
:param background: 背景图像(灰度)
:param watermark: 水印图像(灰度)
:return: 嵌入水印的图像
"""
# 1. 判断是否满足可嵌入的条件
w_h, w_w = watermark.shape
b_h, b_w = background.shape
assert w_w < b_w and w_h < b_h, "请保证watermark尺寸小于background尺寸\r\n当前尺寸watermark:{}, background:{}".format(
watermark.shape, background.shape)
# 2. 获取位平面
bitPlane_background = lsb.get_bitPlane(background) # 获取的平面顺序是从低位到高位的 0 1 2 3 4 5 6 7
bitPlane_watermark = lsb.get_bitPlane(watermark)
# 3. 在位平面嵌入信息
for i in range(embed_bit):
# 信息主要集中在高位,此处将watermark的高三位信息 放置在 background低三位信息中
bitPlane_background[0:w_h, 0:w_w, i] = bitPlane_watermark[0:w_h, 0:w_w, (8 - embed_bit) + i]
# 4. 得到watermark_img 水印嵌入图像
synthesis = np.zeros_like(background)
for i in range(8):
synthesis += bitPlane_background[..., i] * np.power(2, i)
return synthesis.astype(np.uint8)
@staticmethod
def lsb_extract(synthesis, embed_bit=3):
bitPlane_synthesis = lsb.get_bitPlane(synthesis)
extract_watermark = np.zeros_like(synthesis)
extract_background = np.zeros_like(synthesis)
for i in range(8):
if i < embed_bit:
extract_watermark += bitPlane_synthesis[..., i] * np.power(2, (8 - embed_bit) + i)
else:
extract_background += bitPlane_synthesis[..., i] * np.power(2, i)
return extract_watermark.astype(np.uint8), extract_background.astype(np.uint8)
if __name__ == '__main__':
root = ".."
lsb = LSB_Embed()
# 1. 获取背景和水印
background = cv2.imread(r"{}/datasets/background/460.pgm".format(root), cv2.IMREAD_GRAYSCALE)
watermark = cv2.imread(r"{}/datasets/watermark/swjtu2.png".format(root), cv2.IMREAD_GRAYSCALE)
background_backup = background.copy()
watermark_backup = watermark.copy()
# 2. 进行水印嵌入
embed_bit = 2
synthesis = lsb.lsb_embed(background, watermark, embed_bit)
# 3. 进行水印提取
extract_watermark, extract_background = lsb.lsb_extract(synthesis, embed_bit)
imgs = [background_backup, watermark_backup, synthesis, extract_watermark, extract_background]
title = ["background", "watermark", "synthesis", "extract_watermark", "extract_background"]
for i in range(len(imgs)):
plt.subplot(2, 3, i + 1)
plt.imshow(imgs[i], cmap="gray")
plt.axis("off")
plt.title(title[i])
plt.show()
1.3 embed_bit=3(低3位嵌入) 实验现象
1.3 实验现象分析
- background和synthesis不仔细看是分不出来区别的,但是仔细看,能看出来swjtu的logo有些痕迹,如果减少嵌入位数,就无法看出痕迹了。
- extract_watermark的颜色和watermark的颜色不一致。实际测试,这应该是python绘图显示的原因,当我把水印区域的数据单独截取出来进行绘制。效果如下:
几乎与watermark一致,看不出来区别。 - extract_watermark水印的其他部分是因为没有做处理导致的。在进行提取的时候,没有给予提取算法的水印尺寸这个先验信息,算法不知道哪里是水印边界,因此只有水印部分可被算法正常提取,算法将其余部分与水印部分一视同仁进行提取,因此产生了像马赛克一样的图像。
1.4 所有实验现象
- embed_bit = 1
- embed_bit = 2
- embed_bit = 3
- embed_bit = 4
- embed_bit = 5
- embed_bit = 6
- embed_bit = 7
- embed_bit = 8
2. 更新-彩色水印嵌入与提取
该文章是对灰度图进行LSB进行操作,只需进行一些微微修改,即可实现图像的嵌入与提取,查看link。
参考资料