使用Python3.6实现,numpy版本1.19.2,环境使用Jupyter Notebook。
位平面提取算法:
使用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.替换位平面的时没有将隐藏信息位移,导致图像上直接显示隐藏信息。