文章目录
前言
本文主要介绍图像的位平面分解、图像加密和解密以及数字水印。
1. 位平面分解
1.1 位平面图理解
位平面分解这个我也是看了好久才理解的。如何直白解释它呢?
想象你有一张黑白图像,每个像素的亮度值从 0 到 255。这些亮度值可以用 8 位二进制数表示,比如 255 是 11111111,0 是 00000000。位平面分解就是把这张黑白图像的每个像素值先变成一个8位二进制数,然后将每个二进制数的每一位单独拿出来,做成 8 张新图像
。每张新图像只显示原始图像中某一位的所有值。
比如下面一个图像的灰度图矩阵如下所示:
将每一个像素值变成二进制值后:
然后取出每一个二进制数的第 n n n位,这里从低位依次向高位去取:
- 图a: 原图每个像素值的二进制数从左往右,第一个位提取,得到的结果,也叫“最低有效位”位平面,由于该平面图处于载体图像的最低有效位上,所以对于载体图像的影响非常不明显,其具有较高的隐蔽性。
- 图b: 原图每个像素值的二进制数从左往右,第二个位提取,得到的结果,我们称之为第一个位平面。
- 图c: 原图每个像素值的二进制数从左往右,第三个位提取,得到的结果,我们称之为第二个位平面。
- 图d: 原图每个像素值的二进制数从左往右,第四个位提取,得到的结果,我们称之为第三个位平面。
- 图e: 原图每个像素值的二进制数从左往右,第五个位提取,得到的结果,我们称之为第四个位平面。
- 图f: 原图每个像素值的二进制数从左往右,第六个位提取,得到的结果,我们称之为第五个位平面。
- 图g: 原图每个像素值的二进制数从左往右,第七个位提取,得到的结果,我们称之为第六个位平面。
- 图h: 原图每个像素值的二进制数从左往右,第八个位提取,得到的结果,我们称之为第七个位平面,也叫“最高有效位”位平面。该位平面在8位二进制中权重最高(值最大嘛),所以与原图最接近。
这样就可以得到8张新图像了。
1.2 位平面分解步骤
- 读取灰度图像:
首先,加载一个灰度图像。通常,图像的每个像素点都是一个8位的灰度值(0-255),可以用8位二进制数来表示。 - 初始化位平面列表:
创建一个列表或数组,用于存储每个位平面的图像。 - 分解图像的每个位平面:
将8位灰度值图像,分解为8个位平面(每个位平面对应图像的一个二进制位)。对于每个位平面:- 将每个像素值与对应的二进制位进行掩膜操作。
- 根据该位的值,将其转换为二进制图像(第n个位平面),在该平面上只有对应的位为1的地方显示为白色(255),其他地方显示为黑色(0)。
- 保存位平面图像:
将每个位平面图像保存为文件.
1.3 代码
代码如下(示例):
def 位平面分解():
import cv2
import numpy as np
lena = cv2.imread("641.webp", 0)
cv2.imshow("lena", lena)
r, c = lena.shape
x = np.zeros((r, c, 8), dtype=np.uint8)
for i in range(8):
x[:, :, i] = 2 ** i
r = np.zeros((r, c, 8), dtype=np.uint8)
for i in range(8):
r[:, :, i] = cv2.bitwise_and(lena, x[:, :, i])
mask = r[:, :, i] > 0
r[mask] = 255
cv2.imshow(str(i), r[:, :, i])
cv2.waitKey()
cv2.destroyAllWindows()
位平面分解():
结果如下
这是原图
这是8张位平面图
2. 图像加密和解密
图像加密和解密是用于保护图像数据的隐私和安全的一系列技术。加密将图像数据转换为不可读的格式,只有通过解密才能恢复原始图像。
实际上我们通过上一篇文章介绍的按位或运算来实现图像的加密和解密,过按位异或(XOR)进行图像加密和解密是一种简单但有效的对称加密方法。加密和解密过程是相同的,使用相同的密钥进行两者操作。异或操作具有互补性,所以加密解密操作相同
1
2.1 加密和解密原理
加密和解密使用相同的操作和密钥。由于异或运算的性质,使用相同的密钥进行加密和解密是有效的。加密过程可以使用以下公式
C = P ⊕ K (1) C = P ⊕ K \tag{1} C=P⊕K(1)
其中:
C
C
C是加密后的图像。
P
P
P是原始图像。
K
K
K是密钥(与图像大小相同)。
解密过程也是使用相同的公式:
P = C ⊕ K (2) P=C⊕K\tag{2} P=C⊕K(2)
P
P
P是解密后的原始图像。
C
C
C是加密图像。
K
K
K是密钥。
2.2 按位异或操作的步骤
- 生成密钥: 密钥需要与图像的大小相同。密钥的生成可以是随机的,也可以是固定的(但固定密钥的安全性较低)。
- 加密图像: 将图像数据和密钥数据按位进行异或运算,得到加密后的图像。
- 解密图像: 对加密图像使用相同的密钥进行异或运算,得到原始图像的恢复。
2.1 加密解密过程
- 密钥生成: 通过随机数生成与图像大小相同的随机密钥。
- 加密: 将图像数据与密钥进行异或运算,生成加密图像。
- 解密: 将加密图像数据与相同的密钥进行异或运算,恢复原始图像。
2.2 代码
def 图像加密和解密():
import cv2
import numpy as np
lena = cv2.imread("641.webp", 0)
r, c = lena.shape
key = np.random.randint(0, 256, size=[r, c], dtype=np.uint8)
encryption = cv2.bitwise_xor(lena, key)
decryption = cv2.bitwise_xor(encryption, key)
cv2chinese(title='原图', image=lena)
cv2chinese(title='密钥', image=key)
cv2chinese(title='加密', image=encryption)
cv2chinese(title='解密', image=decryption)
图像加密和解密()
结果如下:
3. 数字水印
3.1 数字水印理解
数字水印(Digital Watermarking)是一种将隐形信息嵌入到图像中,这种水印在原图你是看不到了,它被隐藏起来了,一般用于保护版权、验证图像的完整性或传递其他信息的技术。与传统水印不同,数字水印通常不会显著影响图像的视觉质量,因为你根本发现不了水印。所以你用其他人的图片时,你可要小心了,如果你将这种图片用于商业用途,就很容易被告侵权
。
它是怎么做到的呢?还记得我们位平面图中介绍的 最低有效位(Least Significant Bit, LSB) 嘛?数字水印的嵌入其实是将原图最低有效位信息(它有或没有一点都不会改变原图的显示效果)给去掉,然后将一个需要隐藏的二值图像信息(也就是数字水印
)嵌入到原图的最低有效位,即将原图的最低有效位层替换为数字水印二值图像
,从而实现将二值图像隐藏的目的。由于数字水印
处于载体图像(原图)的最低有效位上,所以对于载体图像(原图)的影响非常不明显,其具有较高的隐蔽性。
3.2 数字水印步骤
- 读取原始图像:
加载要嵌入水印的原始图像。 - 读取水印图像:
加载要嵌入到原始图像中的水印图像。 - 调整水印图像大小:
确保水印图像的大小与原始图像相匹配,或者根据需要调整水印图像的大小。 - 嵌入水印:
将水印图像嵌入到原始图像中,创建带有水印的新图像。 - 提取水印:
直接取出原图的最低有效位平面图
3.3 代码
def 数字水印的嵌入和提取():
import cv2
import numpy as np
# 读取原始载体图像
lena = cv2.imread("641.webp", 0)
# 读取水印图像
watermark = cv2.imread("cv.png", 0)
# 获取原始图像的尺寸
lena_height, lena_width = lena.shape
# 调整水印图像的大小,使其与原始图像相同
watermark = cv2.resize(watermark, (lena_width, lena_height))
# cv2.imshow('origin_watermark', watermark)
# 将水印图像内的值255处理为1,以方便嵌入
# 后续章节会介绍使用threshold处理
w = watermark[:, :] > 0
watermark[w] = 1
# 读取原始载体图像的shape值
r, c = lena.shape
# ============嵌入过程============
# 生成元素值都是254的数组
t254 = np.ones((r, c), dtype=np.uint8) * 254
# 获取lena图像的高七位
lenaH7 = cv2.bitwise_and(lena, t254)
# 将watermark嵌入lenaH7内
e = cv2.bitwise_or(lenaH7, watermark)
# ============提取过程============
# 生成元素值都是1的数组
t1 = np.ones((r, c), dtype=np.uint8)
# 从载体图像内提取水印图像
wm = cv2.bitwise_and(e, t1)
print(wm)
# 将水印图像内的值1处理为255,以方便显示
# 后续章节会介绍使用threshold实现
w = wm[:, :] > 0
wm[w] = 255
# ============显示============
cv2.imshow("lena", lena)
cv2.imshow("watermark", watermark * 255) # 当前watermark内最大值为1
cv2.imshow("e", e) # 加水印图
cv2.imshow("wm", wm)
cv2.waitKey()
cv2.destroyAllWindows()
数字水印的嵌入和提取()
结果如下:
3.4 数字水印的优点
- 隐形性: 数字水印信息在图像中隐藏,通常不易被肉眼识别。
- 鲁棒性: 水印应对图像的各种处理(如压缩、裁剪、旋转等)具有一定的鲁棒性,即在这些操作后水印仍然能够被识别。
3.5 数字水印的应用
- 版权保护: 嵌入版权信息或作者标识,防止图像被非法使用。
- 完整性验证: 检测图像是否在传输或存储过程中被篡改。
- 数据嵌入: 将额外信息(如图像拍摄时间、地点等)嵌入图像中。
如果你有 𝐴⊕𝐵=𝐶,则可以通过异或运算恢复原始数:
𝐶⊕𝐵=𝐴
𝐶⊕𝐴=𝐵 ↩︎