python 实现LSB信息隐藏算法

要求:
在这里插入图片描述

具体实现:

"""
@author: Bre Athy
@contact: https://www.zhihu.com/people/you-yi-shi-de-hu-xi
@productware: PyCharm
@file: main.py
@time: 2020/5/15 10:05
"""
from PIL import Image
import os,math,numpy as np,cv2

watermask = "E:\Code\InformationHiding\Lena\watermask.png"
output = "E:\Code\InformationHiding\LSB\output"

lena = "E:\Code\InformationHiding\Lena\LENA\lena512.bmp"     # 原图
embeddedGrey = os.path.join(output, "result.bmp")
originWm = os.path.join(output, "原生的水印二值图片.bmp")
extractWm = os.path.join(output, "提取出的水印二值图片.bmp")

def fillMartix(matrix, height, width):
    # 填充矩阵
    matrix2 = []
    for x in range(height):
        listX = []
        for y in range(width):
            listX.append(matrix[x%len(matrix)][y%len(matrix[0])])
        matrix2.append(listX)
    return matrix2


def getMatrix(img):
    # 获取矩阵
    img_data = img.load()
    matrix = []
    for x in range(img.height):
        listX = [img_data[y,x] for y in range(img.width) ]
        matrix.append(listX)
    return matrix




def putLSB(OriMartrix, WmMatrix, n = -1):
    # LSB嵌入:从原图左上角放置二值水印
    # OriMartrix    原图的灰度矩阵
    # WmMatrix      二值图像的灰度矩阵
    # n             要替换的位数,0表示第1位,-1表示最后一位
    Height = len(OriMartrix)
    height = len(WmMatrix)
    if not height:return OriMartrix
    Width = len(OriMartrix[0])
    width = len(WmMatrix[0])
    if not width: return OriMartrix
    if height > Height or width > Width:
        print("水印矩阵长宽应该小于灰度矩阵!")
        return
    n = n%8
    newMartrix = []
    for row in range(Height):
        listX = []
        for col in range(Width):
            if row < height and col < width:
                w = '0'
                o = "{:08b}".format(OriMartrix[row][col])
                if WmMatrix[row][col]:  w='1'
                listX.append(int(o[:n] + w + o[(n+1):], 2))
            else:
                listX.append(OriMartrix[row][col])
        newMartrix.append(listX)
    return newMartrix

def getLSB(OldMartrix, height = 0, width = 0, n = -1):
    # LSB提取:从原图左上角放置二值水印
    # OldMartrix    嵌入水印的灰度图片的矩阵
    # width,height  获取要裁剪的像素长和宽, 如果为0表示裁剪全图
    # n             水印的位于的位数,0表示第1位,-1表示最后一位
    if width > len(OldMartrix[0]) or height > len(OldMartrix):
        print("水印长宽应该小于灰度矩阵!")
        return
    if width == 0 and height == 0:
        width = len(OldMartrix[0])
        height = len(OldMartrix)
    n = n%8
    NewMartrix = []
    for row in range(height):
        listX = []
        for col in range(width):
            if "{:08b}".format(OldMartrix[row][col])[n] == '1':listX.append(255)
            else:listX.append(0)
        NewMartrix.append(listX)
    return NewMartrix


def psnr(img1, img2):
    # PSNR计算
    mse = np.mean((img1 / 255. - img2 / 255.) ** 2)
    if mse < 1.0e-10:
        return 100
    PIXEL_MAX = 1
    return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))



def main():
    # 获取原图像的大小并转为灰度矩阵
    Ori = Image.open(lena).convert('L')
    OriMartrix = getMatrix(Ori)
    # 将水印图片加载为等大二值矩阵
    Wm = Image.open(watermask).convert('1')
    # 保存二值图片
    Wm.save(originWm)
    # 填充水印的像素为原图的相同大小
    WmMatrix = fillMartix(getMatrix(Wm), Ori.height, Ori.width)
    # 嵌入水印
    NewMatrix = putLSB(OriMartrix, WmMatrix)
    Img = Image.fromarray(np.array(NewMatrix)).convert("L")
    # 保存嵌入图
    Img.save(embeddedGrey)
    print("******************** LSB嵌入 ********************")
    print("原图像:", lena)
    print("水印原图像:",watermask)
    print("水印二值图像:", originWm)
    print("嵌入水印的图像:", embeddedGrey)

    # 读取嵌入图并转为灰度矩阵
    Old = Image.open(embeddedGrey).convert('L')
    OldMartrix = getMatrix(Old)
    # 提取水印图
    WmMatrix = getLSB(OldMartrix)
    WmImg = Image.fromarray(np.array(WmMatrix)).convert("1")
    # 保存提取的水印图
    WmImg.save(extractWm)

    print("******************** LSB提取 ********************")
    print("提取的水印二值图像:", extractWm)

    # 不可见性,PSNR
    # cv2涉及的路径不能包含中文
    print("******************** 不同的图的PSNR ********************")
    inputDir = "E:\Code\InformationHiding\Lena\workplace"
    for bmp in os.listdir(inputDir):
        path1 = os.path.join(inputDir, bmp)
        Ori = getMatrix(Image.open(path1).convert('L'))
        Wm = fillMartix(getMatrix(Image.open(watermask).convert('1')), len(Ori), len(Ori[0]))
        Gen = Image.fromarray(np.array(putLSB(Ori, Wm))).convert('L')
        path2 = os.path.join(output, bmp)
        Gen.save(path2)
        oriImg = cv2.imread(path1)
        genImg = cv2.imread(path2)
        print(psnr(oriImg, genImg), bmp)

    # 相同的图信息量不同的PSNR
    print("******************** 对lena图嵌入不同信息量时的PSNR ********************")
    OriMartrix = getMatrix(Image.open(lena).convert('L'))
    Wm = getMatrix(Image.open(watermask).convert('1'))
    for i in range(0, 110, 10):
        WmMatrix = fillMartix(OriMartrix, int(len(OriMartrix)*i*0.01), len(OriMartrix[0]))
        Gen = Image.fromarray(np.array(putLSB(OriMartrix, WmMatrix))).convert('L')
        path3 = os.path.join(output, "lena " + str(i)+".bmp")
        Gen.save(path3)
        oriImg = cv2.imread(lena)
        genImg = cv2.imread(path3)
        print(i, psnr(oriImg, genImg))

    # 错误率
    # 比较水印的像素矩阵,计算不同的像素个数/总个数
    wm1 = getMatrix(Image.open(originWm).convert("1"))
    wm2 = getMatrix(Image.open(extractWm).convert("1"))
    e,h,w = 0, len(wm1), len(wm1[0])
    for i in range(h):
        for j in range(w):
            if wm1[i][j] != wm2[i][j]:
                e += 1
    print("******************** 错误率 ********************")
    print("错误元素一共", e,"个,错误率:", e/h/w)


    # 鲁棒性,加噪或压缩【保存为jpg】后查看水印错误率, 此处计算的压缩后的值
    jpgPath = os.path.join(output, "result.jpg")
    Old.save(jpgPath)
    jpg = Image.open(jpgPath).convert('L')
    wm2 = getLSB(getMatrix(jpg))
    extractJpg = os.path.join(output, "压缩图片提取出的水印.bmp")
    Image.fromarray(np.array(WmMatrix)).convert("1").save(extractJpg)
    e, h, w = 0, len(wm1), len(wm1[0])
    for i in range(h):
        for j in range(w):
            if wm1[i][j] != wm2[i][j]:
                e += 1
    print("******************** 鲁棒性测试 ********************")
    print("压缩后的图片:", jpgPath)
    print("提取的水印:", extractJpg)
    print("错误元素一共", e, "个,错误率:", e / h / w)


if __name__ == "__main__":
    main()

实机演示:
在这里插入图片描述
附注:

  • PSNR值得计算是参考了网上的代码,才不得已引入了cv2这个库
  • 这个最好载Matlab中实现,可是我懒得在学一门语言,于是就用python做了
  • 项目用到的资源图片会在另外两个实验做完后打包放在一起,这里只放了源码
  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值