数字水印原理
根据之前图像获取位平面的操作可知,最低位位平面对整体图像的影响最小,因此数字水印的原理为在图像的最低有效位上嵌入隐藏信息,即在图像的最低位替换为数字水印位平面,完成数字的嵌入操作,对已嵌入数字水印的图片提取最低位位平面,即可得到数字水印和解密后的图像,因操作在最低位位平面,所以可以忽略对图像的影响。
数字水印制造
数字水印的实现基于上述原理的具体实现,首先准备需要嵌入数字水印的lena图(512*512)以及获取数字水印的原始图(512*512)。
数字水印的原始图是在纯白(255)背景上随便写的字,通过代码把数字水印原始图变成数字水印图。
大体步骤如下:
- 数字原始图片显示为灰度图
- 灰度图中把关键信息独立出来,具体为把背景色置为0(这里用的纯白背景255,实际可能是一定范围的颜色区间)
- 灰度图只有水印关键信息,把此信息的颜色值变为1,灰度图变为最低位平面,得到数字水印
代码如下:
import cv2 as cv
import numpy as np
# --------------------------制造数字水印
# step1 读取原始图
key = cv.imread("key.png", 0)
# step2 得到数字水印灰度图 可以看到文字及背景白色
cv.imshow("key255", key)
# step3 之前提取位平面图的掩模操作,把白色255背景变成黑色0
key[key == 255] = 0
cv.imshow("key0", key)
# step4 再把文字变成1,这样就得到了数字水印
key[key > 0] = 1
cv.imshow("key", key)
cv.waitKey()
cv.destroyAllWindows()
运行效果如下:
数字水印嵌入及提取
理解了数字水印的原理再来分析数字的嵌入及提取就会觉得特别简单了。
- 先把数字水印生成好,看上面即可。
- 把载体图像的最低位位平面给处理掉,使用一个254的矩阵与载体图像做与运算即可。
- 数字水印加入到载体图像的最低位位平面即可,此时完成数字水印的嵌入。
- 生成一个全部为1的矩阵与载体图像做与运算从而得到最低位位平面,此时得到的就是水印。
- 嵌入数字水印的图像做减法运算即可得到丢失了最低位位平面的原始图像
- 此时水印只有1和0,再转为二值图显示数字水印的图像,显示完成即可。
具体实现如下:
import cv2 as cv
import numpy as np
# --------------------------制造数字水印
# step1 读取原始图
key = cv.imread("key.png", 0)
# step2 得到数字水印灰度图 可以看到文字及背景白色
cv.imshow("key255", key)
# step3 之前提取位平面图的掩模操作,把白色255背景变成黑色0
key[key == 255] = 0
cv.imshow("key0", key)
# step4 再把文字变成1,这样就得到了数字水印
key[key > 0] = 1
cv.imshow("key", key)
# -----------------------嵌入水印过程
# step1 生成值全为254的模板
lena = cv.imread("lena.jpg", 0)
cv.imshow("lena", lena)
r, c = lena.shape
mask_254 = np.ones((r, c), dtype=np.uint8) * 254
# step2 用254模板把lena的最低位
lena_high_bit = cv.bitwise_and(lena, mask_254)
# step3 去掉最低位的lena嵌入数字水印 这一步用或运算也行
# lena_water = cv.bitwise_xor(lena_high_bit, key)
lena_water = lena_high_bit + key
cv.imshow("lena_water", lena_water)
# -----------------------提取水印过程
# step4 生成各全为1的模板,用来把数字水印提取出来
mask_1 = np.ones((r, c), dtype=np.uint8)
# step5 嵌入水印的图像与1模板做与运算,把水印提取出来
key_after = cv.bitwise_and(lena_water, mask_1)
# step6 嵌入水印的图像减去水印得到的就是失去最低位的"原图" 这一步也可以用254的模板做与运算
# mask_254 = np.ones((r, c), dtype=np.uint8) * 254
# lena_after = cv.bitwise_and(lena_water, mask_254)
lena_after = lena_water - key_after
cv.imshow("lena_after", lena_after)
# step7 把数字水印转化为二值图,直接显示出来
key_after[key_after > 0] = 255
cv.imshow("key_after", key_after)
cv.waitKey()
cv.destroyAllWindows()
运行效果如下:
总结:知道数字水印的原理整体实现起来就轻松多了,大体就是在图片的最低位加入数字水印,提取水印也就是把提取出已嵌入水印的图像的最低位位平面。后面的可视化水印及艺术文字大体就是对图像和数字水印图像的区域运算,不再做单独讨论。