实验原理

DCT域的图像水印嵌入与提取在信号的频域(变换域)中隐藏信息要比在时域中嵌入信息具有更好的鲁棒性。一副图像经过时域到频域的变换后,可将待隐藏信息藏入图像的的显著区域,这种方法比LSB以及其他一些时域水印算法更具抗攻击能力,而且还保持了对人类感官的不可察觉性。常用的变换域方法有离散余弦变换(DCT)、离散小波变换(DWT)和离散傅立叶变换(DFT)等。
本章介绍一种提取秘密信息的时候不需要原始图像的盲水印算法,算法的思想是利用载体中两个特定DCT系数的相对大小来表示隐藏的信息。载体图像分为8×8分块,进行二维DCT变换,分别选择其中的两个位置,比如用(u1,v1)和(u2,v2)代表所选定的两个系数的坐标。如果Bi(u1,v1) <Bi(u2,v2),代表隐藏1,如果相反,则交换两系数。如果Bi(u1,v1) >Bi(u2,v2),代表隐藏0,如果相反,则交换两系数。
提取的时候接收者对包含水印的图像文件进行二维DCT变换,比较每一块中约定位置的DCT系数值,根据其相对大小,得到隐藏信息的比特串,从而恢复出秘密信息。但是在使用上述算法的过程中,注意到如果有一对系数大小相差非常少,往往难以保证携带图像在保存和传输的过程中以及提取秘密信息的过程中不发生变化。因此在实际的设计过程中,一般都是引入一个Alpha变量对系数的差值进行控制,将两个系数的差别放大,可以保证提取秘密信息的正确性。

实验记录

(1)代码如下:
隐藏:
Dcthiding.m

clc; 
clear; 
msgfid=fopen('hidden.txt','r');%%打开秘密文件,读入秘密信息 
[msg,count]=fread(msgfid); 
count=count*8; 
alpha=0.02; 
fclose(msgfid); 
msg=str2bit(msg)'; 
[len,col]=size(msg); 
io=imread('lena.bmp');%读取载体图像 
io=double(io)/255; 
output=io; 
i1=io(:,:,1);%取图像的一层来隐藏 
T=dctmtx(8);%对图像进行分块 
DCTrgb=blkproc(i1,[8 8],'P1*x*P2',T,T');%对图像分块进行 DCT 变换 
[row,col]=size(DCTrgb); 
row=floor(row/8); 
col=floor(col/8); % 顺序信息嵌入 
temp=0; 
for i=1:count;     
    if msg(i,1)==0     
        if DCTrgb(i+4,i+1)<DCTrgb(i+3,i+2) %选择(5,2)和(4,3)这一对系数             
            temp=DCTrgb(i+4,i+1);        
            DCTrgb(i+4,i+1)=DCTrgb(i+3,i+2);        
            DCTrgb(i+3,i+2)=temp;      
        end
    else
        if  DCTrgb(i+4,i+1)>DCTrgb(i+3,i+2)     
            temp=DCTrgb(i+4,i+1);      
            DCTrgb(i+4,i+1)=DCTrgb(i+3,i+2);     
            DCTrgb(i+3,i+2)=temp;      
        end
    end
    if DCTrgb(i+4,i+1)<DCTrgb(i+3,i+2)    
        DCTrgb(i+4,i+1)=DCTrgb(i+4,i+1)-alpha;%将原本小的系数调整更小,使得系数 差别变大
    else
        DCTrgb(i+3,i+2)=DCTrgb(i+3,i+2)-alpha;
    end
end
wi=blkproc(DCTrgb,[8 8],'P1*x*P2',T',T);
output=io;
output(:,:,1)=wi;
imwrite(output,'watermarkedlena.bmp');
figure;
subplot(1,2,1);imshow('lena.bmp');title('原始图像');
subplot(1,2,2);imshow('watermarkedlena.bmp');title('嵌入图像');

str2bit函数

function msg_bits = str2bit(msgStr)
    msgBin = de2bi(int8(msgStr),8,'left-msb');
    len = size(msgBin,1).*size(msgBin,2);
    msg_bits = reshape(double(msgBin).',len,1).';
    end

提取:
Dctextract.m

clc; 
clear;
wi=imread('watermarkedlena.bmp');%读取携秘图像 
wi=double(wi)/255;
wi=wi(:,:,1);%取图像的一层来提取
T=dctmtx(8);%对图像进行分块 
DCTcheck=blkproc(wi,[8 8],'P1*x*P2',T,T');%对图像分块进行 DCT 变换 
 
for i=1:80 %80 为隐藏的秘密信息的比特数     
    if  DCTcheck(i+4,i+1)<=DCTcheck(i+3,i+2)    
        message(i,1)=1;  
    else
        message(i,1)=0;  
    end
end
out=bit2str(message);
fid=fopen('message.txt', 'wt');
fwrite(fid,out)
fclose(fid);

bit2str函数:

function message = bit2str(databits)
for i=1:(length(databits)/8)
    m=i-1;
    bits_str=strcat(num2str(databits(m*8+1)),num2str(databits(m*8+2)),...
        num2str(databits(m*8+3)),num2str(databits(m*8+4)),num2str(databits(m*8+5)),...
        num2str(databits(m*8+6)),num2str(databits(m*8+7)),num2str(databits(m*8+8)));
    message(i)=bin2dec(bits_str);
end

(2)运行结果:

提前写好hidden.txt文件

音频水印嵌入与提取算法Python 水印嵌入和提取原理_时域


运行隐藏代码

音频水印嵌入与提取算法Python 水印嵌入和提取原理_matlab_02


运行提取代码

看到列表中多了一个message.txt文件,打开查看

音频水印嵌入与提取算法Python 水印嵌入和提取原理_音频水印嵌入与提取算法Python_03

与hidden.txt中的内容一致,说明隐藏且提取成功