Java图片相似度识别

Java图片相似度识别

public class test3 {
    public static void main(String[] args) throws IOException {
        File imageFile1 = new File("C:\\Users\\dell-pc\\Pictures\\Saved Pictures\\g.jpeg");
        File imageFile2 = new File("C:\\Users\\dell-pc\\Pictures\\Saved Pictures\\j.jpeg");
        System.out.println(ImageSimilarity.calSimilarity(imageFile1, imageFile2)*100+"%");
    }
}

package com.tlzn.tkwl.test.service;

import java.awt.Graphics2D;

import java.awt.color.ColorSpace;

import java.awt.image.BufferedImage;

import java.awt.image.ColorConvertOp;

import java.io.File;

import java.io.IOException;

import javax.imageio.ImageIO;

/**
 * 图片相似性
 */

public class ImageSimilarity {

    public static int size = 32;

    public static int smallerSize = 8;


    private static double[] c;

    static {

        c = new double[size];

        for (int i = 1; i < size; i++) {

            c[i] = 1;

        }

        c[0] = 1 / Math.sqrt(2.0);

    }

    /**
     * 通过汉明距离计算相似度
     *
     * @param hash1
     * @param hash2
     * @return
     */

    public static double calSimilarity(String hash1, String hash2) {

        return calSimilarity(getHammingDistance(hash1, hash2));

    }

    /**
     * 通过汉明距离计算相似度
     *
     * @param hammingDistance
     * @return
     */

    public static double calSimilarity(int hammingDistance) {

        int length = size * size;

        double similarity = (length - hammingDistance) / (double) length;

// 使用指数曲线调整相似度结果

        similarity = Math.pow(similarity, 2);

        return similarity;

    }

    /**
     * 通过汉明距离计算相似度
     *
     * @param image1
     * @param image2
     * @return
     * @throws IOException
     */

    public static double calSimilarity(File image1, File image2) throws IOException {

        return calSimilarity(getHammingDistance(image1, image2));

    }

    /**
     * 获得汉明距离
     *
     * @param hash1
     * @param hash2
     * @return
     */

    public static int getHammingDistance(String hash1, String hash2) {

        int counter = 0;

        for (int k = 0; k < hash1.length(); k++) {

            if (hash1.charAt(k) != hash2.charAt(k)) {

                counter++;

            }

        }

        return counter;

    }

    /**
     * 获得汉明距离
     *
     * @param image1
     * @param image2
     * @return
     * @throws IOException
     */

    public static int getHammingDistance(File image1, File image2) throws IOException {

        return getHammingDistance(getHash(image1), getHash(image2));

    }

    /**
     * 返回二进制字符串,类似“001010111011100010”,可用于计算汉明距离
     *
     * @param imageFile
     * @return
     * @throws IOException
     * @throws Exception
     */

    public static String getHash(File imageFile) throws IOException {

        BufferedImage img = ImageIO.read(imageFile);

        /*

         * 1. Reduce size. Like Average Hash, pHash starts with a small image.

         * However, the image is larger than 8x8; 32x32 is a good size. This is

         * really done to simplify the DCT computation and not because it is

         * needed to reduce the high frequencies.

         */

        img = resize(img, size, size);

        /*

         * 2. Reduce color. The image is reduced to a grayscale just to further

         * simplify the number of computations.

         */

        img = grayscale(img);

        double[][] vals = new double[size][size];

        for (int x = 0; x < img.getWidth(); x++) {

            for (int y = 0; y < img.getHeight(); y++) {

                vals[x][y] = getBlue(img, x, y);

            }

        }

        /*

         * 3. Compute the DCT. The DCT separates the image into a collection of

         * frequencies and scalars. While JPEG uses an 8x8 DCT, this algorithm

         * uses a 32x32 DCT.

         */

// long start = System.currentTimeMillis();

        double[][] dctVals = applyDCT(vals);

        /*

         * 4. Reduce the DCT. This is the magic step. While the DCT is 32x32, just

         * keep the top-left 8x8. Those represent the lowest frequencies in the

         * picture.

         */

        /*

         * 5. Compute the average value. Like the Average Hash, compute the mean

         * DCT value (using only the 8x8 DCT low-frequency values and excluding

         * the first term since the DC coefficient can be significantly different

         * from the other values and will throw off the average).

         */

        double total = 0;

        for (int x = 0; x < smallerSize; x++) {

            for (int y = 0; y < smallerSize; y++) {

                total += dctVals[x][y];

            }

        }

        total -= dctVals[0][0];

        double avg = total / (double) ((smallerSize * smallerSize) - 1);

        /*

         * 6. Further reduce the DCT. This is the magic step. Set the 64 hash bits

         * to 0 or 1 depending on whether each of the 64 DCT values is above or

         * below the average value. The result doesn't tell us the actual low

         * frequencies; it just tells us the very-rough relative scale of the

         * frequencies to the mean. The result will not vary as long as the

         * overall structure of the image remains the same; this can survive gamma

         * and color histogram adjustments without a problem.

         */

        StringBuilder hash = new StringBuilder();

        for (int x = 0; x < smallerSize; x++) {

            for (int y = 0; y < smallerSize; y++) {

                if (x != 0 && y != 0) {

                    hash.append((dctVals[x][y] > avg ? "1" : "0"));

                }

            }

        }

        return hash.toString();

    }

    private static BufferedImage resize(BufferedImage image, int width, int height) {

        BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        Graphics2D g = resizedImage.createGraphics();

        g.drawImage(image, 0, 0, width, height, null);

        g.dispose();

        return resizedImage;

    }

    private static BufferedImage grayscale(BufferedImage img) {

        new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(img, img);

        return img;

    }

    private static int getBlue(BufferedImage img, int x, int y) {

        return (img.getRGB(x, y)) & 0xff;

    }

    private static double[][] applyDCT(double[][] f) {

        int N = size;

        double[][] F = new double[N][N];

        for (int u = 0; u < N; u++) {

            for (int v = 0; v < N; v++) {

                double sum = 0.0;

                for (int i = 0; i < N; i++) {

                    for (int j = 0; j < N; j++) {

                        sum += Math.cos(((2 * i + 1) / (2.0 * N)) * u * Math.PI)

                                * Math.cos(((2 * j + 1) / (2.0 * N)) * v * Math.PI) * (f[i][j]);

                    }

                }

                sum *= ((c[u] * c[v]) / 4.0);

                F[u][v] = sum;

            }

        }

        return F;

    }

}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值