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

数字图像空域隐写与分析技术的实现
完成对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

你可能感兴趣的:(信息隐藏,python,numpy)