飞道的博客

Python 基于位平面的信息隐藏算法 阿诺德置乱算法

387人阅读  评论(0)

基于位平面的信息隐藏算法

使用Python3.6实现,numpy版本1.19.2,环境使用Jupyter Notebook。

实现步骤

  1. 提取载体的位平面
  2. 直接替换低位位平面,再组合成图片
  3. 进行阿诺德置乱,直接组合成图片
  4. 阿诺德置乱后对位平面进行异或处理,再组成图片

算法

位平面提取算法:
使用Python的cv2读入图像,转换为Numpy的array类型,对array取余2,得到一个位平面,再整除2后取余2,辗转相除得到8个位平面,存放到数组中。

阿诺德算法:
传入图像和置乱次数,计算替换位置,置乱图像。

位平面还原算法:
将每个位平面乘以对应层次(i)的2^i后相加。

异或算法:
使用numpy 的logical_xor函数实现。函数传入的两个ndarray进行异或,返回ndarray(True或False)

#%%

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt # plt 用于显示图片
import cv2

#%%

np.__version__


#%%

def aPlane(img):
    """
    提取位平面
    :param img:
    :return:返回位平面数组,每层对应一个
    """
    I = np.array(img)
    IMG=[0,0,0,0,0,0,0,0]
    
    for i in range(8):
        IMG[i]=I%2
        I=I//2
    return IMG

def showImg(img):
    """
    辅助函数 显示图片
    :param img:
    :return:
    """
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))#将numpy的图像数据转换为plt的图像数据 (BGR转换为RGB)
    plt.show()
    
def showPlane(IMG):
    """
    辅助函数 显示位平面
    :param IMG:
    :return:
    """
    for i in range(len(IMG)):
        showImg(IMG[i]*255)

#%% md

## 阿诺德置乱算法

#%%

def arnold(img,s):
    r, c,d = img.shape
    img = img[:,:,0]
    p = np.zeros((r, c), np.uint8)
    a = 1
    b = 1
    for _s in range(s):#反置乱次数
        for i in range(r):
            for j in range(c):
                x = (i + b * j) % r
                y = (a * i + (a * b + 1) * j) % c
                p[x, y] = img[i, j]
                """错误:ValueError: setting an array element with a sequence. 两个矩阵没有对齐"""
        img = np.copy(p)#深复制
    return p

#%%

#阿诺德反置乱算法
def dearnold(img,times):
    if len(img.shape)>=3:
        res = img[:,:,0]
    else:
        res = img
    r, c = res.shape
    dp = np.zeros((r, c), np.uint8)
    a = 1
    b = 1
    for s in range(times):#反置乱次数
        for i in range(r):
            for j in range(c):
                x = ((a * b + 1) * i - b * j) % r
                y = (-a * i + j) % c
                dp[x, y] = res[i, j]
        res = np.copy(dp)#深复制
    return res

#%% md

## 组合位平面算法


#%%

def Plane2Origin(r, c ,IMG):
    """
    组合位平面
    :param r: 图像的宽
    :param c: 图像的高
    :param IMG:位平面数组
    :return: 组合后的图像数组
    """
    reduction = np.zeros((r, c), np.uint8)
    for i in range(0,8):
        reduction = reduction + IMG[i]*2**i
        print(IMG[i]*2**i)
    return reduction

#%% md

## 直接写隐藏信息

#%%

def makeSecret():
    """
    辅助函数 直接读取秘密信息 并进行阿诺德置乱
    :return:
    """
    #读取秘密信息
    imgfile = "secret.bmp"
    img = cv2.imread(imgfile)
    print("cv2.imread(imgfile, cv2.IMREAD_GRAYSCALE)结果如下:")
    print('大小:{}'.format(img.shape))
    print("类型:%s" % type(img))
    print(img)
    #置乱
    res = arnold(img,3)
    showImg(res)

    #测试还原
    deres = dearnold(res,3)
    showImg(deres)
    return res

#%%

#读取载体
I = Image.open('LenaGray.bmp')
IMG = aPlane(I)

SecretImgFile = "secret.bmp"
SecretImg = cv2.imread(SecretImgFile)
plt.imshow(SecretImg)
plt.show()
print(SecretImg.shape)
#nick
#%%

print(IMG)
# 直接替换最低位平面

IMG[0] = np.copy(SecretImg[:,:,0])
# IMG[0] = np.copy(SecretImg[:,:,0]//255)#要位移!

#%%
# 结合成原图
r,c = np.array(I).shape
reduction = Plane2Origin(r,c ,IMG)

#显示原图
showImg(reduction)

#%% md
测试提取
#%%
IMG = aPlane(reduction)
showPlane(IMG)

#%% md
## 进行阿诺德置乱后替换
#%%
arnoldres = makeSecret()
#%%
#读取载体
I = Image.open('LenaGray.bmp')
I = np.array(I)
r,c = I.shape
IMG = aPlane(I)
#%%
#替换
# IMG[0] = np.copy(arnoldres)
#这里需要除以255 否则信息会显示
IMG[0] = np.copy(arnoldres//255)
#%%
reduction = Plane2Origin(r, c ,IMG)
print(reduction.shape)
showImg(reduction)
#%% md
~~~置乱过后虽然看不清了 但是载体还是很明显有痕迹~~~

要位移 隐藏后就不显示了

## 提取信息
#%%
#先看看IMG里0的数据
print(IMG[0],IMG[0].shape)
#%%
deIMG = aPlane(reduction)
showPlane(deIMG)
#%%
print(deIMG[0]*255)
deres = dearnold(deIMG[0]*255,3)
showImg(deres)
#%% md
*还原成功*
#%% md
# 置乱并异或 隐藏
#%%
arnoldres = makeSecret()
#%%
#读取载体
I = Image.open('LenaGray.bmp')
I = np.array(I)
r,c = I.shape
IMG = aPlane(I)
#Nick
#%%
IMG[0]//255
#%%
showImg(IMG[0]*255)
IMG[0]
#%%
res =np.logical_xor(IMG[0]//255,IMG[1])
res
false_num = res.astype(int)
print(false_num)
#%%
arnoldres = makeSecret()
#%%

#进行异或处理
res = arnoldres
for i in range(1,8):#从次低位到高位
    #logical_xor 对传入的两个ndarray进行异或 返回逻辑ndarray
    #astype(np.uint8) 将True False 转换为1 0
    #np.uint8 是载体传入时的类型
    res = np.logical_xor(res,IMG[i]).astype(np.uint8)
showImg(res*255)

#%%
IMG[0] = res#替换
r, c = 256,256
reduction2 = Plane2Origin(r, c ,IMG)
print(reduction2.shape)
showImg(reduction2)
#%% md
*成功隐藏*
测试提取 并 反异或
#%%
#提取位平面
deIMG = aPlane(reduction2)
showPlane(deIMG)
#%%
#反阿诺德 (已经被异或处理了 不能进行反阿诺德置乱的)
print(deIMG[0]*255)
deres = dearnold(deIMG[0]*255,3)
showImg(deres)
#%%
#反异或后反阿诺德
res = deIMG[0]
for i in range(1,8):#从次低位到高位
    res = np.logical_xor(res,deIMG[i]).astype(np.uint8)
showImg(res*255)
deres = dearnold(res*255,3)
showImg(deres)

#%%

读取载体:

直接进行替换:

阿诺德置乱后组合:



异或处理后再组合成原图:




结果

1.直接替换最低位平面也能很好的达到隐藏效果。
2.进行阿诺德置乱和异或后使秘密信息更加隐蔽。
3.异或后的最低位平面不能直接进行反阿诺德置乱,且图像也是充满了噪点,使得攻击者无法判断是否有隐藏信息。

出现的错误

1.numpy的ndarray类型没有对齐,导致两个数组无法赋值,需要对shape大的进行截取。
2.使用matplotlib.pyplot显示图像成黄色,因为从numpy传入的数据是BGR的,要转换为RGB才能正常显示。
3.转换图像时使用cv2的方法,float64是numpy的数据类型,opencv中不支持,需要转换为float32或者uint8。
4.替换位平面的时没有将隐藏信息位移,导致图像上直接显示隐藏信息。


转载:https://blog.csdn.net/weixin_43924621/article/details/116211424
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场