首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 圖片指紋識別與感知哈希算法實現

     編輯:Java 相關知識

前言

圖片指紋(Perceptual Hash,pHash)用於以圖搜圖、去重、版權檢測。本文實現經典 平均哈希(aHash) 算法:縮放→灰度→均值→比較→生成 64 位指紋,並計算漢明距離判斷相似度。附完整可運行代碼。

一、算法流程(aHash)

  1. 縮放:將圖片縮至 8×8 像素(64 像素),去除細節保留結構。
  2. 灰度化:gray = 0.3*R + 0.59*G + 0.11*B。
  3. 計算均值:64 個灰度值平均。
  4. 二值化:≥均值→1,<均值→0,得到 64 位二進制串。
  5. 生成指紋:每 4 位轉十六進制,產生 16 字符字串。

二、核心代碼實現

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。
  • 灰度轉換:標準 BT.709 權重。
  • 漢明距離:十六進制字符異或後統計 1 的個數。

四、進階算法對比

算法特點抗幹擾能力適用場景
aHash (平均哈希)最簡單、最快低(縮放、壓縮敏感)縮圖去重、簡單相似檢測
pHash (感知哈希)DCT 頻域、更魯棒高(旋轉、噪聲、水印)版權保護、大規模以圖搜圖
dHash (差值哈希)梯度方向、速度較快中近似檢測、移動端
色彩直方圖顏色分佈低(結構變化不敏感)顏色風格分類

五、工程化建議

  1. 大規模檢索:指紋存入資料庫(CHAR(16)),建立索引;或用 Redis Bitmap / BK-Tree 加速漢明距離查詢。
  2. 異構圖片:預先統一色彩空間(sRGB)、去除 EXIF 方向標籤。
  3. 組合策略:aHash 快速過濾 + pHash 精確驗證。
  4. 深度學習替代:對於語義級相似(不同角度、風格),需用 CNN 提取特徵向量(如 ResNet + 余弦相似度)。

六、總結

aHash 算法簡單高效,適合入門理解圖片指紋原理。生產環境建議根據業務對抗幹擾要求選擇 pHash/dHash 或深度學習嵌入。代碼已模組化,可直接整合至 Spring Boot 服務或批次處理任務。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved