Python 实现LSB算法进行信息隐藏 包含空域与变换域 JPEG信息隐藏算法 对PDF文件进行信息隐藏 基于卷积神经网络的隐写分析 Matlab SRM、SCA隐写分析

空域编码图像


  • 空域编码是指在图像空间域进行编码,也就是直接针对图像像素进行编码

  • 对像素进行编码,如 LSB 算法,主要有下面两种方式

  • 光栅格式

  • 调色板格式 GIF(graphics interchange format)

  • 一个图像编码标准往往包括多类编码方法,一个图像仅仅是其一类方法的实例。例如,常见的 BMP(Bitmap)、 TIFF( Tagged Image File Format)、 PNG(Portable Network Graphics)均支持光栅格式与调色板格式编码,对这两种格式 编码分别又支持多种具体编码方法

LSB 隐写算法


  • LSB 隐写是最基础、最简单的隐写方法,具有容量大、嵌入速度快、对载体图像质量影响小的特点

  • LSB 的大意就是最低比特位隐写。我们将深度为 8 的 BMP 图像,分为 8 个二值平面(位平面),我们将待嵌入的信息(info)直接写到最低的位平面上。换句话说,如果秘密信息与最低比特位相同,则不改动;如果秘密信息与最低比特位不同,则使用秘密信息值代替最低比特位

嵌入信息前的载体图片

嵌入信息后的载体图片

变换域编码图像


JPEG


  • Joint Photographic Experts Group(联合图像专家小组)的缩写

JPEG 编码

JSteg 隐写

  • JSteg 的算法的主要思想是将秘密消息嵌入在量化后的 DCT 系数的最低比特位上,但对原始值为 0、+1、-1 的 DCT 系数不进行嵌入,提取秘密消息时,只需将载密图像中不等于 0、l 的量化 DCT 系数的 LSB 取出即可

  • JSteg 算法步骤

  1. 选择载体图像,并且将载体图像划分为连续的 8×8 的子块。

  1. 对每个子块使用离散余弦变换之后,用相应的质量因数的量化表量化,得到对应的 8×8 量化 DCT 子块。

  1. 将需要隐藏的信息编码为二进制数据流,对 DCT 子块系数进行 Z 字形扫描,并且使用秘密信息的二进制流替换非 0 和非 1 的 DCT 系数的最低比特位。

  1. 进行熵编码等,产生 JPEG 隐密图像。

  • JSteg 的具体嵌入过程

  1. 部分解码 JPEG 图像,得到二进制存储的 AC 系数,判断该 AC 系数是否等于正负 1 或 0,若等于则跳过该 AC 系数,否则,执行下一步

  1. 判断二进制存储的 AC 系数的 LSB 是否与要嵌入的秘密信息比特相同,若相同,则不对其进行修改,否则执行下一步

  1. 用秘密信息比特替换二进制存储的 AC 系数的 LSB,将修改后的 AC 系数重新编码得到隐秘 JPEG 图像

  • JSteg 不使用 0、1 的原因

  1. DCT 系数中“0”的比例最大(一般可达到 60% 以上,取决于图像质量和压缩因子),压缩编码是利用大量出现连零实现的,如果改变 DCT 系数中“0”的话,不能很好的实现压缩

  1. DCT 系数中的“1”若变成“0”,由于接受端无法区分未使用的“0”和嵌入消息后得到的“0”,从而无法实现秘密信息的提取

F3 隐写

  • 为了改善大量 DCT 系数不隐藏信息这一状况,人们提出了 F3 隐写

  • F3 对原始值为 +1 和-1 的 DCT 系数,进行了利用。F3 隐写的规则如下

  1. 每个非 0 的 DCT 数据用于隐藏 1 比特秘密信息,为 0 的 DCT 系数不负载秘密信息

  1. 如果秘密信息与 DCT 的 LSB 相同,便不作改动;如果不同,将 DCT 系数的绝对值减小 1,符号不变

  1. 当原始值为 +1 或-1 且预嵌入秘密信息为 0 时,将这个位置归 0 并视为无效,在下一个 DCT 系数上重新嵌入

  • 编写代码实现嵌入,并观察 DCT 系数变化 代码实现

JPEG的DCT系数
{0: 32939, 1: 15730, 2: 13427, 3: 11523, 4: 9540, 5: 7957, 6: 6607, 7: 5697, 8: 4834, -1: 15294, -2: 13637, -3: 11479, -4: 9683, -5: 7979, -6: 6878, -7: 5631, -8: 4871}
Jsteg begin writing!
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
经过信息隐藏后JPEG的DCT系数变化
{0: 32939, 1: 15730, 2: 12552, 3: 12398, 4: 8739, 5: 8758, 6: 6165, 7: 6139, 8: 4487, -1: 15294, -2: 12721, -3: 12395, -4: 8891, -5: 8771, -6: 6319, -7: 6190, -8: 4463}
F3steg begin writing!
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
经过信息隐藏后JPEG的DCT系数变化
{0: 47068, 1: 13416, 2: 13519, 3: 10075, 4: 9545, 5: 7077, 6: 6650, 7: 5016, 8: 4754, -1: 13308, -2: 13668, -3: 10124, -4: 9571, -5: 7249, -6: 6591, -7: 5098, -8: 4733}
F4steg begin writing!
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
经过信息隐藏后JPEG的DCT系数变化
{0: 59320, 1: 13618, 2: 11987, 3: 9875, 4: 8328, 5: 6860, 6: 5883, 7: 4910, 8: 4239, -1: 13692, -2: 11976, -3: 9976, -4: 8428, -5: 7007, -6: 5834, -7: 4964, -8: 4190}
  • 条形图绘制

  • 未经过信息隐藏的 DCT 系数,系数近似符合拉普拉斯分布,具有几个典型特点

  • 对称性 以 0 为中心达到最大值,两侧分布近似对称

  • 单侧单调性 以 0 值为中心达到最大值,两侧单调下降

梯度下降性 小值样点较多,大值样点较少,分布曲线在两侧下降梯度逐渐减小

  • JSteg 隐写的 DCT 系数

JSteg 隐写可嵌入信息的 DCT 系数较少,隐写量较小,且相邻数值样点的个数接近,如 2 和 3,-2 和-3 形成了值对,卡方特征变化明显,因而提出了 F3 隐写

  • F3 隐写的 DCT 系数

  • F3 的设计虽然防止了相邻值出现数量接近的现象,也维持了分布函数的对称性,但使得偶数的分布增加,没有满足单调性

  • 这是因为载体绝对值为 1 的数值较多,当其被修改为 0 时,嵌入算法继续嵌入直到找到一个偶数值,或者将一个奇数值改为偶数值,这样绝对值为 1 的系数可以支持嵌入 1,但是不支持嵌入 0,需要使用或制造一个偶数

  • 另外,0 系数的数量有相应的增加,产生分布曲线向 0 收缩的现象

F4 隐写

  • 为了克服 F3 的缺陷,F4 对不同正负号的奇偶系数采用了不同的嵌入与消息表示方法

  • F4 用负偶数、正奇数代表嵌入了消息比特 1,用负奇数、正偶数代表嵌入了 0

  • 但仍然通过减小绝对值的方法进行修改,如果减小绝对值后系数为 0 则继续往下嵌入当前比特

代码实现

  • F4 隐写的 DCT 系数

  • F4 显然保持了载体分布函数的对称性,也保持了载体分布函数的单调性与梯度下降性

  • 但 F4 依然存在使含密载体分布函数形状向 0 收缩的现象

F5 隐写

F5 隐写实现了基于汉明码的矩阵编码隐写,在一个分组上最多修改 R=1 次以嵌入 $2^r-1-r$ 比特,采用的基本嵌入方法是基于 F4 隐写的

F5 的嵌入步骤

  • 获得嵌入域。若输入的是位图,则进行 JPEG 编码得到 JPEG 系数;若输入的是 JPEG 图像,则进行熵编码的解码得到 JPEG 系数

  • 位置置乱。根据口令生成的密钥位一个伪随机数发生器,基于伪随机数发生器置乱 JPEG 系数的位置

  • 编码参数确定。为了提高嵌入效率,一般希望 n 尽可能大,因此,根据载体中可用系数的数量与消息的长度确定参数 r,并计算$n=2^r-1$

  • 基于($n=2^r-1,r$)的汉明分组码得到编码校验矩阵,开始嵌入消息:

  • ① 按置乱后的顺序取下面 n 个非零系数,在其中的 LSB 序列中按照以上编码嵌入 n-r 比特的消息;

  • ② 如果未发生修改,并且还有需要嵌入的消息,则返回 ① 继续嵌入下一分组;

  • ③ 如果进行了修改,则判断是不是有系数值收缩到 0,如果没有,并且还有需要嵌入的消息则返回 ① 继续嵌入下一分组,如果有,取出一个新的非零系数组成新的一组 n 个非零系数,在其中的 LSB 序列中按照以上编码重新嵌入以上 n-r 比特的消息,直到没有修改或收缩,最后,如果还有需要嵌入的消息,则返回 ① 继续嵌入下一分组

  • 位置逆置乱。恢复 DCT 系数原来的位置顺序

  • 熵编码。按照 JPEG 标准无损压缩 DCT 量化系数,得到 JPEG 文件

完整代码:https://download.csdn.net/download/weixin_55771290/87416129

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
空域编码图像 空域编码是指在图像空间进行编码,也就是直接针对图像像素进行编码 对像素进行编码,如LSB算法,主要有下面两种方式 光栅格式 调色板格式 GIF(graphics interchange format) 一个图像编码标准往往包括多类编码方法,一个图像仅仅是其一类方法的实例。例如,常见的BMP(Bitmap)、 TIFF( Tagged Image File Format)、 PNG(Portable Network Graphics)均支持光栅格式与调色板格式编码,对这两种格式 编码分别又支持多种具体编码方法 LSB隐写算法 LSB隐写是最基础、最简单的隐写方法,具有容量大、嵌入速度快、对载体图像质量影响小的特点 LSB的大意就是最低比特位隐写。我们将深度为8的BMP图像,分为8个二值平面(位平面),我们将待嵌入的信息(info)直接写到最低的位平面上。换句话说,如果秘密信息与最低比特位相同,则不改动;如果秘密信息与最低比特位不同,则使用秘密信息值代替最低比特位 JPEG编码 JSteg隐写 JSteg的算法的主要思想是将秘密消息嵌入在量化后的DCT系数的最低比特位上,但对原始值为0、+1、-1的DCT系数不进行嵌入,提取秘密消息时,只需将载密图像中不等于0、l的量化DCT系数的LSB取出即可 JSteg算法步骤 选择载体图像,并且将载体图像划分为连续的8×8的子块。 对每个子块使用离散余弦变换之后,用相应的质量因数的量化表量化,得到对应的8×8量化DCT子块。 将需要隐藏的信息编码为二进制数据流,对DCT子块系数进行Z字形扫描,并且使用秘密信息的二进制流替换非0和非1的DCT系数的最低比特位。 进行熵编码等,产生JPEG隐密图像。 JSteg的具体嵌入过程 部分解码JPEG图像,得到二进制存储的AC系数,判断该AC系数是否等于正负1或0,若等于则跳过该AC系数,否则,执行下一步 判断二进制存储的AC系数的LSB是否与要嵌入的秘密信息比特相同,若相同,则不对其进行修改,否则执行下一步 用秘密信息比特替换二进制存储的AC系数的LSB,将修改后的AC系数重新编码得到隐秘JPEG图像 JSteg不使用0、1的原因 DCT系数中“0”的比例最大(一般可达到60%以上,取决于图像质量和压缩因子),压缩编码是利用大量出现连零实现的,如果改变DCT系数中“0”的话,不能很好的实现压缩 DCT系数中的“1”若变成“0”,由于接受端无法区分未使用的“0”和嵌入消息后得到的“0”,从而无法实现秘密信息的提取 代码实现F3隐写
1. LSB信息隐藏算法实现 LSB信息隐藏算法是一种简单的信息隐藏方法,它将消息的二进制码嵌入到像素的最低有效位中,从而实现信息隐藏。以下是一个简单的Python实现: ```python from PIL import Image def encode_image(image_path, secret_message): """将秘密消息嵌入到图像中""" # 打开图像文件 image = Image.open(image_path) # 将秘密消息转换为二进制字符串 binary_message = ''.join([format(ord(char), "08b") for char in secret_message]) # 检查是否有足够的像素来嵌入消息 if len(binary_message) > image.width * image.height: raise ValueError("不够的像素来嵌入消息!") # 将二进制消息嵌入到图像中 encoded_image = image.copy() index = 0 for x in range(image.width): for y in range(image.height): # 获取像素的RGB值 r, g, b = image.getpixel((x, y)) # 将消息嵌入到最低有效位 if index < len(binary_message): r &= 0b11111110 | int(binary_message[index]) index += 1 if index < len(binary_message): g &= 0b11111110 | int(binary_message[index]) index += 1 if index < len(binary_message): b &= 0b11111110 | int(binary_message[index]) index += 1 # 更新像素值 encoded_image.putpixel((x, y), (r, g, b)) # 检查是否已经完成嵌入 if index >= len(binary_message): return encoded_image return encoded_image def decode_image(image_path): """从图像中提取秘密消息""" # 打开图像文件 image = Image.open(image_path) # 从图像中提取秘密消息 binary_message = "" for x in range(image.width): for y in range(image.height): # 获取像素的RGB值 r, g, b = image.getpixel((x, y)) # 提取最低有效位 binary_message += str(r & 1) binary_message += str(g & 1) binary_message += str(b & 1) # 检查是否已经提取完整个消息 if len(binary_message) >= 8 and binary_message[-8:] == "00000000": # 将二进制消息转换回字符串 secret_message = "" for i in range(0, len(binary_message)-8, 8): secret_message += chr(int(binary_message[i:i+8], 2)) return secret_message # 如果未找到消息,则返回None return None ``` 使用示例: ```python # 将秘密消息嵌入到图像中 encoded_image = encode_image("image.png", "Hello, world!") # 保存嵌有秘密消息的图像 encoded_image.save("encoded_image.png") # 从图像中提取秘密消息 secret_message = decode_image("encoded_image.png") print(secret_message) ``` 2. 改进的LSB信息隐藏算法实现 改进的LSB信息隐藏算法是一种更加安全的信息隐藏方法,它在嵌入信息时考虑到了像素值的分布情况,从而使得嵌入的信息更加难以被检测到。以下是一个简单的Python实现: ```python from PIL import Image import numpy as np import math def mean_squared_error(img1, img2): """计算两张图像的均方误差""" mse = np.mean((img1 - img2) ** 2) return mse def peak_signal_to_noise_ratio(img1, img2): """计算两张图像的峰值信噪比""" mse = mean_squared_error(img1, img2) if mse == 0: return float('inf') psnr = 20 * math.log10(255.0 / math.sqrt(mse)) return psnr def encode_image(image_path, secret_message, alpha=0.1): """将秘密消息嵌入到图像中""" # 打开图像文件 image = Image.open(image_path) # 将秘密消息转换为二进制字符串 binary_message = ''.join([format(ord(char), "08b") for char in secret_message]) # 检查是否有足够的像素来嵌入消息 if len(binary_message) > image.width * image.height: raise ValueError("不够的像素来嵌入消息!") # 将二进制消息嵌入到图像中 encoded_image = image.copy() index = 0 for x in range(image.width): for y in range(image.height): # 获取像素的RGB值 r, g, b = image.getpixel((x, y)) # 计算像素的分布情况 rgb = np.array([r, g, b], dtype=np.float32) rgb_std = np.std(rgb) if rgb_std == 0: continue rgb_mean = np.mean(rgb) p = rgb_std / rgb_mean # 计算alpha值 alpha_prime = alpha * p # 将消息嵌入到最低有效位 if index < len(binary_message): if binary_message[index] == "0": r_prime = r - alpha_prime if r_prime < 0: r_prime = 0 else: r_prime = r + alpha_prime if r_prime > 255: r_prime = 255 index += 1 else: r_prime = r if index < len(binary_message): if binary_message[index] == "0": g_prime = g - alpha_prime if g_prime < 0: g_prime = 0 else: g_prime = g + alpha_prime if g_prime > 255: g_prime = 255 index += 1 else: g_prime = g if index < len(binary_message): if binary_message[index] == "0": b_prime = b - alpha_prime if b_prime < 0: b_prime = 0 else: b_prime = b + alpha_prime if b_prime > 255: b_prime = 255 index += 1 else: b_prime = b # 更新像素值 encoded_image.putpixel((x, y), (int(r_prime), int(g_prime), int(b_prime))) # 检查是否已经完成嵌入 if index >= len(binary_message): return encoded_image return encoded_image def decode_image(image_path, alpha=0.1): """从图像中提取秘密消息""" # 打开图像文件 image = Image.open(image_path) # 从图像中提取秘密消息 binary_message = "" for x in range(image.width): for y in range(image.height): # 获取像素的RGB值 r, g, b = image.getpixel((x, y)) # 计算像素的分布情况 rgb = np.array([r, g, b], dtype=np.float32) rgb_std = np.std(rgb) if rgb_std == 0: continue rgb_mean = np.mean(rgb) p = rgb_std / rgb_mean # 计算alpha值 alpha_prime = alpha * p # 提取最低有效位 if abs(r - (r - alpha_prime)) > abs(r - (r + alpha_prime)): binary_message += "1" else: binary_message += "0" if abs(g - (g - alpha_prime)) > abs(g - (g + alpha_prime)): binary_message += "1" else: binary_message += "0" if abs(b - (b - alpha_prime)) > abs(b - (b + alpha_prime)): binary_message += "1" else: binary_message += "0" # 检查是否已经提取完整个消息 if len(binary_message) >= 8 and binary_message[-8:] == "00000000": # 将二进制消息转换回字符串 secret_message = "" for i in range(0, len(binary_message)-8, 8): secret_message += chr(int(binary_message[i:i+8], 2)) return secret_message # 如果未找到消息,则返回None return None ``` 使用示例: ```python # 将秘密消息嵌入到图像中 encoded_image = encode_image("image.png", "Hello, world!", alpha=0.2) # 保存嵌有秘密消息的图像 encoded_image.save("encoded_image.png") # 从图像中提取秘密消息 secret_message = decode_image("encoded_image.png", alpha=0.2) print(secret_message) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员奇奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值