[Python图像处理] 基于离散余弦变换的安全扩频数字水印

数字水印

数字水印是可见的或不可见的标识码,这种标识码被永久嵌入图像中,并且即使在解码过后后仍存在于图像中。为了保证有效性,水印应具有以下特征:

  • 水印应在视觉上不可见,或者其存在至少不会干扰受保护的对象
  • 水印必须难以去除,当然我们希望其不可能被去除。如果只有部分水印相关信息,例如,图像中水印的确切位置未知,那么尝试去除或破坏水印应导致图像质量严重下降

基于离散余弦变换的安全扩频数字水印

在本节中,我们将采用基于离散余弦变换 (Discrete Cosine Transform, DCT) 的水印技术,将水印构造为一个独立同分布的高斯随机向量,该向量以类似扩频的方式隐秘的插入到数据感知上最重要的频谱分量中。
在该机制下的水印插入使水印对信号处理操作(例如有损压缩、滤波、以及常见的几何变换裁剪、缩放、平移和旋转等)具有鲁棒性。当然,前提是原始图像可用,并且可以成功地与变换后的带水印图像进行配准。将随机水印矢量 X 插入图像向量 V 中以获得带水印图片,算法描述如下:
插入水印:

v i ′ = v i ( 1 + α x i ) v'_i=v_i(1+\alpha x_i) vi=vi(1+αxi)

提取水印:

x i ′ = ( v i ′ v i − 1 ) α x'_i=\frac {(\frac {v'_i} {v_i} -1)} {\alpha} xi=α(vivi1)

评估水印间的相似性:

s i m ( X , X ∗ ) = X ∗ ⋅ X x ∗ ⋅ X ∼ N ( 0 , 1 ) sim(X,X^*)=\frac {X^*\cdot X} {\sqrt {x^* \cdot X}}\sim N(0,1) sim(X,X)=xX XXN(0,1)

从测试图像中提取可能的水印后,我们需要计算其与实际水印的相似性,如果相似性很高,我们可以安全地得出测试图像中存在水印的结论。

实现安全扩频数字水印

(1) 首先导入所需 Python 库:

from scipy.fftpack import dct, idct
from skimage.io import imread
from skimage.color import rgb2gray
import numpy as np
import matplotlib.pylab as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable

(2) 使用 scipy.fftpack 实现 2D DCTIDCT

def dct2(a):
    return dct(dct(a.T, norm='ortho').T, norm='ortho')

def idct2(a):
    return idct(idct(a.T, norm='ortho').T, norm='ortho')   

(3) 实现函数 embed() 以在输入图像上嵌入长度为 k (通过参数 k 指定)的随机水印,缩放参数 a 指示水印的对图像的变化程度。函数将水印嵌入到具有最高值的DCT系数中,返回嵌入水印并生成随机水印的索引和系数,以及输出(水印)图像:

def embed(im, k, alpha):
    m, n = im.shape
    d = dct2(im)
    indices = np.dstack(np.unravel_index(np.argsort(d.ravel()), (m, n)))[0]
    indices = indices[-(k+1):-1]
    cw = d[indices[:,0], indices[:,1]]
    w = np.random.randn(k)
    #w = w / np.linalg.norm(w)
    ci = cw * (1 + alpha * w)
    d[indices[:,0], indices[:,1]] = ci
    im1 = idct2(d)
    return im1, indices, cw, w

(4) 实现函数 detect() 以检测图像中是否存在水印。首先,从测试图像中提取可能的水印,然后计算/返回相似度:

def detect(test, indices, cw, w, alpha):
    d = dct2(test)
    testc = d[indices[:,0], indices[:,1]]
    what = (testc/cw - 1) / alpha
    gamma = what@w/(np.linalg.norm(what)) #*np.linalg.norm(w))
    return gamma

(5) 最后,使用该函数将长度 1000 的水印嵌入灰度输入图像中,然后计算图像水印是否存在:

k = 1000
alpha = 0.1
im = rgb2gray(imread('3.png'))
im = (255*im).astype(np.uint8)
im1, indices, cw, w = embed(im, k=k, alpha=alpha)
print('mean difference={}, max difference={}'.format(np.mean(np.abs(im1-im)), np.max(np.abs(im1-im))))
similarity = detect(im1, indices, cw, w, alpha)
print('detected similarity={}'.format(similarity))

从以上结果可以看出,相似性为 31.89,因此,我们可以得出结论,图像中包含水印。

(6) 绘制原始图像、带有水印的图像和两个图像间的差异:

fig = plt.figure(figsize=(20,10))
plt.gray()
plt.subplots_adjust(0,0,1,0.925,0.05,0.05)
plt.subplot(131), plt.imshow(im), plt.axis('off'), plt.title('original image {}'.format(im.shape), size=10)
plt.subplot(132), plt.imshow(im1), plt.axis('off'), plt.title(r'watermarked image: $v_i^{\prime}=v_i.(1+\alpha x_i)$', size=10)
plt.subplot(133)
last_axes = plt.gca()
img = plt.imshow((np.abs(im1-im)).astype(np.uint8))
divider = make_axes_locatable(img.axes)
cax = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(img, cax=cax)
plt.sca(last_axes)
plt.axis('off'), plt.title('difference image', size=10)
plt.show()

数字水印

相关链接

Python图像处理【1】图像与视频处理基础
Python图像处理【2】探索Python图像处理库
Python图像处理【3】Python图像处理库应用
Python图像处理【4】图像线性变换
Python图像处理【5】图像扭曲/逆扭曲
Python图像处理【6】通过哈希查找重复和类似的图像
Python图像处理【7】采样、卷积与离散傅里叶变换
Python图像处理【8】使用低通滤波器模糊图像
Python图像处理【9】使用高通滤波器执行边缘检测
Python图像处理【10】基于离散余弦变换的图像压缩
Python图像处理【11】利用反卷积执行图像去模糊
Python图像处理【12】基于小波变换执行图像去噪

猜你喜欢

转载自blog.csdn.net/qq_30167691/article/details/128436055