还在念书时,就听说过频域水印。它可以通过将水印内容隐藏在宿主图像的高频区域,从而让人肉眼不可见地打上水印。为了详细了解相关技术,结合 LLM,我开发了一个 Python 库:FDWM(Frequency Domain Watermarking)。
技术原理:为什么选择频域?
1. 频域水印的基本原理
数字水印技术主要分为空域和频域两大类。FDWM 选择频域技术,其优势在于:
- 不可见性更好:在高频区域嵌入水印,人眼很难察觉
- 鲁棒性更强:对压缩、裁剪等攻击有更好的抵抗能力
- 容量适中:在不可见性和容量之间取得了很好的平衡
2. 核心算法实现
FDWM 的核心实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| host = _read_image(host_path, gray=True) watermark_norm = watermark.astype(np.float32) / 255.0
host_dft = np.fft.fft2(host) host_dft_shift = np.fft.fftshift(host_dft)
host_dft_shift[r_start:r_end, c_start:c_end] += strength * watermark_norm host_dft_shift[r_start_sym:r_end_sym, c_start_sym:c_end_sym] += ( strength * np.flipud(np.fliplr(watermark_norm)) )
host_idft_shift = np.fft.ifftshift(host_dft_shift) img_back = np.fft.ifft2(host_idft_shift) img_back = np.real(img_back)
|
3. 关键技术细节
对称嵌入策略
FDWM 采用对称嵌入策略,在频谱的四个角落同时嵌入水印。
自适应文本渲染
对于文本水印,FDWM 实现了智能的字体大小调整:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def _text_to_image(text: str, target_size: Tuple[int, int], ...) -> np.ndarray: while font_size > 10: text_bbox = draw.multiline_textbbox((0, 0), wrapped, font=font, spacing=4) text_w = text_bbox[2] - text_bbox[0] text_h = text_bbox[3] - text_bbox[1]
if text_w <= cols and text_h <= rows: x = (cols - text_w) // 2 y = (rows - text_h) // 2 draw.multiline_text((x, y), wrapped, fill=255, font=font, spacing=4) return np.array(img)
font_size -= 2
|
项目架构
1. 模块结构
1 2 3 4 5
| fdwm/ ├── __init__.py # 包入口,导出主要函数 ├── watermark.py # 核心水印算法实现 ├── cli.py # 命令行界面 └── __main__.py # 模块执行入口
|
2. 设计模式
FDWM 采用了清晰的分层架构:
- 算法层:
watermark.py
包含所有核心算法
- 接口层:
__init__.py
提供简洁的 API
- 用户层:
cli.py
提供命令行工具
3. 配置管理
项目使用现代化的 Python 包配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [project] name = "fdwm" version = "0.1.0" description = "Frequency-domain watermarking library and CLI" dependencies = [ "numpy>=1.20", "opencv-python>=4.5", "Pillow>=10.0", "pytesseract>=0.3.10", ]
[project.scripts] fdwm = "fdwm.cli:main"
|
使用体验:简单到让人惊喜
1. 安装简单
2. API 简洁
1 2 3 4 5 6 7 8 9 10
| import cv2 from fdwm import embed, extract, extract_text
watermarked_img = embed(host_img, watermark_img, strength=0.1) extracted_watermark = extract(watermarked_img, watermark_img.shape[:2])
watermarked_img = embed(host_img, "Hello World", strength=0.1, is_text=True) extracted_text = extract_text(watermarked_img)
|
3. 命令行友好
1 2 3 4 5 6 7 8
| fdwm embed host.jpg watermark.png -o watermarked.jpg
fdwm embed host.jpg "Hello World" -o watermarked.jpg --text
fdwm extract watermarked.jpg watermark.png -o extracted.png
|
性能与质量保证:做得相当到位
1. 测试覆盖
项目包含完整的测试套件,这个测试写得很有意思:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| def test_embed_extract(): """完整工作流测试:嵌入 -> 提取 -> 计算相关系数""" generate_host_image(str(host_path)) generate_watermark(str(wm_path))
fdwm.embed(host_path, watermark_path, output_path, strength=5000.0)
extracted = fdwm.extract(watermarked_path, strength=5000.0)
corr = np.corrcoef(wm_resized.flatten(), extracted.flatten())[0, 1] assert corr > 0.5, "水印提取相关系数过低"
|
2. 质量指标
- 相关系数:原始水印与提取水印的相关系数 > 0.5
- 不可见性:水印嵌入后图像质量无明显下降
- 鲁棒性:对常见图像处理操作有良好抵抗能力
总结
FDWM 是一个使用简单、功能完善的数字水印库。它成功地将复杂的频域水印技术封装成易用的 Python 包,为图像版权保护和信息隐藏提供了解决方案。
特别值得一提的事,包括撰写这篇博客本身,整个过程中,我几乎没有手写代码。95% 以上的工作由 LLM 自动完成。
项目地址:https://github.com/Liam0205/fdwm
PyPI 包名:fdwm
许可证:MIT
作者:Liam Huang