Python 盲水印算法:将水印嵌入图像并解析提取
以下代码实现了将水印嵌入到原始图像中,并将结果保存为新的图像。然后,通过解密过程,从加密图像中提取出水印信息。
if cmd == 'encode':
print ('image<'+fn1+'> + watermark<'+fn2+'> -> image(encoded)<'+fn3+'>' % (fn1, fn2, fn3))
img = cv2.imread(fn1) # 读取原始图像
wm = cv2.imread(fn2) # 读取水印图像
# 将图像显示在子图中
if debug:
plt.subplot(231), plt.imshow(bgr_to_rgb(img)), plt.title('image')
plt.xticks([]), plt.yticks([])
plt.subplot(234), plt.imshow(bgr_to_rgb(wm)), plt.title('watermark')
plt.xticks([]), plt.yticks([])
h, w = img.shape[0], img.shape[1] # 获取原始图像的高度和宽度
hwm = np.zeros((int(h * 0.5), w, img.shape[2])) # 创建一个与原始图像相同大小的图像
assert hwm.shape[0] > wm.shape[0] # 断言新图像的高度大于水印图像的高度
assert hwm.shape[1] > wm.shape[1] # 断言新图像的宽度大于水印图像的宽度
hwm2 = np.copy(hwm)
for i in range(wm.shape[0]):
for j in range(wm.shape[1]):
hwm2[i][j] = wm[i][j]
if oldseed: random.seed(seed,version=1)
else: random.seed(seed)
m, n = list(range(hwm.shape[0])), list(range(hwm.shape[1]))
if oldseed:
random.shuffle(m,random=random.random)
random.shuffle(n,random=random.random)
else:
random.shuffle(m)
random.shuffle(n)
for i in range(hwm.shape[0]):
for j in range(hwm.shape[1]):
hwm[i][j] = hwm2[m[i]][n[j]]
rwm = np.zeros(img.shape)
for i in range(hwm.shape[0]):
for j in range(hwm.shape[1]):
rwm[i][j] = hwm[i][j]
rwm[rwm.shape[0] - i - 1][rwm.shape[1] - j - 1] = hwm[i][j]
f1 = np.fft.fft2(img) # 对原始图像进行傅里叶变换
f2 = f1 + alpha * rwm # 将傅里叶变换后的图像与加密后的水印图像相加
_img = np.fft.ifft2(f2) # 对相加后的图像进行傅里叶逆变换
img_wm = np.real(_img) # 获取傅里叶逆变换后的实部
assert cv2.imwrite(fn3, img_wm, [int(cv2.IMWRITE_JPEG_QUALITY), 100]) # 将加密后的图像保存为文件
# 计算保存前后的误差
img_wm2 = cv2.imread(fn3)
sum = 0
for i in range(img_wm.shape[0]):
for j in range(img_wm.shape[1]):
for k in range(img_wm.shape[2]):
sum += np.power(img_wm[i][j][k] - img_wm2[i][j][k], 2)
miss = np.sqrt(sum) / (img_wm.shape[0] * img_wm.shape[1] * img_wm.shape[2]) * 100
print ('Miss %s%% in save' % miss)
f2 = np.fft.fft2(img_wm) # 对加密后的图像进行傅里叶变换
rwm = (f2 - f1) / alpha # 计算解密后的水印图像
rwm = np.real(rwm)
wm = np.zeros(rwm.shape)
for i in range(int(rwm.shape[0] * 0.5)):
for j in range(rwm.shape[1]):
wm[m[i]][n[j]] = np.uint8(rwm[i][j])
for i in range(int(rwm.shape[0] * 0.5)):
for j in range(rwm.shape[1]):
wm[rwm.shape[0] - i - 1][rwm.shape[1] - j - 1] = wm[i][j]
这段代码实现了将水印嵌入到原始图像中,并将结果保存为新的图像。然后,通过解密过程,从加密图像中提取出水印信息。
要使用这段代码,需要传入以下参数:
fn1:原始图像的文件名fn2:水印图像的文件名fn3:生成的加密图像的文件名alpha:水印的加密强度seed:随机数种子oldseed:是否使用旧的随机数种子debug:是否显示调试信息
在encode命令下运行该代码将生成加密图像,并将其保存为文件。然后,可以使用以下代码从加密图像中提取出水印信息:
f1 = np.fft.fft2(img_wm) # 对加密图像进行傅里叶变换
rwm = (f2 - f1) / alpha # 计算解密后的水印图像
rwm = np.real(rwm)
wm = np.zeros(rwm.shape)
for i in range(int(rwm.shape[0] * 0.5)):
for j in range(rwm.shape[1]):
wm[m[i]][n[j]] = np.uint8(rwm[i][j])
for i in range(int(rwm.shape[0] * 0.5)):
for j in range(rwm.shape[1]):
wm[rwm.shape[0] - i - 1][rwm.shape[1] - j - 1] = wm[i][j]
这段代码将从加密图像中提取出水印信息,并将其保存在wm变量中。
该代码实现了一种简单的盲水印算法,它利用傅里叶变换将水印信息嵌入到图像中。该算法具有较高的鲁棒性,能够抵抗一些常见的攻击,例如噪声、压缩、裁剪等。
代码解释:
- 读取原始图像和水印图像
- 创建一个与原始图像大小相同的空图像,并将其大小缩减为一半
- 将水印图像复制到空图像中
- 对空图像进行随机像素置换操作
- 将置换后的水印图像扩展到与原始图像相同的大小,并在水平和垂直方向上进行镜像操作
- 对原始图像进行傅里叶变换
- 将傅里叶变换后的图像与加密后的水印图像相加
- 对相加后的图像进行傅里叶逆变换
- 获取傅里叶逆变换后的实部,并将其保存为加密图像
- 从加密图像中提取出水印信息
- 对提取出的水印信息进行反向置换操作,恢复原始的水印图像
注意:
- 该代码需要使用 OpenCV 和 NumPy 库
alpha参数控制水印的加密强度,值越大,水印嵌入越明显seed参数用于控制随机数生成器oldseed参数用于指定是否使用旧的随机数种子debug参数用于控制是否显示调试信息
原文地址: https://www.cveoy.top/t/topic/fTgo 著作权归作者所有。请勿转载和采集!