简单的 SVD 嵌入数字水印 python 版本

一个最简单的SVD 嵌入数字水印的代码,
这种水印方法是2002年被提出的,单纯的使用这种方法会导致假阳性问题,因此,一般和别的方法结合使用。
为了更好的表现水印嵌入效果,我将一个bit水印信息嵌入到一块内,这样做最简单,但是效果肯定比较差,主要用来理解这个方法。
代码如下:
首先定义 块SVD 变换:

def block_SVD(M,  blk_size):
    row_block = M.shape[0]//blk_size[0]
    col_block = M.shape[1]//blk_size[1]
    U = np.empty((row_block, col_block), dtype = object)
    S = np.empty((row_block, col_block), dtype = object)
    V = np.empty((row_block, col_block), dtype = object)


    M = M[:M.shape[0]-M.shape[0]%blk_size[0], 
          :M.shape[1]-M.shape[1]%blk_size[1]]
    rows = []

    for i in range(0, M.shape[0], blk_size[0]):
        cols = []
        for j in range(0, M.shape[1], blk_size[1]):
            max_ndx = (min(i+blk_size[0], M.shape[0]),
                       min(j+blk_size[1], M.shape[1]))
            
            u, s, v = np.linalg.svd(M[i:max_ndx[0], j:max_ndx[1]])

            U[i//blk_size[0],j//blk_size[1]] = u
            S[i//blk_size[0],j//blk_size[1]] = s
            V[i//blk_size[0],j//blk_size[1]] = v
    return U,S,V


然后是块ISVD变换(我自己起的名字),其实就是矩阵相乘的快处理,用来复原图像:

def block_ISVD(U, S, V, blk_size):
    row_U, col_U = U.shape
    U = U.flatten()
    S = S.flatten()
    V = V.flatten()
    im_tmp = np.empty_like(U)
    im_wm = np.empty((row_U*blk_size[0],col_U*blk_size[1]))

    for i in range(U.size):
        tmp = np.matmul(U[i],np.diag(S[i]))
        im_tmp[i] = np.matmul(tmp,V[i])
    im_tmp = im_tmp.reshape(row_U, col_U)
    for i in range(row_U):
        for j in range(col_U):
            im_wm[i*blk_size[0]:(i+1)*blk_size[0], j*blk_size[1]:(j+1)*blk_size[1]] = im_tmp[i,j]
    return im_wm

然后是提取的嵌入操作

def SVD_embed(im, wm,strength, blk_size):
    U,S,V = block_SVD(im, blk_size)
    S_new = embed(S, wm, strength)
    im_wm = block_ISVD(U, S_new, V, blk_size)
    return im_wm
    
def SVD_extract(im_wm, im, strength, block_size ):
    _,S,_ = block_SVD(im, block_size)
    _,S_wm,_ = block_SVD(im_wm, block_size)
    
    tmp = S_wm - S
    wm_ex = np.empty_like(tmp, dtype = int)
    
    for i in range(tmp.shape[0]):
        for j in range(tmp.shape[1]):
            wm_ex[i,j] = np.sum(tmp[i,j])
    wm_ex = wm_ex / block_size[0]/strength
    return wm_ex

def embed(S, wm, strength):
    wm = wm.flatten()
    row, col = S.shape
    S = S.flatten()
    for i in range(S.size):
        S[i]=S[i]+ strength * wm[i]
    S = S.reshape(row,col)
    return S

最后是主函数:

# SVD Watermark

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from skimage import data

strength = 0.1

im = data.camera()
wm = Image.open('watermark.png')
wm = wm.resize((64,64))
wm = np.array(wm)

im_wm = SVD_embed(im, wm, strength, (8,8))

wm_ex = SVD_extract(im_wm, im, strength, (8,8))

fig, (ax_wm, ax_im, ax_im_wm, ax_wm_ex)=plt.subplots(nrows = 1,ncols = 4, figsize = [20,20])
ax_wm.imshow(wm, cmap = plt.cm.gray)
ax_wm.set_xlabel('wm')
ax_im.imshow(im, cmap = plt.cm.gray)
ax_im.set_xlabel('im')
ax_im_wm.imshow(im_wm, cmap = plt.cm.gray)
ax_im_wm.set_xlabel('im_wm')
ax_wm_ex.imshow(wm_ex, cmap = plt.cm.gray)
ax_wm_ex.set_xlabel('wm_ex')

下面是效果展示,可以看出,由于水印强度比较大,还是有比较强的噪声出现,不喜欢噪声的同学可以将强度设置的小一点。
在这里插入图片描述

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值