圖片指紋(Perceptual Hash,pHash)用於以圖搜圖、去重、版權檢測。本文實現經典 平均哈希(aHash) 算法:縮放→灰度→均值→比較→生成 64 位指紋,並計算漢明距離判斷相似度。附完整可運行代碼。
gray = 0.3*R + 0.59*G + 0.11*B。public class ImageFingerprint {
/** 生成 aHash 指紋 */
public static String produceFingerPrint(BufferedImage src) {
// 1. 縮放 8x8
BufferedImage thumb = Thumbnails.of(src).size(8, 8).asBufferedImage();
// 2. 灰度數組
int[] gray = new int[64];
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
int rgb = thumb.getRGB(x, y);
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = rgb & 0xFF;
gray[y * 8 + x] = (int) (0.3 * r + 0.59 * g + 0.11 * b);
}
}
// 3. 均值
int avg = Arrays.stream(gray).sum() / 64;
// 4. 二值化 + 5. 十六進制
StringBuilder hex = new StringBuilder();
for (int i = 0; i < 64; i += 4) {
int v = (gray[i] >= avg ? 8 : 0) | (gray[i+1] >= avg ? 4 : 0) | (gray[i+2] >= avg ? 2 : 0) | (gray[i+3] >= avg ? 1 : 0);
hex.append(Integer.toHexString(v));
}
return hex.toString(); // 16 字符
}
/** 漢明距離 */
public static int hammingDistance(String fp1, String fp2) {
if (fp1.length() != fp2.length()) throw new IllegalArgumentException();
int diff = 0;
for (int i = 0; i < fp1.length(); i++) {
int c1 = Character.digit(fp1.charAt(i), 16);
int c2 = Character.digit(fp2.charAt(i), 16);
diff += Integer.bitCount(c1 ^ c2);
}
return diff;
}
/** 相似度判斷 */
public static String similarity(int distance) {
if (distance == 0) return "完全相同";
if (distance <= 5) return "極其相似";
if (distance <= 10) return "較為相似";
if (distance <= 15) return "略有相似";
return "完全不同";
}
public static void main(String[] args) throws IOException {
// 載入測試圖片
BufferedImage src = ImageIO.read(new File("source.jpg"));
List samples = IntStream.rangeClosed(1, 6)
.mapToObj(i -> ImageIO.read(new File("example" + i + ".jpg")))
.collect(Collectors.toList());
String srcFp = produceFingerPrint(src);
System.out.println("源圖指紋: " + srcFp);
for (int i = 0; i < samples.size(); i++) {
String fp = produceFingerPrint(samples.get(i));
int dist = hammingDistance(srcFp, fp);
System.out.printf("example%d: 指紋=%s 距離=%d 判定=%s%n", i+1, fp, dist, similarity(dist));
}
}
}
thumbnailator (net.coobird:thumbnailator:0.4.18) 或手寫 AffineTransform。| 算法 | 特點 | 抗幹擾能力 | 適用場景 |
|---|---|---|---|
| aHash (平均哈希) | 最簡單、最快 | 低(縮放、壓縮敏感) | 縮圖去重、簡單相似檢測 |
| pHash (感知哈希) | DCT 頻域、更魯棒 | 高(旋轉、噪聲、水印) | 版權保護、大規模以圖搜圖 |
| dHash (差值哈希) | 梯度方向、速度較快 | 中 | 近似檢測、移動端 |
| 色彩直方圖 | 顏色分佈 | 低(結構變化不敏感) | 顏色風格分類 |
CHAR(16)),建立索引;或用 Redis Bitmap / BK-Tree 加速漢明距離查詢。aHash 算法簡單高效,適合入門理解圖片指紋原理。生產環境建議根據業務對抗幹擾要求選擇 pHash/dHash 或深度學習嵌入。代碼已模組化,可直接整合至 Spring Boot 服務或批次處理任務。