基于DCT离散余弦变换的自适应水印算法的设计

前言

有关基于DCT离散余弦变换的自适应水印算法的设计与实现,代码均为原创,需要对于DCT变换有一定的基础,自适应的思想主要体现在每个处理的像素块中隐藏水印的位置是不同的,能够自动选取合适的位置进行隐藏,本文是信息隐藏技术大作业报告,部分相关知识可能存在赘述,大家可以挑重点看,希望能够抛砖引玉,给大家带来一点启发。

究竟是怎样的终点,才配得上这一路的颠沛流离

一、目的和需求分析

1.1项目设计目的

当今社会经济的快速变革,互联网技术的飞跃进步,信息时代的到来,以及计算机网络技术、多媒体信息技术及相关学科的迅猛发展,数字图像、数字音频、数字视频等数字式作品藉此得到广泛传播,并愈渐融入日常生活。

实际生活中,数字式作品无处不在,其安全保护问题引起广泛关注。在未获得拥有者许可的情况下,数字产品使用者可能会对作品信息进行有意或无意地篡改、复制及传播等,一定程度上使得作品信息的安全受到威胁,其可靠性也就不可避免地随之减弱。因此,对数字多媒体信息传播的安全保护、拥有者合法版权权益的合理保证和作品信息的安全性及可靠性的有效维护等,已经发展变成学术界和产业界急待处理的紧要信息安全问题。

本项目旨在结合上课所学知识,在深入理解水印嵌入和提取原理的基础上,设计出一种自适应的图像水印算法,在保证载体图像的视觉质量的情况下,能够将水印信息嵌入到载体图像中,并能够在一定程度上抵抗水印攻击,同时能够判断需鉴别的图像中是否含有水印信息,为数字图像的版权归属问题提供了一种新的解决方案。

1.2项目需求分析

根据设计目的和实现目标,我所设计水印算法应该能够满足如下功能:
1.能够对原始图像进行预处理并转换成灰度图像。
2.能够将水印数据的完整地嵌入载体图像并提取。
3.水印算法必须含有自适应的思想,能够根据载体图像自适应选择水印数据的嵌入位置。
4.水印需要能够在一定程度上抵抗常见的水印攻击方式。
5.能够通过计算水印图像的相似性判断水印的归属者。

二、图像预处理

2.1 图像预处理的作用

由于原始图像为二进制的黑白图像,如果直接将原始图像当作水印图像进行嵌入,不仅水印图像的安全性会降低,其鲁棒性也会因为嵌入的是二进制黑白图像而降低。而如果原始图像为彩色图像,直接提取彩色图像中各像素点的RGB信息将会使得需要嵌入的水印数据过于冗杂,对载体图像大小的要求则会更高。

为了增强水印图像抵抗攻击的鲁棒性和提高系统的安全性并兼顾嵌入水印的数据量,我采用了依次采用了Logistic混沌映射置乱、细胞自动机处理和均值滤波平滑处理,最终将原始的姓名、学号图像转换成为了灰度图像,将灰度图像的每个像素点的灰度值转换为二进制数据进行嵌入,这样在提取到错误的比特信息时,只会改变提取图像的灰度值,在一定程度上提高了水印的鲁棒性和安全性。

2.2 Logistic混沌映射置乱

Logistic 映射是简单非线性的一维离散迭代映射,实现起来较为简单,成为数字混沌系统中使用最为广泛的混沌映射之一。Logistic函数是源于一个人口统计的动力学系统,其系统方程形式如下:
在这里插入图片描述
其中 为分岔参数,当分岔参数从大约3.56995变化到4时,映射进入混沌状态,不同分岔参数条件下计算得到的方程值:
在这里插入图片描述
从图中可以看出,当分岔参数取得特定值的情况下Logistic 映射将进入混沌状态,在具体的实现过程中,我利用了密钥参数构造一个混沌序列,将原始图像进行置乱,在密钥设计时我将我的学号进行拆分作为参数,得到了混沌系统初始条件,在计算混沌序列值时,若序列值小于或等于127,则将原始图像的像素置换,否则保持不变,具体的代码实现如下,置乱次数设定为3次:
在这里插入图片描述
对比原始图像和置乱后的图像如下:
在这里插入图片描述
通过对比可以看到,置乱后的图像已经不能直接看到原始图像的包含的姓名和学号信息,由于混沌系统对初始值和密钥十分敏感,当初始条件改变时,将不能得到完全一致的置乱图像。
将置乱算法逆着求解,在利用相同密钥的情况下即可将置乱图像恢复成原始图像,这里不再演示。

2.2 细胞自动机处理

细胞自动机(cellular automata)是为模拟包括自组织结构在内的复杂现象提供的一个强有力的方法,也称为元胞自动机(Cellular Automaton)。细胞自动机模型的基本思想是:自然界里许多复杂结构和过程,归根到底只是由大量基本组成单元的简单相互作用所引起。细胞自动机主要研究由小的计算机或部件,按邻域连接方式连接成较大的、并行工作的计算机或部件的理论模型。它分为固定值型、周期型、混沌型以及复杂型。
在这一步中我采用了基于投票规则的细胞自动机对置乱图像进行处理,具体规则定义如下:
1.若该细胞处于边界,则不做处理。
2.若细胞不在边界上,则计算以当前细胞为中心的9宫格中灰度值为255的像素点个数,若灰度值为255的像素点个数大于或等于5,则当前细胞灰度值设定为255,否则当前细胞灰度值设定为0。
具体代码实现如下,细胞自动机处理次数设定为2次:
在这里插入图片描述
对比置乱图像和细胞自动机处理后的图像如下:
在这里插入图片描述

均值滤波平滑处理

图片平滑处理的主要目的是将黑白的二值图像转换为灰度图像,提高水印算法的鲁棒性,均值滤波、方框滤波、高斯滤波及中值滤波都是常用的图像平滑处理的方法,这里选用均值滤波的方式对图像进行平滑化处理。
均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标像素为中心的周围8个像素,构成一个滤波模板,即包括目标像素本身),再用模板中的全体像素的平均值来代替原来像素值,具体代码实现如下:
在这里插入图片描述
均值滤波平滑处理后的结果对比如下:
在这里插入图片描述
至此,图像预处理部分结束,最终将得到的灰度图像当成水印图像进行嵌入,展开水印算法的设计。

三、自适应水印算法设计

3.1 JPEG量化矩阵

在进行JPEG压缩时,会用到JPEG量化矩阵对原始图像像素块进行DCT变换后得到的DCT矩阵进行量化处理,通过JPEG量化矩阵能够将原始图像的像素数据进行量化,从而去除原始图像区域中不重要的数据,在基本不改变图像质量的情况下利用较小的数据保存图像。
为了更好的抵抗JPEG压缩,提高水印的鲁棒性,在我设计的水印算法中也引入了JPEG量化矩阵对DCT系数矩阵进行处理,这样可以使得水印算法能够更好的抵抗JPEG压缩攻击。
实际上JPEG量化矩阵有两个,分别是标准亮度量化矩阵和标准色差量化矩阵,而研究表明,相比于色差,人眼对于亮度的变化更加敏感,因此这里选用了JPEG标准亮度量化矩阵进行计算。标准亮度量化表和标准色差量化表定义如下:
在这里插入图片描述

3.2 DCT频率敏感度矩阵

DCT频率敏感度矩阵是考虑到人眼对8*8的色度DCT频率系数中的低频细节相较高频细节更敏感的现象而定义的矩阵,矩阵中不同位置的值表示每一块中在不存在任何掩蔽噪声的情况下,可被察觉的DCT系数的最小幅度,值越小就说明人眼对该频率越敏感。
在实现水印算法的过程中,由于需要通过修改像素块的DCT系数矩阵来隐藏水印数据,而通过指定的值来修改数据则显得不够灵活,容易造成水印鲁棒性降低或可见性降低。例如,对于含有较高能量中的低频区域,我们希望修改的值较小以提高水印的不可见性,而对于含有较低能量的高频区域,我们则希望修改的值较大以提高水印的鲁棒性,通过DCT敏感度矩阵则可以很好的解决这个问题。由于DCT频率敏感度表中定义了可被察觉的DCT系数的最小幅度,因此可以在DCT矩阵的对应位置上增加或减去DCT频率敏感度表对应位置值与加权因子的乘积来实现水印的嵌入,DCT频率敏感度矩阵定义如下:
在这里插入图片描述

3.3 自适应频带选择

对于DCT系数矩阵,我们知道它可以分为高频带、低频带和中频带,从水印不可见性的角度来看,高频带是水印隐藏区域的最佳选择,但是高频带的信息很容易被各种有损压缩去除,使得水印的鲁棒性难以达到要求。从水印的鲁棒性角度来看,低频带是水印信息的最佳隐藏区域,因为低频带的数据含有大量的能量,受到干扰时的改变较小,能够显著增强水印的鲁棒性,但是更改低频区的数据却容易使图像形变较大,使得水印的不可见性难以达到要求。因此在嵌入水印数据时常常选择中频区的水印进行嵌入水印数据。
而如何选取DCT矩阵中具体的点的位置进行修改呢?这里我采用了一种自适应频带选择的的方式进行实现,主要是通过将DCT系数矩阵除以JPEG量化矩阵,在得到的标志矩阵中结果不为0的位置进行水印数据的嵌入,这么做的依据是在图像受到JPEG有损压缩时,会依据JPEG量化矩阵对图像的像素值进行量化,标志矩阵中结果为0的部分往往会在JPEG压缩时被舍弃,而我通过在标志矩阵中结果不为0的位置嵌入水印信息,且在嵌入水印时,我通过DCT频率敏感度矩阵上对应位置值与加权因子的乘积改变DCT矩阵中对应位置的值,通过这种方法,可以自适应的选择每个DCT矩阵中的最佳水印嵌入位置和修改的量,而不需要通过指定的位置和指定修改量进行水印数据嵌入,这样做能够在一定程度上提高嵌入水印的鲁棒性。

3.4 水印算法定义

3.4.1 水印嵌入算法

我所设计的水印算法主要是通过DCT变换和自适应频带选择的方式来实现的,并且通过JPEG量化矩阵和DCT频率敏感度表来提高对于常见的JPEG压缩攻击的鲁棒性,且对于图像便于10%部分区域不嵌入水印数据,以提升水印抗裁剪攻击的能力,水印的嵌入算法定义如下:
1.首先将载体图像按照 8*8的大小进行分块。
2.跳过处于图像边缘10%部分的矩阵,计算其余每个分块的DCT系数矩阵。
3.将得到的DCT系数矩阵除以JPEG量化矩阵,得到一个标志矩阵。
4.遍历标志矩阵,若标志矩阵的某个点位置不为0,则在对应位置的DCT系数矩阵中嵌入水印数据,若需要嵌入的水印数据为1,则在DCT系数矩阵的对应位置加上DCT频率敏感度矩阵对应位置的值与加权因子的乘积,若需要嵌入的水印数据为0,则在DCT系数矩阵的对应位置减去DCT频率敏感度矩阵对应位置的值与加权因子的乘积。
5.继续处理下一个像素矩阵,直到所有的水印数据都被嵌入。
水印嵌入的流程图如下:
在这里插入图片描述水印嵌入算法的关键代码实现如下:
首先是JPEG量化矩阵和DCT频率敏感度矩阵的定义:
在这里插入图片描述
水印嵌入的主函数:
在这里插入图片描述

3.4.2 水印提取算法

水印的提取算法定义如下:
1.分别将原始的载体图像和含有水印的载体图像按照 8*8的大小进行分块。
2. 跳过处于图像边缘10%部分的矩阵,分别计算其余每个分块的DCT系数矩阵。
3.将原始的载体图像的DCT系数矩阵除以JPEG量化矩阵,得到嵌入水印位置的标志矩阵。
4.对于标志矩阵中每一个不为0的位置,比较原始的载体图像的DCT系数矩阵和含有水印的载体图像的DCT系数矩阵对应位置的大小,若含有水印的载体图像DCT矩阵对应位置大于原始的载体图像的DCT矩阵的对应位置,则提取水印数据为1,否则提取水印数据为0。
5.继续处理下一个像素矩阵,直到提取出全部的水印数据。
水印提取的流程图如下:
在这里插入图片描述
水印提取算法的关键代码定义如下:
在这里插入图片描述

四、水印算法性能评估

4.1 水印嵌入和提取的实现

首先打开项目的目录,准备好原始图片monster663.bmp和载体图像lena.bmp如下:
在这里插入图片描述
接下来运行 1图像预处理过程.py 代码如下:
在这里插入图片描述
在当前目录下将得到四个处理后的图像,分别是:
置乱后的图像: shuffleWM.bmp
细胞自动机处理后的图像: CellAutoImg.bmp
均值滤波平滑处理后的图像: BlurringImg.bmp
用置乱密钥得到的恢复图像: shuffleRecoverImg.bmp
最终得到的文件如下:
在这里插入图片描述
接下来将均值滤波平滑处理后得到的灰度图像作为水印图像嵌入载体,运行 2自适应水印算法的设计.py 如下:
在这里插入图片描述
得到的原始载体图像和含有水印的载体图像的对比如下:
在这里插入图片描述
可以看到程序计算出两张图像的相关系数约为0.9988,可以判定两张图像的相关性极高,且无肉眼可见的差异。
嵌入的水印图像和提取的水印图像的对比如下:
在这里插入图片描述
嵌入水印图像与提取的水印图像相关系数约为0.9999,且提取的误码率为0,即两张图像完全一致,算法实现了水印图像的嵌入和提取。
最终得到的目录如下:
在这里插入图片描述

4.2 水印攻击和性能评估

这里水印攻击的实现主要通过StirMark软件来实现,我分别选取了五种典型的水印攻击方式,分别是JPEG压缩攻击、随机噪声攻击、裁剪攻击、旋转裁剪攻击以及行移除攻击,并分别计算了每种攻击方式的不同参数下得到的水印数据的误码率以及和原始水印图像的相似性。
在实现时只需要将含有水印的载体图像放到StirMark软件中的特定目录下,即.\StirMarkBenchmark\Media\Input\Images\Set1,通过在SMBsettings.ini配置文件中设定相应的参数,即可实现选定的攻击方式。
调整每种攻击的参数,使得每种攻击各生成10张攻击图像,共生成了50张攻击图像,运行攻击程序如下:
在这里插入图片描述
得到攻击后的图像如下:
在这里插入图片描述
此时运行3水印性能评估.py 批量提取水印图像如下:
在这里插入图片描述
可以看到对于提取的每个水印图像都计算了提取水印的误码率和与原始水印图像的相关系数,如何判定载体中是否含有水印信息呢?这里我采用了相关系数这样一个度量值,将提取的水印图片与原始水印图片转换成灰度值矩阵,计算两个矩阵之间的相关系数,相关系数的范围属于[-1,1],当相关系数为-1时表示两张图片具有负相关性,当相关系数为1时表示两图片具有正相关性,当相关系数接近与0时表示两图片几乎没有相关性。
在利用相关系数判定载体图像是否含有水印信息时,我采用了如下规则:
1.当相关系数大于0.5时,我们就认为检测到了水印信息,水印算法可以抵抗该攻击。
2.当相关系数在0.3~0.5时,则认为可能含有水印信息,水印算法仅能一定程度上抵抗该攻击。
3.当相关系数小于0.3时,则认为无法提取水印信息,水印算法完全不能抵抗该攻击。

4.2.1 JPEG压缩攻击

JPEG压缩攻击的参数配置如下:
在这里插入图片描述

这里首先需要解释一下压缩比例的问题,这里的压缩比例指的是压缩后的图片质量为原图的百分之多少,例如压缩率为10%时,压缩后的图像仅含有原图10%的数据,因而会造成图片失真,从实际的对比结果也可以看出压缩比例为10%时明显比压缩比例为100%时模糊。
在实际测试中为了保证攻击后的图像不影响视觉质量,这里采用的JPEG压缩参数为从80%至98%,间隔为2%,共生成了十张攻击后的图像,压缩质量为80%与未受攻击的水印图像的对比如下:
在这里插入图片描述
可以看到经过压缩质量为80%的图像与未受攻击的载体图像没有明显差异,两图像的相关系数为0.9957。压缩质量为90%的载体图像提取出的水印与原始水印图片的对比如下,两图像的相关系数约为0.67:
在这里插入图片描述
不同压缩质量的误码率以及提取水印图像与原始水印图像的相关系数如下:
在这里插入图片描述
根据上表数据绘制的折线图如下:

在这里插入图片描述
从图中可以看到压缩质量大于88%时,相关系数可以大于0.5,也就证明了载体图像中存在并检测到了相应的水印信息。
结论:该水印算法能够在一定程度上抵抗JPEG压缩攻击,当JPEG压缩质量大于90%时,算法能够根据相关性判定载体图像中含有原始的水印信息,当压缩质量小于86%时,算法不能判定载体图像中是否含有水印信息。

4.2.2 随机噪声攻击

随机噪声攻击的参数配置如下:
在这里插入图片描述
随机噪声比例从1%至10%,间隔为1%,共生成十张攻击图像。
这里的随机噪声失真模拟的时图片在传输中的失真情况,随机噪声率为10%则表示图像有10%的数据损失,随机噪声率为100%时则表示图片数据完全失真,10%噪声与未受攻击的载体图像的对比图如下:
在这里插入图片描述
可以看到随机噪声的攻击效果明显,具有肉眼可见的差异,两图像的相关系数为约为0.7384。分别从两图像中提取的水印图像如下,水印图像的相关系数约为0.3899:
在这里插入图片描述
不同随机噪声比例下的提取的水印图像的误码率以及提取水印图像和原始水印图像的相关系数如下:
在这里插入图片描述
根据上表数据绘制的折线图如下:
在这里插入图片描述
从上图中可以看到,随机噪声比例越大时,提取水印的误码率越接近0.5(0.5即表示完全不能提取水印信息,因为随机提取水印误码率也为0.5),提取水印图像与原始水印图像的相关性越低。
结论:该水印算法能够在一定程度上随机噪声攻击,随机噪声比例小于4%时,算法能够根据相关性判定载体图像中含有原始的水印信息,当随机噪声比例大于6%时,算法不能判定载体图像中是否含有水印信息。

4.2.3 裁剪攻击

裁剪攻击的参数配置如下:
在这里插入图片描述
这里的裁剪攻击主要是从图像右下角开始裁剪后保留的图像占原始图像的比例,参数选择从80%至98%,间距为2%,共生成了十张攻击后的图像,裁剪80%与原始图像的对比如下:
在这里插入图片描述
可以看到图像被裁剪后变换比较明显,对比从保留面积90%提取出的水印图像和原始水印图像如下,两图像的相关系数约为0.7564:
在这里插入图片描述
不同参数下提取水印图像得误码率和相关系数如下:
在这里插入图片描述
根据上表数据绘制的折线图如下:
在这里插入图片描述
从上图中可以看到,当保留面积大于90%时,相关系数均大于0.5,即检测到了水印信息,这是由于在设计水印算法时,图像边缘10%的区域没有嵌入水印数据,从而提高了水印的鲁棒性和抗裁剪攻击的能力,而在保留面积小于90%以后,相关系数发生突变,误码率也迅速提高至接近0.5,这是由于裁剪攻击破坏了隐藏水印部分区域的数据,使得原本的矩阵与提取时的矩阵没有对齐,发生了错位的情况,使得提取的水印数据大量出错。
结论:该水印算法能够在一定程度上抵抗裁剪攻击,保留面积大于90%时,算法能够根据相关性判定载体图像中含有原始的水印信息,当保留面积小于90%时,算法不能判定载体图像中是否含有水印信息。

4.2.4 旋转裁剪攻击

旋转裁剪攻击的参数配置如下:
在这里插入图片描述旋转裁剪攻击是将图像按照一定的角度进行旋转,并将旋转后不属于原本矩形区域的图像进行裁剪,为了更好的比较,这里选用的角度均为正数,即顺时针旋转的角度,旋转范围从0.02度至0.2度,间隔为0.2,共生成了十张攻击图像,旋转角度为0.2与原始载体图像的对比如下,旋转裁剪后图像大小发生了变化,两图像的相关系数约为0.9658:
在这里插入图片描述
对比旋转角度为0.1时从载体图像中提取的水印图像和原始的水印图像如下,两图像的相关系数为0.9099:
在这里插入图片描述
不同旋转角度下提取水印数据的误码率以及提取水印图像和原始水印图像的相关系数如下:
在这里插入图片描述
根据上表数据绘制的折线图如下:
在这里插入图片描述
由上面的结果可以看到,旋转角度在0.1度时图像发生了突变,当旋转角度小于0.1时,提取水印的误码率接近于0,相关系数高于0.8,具有强相关性,而当旋转角度大于0.1时,误码率接近0.5,相关系数接近0,图像不具有相关性。原因可能是当旋转角度大于0.1时,原本嵌入水印的像素块与提取水印的像素块发生了严重的偏移和错位,使得水印提取完全错误。
结论:该水印算法能够在一定程度上抵抗旋转裁剪攻击,当旋转角度小于0.1度时,水印算法能够完全抵抗旋转裁剪攻击,而当旋转角度大于0.1度时,水印算法完全不能抵抗旋转裁剪攻击。

4.2.5 行列移除攻击

行列移除攻击的参数配置如下:
在这里插入图片描述
这里的参数指的是移除行和列之后保留的比例,攻击后载体图像的大小会发生改变,例如参数为80%时的载体图像移除了20%的行和列,攻击参数约小,则表明攻击强度约大,且这里的移除并非随意的移除,而是在尽量保证图像质量的前提下进行的移除。攻击参数从80%至98%,间隔为2%,共生成了十张攻击图像,保留行比例为80%时与原始载体图像的对比如下,两图像的相关系数约为0.05085:
在这里插入图片描述
可以看到,受攻击后的图像的视觉质量得以保留,但是仔细观察不难发现受攻击后的载体图像比原始图像要小,且这种大小变化并不是通过缩放导致的,而是去除了图像中的某些行和列。保留行列比例为90%时提取的水印图像与原始水印图像的对比如下,两图像的相关系数约为-0.0053:

不同攻击参数下提取的水印数据的误码率和提取的水印图像与原始图像的相关系数如下:
在这里插入图片描述
根据上表数据绘制的折线图如下:
在这里插入图片描述
从上图中可以看到,保留行列比例从80%至98%的区间内,提取水印数据的误码率一直处于0.5左右,提取水印图像与原始水印图像的相关系数维持在0左右,说明提取水印图像和原始水印图像完全不相关,提取水印数据均失败。原因可能是移除行列后,使得原本嵌入水印的矩形区域发生了偏移和错位,由于原本是按照自适应的位置嵌入的水印信息,错位以后将不能够从正确的位置提取到水印数据,虽然为了抵抗裁剪攻击使得边缘10%的区域都没有嵌入水印数据,但是由于裁剪区域可能处于中心位置或附近,仍然会使得水印数据区域偏移严重,不能提取出正确的水印数据。
结论:该算法难以抵抗行列移除攻击,当保留行列比例小于98%时,算法将不能从载体图像中提取出正确的水印信息,无法判定载体图像中是否含有水印。

网盘资源&githb

所有代码文件和资源将在下一步开源~

后记

在本次实验探究过程中,我构思了两种自适应的水印算法,分别是由DCT矩阵中两个位置的数据交换来隐藏二进制水印数据想到的自适应DCT矩阵中交换位置的选择算法,另一个则是本次大作业实现的通过JPEG压缩矩阵和DCT敏感度系数矩阵的DCT频带自适应水印算法,在比较了两种的实际测试结果后,我发现后一种算法由于对于JPEG压缩攻击做了优化,使得抵抗JPEG压缩攻击的效果具有明显提高,于是选用了后一种算法作为大作业中实现的算法,并通过查阅相关资料完成了水印的嵌入和提取代码的设计。
在水印性能的评估中,为了提高水印算法抗裁剪攻击的能力,我将水印数据嵌入在图像中心位置,即图像边10%的区域不嵌入水印数据,经过实践检验,这种方式能够在一定程度上抵抗裁剪攻击,但当裁剪的面积大于10%时,水印算法将不能很好的提取出正确的水印数据,同时让我比较意外是这种水印算法几乎完全不能够抵抗行列移除攻击,当移除行列数据后,提取水印的相关基本和图像裁剪面积大于10%的效果一致,这也让我发现了这种算法的特性是需要将原始水印嵌入的区块矩阵与待提取水印图像的区块矩阵对齐,若没有对齐的话将会导致对应区块发生错位和偏移,使得水印提取失败。

注:本次实验保证中相关原理解释部分的图像均来自于网络中的各优秀博文,源代码将在下一步进行开源,若对实验过程或代码有不理解的欢迎留言评论~

猜你喜欢

转载自blog.csdn.net/monster663/article/details/125476531