引言
闲言:这篇博客回归了传统图像处理领域,主要是在研究生的数字图像处理课程上接触到了新的知识--图像位平面,觉得还挺有意思的,可以用来做信息隐藏,索性记录一下。因为拖延的缘故,到学期末才赶出来一篇,后续可能还会有一篇消除图像摩尔纹的trick介绍(如果效果好的话)。 本文的主题是介绍图像位平面相关知识,并依据不同位平面包含信息量的多寡设计了一种图像信息隐藏的算法,实际就是位平面的叠加,可以适用于图片加水印等场景。
图像位平面
首先对图像的位平面进行介绍,众所周知,图像在计算机中存储方式为二维矩阵,矩阵的每一个元素都代表对应位置处像素点的亮度值,通常用uint8
来表示,取值范围为0~255。换而言之,每个像素点都是一个8位二进制数,那么如果我们将每个像素点的一位抽取出来就可构造一个对应原图大小的为片面,其元素取值变为了0~1。举例而言,假设有一2*2的图像,其灰度值为: <math xmlns="http://www.w3.org/1998/Math/MathML"> [ [ 1 , 2 ] , [ 3 , 4 ] ] [[1,2],[3,4]] </math>[[1,2],[3,4]] 那么其最低位位平面就为: <math xmlns="http://www.w3.org/1998/Math/MathML"> [ [ 1 , 0 ] , [ 1 , 0 ] ] [[1,0],[1,0]] </math>[[1,0],[1,0]]
值得注意的是,不同位片面的取值范围虽然相同,但其所包含的信息量是不同的(或者说权重),这是因为在构成图像时,它们要乘以对应二进制位数的权重,而位数越高从0变换至1或者从1变化至0给图像带来的影响越剧烈,位数越高保留的图像信息越整体,反之则越细节。对比如下:
那么利用这一性质,我们就可以把用隐藏图片的最高位平面替换载体图片的最低位片面来达到隐藏信息,或者给图片加水印的目的。
代码
代码上实现还是比较简单的,通过与运算提取出待隐藏图片的最高位平面,将其信息移动到要插入的位平面;然后去除载体图片对应的位平面,并进行替换即完成了隐藏部分。复原部分就只是前一阶段的逆过程,整体如下所示
python
import cv2
import warnings
import numpy as np
import matplotlib.pyplot as plt
def InfoHidden(carry_img,info_img,bit_plane):
"""
carry_img: 作为载体的图片
info_img: 作为隐藏信息的图片
bit_plane: 要进行信息替换的平面
"""
assert bit_plane in range(0,8),"Invaied BitPlane"
if carry_img.shape!=info_img.shape:
warnings.warn("shape of the two images don't match")
carry_img=cv2.resize(carry_img,(info_img.shape[1],info_img.shape[0]))
# 抽取info_img信息量最大平面
info_img=np.bitwise_and(info_img,np.left_shift(1,7))
# 转为二进制
info_img_bit=np.right_shift(info_img,(7-bit_plane))
# 构造carry_img的蒙版
mask=np.bitwise_not(np.left_shift(1,bit_plane))
hidden_img=info_img_bit+np.bitwise_and(carry_img,mask)
return hidden_img
def InfoExtrac(hidden_img,bit_plane):
# 提取位平面
recoverd_img = np.bitwise_and(hidden_img, np.left_shift(1,bit_plane))
# 提升到最高位恢复信息
recoverd_img=np.left_shift(recoverd_img,(7-bit_plane))
return recoverd_img
img_path1=r"D:\temp\pic1.jpg"
img_path2=r"D:\temp\pic2.jpg"
carry_img=plt.imread(img_path1)
info_img=plt.imread(img_path2)
hidden_img=InfoHidden(carry_img,info_img,1)
plt.imshow(hidden_img)
plt.show(block=True)
recovered_img=InfoExtrac(hidden_img,1)
plt.axis('off')
plt.title('recovered image')
plt.imshow(recovered_img)
plt.show(block=True)
结果展示
待隐藏图片:
载体图片:
隐藏后图片:
复原图片:
可以看到隐藏效果还是很不错的,只是因为用的图都是彩色图样,所以存在着差异,如果是灰度图,恢复效果会十分优秀。