因为最近帮老师做一些,有关数字水印的东西,在这里我想记录一下,自己在这次帮老师做数字水印过程中的一些小小心得。
在这个项目中,我们做的是基于DCT变换的数字水印,语言方面用的 java 来实现,当中还用到了,JAVACV来处理图形。
下面我来说说,我们是如何准备这次数字水印的项目。
第一天,老师先叫我们,看看数字水印的相关论文,然后在网上找代码,在下周二的时候集中讨论,讲讲你找的数字水印算法,是如何实现的,它的基本原理是什么?
那天我就开始找算法,发现网上很多都是,用 matlab 或者 C++ 来实现的,由于本人matlab 不会,再加上呢? 学 C++的时候学的都是一些皮毛,所以我不是特别想找用 c++ 来实现的代码,然后我就一直找,终于在找了很久的情况下,我终于找到了,一个用 java 实现的数字水印代码,然后直接将其copy下来,运行一下,可以成功,感觉不错,然后我就开始了,漫长的 “考古”之旅,因为本人java的相关知识在那个时候,还在努力学习当中,说以当时那个 java 算法中 有些东西是我第一次接触,不是特别懂,比如 BufferedImage 等相关用法不是特别懂,还有对于 图片 的一些性质也不是特别懂,经过几天的查找资料,然后终于,把这个算法看懂了, 在这里我来说说,我第一个找到的,用java写的数字水印算法,的实现过程,第一步,我们在这里设置一个常数 d = 10,然后我们在将一个图片得到一个 8 * 8的小块,在把这个图片的RGB三个通道中的B通道提取出来,然后在进DCT变换,那个算法中,选择了,5个点作为改变DCT系数的点,在这里我在补充一下,那个算法选的是 嵌入 32 32的二值图片(二值图片就是用0或1表示的像素点),如果我们嵌入的 是 0 ,那么我们就将这 5个点的DCT系数 分别增加 常数d,如果我们嵌入的是 1,那么我们就将这 5个点的DCT系数 分别减少 常数d,然后这8 * 8的小块嵌入完0或1后,我们在做IDCT变换,改变88小块的像素值, 那么我在说说这个算法的提取水印的过程,这个算法是一个非盲水印,(虽然这个算法是一个非盲水印,但它却给我带来接下来帮老师做真正做数字水印的机会),提取过程大致是,用嵌入后的图对应点的DCT系数与原图对应点DCT系数的比较大小,统计这选中5个点中,大于的个数假设是m,小于的个数假设是n,如果 m > n那么提取的数字水印信息是1,反之是0。
我找的第一个用java实现的非盲数字水印算法
然后,到了下周二,老师过来询问我们找数字水印算法的三个人的进展,可能当时,我对我的这个算法理解的比较透彻吧,(就有了老师叫我跟我们专业另一个人合伙写数字水印的机会),当老师得知是非盲水印时,我有开始了寻找盲水印的java实现代码,然后找了一天,终于找到了,一个用java写的非盲水印,当时我很激动,以为自己成功找到了,老师想要的代码,可是没想到,那只是刚刚开始,在这个算法当中,我又接触到了,我重来没有见过和使用过的东西,openCV(在那个算法中用的是openCV中对java开放的接口,简称:javaCV)。然后我有开始了漫长的 “考古”之旅,而这次“考古”也是巨艰难,先是openCV是第一次使用,然后我就将第二个java代码,逐句逐句的百度,用了几个晚上的时间,才看懂一些,openCV的常用用法,本来有些东西想进一步了解的,发现看不了源码,而且马上又要到和老师一起讨论进展的时候了,所以那个时候我很慌,就在星期五的那天晚上,那个时候我记得我还在跟室友一起打卢克,然后老师一个电话说,有事找我一下,于是被逼无奈,我只好挂机了,老师找我们说有一个项目,需要做一个数字水印的系统,然后叫我跟另一个人一起合作,做一个出来,当时我还是满激动的,毕竟是第一次遇见这种事,就答应了,第二天我就拿出来了,我找到的第二个用java实现的盲数字水印算法给那个人看,他觉得不错,然后我也觉得不错,然后我们将那个代码稍稍的改了一下,发现容量扩大了,更不错了,因为我下午跟我同学,一起要去看复联4于是我就提前走了,然后他就一个人,留在那里等老师,过来检查结果,但是老师不是特别满意,勉强能够接受,于是我们开始做,压缩,亮度变换,对比度变换,饱和度变换,缩放攻击,下提取水印信息的情况,一做攻击测试,发现这算法不行,感觉那个时候惊了,于是把这个测试结果告诉了老师,发现老师叫我们继续找代码,或者看论文。然后我们开始找网上现成的代码,发现找不到了,于是我们决定自己写算法,然后我跟那个同学一起看起了论文,那个时候头都大,然后第二天,老师跟我们讨论,看的论文情况,然后我们找到了一篇论文,那个时候,我们看了下那个论文的在各种攻击的情况下,鲁棒性都很不错,于是,我们开始了,自己写数字水印的算法,那天晚上,将那个算法写出来了,但我发现有bug,于是第二天开始调试代码,调试成功后,我们在将代码,给老师看,老师看来之后提了几个问题,然后我们又将这个代码进行了修改,使嵌入后的图片效果更好,然后我们再在网上找了个可以个可以在线压缩图片的网站进行压缩测试发现效果很好,但那个时候也遇到了一个问题我们写的算法只能处理图片格式是bmp或者png的无法处理jpg,当时也不是特别注意,但就是这个问题使我们花费了巨大的代价,然后给老师看,老师还是比较满意的,于是叫我们开始写界面和准备攻击测试,然而就是刚刚提到的那个问题,使我们在找压缩代码的时候发现,找不到压缩png格式的代码,或者找到将bmp压缩成jpg的,但就是提不出来。还是那个同学比较给力,那天他给我看来一篇,有关jpeg压缩的原理,发现压缩用的是YCbCr这种,提取Y的通道,而我们一直用的都是RGB中的B通道去提取信息,然后我们就明白了,于是我们就用Y通道去嵌入水印信息,然后当天晚上加上第二天早上,我们将代码重新修改了一下, 发现可以提取压缩后的图片的水印信息,当时感觉很爽,那时没有做其他攻击测试,然而,那天网上,当我们做其他测试的时候惊了,发现抵抗不了其他攻击,于是又开始修改代码,然后我的那个同学,他提到了一个非常重要的一点,然后我们修改后,发现能够抵抗,压缩,亮度变换,对比度变换,饱和度变换,缩放攻击,这些攻击,然后第二天我又去找了一些非常好的点,和嵌入强度,进行攻击测试,都不错,与写好UI,去给老师看,老师很满意,唯一不好的是,老师希望我能把这个界面重新优化一下,我想行吧。于是开始了我的优化之旅。
下面我来说说,这次数字水印的一些心得(可能也不是特别好,但我想把我这次经历的一些东西记录下来,万一将来,在工作中需要用到数字水印的一些东西,那我岂不是爽歪歪):
1,将图片分成块,从而形成 8* 8 的像素块比较好。因为JPEG压缩也是用的是8 * 8的像素块来进行的。
2,当我们提取一张图片的某个通道的像素值形成的二维矩阵,然后将其进行DCT变换。在这里我们假设 像数值 a 对应点的DCT系数是 b,如果我们将 b = b + 750;然后在将其进行IDCT变换,然后改变了的DCT系数对应点的 像素值 其实和原来相比 变化程度不大。
3,改变DCT系数时,我们需要提取通道,如果你想让你的算法,抗压缩的能力强的话,可以看看这篇文章,有关JPEG压缩的秘密,通过这篇文章我们可以发现一个特点,JPEG压缩的本质是同过,YCbCr中的Y通道来实现压缩的,所以要想抗压缩的能力更强一点,所以我建议大家使用YCbCr中的Y通道,通过改变DCT系数的方式来达到嵌入水印信息的目的。
4,最重要的一点是,如何表示嵌入信息,通过修改DCT系数,那么又是如何修改DCT系数的呢?我们可选择两个点,那么我们要怎么去选择两个点,去修改它们的DCT系数,我们可以通过这样的方式去寻找点
和JPEG量化系数表:
然后我们选择两个合适点,比较接近,而且JPEG量化系数差距不大,作为修改DCT系数的两个点,接下来说说,这样修改点,我们的做法是,我们在先假设两个点 a点 和 b点,如果我们嵌入的数字是1,那么我们 就将a点的DCT系数变为p(p表示嵌入强度),b点的DCT系数变为0,如果我们嵌入的数字是0,那么我们 就将a点的DCT系数变为0,b点的DCT系数变为p。
那么怎样表示提取呢? 将嵌入后的图片先分成8*8的像素块,然后进行DCT变换,找到我们修改DCT系数的a ,b两点,如果 a的DCT系数 > b的DCT系数,那么嵌入的信息表示1,反之表示0。而且p越大,鲁棒性越强,但是也越影响图片的质量。所以我们选择点的时候,要慎重考虑、。
5,为什么,我们可以抵抗,亮度变换,对比度变换,饱和度变换,这些攻击都是通过,改变R,G,B通道的值从而,来进行变换的,而Y通道的值是可以通过R,G,B的值计算得到,而我们选择相似的两个点,他们的R,G,B的值不会相差太大,所以经过这些变换后,他们两个点的大小关系,也不容易,发生变换。
6,缩放攻击,会舍弃高频位置上的点,所以我们选择点时,应该选择,比较靠前的两个点。
总之:改变YCbCr中的Y通道的DCT系数来表示嵌入信息,选择两个比较相近的点,然后在改变这两个点的DCT系数,而且这两个点比较靠前(用于抵抗缩放),通过两个点的大小关系来表示嵌入的信息。
来源:CSDN
作者:P h o n i e x
链接:https://blog.csdn.net/qq_40935723/article/details/90272521