数字水印 | 附彩色图像论文:盲式水印嵌入的方法

目录

    • 前言
      • [1 回顾:论文 A 的嵌入规则](#1 回顾:论文 A 的嵌入规则)
      • [2 论文 B 的嵌入规则](#2 论文 B 的嵌入规则)
      • [3 论文 A 的提取规则](#3 论文 A 的提取规则)
      • [4 论文 A 的嵌入规则](#4 论文 A 的嵌入规则)
      • 5 代码实现

本文附属于数字水印 | 彩色图像论文:A blind and robust color image watermarking scheme based on DCT and DWT domains(三)

前言

最初,我看不懂论文 A 中提到的 量化值水印嵌入规则 ,只觉得莫名其妙。后来看了 盲水印 相关的论文、博客和代码,我突然恍然大悟!

本博客涉及两篇论文:

  • 论文 A:设计的是盲水印方案,即提取水印时不需要使用原始图像;
  • 论文 B:设计的是非盲水印方案,即提取水印时需要使用原始图像;

接下来,我将以人话和 Python 代码来介绍论文 A 的水印嵌入规则。

1 回顾:论文 A 的嵌入规则

这一小节只是回顾一下论文 A 所提出的方案是什么,暂不进行说明😈

步骤五 :基于给定的量化值 Q Q Q,通过以下公式构造一个包含 L H 1 LH1 LH1 子带调整系数的新矩阵 S S S:

S ( i , j ) = ⌊ L H 1 ( i , j ) Q ⌋ S(i,j)=\left \lfloor \frac{LH1(i,j)}{Q} \right \rfloor S(i,j)=⌊QLH1(i,j)⌋

步骤六 :将加密后的水印图像 E W EW EW 按照以下规则嵌入到 L H 1 LH1 LH1 子带中,从而得到 L H 1 ′ LH1' LH1′:

if mod(S(i, j), 2) = EW(k) then
	LH1(i, j) = S(i, j) * Q + Q / 2
End if

if mod(S(i, j), 2) != EW(k) then
	if LH1(i, j) - S(i, j) * Q ∈ [0, Q/2] then
		LH1(i, j) = (S(i, j) - 1) * Q + Q / 2
	Else
		LH1(i, j) = (S(i, j) + 1) * Q + Q / 2
	End if
End if

其中 i = 0 , 1 , 2 , . . . , M / 16 , j = 0 , 1 , 2 , . . . , N / 16 , k = 0 , 1 , 2 , . . . , R × C i=0,1,2,...,M/16,j=0,1,2,...,N/16,k=0,1,2,...,R\times C i=0,1,2,...,M/16,j=0,1,2,...,N/16,k=0,1,2,...,R×C。

2 论文 B 的嵌入规则

这一小节主要介绍非盲的水印嵌入是如何实现的,以及我们为什么需要盲的水印嵌入。

论文 B 所提出的水印嵌入规则如下:

S m a r k = S y + α × S w S_{mark}=S_{y}+\alpha \times S_{w} Smark=Sy+α×Sw

温馨提示:由于这只是一个论文的片段,因此没有必要深究各个变量所代表的含义。只需要知道 S y S_y Sy 是基于原始图像得到的一个值, S w S_{w} Sw 是基于水印得到的一个值,而 S m a r k S_{mark} Smark 将被用于重构出含水印的图像即可。

根据上述水印嵌入规则,易得水印提取规则如下:

S w ′ = ( S m a r k − S y ) / α S'{w}=(S{mark}-S_{y})/\alpha Sw′=(Smark−Sy)/α

其中 S m a r k S_{mark} Smark 根据含水印图像得到, S y S_{y} Sy 根据原始图像得到。

这样的水印嵌入和提取规则是毫无问题的,可是在实际应用中,我们可能并不希望水印的提取过程还需要原始图像的参与。一方面是,提取水印的人可能并不是原始图像的拥有者;另一方面是,不希望因提取水印而需要暴露原始图像。因此,盲水印嵌入技术应运而生。

3 论文 A 的提取规则

这一小节主要介绍论文 A 的提取规则,下一小节再介绍论文 A 的嵌入规则。

首先,我们需要明确的是,论文 A 所针对的水印是二进制的水印,即水印信息是由 01 01 01 二进制数进行表示的。正是这一条件为我们嵌入水印提供了便利!

相较于论文 B,我们不再使用一个直白的数学运算(加减乘除)来嵌入或提取水印信息。而是采用一种类似于零知识证明的方式:在提取水印的过程中,我不需要告诉你原始图像的值是多少,而只需要告诉你 "加密" 后的原始图像的值对 2 2 2 取余的值是多少,而得到的这些余数就是水印信息。

Q1:为什么是对 2 2 2 取余?

A1:因为对 2 2 2 取余的余数只能是 0 0 0 和 1 1 1,所以可以完美地表示我们的二进制水印信息。如果水印信息采用的是三进制,那么就是对 3 3 3 取余了。

Q2:什么是 "加密" 后的原始图像的值?

A2:本质上就是通过数学运算对原始图像的值进行了一些变换,我个人把这样的变换过程称为 "加密" 过程。

论文 A 提取水印的方式是:

S ′ ( i , j ) = ⌊ L H 1 ′ ( i , j ) Q ⌋ E W ′ ( k ) = m o d ( S ′ ( i , j ) , 2 ) \begin{alignat}{2} S'(i,j) =& \left \lfloor \frac{LH1'(i,j)}{Q} \right \rfloor \\ EW'(k) =& \mathrm{mod}(S'(i,j),2) \end{alignat}{} S′(i,j)=EW′(k)=⌊QLH1′(i,j)⌋mod(S′(i,j),2)

说明: L H 1 ( i , j ) LH1(i,j) LH1(i,j) 是根据原始图像得到的值。由于 L H 1 ′ ( i , j ) LH1'(i,j) LH1′(i,j) 是 L H 1 ( i , j ) LH1(i,j) LH1(i,j) 经过一些变换得到的,因此我们可以认为 L H 1 ′ ( i , j ) LH1'(i,j) LH1′(i,j) 是 "加密" 后的原始图像的值。

再来看上述水印提取的过程,我们只需要通过一个和水印嵌入过程相同的变换 ------ L H 1 ′ ( i , j ) LH1'(i,j) LH1′(i,j) 整除 Q Q Q,再对 2 2 2 取余即可获得水印信息。可以看出,我们全程都没有使用到原始图像的值,因此这是一个盲水印方案。那么这到底是如何实现的呢?如何保证整除后取余一定等于水印信息呢?请看下一小节。

说明:上标的那一撇是为了表明这不是原始的信息,而是经过了调整或者是被提取出的信息。不过可以证明的是,嵌入和提取水印的规则保证了 E W ( k ) = E W ′ ( k ) EW(k)=EW'(k) EW(k)=EW′(k) 的成立。

4 论文 A 的嵌入规则

步骤五 :基于给定的量化值 Q Q Q,通过以下公式构造一个包含 L H 1 LH1 LH1 子带调整系数的新矩阵 S S S:

S ( i , j ) = ⌊ L H 1 ( i , j ) Q ⌋ S(i,j)=\left \lfloor \frac{LH1(i,j)}{Q} \right \rfloor S(i,j)=⌊QLH1(i,j)⌋

其实我到现在还是不知道量化值的作用,但是在 Python 中通过以下代码即可实现:

python 复制代码
for i in range(length):
	S[i] = LH1[i] // Q

即 S ( i , j ) S(i,j) S(i,j) 等于 L H 1 ( i , j ) LH1(i,j) LH1(i,j) 整除 Q Q Q。由于这只是一个测试代码,因此我定义的都是一维数组。


步骤六 :将加密后的水印图像 E W EW EW 按照以下规则嵌入到 L H 1 LH1 LH1 子带中,从而得到 L H 1 ′ LH1' LH1′。

① 针对第一种情况

if mod(S(i, j), 2) = EW(k) then
	LH1(i, j) = S(i, j) * Q + Q / 2
End if

如果 S ( i , j ) S(i,j) S(i,j) 对 2 2 2 取余本来就等于对应位置的水印信息 E W ( k ) EW(k) EW(k),那么

L H 1 ′ ( i , j ) = S ( i , j ) × Q + Q 2 LH1'(i,j)=S(i,j)\times Q+\frac{Q}{2} LH1′(i,j)=S(i,j)×Q+2Q

Q:为什么需要 L H 1 ′ ( i , j ) LH1'(i,j) LH1′(i,j) 且它的值和 L H 1 ( i , j ) LH1(i,j) LH1(i,j) 差不多?

A:因为我们希望嵌入水印后的图像和原始图像长得差不多。

提取水印时有

S ′ ( i , j ) = ⌊ L H 1 ′ ( i , j ) Q ⌋ = ⌊ S ( i , j ) × Q + Q / 2 Q ⌋ = ⌊ S ( i , j ) + 1 2 ⌋ = S ( i , j ) \begin{alignat}{2} S'(i,j) =& \left \lfloor \frac{LH1'(i,j)}{Q} \right \rfloor=\left \lfloor \frac{S(i,j)\times Q+Q/2}{Q} \right \rfloor \\ =& \left \lfloor S(i,j)+\frac{1}{2} \right \rfloor=S(i,j) \end{alignat}{} S′(i,j)==⌊QLH1′(i,j)⌋=⌊QS(i,j)×Q+Q/2⌋⌊S(i,j)+21⌋=S(i,j)

由于 S ( i , j ) S(i,j) S(i,j) 是由整除得到的,因此 S ( i , j ) S(i,j) S(i,j) 一定是一个整数。一个整数加上 0.5 0.5 0.5 后再向下取整,一定等于自身。那岂不是显得 0.5 0.5 0.5 很多余?还有必要加 0.5 0.5 0.5 吗?

从而有

E W ′ ( k ) = m o d ( S ′ ( i , j ) , 2 ) = m o d ( S ( i , j ) , 2 ) = E W ( k ) EW'(k) = \mathrm{mod}(S'(i,j),2) = \mathrm{mod}(S(i,j),2) = EW(k) EW′(k)=mod(S′(i,j),2)=mod(S(i,j),2)=EW(k)

② 针对第二种情况

if mod(S(i, j), 2) != EW(k) then
	if LH1(i, j) - S(i, j) * Q ∈ [0, Q/2] then
		LH1(i, j) = (S(i, j) - 1) * Q + Q / 2
	Else
		LH1(i, j) = (S(i, j) + 1) * Q + Q / 2
	End if
End if

如果 S ( i , j ) S(i,j) S(i,j) 对 2 2 2 取余不等于对应位置的水印信息 E W ( k ) EW(k) EW(k),那么我们需要分情况讨论。

0 ≤ L H 1 ( i , j ) − S ( i , j ) × Q ≤ Q 2 0 \le LH1(i, j) - S(i, j) \times Q \le \frac{Q}{2} 0≤LH1(i,j)−S(i,j)×Q≤2Q

那么

L H 1 ′ ( i , j ) = ( S ( i , j ) − 1 ) × Q + Q 2 LH1'(i,j)=(S(i,j)-1)\times Q+\frac{Q}{2} LH1′(i,j)=(S(i,j)−1)×Q+2Q

提取水印时有

S ′ ( i , j ) = ⌊ L H 1 ′ ( i , j ) Q ⌋ = ⌊ ( S ( i , j ) − 1 ) × Q + Q / 2 Q ⌋ = ⌊ S ( i , j ) − 1 2 ⌋ = S ( i , j ) − 1 \begin{alignat}{2} S'(i,j) =& \left \lfloor \frac{LH1'(i,j)}{Q} \right \rfloor=\left \lfloor \frac{(S(i,j)-1)\times Q+Q/2}{Q} \right \rfloor \\ =& \left \lfloor S(i,j)-\frac{1}{2} \right \rfloor=S(i,j)-1 \end{alignat}{} S′(i,j)==⌊QLH1′(i,j)⌋=⌊Q(S(i,j)−1)×Q+Q/2⌋⌊S(i,j)−21⌋=S(i,j)−1

由于 S ( i , j ) S(i,j) S(i,j) 对 2 2 2 取余不等于对应位置的水印信息 E W ( k ) EW(k) EW(k),因此 S ( i , j ) − 1 S(i,j)-1 S(i,j)−1 对 2 2 2 取余一定等于对应位置的水印信息 E W ( k ) EW(k) EW(k)。这就是二进制的好处!

5 代码实现

python 复制代码
import numpy as np

Q = 3.56  # 对应论文中的Q,即量化值
EW1 = [1, 0, 0, 1, 1, 0]  # 原始的EW
LH1 = [255, 204, 230, 198, 160, 98]  # 原始的LH
LH1 = np.array(LH1)

length = len(EW1)
S = np.zeros(length)  # 对应论文中的S
LH2 = np.zeros(length)  # 调整后的LH
EW2 = np.zeros(length)  # 提取出的EW


# 嵌入水印:获取LH2
def get_new_lh(lh1, s, ew):
    if s % 2 == ew:
        return s * Q + Q / 2
    else:
        if 0 <= lh1 - s * Q <= Q / 2:
            return (s - 1) * Q + Q / 2
        else:
            return (s + 1) * Q + Q / 2


for i in range(length):
    S[i] = LH1[i] // Q

for i in range(length):
    LH2[i] = get_new_lh(LH1[i], S[i], EW1[i])

print(LH2)


# 提取水印:获取EW2
def get_ew(s):
    return s % 2


for i in range(length):
    S[i] = LH2[i] // Q

for i in range(length):
    EW2[i] = get_ew(S[i])

print("原始的水印信息:", EW1)
print("提取的水印信息:", EW2)

按理来说 S S S 和 L H LH LH 都应该是二维数组,但因为这只是一个简单的测试代码,因此我定义成了一维数组。

相关推荐
狂放不羁霸5 个月前
数字水印 | Python 基于离散小波变换 DWT 的图像水印嵌入(下)
python·数字水印
狂放不羁霸5 个月前
数字水印 | 基于小波变换的数字水印技术
数字水印
亦世凡华、7 个月前
机器学习 | 实现图像加密解密与数字水印处理
开发语言·python·图像加密·图像解密·数字水印