Java检测重复图片的核心是图像哈希,常用aHash、pHash、dHash三种算法;dHash推荐入门,用BufferedImage缩放为9×8灰度图,比较相邻像素差生成64位二进制指纹,汉明距离≤3–5视为重复。

Java 检测重复图片,核心思路是用图像哈希(Image Hash)把图片转成固定长度的指纹,再比对指纹相似度。不是逐像素比较,而是提取视觉特征后降维,兼顾速度和鲁棒性(对缩放、亮度微调、轻微压缩不敏感)。
选哪种 Hash 算法?
常用且适合 Java 实战的有三种:
- 平均哈希(aHash):最简单快速,适合大量初筛。缩放为 8×8 灰度图 → 算平均值 → 每个像素转 0/1 → 得 64 位二进制 hash。差异 ≤ 5 位大概率是同一图。
- 感知哈希(pHash):更抗干扰。缩放为 32×32 → DCT 变换 → 取左上 8×8 低频系数 → 算中值 → 生成 64 位 hash。适合识别缩略图、轻微裁剪或 JPEG 压缩后的重复图。
- dHash(差异哈希):比 aHash 更稳定。缩放为 9×8 → 计算相邻像素差值 → 转 0/1 → 得 64 位 hash。对平移和局部变化更鲁棒,计算也快。
用 Java 快速实现 dHash(推荐入门)
不需要复杂依赖,JDK 自带 BufferedImage 就够用:
public static String dHash(BufferedImage img) {
int width = 9, height = 8;
BufferedImage resized = resizeGray(img, width, height); // 缩放+灰度
StringBuilder sb = new StringBuilder();
for (int i = 0; i < height; i++) {
for (int j = 0; j < width - 1; j++) {
int pixelLeft = resized.getRGB(j, i) & 0xFF;
int pixelRight = resized.getRGB(j + 1, i) & 0xFF;
sb.append(pixelLeft > pixelRight ? "1" : "0");
}
}
return sb.toString(); // 返回 64 字符二进制串
}
比对时直接计算汉明距离(异或后数 1 的个数),≤ 3–5 通常视为重复。
立即学习“Java免费学习笔记(深入)”;
实战优化建议
- 先粗筛再精排:用 aHash 或 dHash 扫全量图库生成 hash 表;查重时只对 hash 相似(如汉明距离
- 预处理统一化:读图后强制转 RGB 格式、去透明通道(alpha 设为白底),避免同图因 PNG/WEBP 存储差异导致 hash 偏移。
-
用 Long 替代 String 存 hash:64 位二进制可转为
long,比对用Long.bitCount(h1 ^ h2),性能提升 5–10 倍。 - 加文件尺寸/宽高过滤:明显尺寸不同的图无需算 hash,前置判断能省下大量 IO 和计算。
基本上就这些。Hash 不是万能——完全翻转、大幅裁剪、加水印的图可能漏判,但对日常去重、相册整理、上传防重,dHash + 汉明阈值已足够好用。










