基于小波变换的数字水印检测 数字水印技术原理

数字水印技术实际上就是通过对水印载体的分析、水印信息的处理、水印嵌入点的选择、嵌入方式的设计、嵌入调制的控制和提取检测方法等相关技术环节进行合理优化,寻求满足不可感知性、鲁棒性和安全性等约束条件下的准最优化设计问题。在实际应用中,一个完整水印系统的设计通常包括水印的生成、嵌入、检测和提取四个部分。

1   水印生成

通常基于伪随机数发生器或混沌系统来产生水印信号,从水印的鲁棒性和安全性方面来考虑,常常需要对原水印进行预处理来适应水印嵌入贺认。

2 水印嵌入

在尽量保证水印不可感知性的前提下,嵌入最大强度的水印,可提高水印的稳健性。常用的水印嵌入准则有加法准则、乘法准则和融合准则。

3 水印检测

指判断水印载体中是否存在水印的过程。

4 水印提取

指水印被比较精确地提取的过程。 水印的提取和检测可以需要原始图像的参与(明检测), 也可不需要原始图像的参与(盲检测)

数字水印的分类

  • 按水印的特性
  • 鲁棒数字水印:要求嵌入的水印能够经受各种常用的编辑处理
  • 脆弱数字水印:需要对信号的改动足够敏感,是人们能够根据脆弱水印的状态判断出数据是否被篡改。
  • 按水印的检测过程
  • 明文水印:检测工程中,需要原始数据。普遍来讲,鲁棒性较之盲水印要好。
  • 盲水印:只需要密钥,不需要原始数据
  • 按水印的内容
  • 有意义水印:水印是商标、音频片段等
  • 无意义水印:序列号,仅检测是否含水印
  • 按水印的隐藏位置
  • 空域
  • 频域
  • 时域

数字水印技术基本上具有下面几个方面的特点:

----安全性:数字水印的信息应是安全的,难以篡改或伪造,同时,应当有较低的误检测率,当原内容发生变化时,数字水印应当发生变化,从而可以检测原始数据的变更;当然数字水印同样对重复添加有很强的抵抗性

----隐蔽性:数字水印应是不可知觉的,而且应不影响被保护数据的正常使用;不会降质;

----鲁棒性:是指在经历多种无意或有意的信号处理过程后,数字水印仍能保持部分完整性并能被准确鉴别。可能的信号处理过程包括信道噪声、滤波、数/模与模/数转换、重采样、剪切、位移、尺度变化以及有损压缩编码等。

嵌入容量(embedding capacity):是指载体在不发生形变的前提下可嵌入的水印信息量。尤其是隐蔽通信领域的特殊性,对水印的容量需求很大。

图 1 数字水印嵌入与提取框图

典型的数字水印算法

数字水印的技术实现

空域-LSB

LSB 方法是最简单的嵌入水印的方法。事实上 ,任何一幅 图片都具备一定的容噪性 ,这表现在像素数据的最低有效位(Least Significant Bit,LSB)对 人 眼的视觉影响很 小,秘密信息就隐藏在图像每一个像素的最低位或次低位 ,实现其不 可见性。

频域

将图片的灰度强弱,视为图片的频域。通过某种变换手段(傅里叶变换,离散余弦变换,小波变换等)将图像变换到频域(小波域),在频域对图像添加水印,再通过逆变换,将图像转换为空间域。相对于空域手段,频域手段隐匿性更强,抗攻击性更高。

DCT

DCT 以 8x8 的像素为单位进行,生成的是 8x8 的 DCT 系数数据块。DCT 变换的最大特点是对于一般的图像都能够将像块的能量集中于少数低频 DCT 系数上,即生成 8x8DCT 系数块中,仅左上角的少量低频系数数值较大,其余系数的数值很小,这样就可能只编码和传输少数系数而不严重影响图像质量。

小波变换

“小波”就是小区域、长度有限、均值为 0 的波形。小波变换就是选择适当的基本小波或母小波 ψ(t),通过对基本小波的平移、伸缩而形成一系列的小波,这簇小波作为基可以构成一系列嵌套的(信号)子空间,然后将欲分析的信号(例如图像)投影到各个大小不同的(信号)子空间之中,以观察相应的特性。这样,就相当于我们用不同的焦距去观察一个物体,可从宏观到微观,从概貌到细节观察得十分详尽。所以小波变换又被称为“数学显微镜”。

空域+频域

该算法通过混沌置乱水印图像,建立水印与载体数据之间的 Hash 单向映射函数,使用两种不同的嵌入方法,先后嵌入水印到空域和 DFT 域。水印被多次嵌入,实现了水印的盲提取。

数字水印的应用场景

  • 多媒体作品盗版追溯:利用数字水印的不可见性,在不影响作品的情况下,加入版权信息的数字水印,可抗击拷贝,剪切。
  • 证件的防伪认证:如学历证,合同,票据等,携带数字水印后,可通过制定的方式提取水印,验证证件等数字文件是否被涂改;
  • 阿里事件:阿里追查泄密员工的时间本身,说明,水印可以有效的追溯信息的释放源;
  • 隐蔽信息传递:水印可携带加密信息后,藏在多媒体文件中传播,并通过特定的提取方式获取水印。可以作为一种隐蔽信息的通信方式。

源程序代码及部分注释

基础设置模块,同时存储着密钥,全局变量 main.m

1
2
3
4
5
6
7
global I ;
global W;
global P;
global Iw;
ntimes=23; % 秘钥1,Arnold置乱次数
rngseed=59433; % 秘钥2,随机数种子
flag=1; %是否显示图像,0 不显示,1 显示

嵌入水印模块:setdwtwatermark.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
matlabfunction [Iw,psnr]=setdwtwatermark(I,W,ntimes,rngseed,flag)
%基于小波变换数字水印嵌入
%I:载体图像,灰度图
%W:水印图像,二值图,且长宽相等
%ntimes: 秘钥1,Arnold置乱次数
I=imcrop(I,[0 0 size(I,2) size(I,1)-1]);
type=class(I);
I=double(I);
W=logical(W);
[mI,nI]=size(I);
[mW,nW]=size(W);
if mW~=nW
error('SETDWTWATERMARK:ARNOLD','ARNOLD置乱要求水印图像长宽必须相等!')
end
[ca1,ch1,cv1,cd1]=dwt2(I,'haar');
[ca2,ch2,cv2,cd2]=dwt2(ca1,'haar');
if flag
figure('Name','载体小波分解')
subplot(121)
imagesc([wcodemat(ca1),wcodemat(ch1);wcodemat(cv1),wcodemat(cd1)])
title('一级小波分解')
subplot(122)
imagesc([wcodemat(ca2),wcodemat(ch2);wcodemat(cv2),wcodemat(cd2)])
title('二级小波分解')
end
Wa=W;
H=[1,1;1,2]^ntimes;
for i=1:nW
for j=1:nW
idx=mod(H*[i-1;j-1],nW)+1;
Wa(idx(1),idx(2))=W(i,j);
end
end
flag=1;
if flag
figure('Name','水印置乱与嵌入')
subplot(221)
imshow(W)
title('原始水印')
subplot(222)
imshow(Wa)
title(['置乱水印,变换次数=',num2str(ntimes)]);
end
%数字水印嵌入
ca2w=ca2;
rng(rngseed);
idx=randperm(numel(ca2),numel(Wa));
for i=1:numel(Wa)
c=ca2(idx(i));
z=mod(c,nW);
if Wa(i)
if z<nW/4
f=c-nW/4-z;
else
f=c+nW*3/4-z;
end
else
if z<nW*3/4
f=c+nW/4-z;
else
f=c+nW*5/4-z;
end
end
ca2w(idx(i))=f;
end
ca1w=idwt2(ca2w,ch2,cv2,cd2,'haar');
Iw=idwt2(ca1w,ch1,cv1,cd1,'haar');
Iw=Iw(1:mI,1:nI);
mn=numel(I);
Imax=max(I(:));
psnr=10*log10(mn*Imax^2/sum((I(:)-Iw(:)).^2));
I=cast(I,type);
Iw=cast(Iw,type);
if flag
subplot(223)
imshow(I);
title('原始图像')
subplot(224);
imshow(Iw);
title(['添加水印,PSNR=',num2str(psnr)]);
end

提取水印模块:getdwtwatermark.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function [Wg,nc]=getdwtwatermark(Iw,W,P,ntimes,rngseed,flag)
[mW,nW]=size(W);
if mW~=nW
error('GETDWTWATERMARK:ARNOLD','ARNOLD置乱要求水印图像长宽必须相等!')
end
Iw=double(Iw);
W=logical(W);
ca1w=dwt2(Iw,'haar');
ca2w=dwt2(ca1w,'haar');
Wa=W;
rng(rngseed);
idx=randperm(numel(ca2w),numel(Wa));
for i=1:numel(Wa)
c=ca2w(idx(i));
z=mod(c,nW);
if z<nW/2
Wa(i)=0;
else
Wa(i)=1;
end
end
Wg=Wa;
H=[2 -1;-1,1]^ntimes;
for i=1:nW
for j=1:nW
idx=mod(H*[i-1;j-1],nW)+1;
Wg(idx(1),idx(2))=Wa(i,j);
end
end
nc=sum(Wg(:).*W(:))/sqrt(sum(Wg(:).^2))/sqrt(sum(W(:).^2));
flag=1;
if flag
figure('Name','数字水印提取结果')
subplot(121)
W=imcrop(W,[0 0 size(P,2) size(P,1)]);
imshow(W)
title('原始水印')
subplot(122)
Wg=imcrop(Wg,[0 0 122 107]);
imshow(Wg)
title(['提取水印,NC=',num2str(nc)]);
end

GUI 调用模块 watermatk.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
function varargout = watermark(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @watermark_OpeningFcn, ...
'gui_OutputFcn', @watermark_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
function watermark_OpeningFcn(hObject, eventdata, handles, varargin)
movegui( hObject,'center' );
handles.output = hObject;%移动窗口到屏幕中心
guidata(hObject, handles);
function varargout = watermark_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
main
[filename pathname]=uigetfile({'*.jpg;*.bmp';'*.*'},'请选择底图文件');
%%打开图像
I=imread(filename); %读取原始图像
[filename pathname]=uigetfile({'*.png;*.tif';'*.*'},'请选择水印文件');
helpdlg('选择完毕,您可点击查看以确认是否需要重新选择','提示');
I = rgb2gray(I);%转换为灰度图
W = imread(filename);%读取水印图像
if strcmp(filename(end-3:end),'tif')
W= rgb2gray(W);
W=imbinarize(W);%转化成二值图像
end
P=W;
Mm=size(W,1); %水印的行数
Nm=size(W,2); %水印的列数
%将图像扩展为长宽相等
if Mm<Nm
Max=Nm;
Min=Mm;
for i=Min:Max
for j=1:Max
W(i,j)=1;
end
end
else
Max=Mm;
Min=Nm;
for i=1:Max
for j=Min:Max
W(i,j)=1;
end
end
end
function pushbutton2_Callback(hObject, eventdata, handles)
main
figure('Name','载体图像与水印图像')
subplot(211);
imshow(I);
title('载体图像')
subplot(212);
imshow(P);
title('水印图像')
function pushbutton3_Callback(hObject, eventdata, handles)
main
[Iw,psnr]=setdwtwatermark(I,W,ntimes,rngseed,0);
function pushbutton4_Callback(hObject, eventdata, handles)
main
[Wg,nc]=getdwtwatermark(Iw,W,P,ntimes,rngseed,0);

基于小波的水印技术 运行结果演示

1 图像的选择与导入

进入 GUI 主界面

图 2 GUI 主界面

点击选择图片,分别选择载体图像和水印图像

图 3 选择底图文件

图 4 选择水印文件

两项都选择完毕后提示选择完成,

图 5 选择完毕 帮助提示框

对于取消选择未设置警告与报错提示,防止过多弹窗

2 载体图像小波变换

这部分未单独新开按钮和图片显示窗口,但程序的确执行了,用户无需知晓

3 水印图像的预处理

图 6 预处理成二值图像后的水印

4 小波数字水印的嵌入

图 7 原始水印和置乱水印以及原始图像和添加水印之后的图像对比

5 小波数字水印的提取

图 8 原始水印和提取的水印的对比

将原始水印和提取水印进行对比,两个相关系数为 0.99356,相关系数越接近 1, 则提取的水印和原始水印越相似。