|
|
利用 blind-watermark 为图片批量添加与提取盲水印(Python 教程)
本教程基于 GitHub 开源项目 blind-watermark,支持单张及批量图片的盲水印嵌入与提取,水印内容为字符串或图片,本篇教程只讲字符串。盲水印的特点是人眼不可见、鲁棒性强,即使图片经过裁剪、压缩等处理,仍有可能成功提取。
项目地址:blind-watermark
1.环境准备
编译器:任意支持 Python 的环境(如 PyCharm、VS Code)
Python 版本:3.6 及以上
依赖安装:在终端中执行以下命令
- pip install blind-watermark
复制代码 项目结构:新建一个空文件夹,在其中创建以下目录
- mkdir pic # 存放原始图片
- mkdir output # 存放加水印后的图片
复制代码 最终的项目结构示例:
your_project/
│
├── pic/ # 原始图片
├── output/ # 水印图片
├── embed.py # 单张嵌入脚本
├── extract.py # 单张提取脚本
├── batch_embed.py # 批量嵌入脚本
├── batch_extract.py # 批量提取脚本
└── ...
2. 单张图片:添加与提取水印
2.1 创建脚本文件
新建 embed.py 和 extract.py 两个文件。
2.2 嵌入水印代码(embed.py)
- from blind_watermark import WaterMark
- import os
- # 确保输出文件夹存在
- os.makedirs('output', exist_ok=True)
- # 创建水印对象
- bwm = WaterMark(password_img=1, password_wm=1)
- # 读取原始图片(你需要先放一张图片到 pic 文件夹)
- bwm.read_img('pic/0001.jpg')
- # 水印内容
- wm = '这只是一个测试!'
- bwm.read_wm(wm, mode='str')
- # 嵌入水印
- bwm.embed('output/embedded.png')
- # 获取水印长度(提取时需要)
- len_wm = len(bwm.wm_bit)
- print(f'水印嵌入成功!')
- print(f'水印长度: {len_wm}')
- print(f'输出文件: output/embedded.png')
- # 保存水印长度供后续使用
- with open('watermark_length.txt', 'w') as f:
- f.write(str(len_wm))
复制代码 2.3 提取水印代码(extract.py)
- from blind_watermark import WaterMark
- # 读取之前保存的水印长度
- try:
- with open('watermark_length.txt', 'r') as f:
- len_wm = int(f.read())
- except FileNotFoundError:
- print("找不到 watermark_length.txt,请先运行 embed.py")
- exit(1)
- # 创建水印对象(使用相同密码)
- bwm = WaterMark(password_img=1, password_wm=1)
- # 提取水印
- wm_extract = bwm.extract('output/embedded.png', wm_shape=len_wm, mode='str')
- print(f'提取出的水印: {wm_extract}')
复制代码 运行效果示例:
3. 多张图片:添加与提取水印
3.1 创建脚本文件
新建 batch_embed.py 和 batch_extract.py
3.2 批量嵌入代码(batch_embed.py)
- from blind_watermark import WaterMark
- import glob
- import os
- # 配置
- PASSWORD_IMG = 1
- PASSWORD_WM = 1
- WATERMARK_TEXT = '这只是一个测试!'
- INPUT_FOLDER = 'pic/'
- OUTPUT_FOLDER = 'output/'
- # 确保输出文件夹存在
- os.makedirs(OUTPUT_FOLDER, exist_ok=True)
- # 支持的图片格式
- image_files = []
- for ext in ['*.jpg', '*.jpeg', '*.png', '*.bmp']:
- image_files.extend(glob.glob(f'{INPUT_FOLDER}{ext}'))
- print(f"找到 {len(image_files)} 张图片")
- # 记录所有水印信息
- all_info = {}
- for i, img_path in enumerate(image_files, 1):
- basename = os.path.basename(img_path)
- name, ext = os.path.splitext(basename)
- output_path = f'{OUTPUT_FOLDER}{name}{ext}'
- # 嵌入水印
- bwm = WaterMark(password_img=PASSWORD_IMG, password_wm=PASSWORD_WM)
- bwm.read_img(img_path)
- bwm.read_wm(WATERMARK_TEXT, mode='str')
- bwm.embed(output_path)
- len_wm = len(bwm.wm_bit)
- all_info[output_path] = len_wm
- print(f"[{i}/{len(image_files)}] {basename} -> {output_path} (长度: {len_wm})")
- # 保存所有水印信息
- with open(f'{OUTPUT_FOLDER}watermark_info.txt', 'w', encoding='utf-8') as f:
- for output_path, length in all_info.items():
- f.write(f"{output_path}: {length}\n")
- print(f"\n 批量处理完成!共处理 {len(image_files)} 张图片")
复制代码 3.3 批量提取代码(batch_extract.py)
- from blind_watermark import WaterMark
- from blind_watermark import bw_notes
- import warnings
- import glob
- import os
- # 关闭欢迎信息和警告
- bw_notes.close()
- warnings.filterwarnings('ignore')
- # 配置
- PASSWORD_IMG = 1
- PASSWORD_WM = 1
- INPUT_FOLDER = 'output/' # 带水印的图片所在文件夹
- OUTPUT_INFO_FILE = 'output/watermark_info.txt' # 之前保存的水印信息文件
- # 读取水印信息(文件名 -> 水印长度)
- watermark_lengths = {}
- with open(OUTPUT_INFO_FILE, 'r', encoding='utf-8') as f:
- for line in f:
- if ': ' in line:
- file_path, length = line.strip().split(': ')
- # 只取文件名(不含路径)
- filename = os.path.basename(file_path)
- watermark_lengths[filename] = int(length)
- print(f"读取到 {len(watermark_lengths)} 条水印信息")
- print(f"水印信息文件列表: {list(watermark_lengths.keys())}")
- # 获取所有带水印的图片
- watermarked_images = []
- for ext in ['*.jpg', '*.jpeg', '*.png', '*.bmp']:
- watermarked_images.extend(glob.glob(f'{INPUT_FOLDER}{ext}'))
- print(f"找到 {len(watermarked_images)} 张带水印的图片")
- print(f"图片文件列表: {[os.path.basename(f) for f in watermarked_images]}")
- print("=" * 60)
- # 批量提取水印
- success_count = 0
- for img_path in watermarked_images:
- basename = os.path.basename(img_path)
- # 检查是否有对应的水印长度信息
- if basename not in watermark_lengths:
- print(f" {basename} - 找不到水印长度信息,跳过")
- continue
- len_wm = watermark_lengths[basename]
- # 提取水印
- bwm = WaterMark(password_img=PASSWORD_IMG, password_wm=PASSWORD_WM)
- try:
- wm_extract = bwm.extract(img_path, wm_shape=len_wm, mode='str')
- print(f" {basename} -> 提取水印: {wm_extract}")
- success_count += 1
- except Exception as e:
- print(f" {basename} - 提取失败: {e}")
- print(f"\n 批量提取完成!成功提取 {success_count}/{len(watermarked_images)} 张图片的水印")
复制代码 运行效果示例:
若图片内容为空白(图中第二张)(如纯色或无效图像数据),水印将无法被正确识别或提取。
4. 注意事项
密码一致:嵌入和提取时使用的 password_img 和 password_wm 必须相同,否则无法正确提取。
水印长度:提取时需要知道水印的二进制长度,脚本中已通过文件保存,请勿删除。
水印内容:支持字符串、二进制等多种模式,本教程以字符串为例。
来自群组: 小浣熊饲养中心 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
评分
-
查看全部评分
|