1、运行MAIN.m即可开始水印的嵌入和提取。
2、文件夹中的两幅图片为载体图像和水印图像。
3、其他文件为主程序所调用的自定义函数,说明如下:
sdwt.m:对图像依视觉能量进行树状小波分解
embed.m:对标记的嵌入点进行水印嵌入
nembed.m:对每个节点实施水印嵌入
sidwt.m:对嵌入后的树形子图以小波逆变换进行重组
sdwt_ex.m:依密钥树对含水印图像进行分解
extract.m:依密钥树抽取水印
nextract.m:对每个节点实施水印抽取
jadeR.m:JADE算法,用于实现ICA
fuse_pca.m:PCA算法,用于实现融合
rand_orth.m:生成混叠矩阵随机数
MAIN.m 主程序
%-------------------水印嵌入------------------------------------------------
while 1
clear;
c=0.3;
a=imread('lina.jpg');%原图像
b=imread('changsha.bmp')*255;%二值水印图像
[m1,n1]=size(a);
[m2,n2]=size(b);
e0=(sum(sum(a.^2)))/(m1*n1);
e0=c*e0;%计算基准能量
[t,tkey]=sdwt(double(a),'db2',m2,n2,e0);%树状小波分解
[t,tkey]=embed(t,tkey,b);%嵌入水印
aw=sidwt(t,'db2');%重组
figure(1);
subplot(1,2,1);imshow(uint8(a));title('原图');
subplot(1,2,2);imshow(uint8(aw));title('嵌入图');
imwrite(uint8(aw),'watermark.jpg');
% csvwrite('key.txt',reshape(tkey,m2,n2));
v1=m1*m1*255*255;
v2=sum(sum((double(a)-aw).^2));
snr=10*log10(v1/v2);% 峰值信噪比snr。
disp('信噪比');disp(snr);
%---攻击预处理--------------------------------------------------------------
% clear;
% pause;
f=imread('watermark.jpg');
%将含水印图像f归一化,以便于攻击处理。
m=max(max(f));
f=double(f)./double(m);
%---攻击-------------------------------------------------------------------
attack=0;
switch attack
case 0,
attackf=f;
att='未攻击';
case 1,
%%1. JPEG 压缩
imwrite(f,'attackf.jpg','jpg','quality',30);
attackf=imread('attackf.jpg');
attackf=double(attackf)/255;
att='JPEG压缩';
case 2,
% %2. 高斯低通滤波
h=fspecial('gaussian',3,1);
attackf=filter2(h,f);
att='高斯低通滤波';
case 3,
%%3. 直方图均衡化
attackf=histeq(f);
att='直方图均衡化';
case 4,
%%4. 图像增亮
attackf=imadjust(f,[],[0.4,1]);
att='图像增亮';
case 5,
%%5. 图像变暗
attackf=imadjust(f,[],[0,0.85]);
att='图像变暗';
case 6,
%%6. 增加对比度
attackf=imadjust(f,[0.3,0.6],[]);
att='增加对比度';
case 7,
%%7. 降低对比度
attackf=imadjust(f,[],[0.2,0.8]);
att='降低对比度';
case 8,
%%8. 添加高斯噪声
attackf=imnoise(f,'gaussian',0,0.01);
att='添加高斯噪声';
case 9,
%%9. 椒盐噪声
attackf=imnoise(f,'salt & pepper',0.06);
att='椒盐噪声';
case 10,
%%10. 添加乘积性噪声
attackf=imnoise(f,'speckle',0.08);
att='添加乘积性噪声';
end;
%---攻击后处理--------------------------------------------------------------
f=attackf.*double(m);
figure(2);
imshow(uint8(f));%显示水印嵌入图攻击后效果
title(att);
imwrite(uint8(f),'watermark.jpg');
%---提取水印----------------------------------------------------------------
% clear;
a=imread('watermark.jpg');
t=sdwt_ex(double(a),'db2',tkey);%根据密钥树分解
[w,map]=extract(t,tkey);%抽取水印
[r,c]=size(w);
figure(3);
for i=1:r
subplot(ceil(r/3),3,i)
imshow(255-100*abs(uint8(reshape(w(i,:),map(1),map(2)))));
title(strcat('抽取水印图',num2str(i)));
end;
%---分析水印并融合----------------------------------------------------------
Rarr=[];
for i=1:r %建立相关系数矩阵
for j=i+1:r
R(i,j)=abs(corr2(reshape(w(i,:),map(1),map(2)),reshape(w(j,:),map(1),map(2))));
if i~=j
Rarr=[Rarr;i,j,abs(R(i,j))];
end;
end;
end;
[cor,idx]=sort(Rarr(:,3),'descend');
max1=cor(1);max2=cor(2);
m1=Rarr(idx(1),1);n1=Rarr(idx(1),2);
m2=Rarr(idx(2),1);n2=Rarr(idx(2),2);
maxcor(1)=abs(corr2(reshape(w(m1,:),map(1),map(2)),reshape(w(m2,:),map(1),map(2))))
maxcor(2)=abs(corr2(reshape(w(m1,:),map(1),map(2)),reshape(w(n2,:),map(1),map(2))))
maxcor(3)=abs(corr2(reshape(w(n1,:),map(1),map(2)),reshape(w(m2,:),map(1),map(2))))
maxcor(4)=abs(corr2(reshape(w(n1,:),map(1),map(2)),reshape(w(n2,:),map(1),map(2))))
if mean(maxcor)>(max1*0.8)
stdw=fuse_pca(reshape(w(m1,:),map(1),map(2)), reshape(w(n1,:),map(1),map(2)));
figure(4);
subplot(1,2,1)
imshow(b);
title('原水印');
subplot(1,2,2)
wf=255-100*abs(uint8(stdw));
imshow(wf);
title('pca融合后的水印');
else
disp('重新融合');
end;
if abs(corr2(wf,b))>0.9
break;
end;
end;
disp('水印相似度');disp(corr2(wf,b));
%--------------------------------------------------------------------------
sdwt.m:对图像依视觉能量进行树状小波分解
function [t,tkey]=sdwt(node,wname,m2,n2,e0)
[A,H,V,D]=dwt2(node,wname);
[mi,ni]=size(A);
if mi*ni<m2*n2
t=node;tkey=1;
return;
end;
ea=(sum(sum(A.^2)))/(mi*ni);
eh=(sum(sum(H.^2)))/(mi*ni);
ev=(sum(sum(V.^2)))/(mi*ni);
ed=(sum(sum(D.^2)))/(mi*ni);
if ea<e0&ea>0.1*e0
[A,ka]=sdwt(A,wname,m2,n2,e0);
else
ka=-1;
end;
if eh<e0&eh>0.1*e0
[H,kh]=sdwt(H,wname,m2,n2,e0);
else
kh=-1;
end;
if ev>e0&ev>0.1*e0
[V,kv]=sdwt(V,wname,m2,n2,e0);
else
kv=-1;
end;
if ed<e0&ed>0.1*e0
[D,kd]=sdwt(D,wname,m2,n2,e0);
else
kd=-1;
end;
t={A,H,V,D};
tkey={ka,kh,kv,kd};
return;
embed.m:对标记的嵌入点进行水印嵌入
function [t,tkey]=embed(t,tkey,b)
[m2,n2]=size(b);
for i=1:4
if ~iscell(tkey{1,i})
if tkey{1,i}==1
[t{1,i},tkey{1,i}]=nembed(t{1,i},b);
end;
else
[t{1,i},tkey{1,i}]=embed(t{1,i},tkey{1,i},b);
end;
end;
return;
nembed.m:对每个节点实施水印嵌入
function [wnode,nodekey]=nembed(nd,b)
[m1,n1]=size(nd);
[m2,n2]=size(b);
node=nd;
node1=node(1:m2*n2);
node2=node(m2*n2+1:m1*n1);
b=b(1:m2*n2);
%---互信息法---------------------------------------------------------------
S=[];
for i=1:2
switch i
case 1, s=double(node1);
case 2, s=double(b);
end
s=s-mean(s); % 归一
s=s/std(s,1); % 标准化
S=[S; s];
end
A=rand_orth(2);
% A=rand(2,2);
X=A*S;
x1=X(1,:);
x1=[x1,node2];
x2=X(2,:)
nodekey=reshape(x2,m2,n2);
%--------------------------------------------------------------------------
%---加法-------------------------------------------------------------------
% x1=node1+b*0.02;
% x1=[x1 node2];
% nodekey=[0.02,-1];
%--------------------------------------------------------------------------
wnode=reshape(x1,m1,n1);
return;
sidwt.m:对嵌入后的树形子图以小波逆变换进行重组
function t=sidwt(t,wname)
if ~iscell(t{1,1})
if ~iscell(t{1,2})
if ~iscell(t{1,3})
if ~iscell(t{1,4})
[mi(1),ni(1)]=size(t{1,1});[mi(2),ni(2)]=size(t{1,2});
[mi(3),ni(3)]=size(t{1,3});[mi(4),ni(4)]=size(t{1,4});
m=min(mi);n=min(ni);
t{1,1}=t{1,1}(1:m,1:n);
t{1,2}=t{1,2}(1:m,1:n);
t{1,3}=t{1,3}(1:m,1:n);
t{1,4}=t{1,4}(1:m,1:n);
t=idwt2(t{1,1},t{1,2},t{1,3},t{1,4},wname);
else
t{1,4}=sidwt(t{1,4},wname);
[mi(1),ni(1)]=size(t{1,1});[mi(2),ni(2)]=size(t{1,2});
[mi(3),ni(3)]=size(t{1,3});[mi(4),ni(4)]=size(t{1,4});
m=min(mi);n=min(ni);
t{1,1}=t{1,1}(1:m,1:n);
t{1,2}=t{1,2}(1:m,1:n);
t{1,3}=t{1,3}(1:m,1:n);
t{1,4}=t{1,4}(1:m,1:n);
t=idwt2(t{1,1},t{1,2},t{1,3},t{1,4},wname);
end;
else
if iscell(t{1,4})
t{1,4}=sidwt(t{1,4},wname);
end;
t{1,3}=sidwt(t{1,3},wname);
[mi(1),ni(1)]=size(t{1,1});[mi(2),ni(2)]=size(t{1,2});
[mi(3),ni(3)]=size(t{1,3});[mi(4),ni(4)]=size(t{1,4});
m=min(mi);n=min(ni);
t{1,1}=t{1,1}(1:m,1:n);
t{1,2}=t{1,2}(1:m,1:n);
t{1,3}=t{1,3}(1:m,1:n);
t{1,4}=t{1,4}(1:m,1:n);
t=idwt2(t{1,1},t{1,2},t{1,3},t{1,4},wname);
end;
else
if iscell(t{1,4})
t{1,4}=sidwt(t{1,4},wname);
end;
if iscell(t{1,3})
t{1,3}=sidwt(t{1,3},wname);
end;
t{1,2}=sidwt(t{1,2},wname);
[mi(1),ni(1)]=size(t{1,1});[mi(2),ni(2)]=size(t{1,2});
[mi(3),ni(3)]=size(t{1,3});[mi(4),ni(4)]=size(t{1,4});
m=min(mi);n=min(ni);
t{1,1}=t{1,1}(1:m,1:n);
t{1,2}=t{1,2}(1:m,1:n);
t{1,3}=t{1,3}(1:m,1:n);
t{1,4}=t{1,4}(1:m,1:n);
t=idwt2(t{1,1},t{1,2},t{1,3},t{1,4},wname);
end;
else
if iscell(t{1,4})
t{1,4}=sidwt(t{1,4},wname);
end;
if iscell(t{1,3})
t{1,3}=sidwt(t{1,3},wname);
end;
if iscell(t{1,2})
t{1,2}=sidwt(t{1,2},wname);
end;
t{1,1}=sidwt(t{1,1},wname);
[mi(1),ni(1)]=size(t{1,1});[mi(2),ni(2)]=size(t{1,2});
[mi(3),ni(3)]=size(t{1,3});[mi(4),ni(4)]=size(t{1,4});
m=min(mi);n=min(ni);
t{1,1}=t{1,1}(1:m,1:n);
t{1,2}=t{1,2}(1:m,1:n);
t{1,3}=t{1,3}(1:m,1:n);
t{1,4}=t{1,4}(1:m,1:n);
t=idwt2(t{1,1},t{1,2},t{1,3},t{1,4},wname);
end;
return;
sdwt_ex.m:依密钥树对含水印图像进行分解
function t=sdwt_ex(node,wname,tkey)
[A,H,V,D]=dwt2(node,wname);
AHVD={A,H,V,D};
for i=1:length(tkey)
if iscell(tkey{1,i})
t{1,i}=sdwt_ex(AHVD{1,i},wname,tkey{1,i});
else
if tkey{1,i}~=-1
t{1,i}=node;
else
t{1,i}={};
end;
end;
end;
extract.m:依密钥树抽取水印
function [w,map]=extract(t,tkey);
w=[];
for i=1:4
if ~iscell(tkey{1,i})
if tkey{1,i}~=-1
[wi,map]=nextract(t{1,i},tkey{1,i});
else
wi=[];
end;
else
[wi,map]=extract(t{1,i},tkey{1,i});
end;
if length(wi)>0
w=[w;wi];
end;
end;
return;
nextract.m:对每个节点实施水印抽取
function [wi,map]=nextract(tnd,tkey)
[m2,n2]=size(tkey);
x1=tnd(1:m2*n2);
x2=tkey(1:m2*n2);
X=[x1;x2];
B=jadeR(double(X),2);
Y=B*double(X);
y2=Y(2,:);
wi=y2;
map=[m2,n2];
return;
fuse_pca.m:PCA算法,用于实现融合
function Y = fuse_pca(M1, M2)
[z1 s1] = size(M1);
[z2 s2] = size(M2);
if (z1 ~= z2) | (s1 ~= s2)
error('Input images are not of same size');
end;
[V, D] = eig(cov([M1(:) M2(:)]));
if (D(1,1) > D(2,2))
a = V(:,1)./sum(V(:,1));
else
a = V(:,2)./sum(V(:,2));
end;
Y = a(1)*M1+a(2)*M2;
rand_orth.m:生成混叠矩阵随机数
function W=rand_orth(n,m);
if (nargin<2)
m=n;
end
W=rand(m)-.5;
[W,cococococo]=qr(W);
W=W(1:m,1:n);
jadeR.m:JADE算法,用于实现ICA
function B = jadeR(X,m)
% B = jadeR(X, m) is an m*n matrix such that Y=B*X are separated sources
% extracted from the n*T data matrix X.
% If m is omitted, B=jadeR(X) is a square n*n matrix (as many sources as sensors)
%
% Blind separation of real signals with JADE. Version 1.8. * If X is an nxT data matrix (n sensors, T samples) then
% B=jadeR(X) is a nxn separating matrix such that S=B*X is an nxT
% matrix of estimated source signals.
% * If B=jadeR(X,m), then B has size mxn so that only m sources are
% extracted. This is done by restricting the operation of jadeR
% to the m first principal components.
% * Also, the rows of B are ordered such that the columns of pinv(B)
% are in order of decreasing norm; this has the effect that the
% `most energetically significant' components appear first in the
% rows of S=B*X.
%
% Quick notes (more at the end of this file)
%
% o this code is for REAL-valued signals. An implementation of JADE
% for both real and complex signals is also available from
% http://sig.enst.fr/~cardoso/stuff.html
%
% o This algorithm differs from the first released implementations of
% JADE in that it has been optimized to deal more efficiently
% 1) with real signals (as opposed to complex)
% 2) with the case when the ICA model does not necessarily hold.
%
% o There is a practical limit to the number of independent
% components that can be extracted with this implementation. Note
% that the first step of JADE amounts to a PCA with dimensionality
% reduction from n to m (which defaults to n). In practice m
% cannot be `very large' (more than 40, 50, 60... depending on
% available memory)
%
% o See more notes, references and revision history at the end of
% this file and more stuff on the WEB
% http://sig.enst.fr/~cardoso/stuff.html
%
% o This code is supposed to do a good job! Please report any
% problem to cardoso@sig.enst.fr
verbose = 1 ; % Set to 0 for quiet operation
% Finding the number of sources
[n,T] = size(X);
if nargin==1, m=n ; end; % Number of sources defaults to # of sensors
if m>n , fprintf('jade -> Do not ask more sources than sensors here!!!\n'), return,end
if verbose, fprintf('jade -> Looking for %d sources\n',m); end ;
% to do: add a warning about complex signals
% Mean removal
%=============
if verbose, fprintf('jade -> Removing the mean value\n'); end
X = X - mean(X')' * ones(1,T);
%%% whitening & projection onto signal subspace
% ===========================================
if verbose, fprintf('jade -> Whitening the data\n'); end
[U,D] = eig((X*X')/T) ; %% An eigen basis for the sample covariance matrix
[Ds,k] = sort(diag(D)) ; %% Sort by increasing variances
PCs = ; %% The m most significant princip. comp. by decreasing variance
%% --- PCA ----------------------------------------------------------
B = ; % At this stage, B does the PCA on m components
%% --- Scaling ------------------------------------------------------
scales = sqrt(Ds(PCs)) ; % The scales of the principal components .
B = diag(1./scales)*B ; % Now, B does PCA followed by a rescaling = sphering
%% --- Sphering ------------------------------------------------------
X = B*X;
Any further rotation of X will preserve the
%%% property that X is a vector of uncorrelated components. It remains to find the
%%% rotation matrix such that the entries of X are not only uncorrelated but also `as
%%% independent as possible'. This independence is measured by correlations of order
%%% higher than 2. We have defined such a measure of independence which
%%% 1) is a reasonable approximation of the mutual information
%%% 2) can be optimized by a `fast algorithm'
%%% This measure of independence also corresponds to the `diagonality' of a set of
%%% cumulant matrices. The code below finds the `missing rotation ' as the matrix which
%%% best diagonalizes a particular set of cumulant matrices.
%%% Estimation of the cumulant matrices.
% ====================================
if verbose, fprintf('jade -> Estimating cumulant matrices\n'); end
%% Reshaping of the data, hoping to speed up things a little bit...
X = X';
dimsymm = (m*(m+1))/2; % Dim. of the space of real symm matrices
nbcm = dimsymm ; % number of cumulant matrices
CM = zeros(m,m*nbcm); % Storage for cumulant matrices
R = eye(m); %%
Qij = zeros(m); % Temp for a cum. matrix
Xim = zeros(m,1); % Temp
Xijm = zeros(m,1); % Temp
Uns = ones(1,m); % for convenience
%% I am using a symmetry trick to save storage. I should write a short note one of these
%% days explaining what is going on here.
%%
Range = % will index the columns of CM where to store the cum. mats.
for im = Xim =
Xijm= Xim.*Xim ;
%% the joint diagonalization criterion
Qij =
= Qij ;
Range = Range + m ;
for jm = Xijm =
Qij =
= Qij ;
Range = Range + m ;
end ;
end;
%%%% Now we have nbcm = It can be found at
%% "http://www.tsi.enst.fr/~cardoso/Papers.PS/neuralcomp_2ppf.ps",
%%
%%
%%
%% if 1,
%%
%% Matcum = zeros(m,m,m,m) ;
%% for i1=1:m,
%% for i2=1:m,
%% for i3=1:m,
%% for i4=1:m,
%% Matcum(i1,i2,i3,i4) = - R(i1,i2)*R(i3,i4) ...
%% - R(i1,i3)*R(i2,i4) ...
%% - R(i1,i4)*R(i2,i3) ;
%% end
%% end
%% end
%% end
%%
%% %% Step 2; We compute a basis of the space of symmetric m*m matrices
%% CMM = zeros(m, m, nbcm) ; %% Holds the basis.
%% icm = 0 ; %% index to the elements of the basis
%% vi = zeros(m,1); %% the ith basis vetor of R^m
%% vj = zeros(m,1); %% the jth basis vetor of R^m
%% Id = eye (m) ; %% convenience
%% for im=1:m,
%% vi =
%% icm = icm + 1 ;
%% CMM(:, :, icm) = vi*vi' ;
%% for jm=1:im-1,
%% vj =
%% icm = icm + 1 ;
%% CMM(:, :, icm) = sqrt(0.5) * (vi*vj'+vj*vi') ;
%% end
%% end
%%
%% %% Step 3. We compute the image of each basis element by the cumulant tensor and store it back into CMM.
%% mat = zeros(m) ; %% tmp
%% for icm=1:nbcm
%% mat =
%% for i1=1:m
%% for i2=1:m
%% CMM(i1, i2, icm) = .* mat )) ;
%% end
%% end
%% end;
%% %% This is doing something like \sum_kl [ Cum(xi,xj,xk,xl) * mat_kl ]
%%
%% %% Step 4. Now, we can check that CMM and CM are equivalent
%% Range =
%% for icm=1:nbcm,
%% M1 =
%% M2 =
%% Range = Range + m ;
%% norm (M1-M2, 'fro' ) , %% This should be a numerical zero.
%% end;
%%
%% end; %% End of the demo code for the computation of cumulant matrices
%%
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%