5 分钟跑通 blind_watermark 盲水印:3 条命令嵌入,提取不用原图
【免费下载链接】blind_watermarkBlind&Invisible Watermark ,图片盲水印,提取水印无须原图!项目地址: https://gitcode.com/GitHub_Trending/bl/blind_watermark
上周一个做插画的朋友跟我吐槽:他发在网上的一张图,被某电商直接拿去当商品详情页,署名也被抹掉了。他想去理论,对方一句"一张图而已,你怎么证明是你拍的"就把他噎住了。这事让我意识到,证据其实可以就藏在图片本身里——如果当初就嵌入一条盲水印,现在直接提取出来就是证据。我由此开始找图片盲水印工具,试了几个之后,blind_watermark 这个开源项目用得最顺手,这里把它整理出来。
它凭什么值得挑一个用
不少水印方案有个要命的短板:提取水印时要拿原图去比对。可图片一旦流出去,你手里只有被裁剪、截图、压缩过的版本,根本找不回原图,"依赖原图"的方案基本等于白做。
blind_watermark 把这个关系反过来了:提取水印无须原图。只需要拿到手的这张图,加上嵌入时用的同一个口令,就能把藏进去的信息恢复出来。算法基于 DWT-DCT-SVD,在频域上动手脚,核心逻辑都在 bwm_core.py 里。这些数学细节你完全可以不管,调接口就行。
5 分钟跑通盲水印嵌入与提取
先装:
pip install blind-watermark仓库自带示例图片,终端里两条命令就能走完嵌入和提取全流程(命令行入口是 cli_tools.py):
# 第一条:嵌入水印 blind_watermark --embed --pwd 1234 examples/pic/ori_img.jpeg "watermark text" examples/output/embedded.png # 第二条:提取水印,不需要原图 blind_watermark --extract --pwd 1234 --wm_shape 111 examples/output/embedded.png有两个细节值得记下来。一是--pwd口令:嵌入和提取必须一致,对不上提出来就是一串乱码。二是--wm_shape:它告诉程序水印有多长,文本水印就是比特数,嵌入时程序会打印出来,或者用len(bwm.wm_bit)顺手取到。
用 Python 写也差不多,最小版本长这样:
from blind_watermark import WaterMark bwm = WaterMark(password_img=1, password_wm=1) bwm.read_img('examples/pic/ori_img.jpeg') bwm.read_wm('@yourname', mode='str') bwm.embed('output/embedded.png')bwm1 = WaterMark(password_img=1, password_wm=1) wm = bwm1.extract('output/embedded.png', wm_shape=len(bwm.wm_bit), mode='str') print(wm) # @yourname跑完把两张图放在一起对比——肉眼看不出差别,这才是盲水印该有的样子:
| 原图 | 嵌入盲水印后 |
|---|---|
藏什么:按使用场景选模式
它支持三种嵌入方式,各管各的活,按自己的场景挑就行。
个人作品署名的,选文本模式
最常见的需求就是把名字、账号或者一句话留在图里。mode='str'直接传字符串,一条命令搞定:
blind_watermark --embed --pwd 1234 your.jpg "© YourName" out.jpg短文案完全够用,提取也最省事,适合摄影师、博客作者这类给个人作品署名的场景。
要嵌 Logo 或二维码的,选图片模式
品牌方想埋的往往是一个小 Logo 或者二维码图片。这时水印就按整张图处理,read_wm直接给水印图路径,不用传 mode;提取时要额外告诉它水印的高宽,以及把结果存到哪:
bwm.read_wm('logo.png') bwm.embed('out.jpg') # 提取时 wm_shape 是 logo 的 (高, 宽) bwm1.extract('out.jpg', wm_shape=(64, 64), out_wm_name='extracted.png')完整可跑的版本在 example_img.py。
藏流水号、数字指纹的,选二进制模式
开发者还有另一类玩法:给每张图绑定一个流水号、订单号或指纹位串,将来图片外泄了,能查出来是哪一批、哪个渠道出去的。mode='bit'就是一串 0/1:
bwm.read_wm([True, False, True, False] * 50, mode='bit') bwm.embed('out.jpg')提取回来是一组浮点数,按 0.5 划阈值就能还原成 0/1。能编码成比特的东西都能塞进去,灵活性最高。
三种模式的完整示例都在 examples/ 目录下,每个模式一份脚本,照抄就能跑。
旋转、裁剪、遮挡之后还能捞回来吗
这才是盲水印好不好用的分水岭。图片在传播中免不了被缩放、被裁、被截图,水印如果一次处理就失效,那就只是装饰。项目示例里真的跑了一轮攻击测试,效果如下:
| 攻击 | 攻击后的图 | 从攻击后的图里提取的水印 |
|---|---|---|
| 旋转 45° | ||
| 60 处随机遮挡 | ||
| 缩放到 400×300 |
三次的提取结果都和嵌入时完全一致。实践上还有两点经验:
- 旋转、缩放这类攻击,提取前通常先做一次"反向操作"(转回来、拉回原分辨率),命中率更高,att.py 里有现成的工具函数。
- 截图和裁剪是最麻烦的,图变小了、位置也跑了。recover.py 能推断出裁剪参数、把图先还原回原始尺寸再提取,完整流程见 example_str.py。
需要提醒一句:这些测试图都是先压成 JPG 再处理的,已经比较贴近真实传播环境。但别指望百战百胜——图被切成一小块、再经过多轮重度压缩,任何方案都会更吃力。
一页选型速查
| 你要干什么 | 模式 | 水印内容 | 提取时要记住什么 |
|---|---|---|---|
| 署名、嵌联系方式 | str | 几个字到一句话 | 文本的比特长度 |
| 嵌 Logo、二维码 | img | 一张小图 | 图片高宽 + 输出文件名 |
| 流水号、指纹、自定义数据 | bit | 一串 0/1 | 比特个数 |
| 要扛旋转、裁剪、遮挡 | 上面任意 | 同上 | 相同口令;裁剪场景还要原图尺寸 |
想快速体验就从文本模式开始;要上线使用,建议先拿自己业务里真实的图片质量(压缩后的、缩略图尺寸的)跑一遍攻击示例,确认提取还稳不稳,再铺开。
就到这里
blind_watermark 体量小,个人装完敲几条命令就能用,开发场景接WaterMark这个类即可。细节可以翻 docs/ 里的文档,或者通读一遍 bwm_core.py,核心算法不长,读下来心里就有底了。
【免费下载链接】blind_watermarkBlind&Invisible Watermark ,图片盲水印,提取水印无须原图!项目地址: https://gitcode.com/GitHub_Trending/bl/blind_watermark
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考