数字图像空域隐写与分析技术的实现

数字图像空域隐写与分析技术的实现
完成对BMP位图格式图像文件的MLSB数据位的随机隐写
完成对BMP位图格式图像文件的LSB顺序隐写
图片为BMP格式 语言为 Python
要下载完需要的库 如果下载完还要报错请检查路径是否编写正确和注释是否编写正确
前提提要:在需要手动输入路径时建议选一个比较短的路径的文件夹 且为英文路径的文件夹 这样方便输入,路径建议手动输入,粘贴路径可能会出现错误。
在输入隐写时隐写后的图片的命名要和原图不一样列如:12_1.bmp 和 12_1_LSB.bmp,原图是路径,隐写后的图片路径用来创造隐写后的图片


#%matplotlib inline
import re
import random
import math
import operator
from functools import reduce
from PIL import Image
import sys
import numpy
import matplotlib.pyplot as plt
from tkinter import filedialog


def LstBit(source, target):
    '''替换最后一位的数据'''
    replace_reg = re.compile(r'[1|0]$')  # 匹配二进制最后一位
    return replace_reg.sub(target, source)


def StringtoBin(file):#'''将字符串转换成二进制,不够8位补齐8位'''

    result = ''
    try:
        for s in file:
            for c in s:
                result += str(bin(ord(c))[2:])
    except:
        print("s: %s,c: %s" % (s, c))
    #     return ''.join(bin(ord(c)).replace('0b','').rjust(8,'0') for c in string)
    return result


def plus(str):
    # Python zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0
    return str.zfill(8)


def toasc(str):
    return int(str, 2)


def get_key(strr):
    # 获取要隐藏的文件内容
    tmp = strr
    with open(tmp, 'rb') as f:
        str = ""
        s = f.read()
        for i in range(len(s)):
            str = str + plus(bin((s[i])).replace('0b', ''))
        # print str
        print(len(str))
        f.closed
        return str


def mod(x, y):
    return x % y;


# Path为载体图片路径,New_Path为隐写文件路径,Data_Path为加密图片保存的路径
def lsb_shunxu(Path, New_Path, Data_Path):
    key = get_key(Data_Path)
    im = Image.open(Path)
    # 获取图片的宽和高
    width = im.size[0]
    height = im.size[1]
    count = 0
    # 获取需要隐藏的信息
    keylen = len(key)
    if width * height * 6 < len(key):
        print("请更换图片或更换需要隐写的信息")
        exit()
    if width * height * 6 >= len(key):
        print("可以隐写,请继续")
    for h in range(0, height):
        for w in range(0, width):
            '''
            pixel = im.getpixel((w, h))

            a = pixel[0]

            b = pixel[1]

            c = pixel[2]

            if count == keylen:
                break

            # 下面的操作是将信息隐藏进去

            # 分别将每个像素点的RGB值余2,这样可以去掉最低位的值

            # 再从需要隐藏的信息中取出一位,转换为整型

            # 两值相加,就把信息隐藏起来了

            a = a - mod(a, 2) + int(key[count])

            count += 1

            if count == keylen:
                im.putpixel((w, h), (a, b, c))

                break

            b = b - mod(b, 2) + int(key[count])

            count += 1

            if count == keylen:
                im.putpixel((w, h), (a, b, c))

                break

            c = c - mod(c, 2) + int(key[count])

            count += 1

            if count == keylen:
                im.putpixel((w, h), (a, b, c))

                break

            if count % 3 == 0:
                im.putpixel((w, h), (a, b, c))

        im.save(New_Path)

        '''
            pixel = im.getpixel((w, h))
            a = pixel[0]
            b = pixel[1]
            c = pixel[2]
            if count == keylen:
                break
                # 下面的操作是将信息隐藏进去

                # 分别将每个像素点的RGB值余2,这样可以去掉最低位的值

                # 再从需要隐藏的信息中取出一位,转换为整型

                # 两值相加,就把信息隐藏起来了
            a = a - mod(a, 2) - mod(int(a / 2), 2) * 2 + int(key[count]) * 2 + int(key[count + 1])
            count += 2
            if count == keylen:
                im.putpixel((w, h), (a, b, c))
                break
            b = b - mod(b, 2) - mod(int(b / 2), 2) * 2 + int(key[count]) * 2 + int(key[count + 1])
            count += 2
            if count == keylen:
                im.putpixel((w, h), (a, b, c))
                break
            c = c - mod(c, 2) - mod(int(c / 2), 2) * 2 + int(key[count]) * 2 + int(key[count + 1])
            count += 2
            if count == keylen:
                im.putpixel((w, h), (a, b, c))
                break
            if count % 3 == 0:
                im.putpixel((w, h), (a, b, c))

    im.save(New_Path)

#卡方分析需要的计算图片的灰度,用字典表示
def Ana(s2):
    im = Image.open(s2)
    width = im.size[0]
    height = im.size[1]
    photo = {}
    list = []
    for w in range(0, width):
        for h in range(0, height):
            pixel = im.getpixel((w, h))
            a = pixel[0]
            b = pixel[1]
            c = pixel[2]
            if a % 10 == 0 or a % 10 == 1 or a % 10 == 6 or a % 10 == 7:
                list.append(a)
            if b % 10 == 0 or b % 10 == 1 or b % 10 == 6 or b % 10 == 7:
                list.append(b)
            if b % 10 == 0 or c % 10 == 1 or c % 10 == 6 or c % 10 == 7:
                list.append(c)
    for word in list:
        photo[word] = photo.get(word, 0) + 1
    return photo


def EncodeLSB(Path, New_Path, Data):
    '''
    LSB加密
    path: 原图路径
    new_path: 为加密后图片的路径
    data: 为需要加密的数据
    '''
    # 初始化、定义

    data = StringtoBin(Data)#通过StringtoBin转化为8位二进制的格式
    #print(data)#添加行,此时的data已经是二进制
    im = Image.open(Path)#打开图片
    width = im.size[0]  # 宽度
    height = im.size[1]  # 高度
    count = 0
    if width * height * 3 / 5 < len(data):#
        print("数据过大,请更换图片或更换需要隐写的信息")
        return
    # 遍历图片所有像素点
    for h in range(0,height):#原heigth
        sum = 0
        for w in range(0,width):#原 width
            # 获取像素点
            choose = random.randint(0, 5)
            sum = sum + choose
            if sum >= width:
                sum = width - 1#
            pixel = im.getpixel((sum, h))
            # 取三通道值(十进制)
            R = pixel[0]
            G = pixel[1]
            B = pixel[2]
            # 十进制转二进制
            R_bit = bin(R).replace("0b", "")
            G_bit = bin(G).replace("0b", "")
            B_bit = bin(B).replace("0b", "")
            # 随机选取一个通道存末位二进制
            R_bit = LstBit(R_bit, data[count])
            count += 1
            if count == len(data):  # 存完数据时
                break
            # 在G通道的末位存数据
            G_bit = LstBit(G_bit, data[count])
            count += 1
            if count == len(data):  # 存完数据时
                break
            # 在B通道的末位存数据
            B_bit = LstBit(R_bit, data[count])
            count += 1
            if count == len(data):  # 存完数据时
                break
            # 二进制转十进制
            R_bit = int(R_bit, 2)
            G_bit = int(G_bit, 2)
            B_bit = int(B_bit, 2)
            # 写回像素点
            im.putpixel((sum, w), (R_bit, G_bit, B_bit))
            if sum == width - 1:
                break
        if count == len(data):  # 存完数据时
            break
    im.save(New_Path)

#信息量估计分析
def image_contrast(img1, img2):
    image1 = Image.open(img1)
    image2 = Image.open(img2)

    h1 = image1.histogram()
    h2 = image2.histogram()

    result = math.sqrt(reduce(operator.add, list(map(lambda a, b: (a - b) ** 2, h1, h2))) / len(h1))
    return result

#制作灰度直方图
def draw():
    s1 = input("请输入第一张图片地址:")
    s2 = input("请输入第二张图片地址:")
    a = Ana(s1)
    alen = len(a)
    b = Ana(s2)
    blen = len(b)
    list1 = list(a.values())#获取字典中的值
    list2 = list(b.values())
    plt.rcParams['font.sans-serif'] = 'SimHei'
    f = plt.figure(figsize=(8, 8))
    ax1 = f.add_subplot(2, 1, 1)
    plt.bar(range(0, len(list1)), list1)
    plt.title('原图灰度直方图')
    ax2 = f.add_subplot(2, 1, 2)
    plt.bar(range(0, len(list2)), list2)
    plt.title('隐藏信息灰度直方图')
    plt.show()


while (1):
    print("1. 进行MLSB顺序隐写")
    print("2. 进行卡方分析")
    print("3. 进行LSB随机隐写")
    print("4. 进行信息量估计法分析")
    print("5. 退出")
    choose = eval(input("请输入你想进行的操作的选项:"))
    if choose == 1:
        Path = input("请输入你想对哪张图片进行MLSB隐写的地址:")
        New_Path = input("请输入经过MLSB隐写后生成的图片地址:")
        Data_Path = input("请输入想要存储的文件地址:")
        lsb_shunxu(Path, New_Path, Data_Path)
    if choose == 2:
        draw()
    if choose == 3:
        random.seed(17)
        Path = input("请输入你想对哪张图片进行LSB随机的地址:")
        New_Path = input("请输入经过LSB随机隐写后生成的图片地址:")
        Data_Path = input("请输入想要存储的文件地址:")
        #Data = get_key(Data_Path)
        #Data = open(Data_Path, encoding="utf-8")上一行添加
        # 关闭文件
        with open(Data_Path) as f:
            Data = f.read()

        EncodeLSB(Path, New_Path,Data )#改了Data是读取后的文件内容
        #Data = open(Data_Path)#上一行添加
        #Data.close()
    if choose == 4:
        img1 = input("请输入第一张图片地址:")
        img2 = input("请输入第二张图片地址:")
        result = image_contrast(img1, img2)
        print(result)
    if choose == 5:
        break

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
空域编码图像 空域编码是指在图像空间域进行编码,也就是直接针对图像像素进行编码 对像素进行编码,如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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值