1. 实验类别
设计型实验:MATLAB设计并实现基于DCT的图像数字水印算法。
2. 实验目的
了解基于DCT的图像数字水印技术,掌握基于DCT系数关系的图像水印算法原理,设计并实现一种基于DCT的数字水印算法。
3. 实验条件
(1) Windows 2000或Windows Xp以上操作系统;
(2) MATLAB 6.5以上版本软件;
(3)图像文件
4. 实验原理
基于DCT的图像数字水印
在信号的频域(变换域)中隐藏信息要比在时域中嵌入信息具有更好的鲁棒性。一幅图像经过时域到频域的变换后,可将待隐藏信息嵌入图像的显著区域,这种算法更具抗攻击能力,而且保持了人类感官的不可察觉性。常用的变换域方法有离散余弦变换、离散小波变换和离散傅立叶变换等。
本实验介绍一种提取秘密信息的时候不需要原始图像的盲水印算法,算法的思想是利用载体中两个特定的DCT系数的相对大小来表示隐藏的信息。首先载体图像分为8*8分块,进行二维DCT变换,分别选择其中约定的两个位置,比如用(u1,v1)和(u2,v2)代表所选定的两个系数的坐标。如果Bi(u1,v1)< Bi(u2,v2),代表隐藏1。如果Bi(u1,v1)> Bi(u2,v2),代表隐藏0。
提取的时候接收者对包含水印的图像文件进行二维DCT变换,比较每一块中约定位置的DCT系数值,根据其相对大小,如果Bi(u1,v1)< Bi(u2,v2),则提取1;如果Bi(u1,v1)> Bi(u2,v2),则提取0。最终得到隐藏信息的比特串,从而恢复出秘密信息。
在上述算法过程中,如果有一对系数大小相差非常少,往往难以保证携带图像在保存和传输的过程中以及提取秘密信息的过程中不发生变化。因此在实际的设计过程中,一般都是引入一个Alpha变量对系数的差值进行控制,将两个系数的差值放大,可以保证提取秘密信息的正确性。
1.DCT数字水印嵌入.m脚本代码:
clc; clear all; pic_path = input('请输入要嵌入水印的图片绝对路径(要加单引号):'); watermark_txt = input('请输入水印所在文件绝对路径(要加单引号):'); msgfid=fopen(watermark_txt,'r'); %打开秘密文件,读入秘密信息 [key,count]=fread(msgfid,'ubit1'); alpha=0.01; block = 8; fclose(msgfid); [len,col]=size(key); io=imread(pic_path); %读取载体彩色图像 io=double(io)/255; output=io; i1=io(:,:,1); %取图像的第1层来隐藏,彩色图像空间RGB三层 T=dctmtx(block); %生成一个8*8 DCT变换矩阵 DCTrgb=blkproc(i1,[block block],'P1*x*P2',T,T');% x就是每一个分成的8*8大小的块,P1*x*P2相当于像素块的处理函数(记为fun),p1=T p2=T’,也就是fun=p1*x*p2=T*x*T'的功能是进行离散余弦变换,T,T'就是前面函数fun参数 [row,col]=size(DCTrgb); row=floor(row/block); col=floor(col/block); contents = row * col; %contents表示图像矩阵能嵌入的最大比特数 if count > contents disp('Warning: 图像容量无法嵌入所有水印信息! 按enter退出matlab!'); pause; quit; else disp(['该图像能嵌入的水印信息最大值为:',num2str(contents),' bits']); end %纵向顺序信息嵌入 cow1 = 5; cow2 = 4; column1 = 2; column2 = 3; key_counter = 1; temp = 0; round_counter = 0; total_marked_bits = 0; if mod(count,row) == 0 round = floor(count/row); % round记录需要图像矩阵多少列来嵌入水印(这里以一个8*8矩阵为一个bit嵌入单元) else round = floor(count/row)+1; % round记录需要图像矩阵多少列来嵌入水印(这里以一个8*8矩阵为一个bit嵌入单元) end for ii=1:1:round for jj=1:1:row if DCTrgb(cow1,column1) == DCTrgb(cow2,column2) DCTrgb(cow1,column1) = DCTrgb(cow1,column1) - 0.0002; end if key(key_counter,1) == 1 if DCTrgb(cow1,column1) > DCTrgb(cow2,column2) temp = DCTrgb(cow1,column1); DCTrgb(cow1,column1) = DCTrgb(cow2,column2); DCTrgb(cow2,column2) = temp; DCTrgb(cow1,column1) = DCTrgb(cow1,column1) - alpha;% 扩大差距 else DCTrgb(cow1,column1) = DCTrgb(cow1,column1) - alpha;% 扩大差距 end elseif key(key_counter,1) == 0 if DCTrgb(cow1,column1) < DCTrgb(cow2,column2) temp = DCTrgb(cow1,column1); DCTrgb(cow1,column1) = DCTrgb(cow2,column2); DCTrgb(cow2,column2) = temp; DCTrgb(cow2,column2) = DCTrgb(cow2,column2) - alpha;% 扩大差距 else DCTrgb(cow2,column2) = DCTrgb(cow2,column2) - alpha;% 扩大差距 end else disp('BitValueError: key bit value is invalid , neither 0 nor 1 !'); disp('按 enter 退出matlab.'); pause; quit; end cow1 = cow1 + block; cow2 = cow2 + block; key_counter = key_counter + 1; total_marked_bits = total_marked_bits + 1; if key_counter > count break; end end %内层for round_counter = round_counter + 1; disp(['当前嵌入轮数 :', num2str(round_counter)]); if key_counter > count disp(['水印嵌入正常结束!共嵌入:',num2str(total_marked_bits),' bits']); break; end cow1 = 5; cow2 = 4; column1 = column1 + block; column2 = column2 + block; end %外层for %将信息写回并保存 wi=blkproc(DCTrgb,[block block],'P1*x*P2',T',T);%对DCTrgb进行逆变换 output(:,:,1)=wi; imwrite(output,'E:\new\dct_watermarked.bmp'); figure; subplot(1,2,1); imshow(pic_path); title('原始图像'); subplot(1,2,2); imshow('E:\new\dct_watermarked.bmp'); title('嵌入水印图像');
运行截图:
2.DCT水印提取脚本代码:
clc; clear all; watermarked_picpath = input('请输入待提取的dct水印图片绝对路径(要加单引号):'); watermarked_bits = input('请输入嵌入的水印比特数:'); i=imread(watermarked_picpath); i=double(i)/255; i1=i(:,:,1); block = 8; T=dctmtx(block); DCTcheck=blkproc(i1,[block block],'P1*x*P2',T,T');%对图像分块进行DCT变换 key = zeros(watermarked_bits,1); [row,col]=size(DCTcheck); row=floor(row/block); col=floor(col/block); cow1 = 5; cow2 = 4; column1 = 2; column2 = 3; key_counter = 1; round_counter = 0; total_get_bits = 0; if mod(watermarked_bits,row) == 0 round = floor(watermarked_bits/row); % round记录需要图像矩阵多少列来嵌入水印(这里以一个8*8矩阵为一个bit嵌入单元) else round = floor(watermarked_bits/row)+1; % round记录需要图像矩阵多少列来嵌入水印(这里以一个8*8矩阵为一个bit嵌入单元) end for ii=1:1:round for jj=1:1:row if DCTcheck(cow1,column1) <= DCTcheck(cow2,column2) key(key_counter,1) = 1; else key(key_counter,1) = 0; end total_get_bits = total_get_bits + 1; key_counter = key_counter + 1; if key_counter > watermarked_bits break; end cow1 = cow1 + block; cow2 = cow2 + block; end %内层for round_counter = round_counter + 1; disp(['当前提取轮数 :', num2str(round_counter)]); if key_counter > watermarked_bits disp(['水印提取正常结束!共提取水印:',num2str(total_get_bits),' bits']); break; end cow1 = 5; cow2 = 4; column1 = column1 + block; column2 = column2 + block; end %外层for fid=fopen('E:\new\dct_watermark_msg.txt','wt'); fwrite(fid,key,'bit1'); fclose(fid);
提取水印信息与原信息对比:
DCT水印实验遇到的问题及要点:
1.该实验对象是彩色RGB图像,任需要提取一层进行嵌入.
2.该实验中对每个矩阵块中的固定2个像素值比较时要考虑相等的情况,如若相等嵌入时先将其中任意一个减小少量,然后再比较大小考虑是否要互换像素值;最后提取时理论上是不会出现2个像素值一样的情况,但实验发现可能出现相等的情况,if DCTcheck(cow1,column1) <= DCTcheck(cow2,column2)代码中若去掉等号则提取的水印信息不正确.至今没明白为什么?
上述脚本在matlab6.5能正确运行,若有不足欢迎指正;若有疑问鄙人也乐于为道友解答,欢迎留言!
欢迎加入QQ群:735472015,群内有VC,MFC,win32API,批处理,python学习资料干货喔