fire-keeper / BlindWatermark

使用盲水印保护创作者的知识产权using invisible watermark to protect creator's intellectual property
GNU General Public License v3.0
1.29k stars 180 forks source link

盲水印

介绍

你还在为别人盗用你的图片却不承认而烦恼吗? 你还在为自己创作的图片被坏东西(视觉xx)拿去找别人索赔,版权还莫名其妙到了坏东西手里而烦恼吗?

为了解决这个问题,我创建了这个项目,并用python实现了它

什么是盲水印? 盲水印算法可以把你的水印嵌入到图片里面,而得到的图片在视觉上和原图几乎没有差别,但是可以通过算法和自己的密钥解出你的水印

盲水印相比普通水印有什么优势呢? 盲水印首先不会对影响你的图片观感,而且不像普通水印一样被裁剪,覆盖而失去作用。我的这个盲水印算法可以有效抵抗模糊,图片覆盖,椒盐噪声,亮度变化,裁剪带来的影响,甚至连截图也能提取出水印(要先用ps去除掉截图中和目标图片无关的部分, 并缩放会原本的大小)

todo list

大更新

条件

现在的问题

如果你不想因为当前本程序的不足之处而使得你对本程序有偏见, 请跳过这一部分

适用情况

如何使用

B站视频链接

恰饭警告 请关注我的B站账号,三连, 和star

使用git pull https://github.com/fire-keeper/BlindWatermark.git或者直接下载压缩包把项目拉到本地, 然后在项目目录下

命令行版

#嵌入
python bwm.py -k 4399 2333 32 -em -r pic/lena_grey.png -wm pic/wm.png -o out.png -s
#提取
python bwm.py -k 4399 2333 32 -ex -r out.png -wm pic/wm.png -ws 64 64 -o out_wm.png -s

参数介绍

"--key",'-k' 依次输入2个随机种子和除数(正数),除数可以是一个或者两个,之间用空格隔开.如(4399,2333,32)
'-em','--embed' 后不带参数,表征本次操作是嵌入水印
'-ex','--extract' 后不带参数,表征本次操作是提取水印
               以上两者要求必须有且只有一个
"--read",'-r'   "要嵌入或提取水印的图片的路径"
"--read_wm",'-wm'  要嵌入的水印的路径
"--wm_shape",'-ws' 要解出水印的形状
"--out_put",'-o'   图片的输出路径
"--show_ncc",'-s'  展示输出图片和原图的NC值(相似度)

'-bs','--block_shape' 设定分块大小,因为限定长宽相同,所以只需要传一个整数就行了,对于大图可以使用更大的数,如8,更大的形状使得对原图影响更小,而且运算时间减少,但对鲁棒性没有提高,注意太大会使得水印信息超过图片的承载能力
'-d','--dwt_deep',设定小波变换的次数,次数增加会提高鲁棒性,但会减少图片承载水印的能力,通常取1,2,3

在调节参数的时候主要调节除数,即--key的第3(第4)个参数, 在图片没有失真的前提下使得值最大

运行以下python命令

# python代码
#导入模块
from BlindWatermark import watermark
#嵌入

bwm1 = watermark(4399,2333,36,20)
#4399和2333是两个随机种子,36和20是用于嵌入算法的除数,理论上第一个除数要大于第二个,除数越大鲁棒性越强,但是除数越大,输出图片的失真越大,需要权衡后决定
#这两个随机种子最好对不同图片有不同的取值, 防止种子暴露而使得所有图片失去保护
#第二个除数可以不加,增加对水印鲁棒性没有明显的提升,但是会一定情况想影响输出图片的质量
bwm1.read_ori_img("pic/lena_grey.png")
#读取原图
bwm1.read_wm("pic/wm.png")
#读取水印
bwm1.embed('out.png')
#在原图中嵌入水印并输出到'out.png'
# 用NCC数值化判断输出图片与原图的相似度
from BlindWatermark import test_ncc

test_ncc('pic/lena_grey.png','out.png')
#判断这两种图片的相似度, 输出为0~1,数值越接近1表示二者越相似
#提取

bwm1 = watermark(4399,2333,36,20,wm_shape=(64,64))
#用之前嵌入水印的参数,实例化对象,注意需要设定水印的长宽
bwm1.extract("out.png","out_wm.png")   
#注意需要在输出的水印的同级目录下创建 Y_U_V/ 文件夹, 否则单通道提取出来的水印不会被保存

支援恰饭

Alipaysetu

效果展示

要嵌入水印的原图lena_grey.png和水印图片wm.png

lena watermark

嵌入后的图片

嵌入水印后的图片

提取出的图片

提取出的图片

各种攻击以及提取出的水印

攻击方式 攻击后的图片 提取出的水印
模糊 blur_lena.png blur_wm.png
用图像覆盖 cover_lena.png
用线条覆盖 randline_lena.png
亮度调高10% brighter10_lena.png
亮度调低10% darker10_lena.png
添加椒盐噪声 saltnoise_lena.png
裁剪5%并填充
裁剪10%
裁剪30%

针对jpeg压缩, 经检验单独对Y通道解水印效果最好,以下解出的水印均来自Y通道

压缩因子 压缩后的图片 提取出的水印
90
85
80
70
60
50
40

水印防破解

如果有不良商家要破坏我们的水印再加上他的水印时, 如果他知道了我们的加密方式(不知道我们的随机种子和除数)时, 破解影响应该是最大的, 针对这种情况作出演示

现在网络上有两种图片A,B. A是我们嵌入水印后发表出去的, B是破解者在A上用相同的添加盲水印方式添加了自己的水印生成的. 然而我们使用我们的参数(随机种子和除数)可以从A,B中提取出我们的水印, 但是用破解者的参数进行提取时,不能从A中提取出破解者的水印,,只能从B中提取出破解者的水印

这便能说明这张图的创作者究竟是谁, 我认为这对保护创作者的权益是至关重要的一步

破解者的水印

介绍 图片 提取出的水印
我们嵌入水印的图片A
破解者在上面这种我们已经嵌入水印的图中再次嵌入水印的图片B
用我们的参数提取破解者的图片B
用破解者的参数提取我们的图片A