目录
基本原理
数字水印技术基本概述
数字水印技术是一种有效的数字产品版权保护和数据安全维护技术,是信息隐藏技术研究领域的一个重要分支。其基本思想是利用数字图像中普遍存在的冗余数据与随机性,将具有特定意义的标记(水印),利用数字嵌入的方法隐藏在数字图像等数字产品,从而起到保护数字图像版权或者完整性的一种技术。这种标记是不可见的,只有通过专用的检测器或阅读器才能提取。一个有效的数字水印系统至少应具备三个最基本特性:
- 隐蔽性:在数字图像作品中嵌入数字水印不会引起图像明显的降质,数字水印的图像和原始图像对人的感觉器官的刺激应该是无差别或差别很小,主观感觉变化微小并且不易被察觉。
- 隐藏位置的安全性:水印信息隐藏于数据图像而非文件头中,文件格式的变换不应导致水印数据的丢失。
- 鲁棒性:所谓鲁棒性是指在经历多种无意或有意的信号处理过程后,数字水印仍能保持完整性或仍能被准确鉴别。可能的信号处理过程包括信道噪声、滤波、数/模与模/数转换、重采样、剪切、位移、尺度变化以及JPEG压缩等。
数字水印系统基本原理
数字水印技术的基本框架包括嵌入和检测两个主要过程。
在嵌入过程中,数字水印通常是一段二进制数据,可以是数字签名、版权信息、加密密钥、序列号等信息。数字水印嵌入的方法常见的有频域和空域两种方法。在频域中,数字水印被嵌入到数字图像的频域系数中,通常使用离散余弦变换(DCT)或小波变换(WT)等方法。在空域中,数字水印被嵌入到数字图像的像素值中,常见的方法有LSB(最低有效位)替换和伸缩算法等。
在检测过程中,数字水印需要从数字图像、音频、视频等多媒体数据中提取出来,进行比对和验证。数字水印提取需要通过相应的解码算法,将数字水印从数字图像中提取出来。相应的验证算法则用于验证数字水印的正确性和完整性。同时数字水印检测需要考虑信噪比、攻击强度和检测误差等因素。
数字水印的嵌入和提取的一般过程基本框架如图1,图2所示。
图2.1水印嵌入的一般过程基本框架
图2.2水印嵌入的一般过程基本框架
DCT算法原理公式
数字图像f(x,y)是具有M行N列的一个矩阵。为了减弱或去除图像数据相关性,可以运用二维DCT,将图像从空间域转换到DCT变换域。其中,二维DCT变换公式如下:
图像经DCT后,得到的DCT图像有三个特点:
1.系数值全部集中在0值附近,动态范围很小;
2.DCT变换后图像能量集中在图像的低频部分,即DCT图像中不为零的系数大部分集中在一起;
3.没有保留原图像块的精细结构,从中反映不了原图像块的边缘、轮廓等信息。
DCT水印嵌入算法
DCT信息嵌入算法是以DCT变换为基础,对图像经过DCT变换后的DCT系数进行适当改变,以达到隐藏秘密信息的目的。生物学研究表明,人眼对图像平滑区域的变换比较敏感,而对纹理区域的变换不太敏感。经过离散余弦变换之后,图像信息集中在少数低频系数上,而纹理和边缘信息则在中高频系数中,所以低频系数的改变对图像视觉上的影响远大于高频系数。因此,在DCT信息嵌入的时候我们也是选择中频系数来隐藏信息。在DCT系数矩阵中,低频和高频分别分布在左上角和右下角,所以嵌入选择中间任意位置即可。
嵌入过程中,将载体图像分成8×8的像素块,并对每个块进行DCT变换,得到8×8的DCT系数矩阵。这个8×8的DCT系数矩阵可以看作是载体图像在频域的表示,然后将秘密信息嵌入到这些DCT系数中,最后进行反变换得到嵌入水印的图像。如果水印图像的像素数与载体图像总的分块数,我们便可以将每一个水印像素嵌入到每一个块矩阵中,嵌入位置可以自己选择。
如下图举例:假设图像大小为16*16,水印大小为2*2,x代表嵌入后的数值(由当前水印图像的二值图和尺度因子以及加密矩阵决定),我们选择每个块嵌入8个由水印像素决定的隐藏系数。
图3 嵌入算法举例
DCT水印提取算法
DCT信息提取是DCT信息嵌入的逆变换,将带水印的图像分成8×8的像素块然后进行DCT变换得到DCT频域系数,然后根据嵌入水印时使用的算法,确定嵌入水印的位置和提取规则,最后根据提取规则,提取嵌入在图像中的水印信息并对提取出的水印信息进行解密和反变换,得到原始水印信息。
基于DCT算法的数字水印设计方案
利用DCT算法对图像进行数字水印嵌入步骤如下:
1、将载体图像分成8×8的像素块。
2、对每个小块进行DCT变换。
3、预处理水印图像并转化为二值图数据以便嵌入。
4、将水印的每一个点加密后以一定的尺度系数嵌入频域信息中。
5、对含有水印的图像进行模拟攻击(噪声、裁剪、压缩等)。
6、提取受攻击的图像中的水印并进行对比分析。
图2.4总体流程框架
程序代码
载体图像的读取
通过调用MATLAB中的uigetfile函数打开文件选择对话框选取图片文件,再采用imread函数将选取图片存储在数值矩阵中,同时传递给全局handles方便后续调用,最后显示在UI界面的axes控件中。
读取原始图像的主要代码:
1.[filename,pathname]=uigetfile({'*.bmp';'*.jpg';'*.*'},'读取图片文件');%选择要读取的图像文件如.bmp、.jpg 或任何其他文件类型的文件
2.str=[pathname filename]; %创建一个字符串,其中包含所选图像文件的文件路径和名称。
3.[handles.I,handles.map]=imread(str);%将图像文件读入内存。如果图像是索引图像,则“handles.map”变量用于存储颜色映射表,而“handles.I”变量用于存储图像数据。
4.img=imread(str);%再读取将其存储在“img”变量中
5.guidata(hObject,handles);%将图像数据存储在“handles”中方便后续调用
6.axes(handles.axes3);%选择GUI中的“axes3”对象,该对象用于显示图像
7.imshow(img,[]);%显示图像
8.dim=size(img);
9.set(handles.text12,'string',num2str(dim));%显示图片大小
水印图像的读取与处理
读取方法与原始图像读取方法一致,但是在读取到水印图像之后对首先对水印图像进行灰度处理,然后将图像二值化,最后显示在UI界面的axes控件中。
读取并预处理水印图像的主要代码:
1.mark=imread(str);
2.mark_gray=rgb2gray(mark);
3.water=im2bw(mark_gray); %使水印图像变为二值图
4.axes(handles.axes4);
5.imshow(water);title('原水印图像'); %在axes2中显示原水印图像
水印图像的嵌入算法
首先将原始图像分块后进行DCT变换,并将变换后的系数矩阵与强度值和水印图像相应点二值图信息相乘完成嵌入,即每一个图像块都嵌入了由加密矩阵和尺度因子共同加密的一个水印图像灰度值。如果是彩色图像,因为人眼对亮度的敏感度大于色彩敏感度,因此先将彩色图像变换YUV模式,然后采用同样的方法嵌入到彩色图像的色度层U,最大程度上保证水印的不可见性。最后将将嵌入后的块数据分别进行反DCT变换得到嵌入图像。
global k1;global k2;
k1=randn(1,8);k2=randn(1,8);%产生两个不同的随机序列矩阵用于加密
mysize=ndims(handles.I);%判断矩阵维度
if mysize>2 %如果是彩色图像
yuv=rgb2ycbcr(handles.I); %将RGB模式的原图变成YUV模式:亮度“Y”、色度“U”和浓度“V”
Y=yuv(:,:,1); %分别获取三层,该层为亮度层
U=yuv(:,:,2); %因为人对亮度的敏感度大于对色彩的敏感度,因此水印嵌在色度层上
V=yuv(:,:,3);
cda0=blkproc(U,[8,8],'dct2'); %将原始图像色度层分为8×8的小块并做二维DCT变换
else %灰度图像
cda0=blkproc(handles.I,[8,8],'dct2'); %将原始图像的灰度层分为8×8的小块并做二维DCT变换
end
cda1=cda0;
for i=1:rm %嵌入水印
for j=1:cm
x=(i-1)*X1;y=(j-1)*Y1;
if mark(i,j)==1%加密过程
k=k1;
else
k=k2;
end
cda1(x+1,y+8)=cda0(x+1,y+8)+alpha*k(1);
cda1(x+2,y+7)=cda0(x+2,y+7)+alpha*k(2);
cda1(x+3,y+6)=cda0(x+3,y+6)+alpha*k(3);
cda1(x+4,y+5)=cda0(x+4,y+5)+alpha*k(4);
cda1(x+5,y+4)=cda0(x+5,y+4)+alpha*k(5);
cda1(x+6,y+3)=cda0(x+6,y+3)+alpha*k(6);
cda1(x+7,y+2)=cda0(x+7,y+2)+alpha*k(7);
cda1(x+8,y+1)=cda0(x+8,y+1)+alpha*k(8);
end
end
global res; global res1;
%恢复空域
if mysize>2%如果是彩色图像
res=blkproc(cda1,[8,8],'idct2'); %二维DCT逆变换
res=cat(3,Y,res,V); %将经处理的色彩层和两个未处理的层合成
res=ycbcr2rgb(res); %使YUV图像变回RGB图像
else%如果是灰度图像
res1=blkproc(cda1,[8,8],'idct2'); %二维DCT逆变换
res=uint8(res1);%转换无符号数
end
基于DCT变换的水印提取
DCT水印提取通过对含水印图像进行分块后DCT变换,根据嵌入的规则提取水印图像的加密信息,比较提取出来的数值与加密数组k1和k2的相似度进行解密,还原水印图样信息后最后反变换到空域显示提取的水印图像。
dca1=blkproc(gong,[8,8],'dct2');%此步开始提取水印,将灰度层分块进行DCT变换
p=zeros(1,8);%初始化提取数值用的矩阵
for i=1:dimI(1)
for j=1:dimI(2)
x=(i-1)*X1;y=(j-1)*Y1;
p(1)=dca1(x+1,y+8);
p(2)=dca1(x+2,y+7); %将之前改变过数值的点的数值(数组)提取出来
p(3)=dca1(x+3,y+6);
p(4)=dca1(x+4,y+5);
p(5)=dca1(x+5,y+4);
p(6)=dca1(x+6,y+3);
p(7)=dca1(x+7,y+2);
p(8)=dca1(x+8,y+1);
if corr2(p,k1)>corr2(p,k2)%以下为解码过程,分彩色和灰度图像,还原水印图样
if mysize>2
mark1(i,j)=0;
else
mark1(i,j)=1;
end
else
if mysize>2
mark1(i,j)=1;
else
mark1(i,j)=0;
end
end
end
end
模拟图像攻击的实现
白噪声、椒盐噪声、裁剪、旋转、压缩等是常见的图像处理和加密攻击手段,可以导致图像失真、信息丢失、降低图像质量等问题。因此,在进行图像处理和传输时,需要对图像进行加密和鲁棒性处理,以提高图像的安全性和可靠性。这里代码比较简单便不再阐述。
运行结果展示
说明:
部分程序是结合开源工程改进而成,加密算法或者嵌入位置可以按照自己的思路修改,但基本实现思路是一样的。