LSB水印嵌入与提取-灰度图像_Python Version


在这里插入图片描述

摘要

数字水印技术是一种保护图像版权的方式。LSB(Least Significant Bits, 最低有效位)技术是空域水印嵌入的一种方式。本文以灰度图像为对象,使用Python实现了任意长度位平面的水印嵌入方式,并且可以提取出水印对应的灰度图像。

1. 方法

1.1 步骤

  1. 读取图像(background、watermark)
  2. 对读取的图像进行嵌入
    2.1 划分对应的位平面
    2.2 将background的低位位平面替换为watermark的高位位平面
    2.3 合成图像(synthesis) ,实现嵌入
  3. 进行提取并绘制结果

本实验选择的嵌入位数是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 实验现象分析

  1. background和synthesis不仔细看是分不出来区别的,但是仔细看,能看出来swjtu的logo有些痕迹,如果减少嵌入位数,就无法看出痕迹了。
  2. extract_watermark的颜色和watermark的颜色不一致。实际测试,这应该是python绘图显示的原因,当我把水印区域的数据单独截取出来进行绘制。效果如下:
    在这里插入图片描述
    几乎与watermark一致,看不出来区别。
  3. extract_watermark水印的其他部分是因为没有做处理导致的。在进行提取的时候,没有给予提取算法的水印尺寸这个先验信息,算法不知道哪里是水印边界,因此只有水印部分可被算法正常提取,算法将其余部分与水印部分一视同仁进行提取,因此产生了像马赛克一样的图像。

1.4 所有实验现象

  1. embed_bit = 1
    在这里插入图片描述

  2. embed_bit = 2
    在这里插入图片描述

  3. embed_bit = 3
    4.

  4. embed_bit = 4
    5.

  5. embed_bit = 5
    6.

  6. embed_bit = 6
    7.

  7. embed_bit = 7
    8.

  8. embed_bit = 8
    9.

2. 更新-彩色水印嵌入与提取

该文章是对灰度图进行LSB进行操作,只需进行一些微微修改,即可实现图像的嵌入与提取,点击查看link

参考资料

[1]. github
[2]. 最低有效位LSB图像水印法[1.5x]

  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
LSB(Least Significant Bit)图像水印法是一种基于比特替换的图像水印技术,可以将一张水印图片嵌入到原始图像中,以达到保护版权、鉴别真伪等目的。下面是一个简单的 LSB 图像水印法的 Python 实现。 首先,我们需要安装 Pillow 库,它是 Python 的一个图像处理库,可以方便地进行图像读取、处理和保存等操作。在命令行中输入以下命令安装 Pillow: ``` pip install Pillow ``` 然后,我们定义一个函数 `encode_lsb()`,用于将水印图像嵌入到原始图像中。其中,参数 `src_path` 和 `watermark_path` 分别表示原始图像水印图像的路径,参数 `dst_path` 表示输出的带水印图像的路径: ```python from PIL import Image def encode_lsb(src_path, watermark_path, dst_path): # 加载原始图像水印图像 src_img = Image.open(src_path).convert('RGBA') watermark_img = Image.open(watermark_path).convert('RGBA') # 将水印图像缩放为原始图像的大小 watermark_img = watermark_img.resize(src_img.size, Image.ANTIALIAS) # 将水印图像转换为灰度图像,并获取它的像素值矩阵 watermark_data = watermark_img.convert('L').getdata() # 获取原始图像的像素值矩阵 src_data = list(src_img.getdata()) # 将水印图像的像素值嵌入到原始图像中 for i in range(len(src_data)): r, g, b, a = src_data[i] if i < len(watermark_data): watermark_bit = watermark_data[i] & 1 # 获取水印像素的最低位 if watermark_bit == 1: r |= 1 # 将原始像素的红色通道的最低位替换为1 else: r &= ~1 # 将原始像素的红色通道的最低位替换为0 src_data[i] = (r, g, b, a) # 保存带水印图像 dst_img = Image.new('RGBA', src_img.size) dst_img.putdata(src_data) dst_img.save(dst_path) ``` 接下来,我们定义一个函数 `decode_lsb()`,用于从带水印图像提取水印图像。其中,参数 `src_path` 表示带水印图像的路径,参数 `dst_path` 表示输出的水印图像的路径: ```python def decode_lsb(src_path, dst_path): # 加载带水印图像 src_img = Image.open(src_path).convert('RGBA') # 获取带水印图像的像素值矩阵 src_data = list(src_img.getdata()) # 从带水印图像提取水印图像的像素值 watermark_data = [] for i in range(len(src_data)): r, g, b, a = src_data[i] watermark_bit = r & 1 # 获取原始像素的红色通道的最低位 watermark_data.append(watermark_bit * 255) # 将最低位转换为像素值 # 保存水印图像 watermark_img = Image.new('L', src_img.size) watermark_img.putdata(watermark_data) watermark_img.save(dst_path) ``` 最后,我们可以调用这两个函数来进行 LSB 图像水印嵌入提取操作: ```python # 将水印图像嵌入到原始图像中 encode_lsb('原始图像路径', '水印图像路径', '输出图像路径') # 从带水印图像提取水印图像 decode_lsb('带水印图像路径', '输出图像路径') ``` 需要注意的是,LSB 图像水印法是一种比较简单的图像水印技术,易被攻击和破解。在实际应用中,需要考虑到安全性和鲁棒性等因素,并结合其他技术进行综合保护。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值