图像指纹技术 - 使用 pHash 和 dHash 检测相似图像
什么是图像指纹 - 感知哈希基础
图像指纹(感知哈希)是将图像转换为紧凑的固定长度哈希值的技术。与加密哈希(MD5、SHA)不同,感知哈希对视觉上相似的图像产生相似的哈希值,即使图像经过缩放、压缩或轻微修改。
与加密哈希的区别:
- 加密哈希:1 位变化导致完全不同的哈希。用于验证文件完整性
- 感知哈希:视觉上相似的图像产生相近的哈希。用于相似性检测
应用场景:
- 重复图像检测:在大型图库中找出重复或近似重复的图像
- 版权保护:检测未授权使用的图像(即使经过裁剪、缩放、滤镜处理)
- 内容审核:检测已知违规图像的变体
- 反向图像搜索:根据图像内容查找来源
- 缓存去重:避免存储视觉上相同的图像的多个副本
aHash(平均哈希)- 最简单的图像哈希
aHash 是最简单的感知哈希算法,通过比较每个像素与平均亮度的关系生成哈希值。
算法步骤:
- 将图像缩小到 8x8(64 像素),消除尺寸差异
- 转为灰度图
- 计算 64 个像素的平均亮度值
- 每个像素与平均值比较:大于平均值为 1,否则为 0
- 生成 64 位哈希值
优点:
- 实现极其简单,计算速度最快
- 对缩放和轻微亮度变化有一定鲁棒性
缺点:
- 对伽马校正和直方图调整敏感
- 区分度较低,容易产生误匹配
- 无法处理局部修改(如添加水印)
适用场景:快速预筛选,作为更精确方法的第一步过滤。对精度要求不高的简单去重。
dHash(差异哈希)- 基于梯度的快速哈希
dHash 通过比较相邻像素的亮度差异(梯度)生成哈希,比 aHash 更能捕获图像的结构信息。
算法步骤:
- 将图像缩小到 9x8(72 像素,宽度多 1 列用于计算差异)
- 转为灰度图
- 对每行,比较相邻像素:右侧像素比左侧亮为 1,否则为 0
- 8 行 x 8 列差异 = 64 位哈希值
为什么比 aHash 好:
- 捕获的是相对亮度变化(梯度)而非绝对亮度,对整体亮度/对比度调整更鲁棒
- 保留了图像的结构信息(边缘方向)
- 计算速度与 aHash 相当
实现(Python):
from PIL import Imageimg = Image.open(path).resize((9, 8)).convert("L")- 比较相邻像素生成位串
适用场景:需要快速且比 aHash 更准确的场景。大规模图像去重的首选方法。
pHash(感知哈希)- 基于 DCT 的高精度哈希
pHash 使用离散余弦变换(DCT)提取图像的频率特征,精度最高但计算量也最大。
算法步骤:
- 将图像缩小到 32x32,转为灰度
- 对 32x32 图像执行 DCT 变换
- 取左上角 8x8 的低频系数(代表图像的整体结构,忽略高频细节)
- 计算 64 个系数的中位数
- 每个系数与中位数比较:大于中位数为 1,否则为 0
- 生成 64 位哈希值
为什么精度最高:
- DCT 将图像从空间域转换到频率域,低频系数代表图像的本质结构
- 对高频噪声(压缩伪影、轻微模糊)天然不敏感
- 使用中位数而非平均值,对异常值更鲁棒
与 dHash 的对比:
- pHash 对 JPEG 压缩、轻微旋转、颜色调整的鲁棒性更好
- dHash 速度更快(无需 DCT),适合大规模预筛选
- 实践中常组合使用:dHash 快速过滤 + pHash 精确验证
汉明距离相似度评分与阈值设计
两个哈希值之间的汉明距离(不同位的数量)衡量图像的相似程度。阈值的选择直接影响检测的精确率和召回率。
汉明距离计算:
- 对两个 64 位哈希进行 XOR 运算,统计结果中 1 的数量
- 距离 0:完全相同的哈希(极可能是同一图像)
- 距离 1-10:非常相似(可能是同一图像的不同版本)
- 距离 > 20:很可能是不同图像
阈值设计:
- 严格匹配(距离 ≤ 5):仅检测近乎相同的图像。高精确率,低召回率
- 宽松匹配(距离 ≤ 10):检测经过修改的相似图像。平衡精确率和召回率
- 模糊匹配(距离 ≤ 15):检测视觉上相关的图像。高召回率,可能有误报
多哈希组合策略:
- 同时计算 dHash 和 pHash,两者都满足阈值才判定为相似
- 或使用加权组合:总分 = 0.4 * dHash距离 + 0.6 * pHash距离
- 不同应用场景调整权重和阈值
实现模式与实际系统架构
在生产环境中部署图像指纹系统需要考虑存储、索引和查询效率。
存储与索引:
- 数据库存储:将 64 位哈希存为 BIGINT 类型,支持位运算查询
- 分桶索引:将哈希分为多个子段(如 4 个 16 位段),对每段建立倒排索引。查询时在各段分别搜索,取交集
- VP-Tree:Vantage-Point Tree,专为汉明距离设计的空间索引结构。支持高效的范围查询
大规模系统架构:
- 入库流程:图像上传 → 计算多种哈希(dHash + pHash)→ 存入数据库 → 建立索引
- 查询流程:查询图像 → 计算哈希 → 索引搜索候选集 → 精确汉明距离计算 → 返回相似图像
- 增量更新:新图像入库时与现有库对比,检测重复
性能参考:
- 百万级图库:dHash 索引查询 < 10ms
- 千万级图库:需要分布式索引(如 Elasticsearch 的位向量插件)
- 哈希计算:单张图像 < 5ms(dHash)、< 20ms(pHash)