图片盲水印实战:文字、图片、比特三种模式怎么选
【免费下载链接】blind_watermarkBlind&Invisible Watermark ,图片盲水印,提取水印无须原图!项目地址: https://gitcode.com/GitHub_Trending/bl/blind_watermark
blind_watermark 是一个图片盲水印工具:能把文字、整张图片或任意比特数据写进照片,嵌入的内容肉眼不可见。更重要的是提取时不需要原图——拿着打了水印的图,加上密码和水印长度,就能把水印取出来。底层算法是 DWT-DCT-SVD,核心实现在 bwm_core.py。pip install blind-watermark装好之后,直接用命令行工具就能跑,不用写代码。
嵌入一行文字:最常用的版权声明用法
文字模式(mode='str')是多数人最先需要的:把署名、版权声明、联系方式嵌进图片,整个流程就是"嵌入 → 记长度 → 提取"。
一次性任务用命令行最省事。下面这条命令会把 "watermark text" 写进示例图,存成一张新的 PNG:
blind_watermark --embed --pwd 1234 examples/pic/ori_img.jpeg \ "watermark text" examples/output/embedded.png嵌入时留意两件事:密码(--pwd)和打印出来的水印比特长度,提取时两者都要用。接着这条命令就能把水印原样提出来:
blind_watermark --extract --pwd 1234 --wm_shape 111 examples/output/embedded.png在项目里做批量嵌入时,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('copyright 2026', 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')把整张 Logo 图片藏进照片里
要嵌的不是文字、而是一张二维图形——比如品牌 Logo 或插画小图——就用 img 模式。水印源是一张灰度图,程序按灰度 128 二值化:128 以下的像素统一变黑,以上变白,只保留图案、丢掉渐变,所以水印图最好是边缘清晰的图形。
嵌入代码和文字模式只差一行,读水印时不用传 mode:
bwm = WaterMark(password_wm=1, password_img=1) bwm.read_img('examples/pic/ori_img.jpeg') bwm.read_wm('examples/pic/watermark.png') bwm.embed('output/embedded.png')提取时要告诉它水印图的尺寸,并把结果直接存成一张黑白图片:
import cv2 wm_shape = cv2.imread('examples/pic/watermark.png', flags=cv2.IMREAD_GRAYSCALE).shape bwm1 = WaterMark(password_wm=1, password_img=1) bwm1.extract('output/embedded.png', wm_shape=wm_shape, out_wm_name='output/wm_extracted.png')这个模式的容量优势明显:一张 64×64 的水印图就是 4096 个比特,比一行文字多一个量级以上。完整流程见 example_img.py。
只嵌几个比特:写给程序读的标记
bit 模式最灵活:直接传一个布尔数组,比如用 10 比特当资产编号或 A/B 版本标记。10 比特只是演示长度,想换上百个比特也只是改数组的事。
wm = [True, False, True, False, True, False, True, False, True, False] bwm.read_wm(wm, mode='bit') bwm.embed('output/embedded.png')提取时有一个坑:返回值是浮点数组而不是布尔数组,要自己设阈值换算(0.5 通常够用):
vals = bwm1.extract('output/embedded.png', wm_shape=len(wm), mode='bit') recovered = [v >= 0.5 for v in vals]如果还要在截屏裁剪、缩放之后再提取,example_bit.py 里有完整的攻击恢复流程。我的经验是:给人看的用文字模式,给系统读的用比特模式,别过度设计。
旋转 45°、裁剪、缩放之后水印还能提取吗
这是盲水印的核心卖点,仓库自带一整套攻击模拟(在 att.py 里):旋转 45°、随机裁剪、60 处遮挡、缩放、5% 椒盐噪声、亮度降低 10%。水印写在 DWT-DCT-SVD 变换出的频域系数里,所以这类几何和亮度变化冲不掉它。攻击前后与提取结果的样图都放在 docs/ 目录,项目测试记录里各攻击下的提取结果和原始水印一致。
最难的是"截屏裁剪 + 缩放":你不知道它从哪裁的、缩了多少。recover.py 提供了两个工具——estimate_crop_parameters能从带水印图与被攻击图反推裁剪区域和缩放比例,recover_crop再把图还原到原始尺寸,之后照常提取。完整演示见 example_str.py。
但要注意:裁剪掉的部分信息是真的没了,裁剪比例太大或噪声太强时提取会失败。docs 里的记录是特定参数下的结果,落地前建议用自己的参数验证一遍。
三种模式怎么选:先记密码,再记长度
一句话选模式:人读署名声明 → str;嵌 Logo 这类二维图形 → img;给程序读几个比特标记 → bit。
比选模式更容易踩的是两个细节。一是密码:嵌入和提取时的 password_img、password_wm 必须一致,CLI 的 --pwd 对应前者。二是 wm_shape:文字和比特要长度、img 模式要二维尺寸,缺了它提取会直接报错。嵌入时丢了长度,只能重嵌。
还有两个实用点:嵌入后想控制文件大小,embed 方法支持 compression_ratio 参数(0-100,越小文件越小);批量嵌入可以给 WaterMark 传processes='multiprocessing'开多进程加速,参考 example_str_multi.py。想深入实现,从 bwm_core.py 的频域嵌入和 examples/ 的完整场景看起。
【免费下载链接】blind_watermarkBlind&Invisible Watermark ,图片盲水印,提取水印无须原图!项目地址: https://gitcode.com/GitHub_Trending/bl/blind_watermark
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考