列举一些算法对照片、图像进行相似度对比分析比较

首先: 图片如下

           

                                       18.jpg                                                                                    19.jpg

           

                                       20.jpg                                                                                    21.jpg

                        2.jpg

                        3.jpg

算法以及对比结果

一、

18/19/20/21 图片对比以及结果

package com.aliyun.picture.demo;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @BelongsProject: maven-demo
 * @BelongsPackage: com.aliyun.picture.demo
 * @Author: Guoyh
 * @CreateTime: 2018-10-12 15:25
 * @Description: 对比图片相似度
 */
public class ImageContrastUtil {
    // 对比方法
    public static Double imageComparison(InputStream sampleInputStream,InputStream contrastInputStream ) throws IOException {
        //获取灰度像素的比较数组
        int[] photoArrayTwo = getPhotoArray(contrastInputStream);
        int[] photoArrayOne = getPhotoArray(sampleInputStream);

        // 获取两个图的汉明距离
        int hammingDistance = getHammingDistance(photoArrayOne, photoArrayTwo);
        // 通过汉明距离计算相似度,取值范围 [0.0, 1.0]
        double similarity = calSimilarity(hammingDistance);

        //返回相似精度
        return  similarity;
    }

    // 将任意Image类型图像转换为BufferedImage类型,方便后续操作
    public static BufferedImage convertToBufferedFrom(Image srcImage) {
        BufferedImage bufferedImage = new BufferedImage(srcImage.getWidth(null),
                srcImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(srcImage, null, null);
        g.dispose();
        return bufferedImage;
    }

    // 转换至灰度图
    public static BufferedImage toGrayscale(Image image) {
        BufferedImage sourceBuffered = convertToBufferedFrom(image);
        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
        ColorConvertOp op = new ColorConvertOp(cs, null);
        BufferedImage grayBuffered = op.filter(sourceBuffered, null);
        return grayBuffered;
    }

    // 缩放至32x32像素缩略图
    public static Image scale(Image image) {
        image = image.getScaledInstance(32, 32, Image.SCALE_SMOOTH);
        return image;
    }

    // 获取像素数组
    public static int[] getPixels(Image image) {
        int width = image.getWidth(null);
        int height = image.getHeight(null);
        int[] pixels = convertToBufferedFrom(image).getRGB(0, 0, width, height,
                null, 0, width);
        return pixels;
    }

    // 获取灰度图的平均像素颜色值
    public static int getAverageOfPixelArray(int[] pixels) {
        Color color;
        long sumRed = 0;
        for (int i = 0; i < pixels.length; i++) {
            color = new Color(pixels[i], true);
            sumRed += color.getRed();
        }
        int averageRed = (int) (sumRed / pixels.length);
        return averageRed;
    }

    // 获取灰度图的像素比较数组(平均值的离差)
    public static int[] getPixelDeviateWeightsArray(int[] pixels, final int averageColor) {
        Color color;
        int[] dest = new int[pixels.length];
        for (int i = 0; i < pixels.length; i++) {
            color = new Color(pixels[i], true);
            dest[i] = color.getRed() - averageColor > 0 ? 1 : 0;
        }
        return dest;
    }

    // 获取两个缩略图的平均像素比较数组的汉明距离(距离越大差异越大)
    public static int getHammingDistance(int[] a, int[] b) {
        int sum = 0;
        for (int i = 0; i < a.length; i++) {
            sum += a[i] == b[i] ? 0 : 1;
        }
        return sum;
    }

    //获取灰度像素的比较数组
    public static int[] getPhotoArray(InputStream inputStream) throws IOException {
        Image image = ImageIO.read(inputStream);
//        Image image = ImageIO.read(imageFile);
        // 转换至灰度
        image = toGrayscale(image);
        // 缩小成32x32的缩略图
        image = scale(image);
        // 获取灰度像素数组
        int[] pixels = getPixels(image);
        // 获取平均灰度颜色
        int averageColor = getAverageOfPixelArray(pixels);
        // 获取灰度像素的比较数组(即图像指纹序列)
        pixels = getPixelDeviateWeightsArray(pixels, averageColor);

        return pixels;
    }

    // 通过汉明距离计算相似度
    public static double calSimilarity(int hammingDistance) {
        int length = 32 * 32;
        double similarity = (length - hammingDistance) / (double) length;

        // 使用指数曲线调整相似度结果
        similarity = java.lang.Math.pow(similarity, 2);
        return similarity;
    }

    /**
     * @param args
     * @return void
     * @author Guoyh
     * @date 2018/10/12 15:27
     */
    public static void main(String[] args) throws Exception {

        //(数据类型)(最小值+Math.random()*(最大值-最小值+1))
        for (int i = 18; i <= 21; i++) {
            Double imageComparison =  imageComparison(new FileInputStream("G:/oss/pk/" + 18 + ".jpg"),new FileInputStream("G:/oss/pk/" +i + ".jpg"));
            System.out.println("\t" + "\t"+"G:/oss/pk/" + 18 + ".jpg"+"\t"+"与"+"\t"+"G:/oss/pk/" + i + ".jpg"+"\t"+"两张图片的相似度为:" + imageComparison * 100 + "%");
        }
    }
}

ImageContrastUtil

2/3  图片对比以及结果

package com.aliyun.picture.demo;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @BelongsProject: maven-demo
 * @BelongsPackage: com.aliyun.picture.demo
 * @Author: Guoyh
 * @CreateTime: 2018-10-12 15:25
 * @Description: 对比图片相似度
 */
public class ImageContrastUtil {
    // 对比方法
    public static Double imageComparison(InputStream sampleInputStream,InputStream contrastInputStream ) throws IOException {
        //获取灰度像素的比较数组
        int[] photoArrayTwo = getPhotoArray(contrastInputStream);
        int[] photoArrayOne = getPhotoArray(sampleInputStream);

        // 获取两个图的汉明距离
        int hammingDistance = getHammingDistance(photoArrayOne, photoArrayTwo);
        // 通过汉明距离计算相似度,取值范围 [0.0, 1.0]
        double similarity = calSimilarity(hammingDistance);

        //返回相似精度
        return  similarity;
    }

    // 将任意Image类型图像转换为BufferedImage类型,方便后续操作
    public static BufferedImage convertToBufferedFrom(Image srcImage) {
        BufferedImage bufferedImage = new BufferedImage(srcImage.getWidth(null),
                srcImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(srcImage, null, null);
        g.dispose();
        return bufferedImage;
    }

    // 转换至灰度图
    public static BufferedImage toGrayscale(Image image) {
        BufferedImage sourceBuffered = convertToBufferedFrom(image);
        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
        ColorConvertOp op = new ColorConvertOp(cs, null);
        BufferedImage grayBuffered = op.filter(sourceBuffered, null);
        return grayBuffered;
    }

    // 缩放至32x32像素缩略图
    public static Image scale(Image image) {
        image = image.getScaledInstance(32, 32, Image.SCALE_SMOOTH);
        return image;
    }

    // 获取像素数组
    public static int[] getPixels(Image image) {
        int width = image.getWidth(null);
        int height = image.getHeight(null);
        int[] pixels = convertToBufferedFrom(image).getRGB(0, 0, width, height,
                null, 0, width);
        return pixels;
    }

    // 获取灰度图的平均像素颜色值
    public static int getAverageOfPixelArray(int[] pixels) {
        Color color;
        long sumRed = 0;
        for (int i = 0; i < pixels.length; i++) {
            color = new Color(pixels[i], true);
            sumRed += color.getRed();
        }
        int averageRed = (int) (sumRed / pixels.length);
        return averageRed;
    }

    // 获取灰度图的像素比较数组(平均值的离差)
    public static int[] getPixelDeviateWeightsArray(int[] pixels, final int averageColor) {
        Color color;
        int[] dest = new int[pixels.length];
        for (int i = 0; i < pixels.length; i++) {
            color = new Color(pixels[i], true);
            dest[i] = color.getRed() - averageColor > 0 ? 1 : 0;
        }
        return dest;
    }

    // 获取两个缩略图的平均像素比较数组的汉明距离(距离越大差异越大)
    public static int getHammingDistance(int[] a, int[] b) {
        int sum = 0;
        for (int i = 0; i < a.length; i++) {
            sum += a[i] == b[i] ? 0 : 1;
        }
        return sum;
    }

    //获取灰度像素的比较数组
    public static int[] getPhotoArray(InputStream inputStream) throws IOException {
        Image image = ImageIO.read(inputStream);
//        Image image = ImageIO.read(imageFile);
        // 转换至灰度
        image = toGrayscale(image);
        // 缩小成32x32的缩略图
        image = scale(image);
        // 获取灰度像素数组
        int[] pixels = getPixels(image);
        // 获取平均灰度颜色
        int averageColor = getAverageOfPixelArray(pixels);
        // 获取灰度像素的比较数组(即图像指纹序列)
        pixels = getPixelDeviateWeightsArray(pixels, averageColor);

        return pixels;
    }

    // 通过汉明距离计算相似度
    public static double calSimilarity(int hammingDistance) {
        int length = 32 * 32;
        double similarity = (length - hammingDistance) / (double) length;

        // 使用指数曲线调整相似度结果
        similarity = java.lang.Math.pow(similarity, 2);
        return similarity;
    }

    /**
     * @param args
     * @return void
     * @author Guoyh
     * @date 2018/10/12 15:27
     */
    public static void main(String[] args) throws Exception {

        //(数据类型)(最小值+Math.random()*(最大值-最小值+1))
        for (int i = 2; i <= 3; i++) {
            Double imageComparison =  imageComparison(new FileInputStream("G:/oss/pk/" + 2 + ".jpg"),new FileInputStream("G:/oss/pk/" +i + ".jpg"));
            System.out.println("\t" + "\t"+"G:/oss/pk/" + 2 + ".jpg"+"\t"+"与"+"\t"+"G:/oss/pk/" + i + ".jpg"+"\t"+"两张图片的相似度为:" + imageComparison * 100 + "%");
        }
    }
}

ImageContrastUtil

二、

18/19/20/21 图片对比以及结果

package com.aliyun.picture.demo;

/**
 * @BelongsProject: maven-demo
 * @BelongsPackage: com.aliyun.picture.demo
 * @Author: Guoyh
 * @CreateTime: 2018-10-12 14:55
 * @Description: 比较两张图像的相似度
 */

import javax.imageio.*;
import java.awt.image.*;
import java.awt.*;//Color
import java.io.*;

public class PhotoDigest {

    public static int[] getData(String name) {
        try {
            BufferedImage img = ImageIO.read(new File(name));
            BufferedImage slt = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
            slt.getGraphics().drawImage(img, 0, 0, 100, 100, null);
            // ImageIO.write(slt,"jpeg",new File("slt.jpg"));
            int[] data = new int[256];
            for (int x = 0; x < slt.getWidth(); x++) {
                for (int y = 0; y < slt.getHeight(); y++) {
                    int rgb = slt.getRGB(x, y);
                    Color myColor = new Color(rgb);
                    int r = myColor.getRed();
                    int g = myColor.getGreen();
                    int b = myColor.getBlue();
                    data[(r + g + b) / 3]++;
                }
            }
            // data 就是所谓图形学当中的直方图的概念
            return data;
        } catch (Exception exception) {
            System.out.println("有文件没有找到,请检查文件是否存在或路径是否正确");
            return null;
        }
    }

    public static float compare(int[] s, int[] t) {
        try {
            float result = 0F;
            for (int i = 0; i < 256; i++) {
                int abs = Math.abs(s[i] - t[i]);
                int max = Math.max(s[i], t[i]);
                result += (1 - ((float) abs / (max == 0 ? 1 : max)));
            }
            return (result / 256) * 100;
        } catch (Exception exception) {
            return 0;
        }
    }

    public static void main(String[] args) throws Exception {

        //(数据类型)(最小值+Math.random()*(最大值-最小值+1))
        for (int i = 18; i <= 21; i++) {

            float percent = compare(getData("G:/oss/pk/" + 18 + ".jpg"),
                    getData("G:/oss/pk/" + i + ".jpg"));
            if (percent == 0) {
                System.out.println("无法比较");
            } else {
                System.out.println("\t"+"G:/oss/pk/" + 18 + ".jpg"+"\t"+"与"+"\t"+"G:/oss/pk/" + i + ".jpg"+"\t"+"两张图片的相似度为:" + percent + "%");
            }
        }
    }
}

PhotoDigest

2/3  图片对比以及结果

package com.aliyun.picture.demo;

/**
 * @BelongsProject: maven-demo
 * @BelongsPackage: com.aliyun.picture.demo
 * @Author: Guoyh
 * @CreateTime: 2018-10-12 14:55
 * @Description: 比较两张图像的相似度
 */

import javax.imageio.*;
import java.awt.image.*;
import java.awt.*;//Color
import java.io.*;

public class PhotoDigest {

    public static int[] getData(String name) {
        try {
            BufferedImage img = ImageIO.read(new File(name));
            BufferedImage slt = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
            slt.getGraphics().drawImage(img, 0, 0, 100, 100, null);
            // ImageIO.write(slt,"jpeg",new File("slt.jpg"));
            int[] data = new int[256];
            for (int x = 0; x < slt.getWidth(); x++) {
                for (int y = 0; y < slt.getHeight(); y++) {
                    int rgb = slt.getRGB(x, y);
                    Color myColor = new Color(rgb);
                    int r = myColor.getRed();
                    int g = myColor.getGreen();
                    int b = myColor.getBlue();
                    data[(r + g + b) / 3]++;
                }
            }
            // data 就是所谓图形学当中的直方图的概念
            return data;
        } catch (Exception exception) {
            System.out.println("有文件没有找到,请检查文件是否存在或路径是否正确");
            return null;
        }
    }

    public static float compare(int[] s, int[] t) {
        try {
            float result = 0F;
            for (int i = 0; i < 256; i++) {
                int abs = Math.abs(s[i] - t[i]);
                int max = Math.max(s[i], t[i]);
                result += (1 - ((float) abs / (max == 0 ? 1 : max)));
            }
            return (result / 256) * 100;
        } catch (Exception exception) {
            return 0;
        }
    }

    public static void main(String[] args) throws Exception {

        //(数据类型)(最小值+Math.random()*(最大值-最小值+1))
        for (int i = 2; i <= 3; i++) {

            float percent = compare(getData("G:/oss/pk/" + 2 + ".jpg"),
                    getData("G:/oss/pk/" + i + ".jpg"));
            if (percent == 0) {
                System.out.println("无法比较");
            } else {
                System.out.println("\t"+"G:/oss/pk/" + 2 + ".jpg"+"\t"+"与"+"\t"+"G:/oss/pk/" + i + ".jpg"+"\t"+"两张图片的相似度为:" + percent + "%");
            }
        }
    }
}

PhotoDigest

三、

18/19/20/21 图片对比以及结果

package com.aliyun.picture.demo;

/**
 * 比较两张图片的相似度
 *
 * @BelongsProject: maven-demo
 * @BelongsPackage: com.aliyun.picture.demo
 * @Author: Guoyh
 * @CreateTime: 2018-10-12 14:12
 * @Description: 图像比对技术
 */

import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class BMPLoader {
    // 改变成二进制码
    public static String[][] getPX(String args) {
        int[] rgb = new int[3];
        File file = new File(args);
        BufferedImage bi = null;
        try {
            bi = ImageIO.read(file);
        } catch (Exception e) {
            e.printStackTrace();
        }
        int width = bi.getWidth();
        int height = bi.getHeight();
        int minx = bi.getMinX();
        int miny = bi.getMinY();
        String[][] list = new String[width][height];
        for (int i = minx; i < width; i++) {
            for (int j = miny; j < height; j++) {
                int pixel = bi.getRGB(i, j);
                rgb[0] = (pixel & 0xff0000) >> 16;
                rgb[1] = (pixel & 0xff00) >> 8;
                rgb[2] = (pixel & 0xff);
                list[i][j] = rgb[0] + "," + rgb[1] + "," + rgb[2];
            }
        }
        return list;
    }

    public static void compareImage(String imgPath1, String imgPath2) {
        String[] images = {imgPath1, imgPath2};
        if (images.length == 0) {
            System.out.println("Usage >java BMPLoader ImageFile.bmp");
            System.exit(0);
        }
        // 分析图片相似度 begin
        String[][] list1 = getPX(images[0]);
        String[][] list2 = getPX(images[1]);
        int xiangsi = 0;
        int busi = 0;
        int i = 0, j = 0;
        for (String[] strings : list1) {
            if ((i + 1) == list1.length) {
                continue;
            }
            for (int m = 0; m < strings.length; m++) {
                try {
                    String[] value1 = list1[i][j].toString().split(",");
                    String[] value2 = list2[i][j].toString().split(",");
                    int k = 0;
                    for (int n = 0; n < value2.length; n++) {
                        if (Math.abs(Integer.parseInt(value1[k]) - Integer.parseInt(value2[k])) < 5) {
                            xiangsi++;
                        } else {
                            busi++;
                        }
                    }
                } catch (RuntimeException e) {
                    continue;
                }
                j++;
            }
            i++;
        }
        list1 = getPX(images[1]);
        list2 = getPX(images[0]);
        i = 0;
        j = 0;
        for (String[] strings : list1) {
            if ((i + 1) == list1.length) {
                continue;
            }
            for (int m = 0; m < strings.length; m++) {
                try {
                    String[] value1 = list1[i][j].toString().split(",");
                    String[] value2 = list2[i][j].toString().split(",");
                    int k = 0;
                    for (int n = 0; n < value2.length; n++) {
                        if (Math.abs(Integer.parseInt(value1[k]) - Integer.parseInt(value2[k])) < 5) {
                            xiangsi++;
                        } else {
                            busi++;
                        }
                    }
                } catch (RuntimeException e) {
                    continue;
                }
                j++;
            }
            i++;
        }
        String baifen = "";
        try {
            baifen = ((Double.parseDouble(xiangsi + "") / Double.parseDouble((busi + xiangsi) + "")) + "");
            baifen = baifen.substring(baifen.indexOf(".") + 1, baifen.indexOf(".") + 3);
        } catch (Exception e) {
            baifen = "0";
        }
        if (baifen.length() <= 0) {
            baifen = "0";
        }
        if (busi == 0) {
            baifen = "100";
        }
        System.out.println(imgPath1 + "\t" + " PK " + imgPath2 + "\t" + "相似像素数量:" + "\t" + xiangsi + "\t" + "不相似像素数量:" + "\t" + busi + "\t" + "相似率:" + "\t" + Integer.parseInt(baifen) + "%");
    }

    public static void main(String[] args) {
        //(数据类型)(最小值+Math.random()*(最大值-最小值+1))
        for (int i = 18; i <= 21; i++) {

            BMPLoader.compareImage("G:/oss/pk/" + 18 + ".jpg", "G:/oss/pk/" + i + ".jpg");
        }
    }
}

BMPLoader

2/3  图片对比以及结果

package com.aliyun.picture.demo;

/**
 * 比较两张图片的相似度
 *
 * @BelongsProject: maven-demo
 * @BelongsPackage: com.aliyun.picture.demo
 * @Author: Guoyh
 * @CreateTime: 2018-10-12 14:12
 * @Description: 图像比对技术
 */

import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class BMPLoader {
    // 改变成二进制码
    public static String[][] getPX(String args) {
        int[] rgb = new int[3];
        File file = new File(args);
        BufferedImage bi = null;
        try {
            bi = ImageIO.read(file);
        } catch (Exception e) {
            e.printStackTrace();
        }
        int width = bi.getWidth();
        int height = bi.getHeight();
        int minx = bi.getMinX();
        int miny = bi.getMinY();
        String[][] list = new String[width][height];
        for (int i = minx; i < width; i++) {
            for (int j = miny; j < height; j++) {
                int pixel = bi.getRGB(i, j);
                rgb[0] = (pixel & 0xff0000) >> 16;
                rgb[1] = (pixel & 0xff00) >> 8;
                rgb[2] = (pixel & 0xff);
                list[i][j] = rgb[0] + "," + rgb[1] + "," + rgb[2];
            }
        }
        return list;
    }

    public static void compareImage(String imgPath1, String imgPath2) {
        String[] images = {imgPath1, imgPath2};
        if (images.length == 0) {
            System.out.println("Usage >java BMPLoader ImageFile.bmp");
            System.exit(0);
        }
        // 分析图片相似度 begin
        String[][] list1 = getPX(images[0]);
        String[][] list2 = getPX(images[1]);
        int xiangsi = 0;
        int busi = 0;
        int i = 0, j = 0;
        for (String[] strings : list1) {
            if ((i + 1) == list1.length) {
                continue;
            }
            for (int m = 0; m < strings.length; m++) {
                try {
                    String[] value1 = list1[i][j].toString().split(",");
                    String[] value2 = list2[i][j].toString().split(",");
                    int k = 0;
                    for (int n = 0; n < value2.length; n++) {
                        if (Math.abs(Integer.parseInt(value1[k]) - Integer.parseInt(value2[k])) < 5) {
                            xiangsi++;
                        } else {
                            busi++;
                        }
                    }
                } catch (RuntimeException e) {
                    continue;
                }
                j++;
            }
            i++;
        }
        list1 = getPX(images[1]);
        list2 = getPX(images[0]);
        i = 0;
        j = 0;
        for (String[] strings : list1) {
            if ((i + 1) == list1.length) {
                continue;
            }
            for (int m = 0; m < strings.length; m++) {
                try {
                    String[] value1 = list1[i][j].toString().split(",");
                    String[] value2 = list2[i][j].toString().split(",");
                    int k = 0;
                    for (int n = 0; n < value2.length; n++) {
                        if (Math.abs(Integer.parseInt(value1[k]) - Integer.parseInt(value2[k])) < 5) {
                            xiangsi++;
                        } else {
                            busi++;
                        }
                    }
                } catch (RuntimeException e) {
                    continue;
                }
                j++;
            }
            i++;
        }
        String baifen = "";
        try {
            baifen = ((Double.parseDouble(xiangsi + "") / Double.parseDouble((busi + xiangsi) + "")) + "");
            baifen = baifen.substring(baifen.indexOf(".") + 1, baifen.indexOf(".") + 3);
        } catch (Exception e) {
            baifen = "0";
        }
        if (baifen.length() <= 0) {
            baifen = "0";
        }
        if (busi == 0) {
            baifen = "100";
        }
        System.out.println(imgPath1 + "\t" + " PK " + imgPath2 + "\t" + "相似像素数量:" + "\t" + xiangsi + "\t" + "不相似像素数量:" + "\t" + busi + "\t" + "相似率:" + "\t" + Integer.parseInt(baifen) + "%");
    }

    public static void main(String[] args) {
        //(数据类型)(最小值+Math.random()*(最大值-最小值+1))
        for (int i = 2; i <= 3; i++) {

            BMPLoader.compareImage("G:/oss/pk/" + 2 + ".jpg", "G:/oss/pk/" + i + ".jpg");
        }
    }
}

BMPLoader

四、

18/19/20/21 图片对比以及结果

package com.aliyun.picture.demo;

/**
 * @BelongsProject: maven-demo
 * @BelongsPackage: com.aliyun.picture.demo
 * @Author: Guoyh
 * @CreateTime: 2018-10-12 15:05
 * @Description: 感知哈希算法(均值哈希算法)比较两图的相似性
 */

import javax.imageio.ImageIO;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.util.Arrays;
import java.io.File;

public final class FingerPrint {
    /**
     * 图像指纹的尺寸,将图像resize到指定的尺寸,来计算哈希数组
     */
    private static final int HASH_SIZE = 16;
    /**
     * 保存图像指纹的二值化矩阵
     */
    private final byte[] binaryzationMatrix;

    public FingerPrint(byte[] hashValue) {
        if (hashValue.length != HASH_SIZE * HASH_SIZE) {
            throw new IllegalArgumentException(String.format("length of hashValue must be %d", HASH_SIZE * HASH_SIZE));
        }
        this.binaryzationMatrix = hashValue;
    }

    public FingerPrint(String hashValue) {
        this(toBytes(hashValue));
    }

    public FingerPrint(BufferedImage src) {
        this(hashValue(src));
    }

    private static byte[] hashValue(BufferedImage src) {
        BufferedImage hashImage = resize(src, HASH_SIZE, HASH_SIZE);
        byte[] matrixGray = (byte[]) toGray(hashImage).getData().getDataElements(0, 0, HASH_SIZE, HASH_SIZE, null);
        return binaryzation(matrixGray);
    }

    /**
     * 从压缩格式指纹创建{@link FingerPrint}对象
     *
     * @param compactValue
     * @return
     */
    public static FingerPrint createFromCompact(byte[] compactValue) {
        return new FingerPrint(uncompact(compactValue));
    }

    public static boolean validHashValue(byte[] hashValue) {
        if (hashValue.length != HASH_SIZE) {
            return false;
        }
        for (byte b : hashValue) {
            {
                if (0 != b && 1 != b) {
                    return false;
                }
            }
        }
        return true;
    }

    public static boolean validHashValue(String hashValue) {
        if (hashValue.length() != HASH_SIZE) {
            return false;
        }
        for (int i = 0; i < hashValue.length(); ++i) {
            if (‘0‘ != hashValue.charAt(i) && ‘1‘ != hashValue.charAt(i)) {
                return false;
            }
        }
        return true;
    }

    public byte[] compact() {
        return compact(binaryzationMatrix);
    }

    /**
     * 指纹数据按位压缩
     *
     * @param hashValue
     * @return
     */
    private static byte[] compact(byte[] hashValue) {
        byte[] result = new byte[(hashValue.length + 7) >> 3];
        byte b = 0;
        for (int i = 0; i < hashValue.length; ++i) {
            if (0 == (i & 7)) {
                b = 0;
            }
            if (1 == hashValue[i]) {
                b |= 1 << (i & 7);
            } else if (hashValue[i] != 0) {
                throw new IllegalArgumentException("invalid hashValue,every element must be 0 or 1");
            }
            if (7 == (i & 7) || i == hashValue.length - 1) {
                result[i >> 3] = b;
            }
        }
        return result;
    }

    /**
     * 压缩格式的指纹解压缩
     *
     * @param compactValue
     * @return
     */
    private static byte[] uncompact(byte[] compactValue) {
        byte[] result = new byte[compactValue.length << 3];
        for (int i = 0; i < result.length; ++i) {
            if ((compactValue[i >> 3] & (1 << (i & 7))) == 0) {
                result[i] = 0;
            } else {
                result[i] = 1;
            }
        }
        return result;
    }

    /**
     * 字符串类型的指纹数据转为字节数组
     *
     * @param hashValue
     * @return
     */
    private static byte[] toBytes(String hashValue) {
        hashValue = hashValue.replaceAll("\\s", "");
        byte[] result = new byte[hashValue.length()];
        for (int i = 0; i < result.length; ++i) {
            char c = hashValue.charAt(i);
            if (‘0‘ == c) {
                result[i] = 0;
            } else if (‘1‘ == c) {
                result[i] = 1;
            } else {
                throw new IllegalArgumentException("invalid hashValue String");
            }
        }
        return result;
    }

    /**
     * 缩放图像到指定尺寸
     *
     * @param src
     * @param width
     * @param height
     * @return
     */
    private static BufferedImage resize(Image src, int width, int height) {
        BufferedImage result = new BufferedImage(width, height,
                BufferedImage.TYPE_3BYTE_BGR);
        Graphics g = result.getGraphics();
        try {
            g.drawImage(src.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
        } finally {
            g.dispose();
        }
        return result;
    }

    /**
     * 计算均值
     *
     * @param src
     * @return
     */
    private static int mean(byte[] src) {
        long sum = 0;
        // 将数组元素转为无符号整数
        for (byte b : src) {
            sum += (long) b & 0xff;
        }
        return (int) (Math.round((float) sum / src.length));
    }

    /**
     * 二值化处理
     *
     * @param src
     * @return
     */
    private static byte[] binaryzation(byte[] src) {
        byte[] dst = src.clone();
        int mean = mean(src);
        for (int i = 0; i < dst.length; ++i) {
            // 将数组元素转为无符号整数再比较
            dst[i] = (byte) (((int) dst[i] & 0xff) >= mean ? 1 : 0);
        }
        return dst;

    }

    /**
     * 转灰度图像
     *
     * @param src
     * @return
     */
    private static BufferedImage toGray(BufferedImage src) {
        if (src.getType() == BufferedImage.TYPE_BYTE_GRAY) {
            return src;
        } else {
            // 图像转灰
            BufferedImage grayImage = new BufferedImage(src.getWidth(), src.getHeight(),
                    BufferedImage.TYPE_BYTE_GRAY);
            new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(src, grayImage);
            return grayImage;
        }
    }

    @Override
    public String toString() {
        return toString(true);
    }

    /**
     * @param multiLine 是否分行
     * @return
     */
    public String toString(boolean multiLine) {
        StringBuffer buffer = new StringBuffer();
        int count = 0;
        for (byte b : this.binaryzationMatrix) {
            buffer.append(0 == b ? ‘0‘ : ‘1‘);
            if (multiLine && ++count % HASH_SIZE == 0) {
                buffer.append(‘\n‘);
            }
        }
        return buffer.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof FingerPrint) {
            return Arrays.equals(this.binaryzationMatrix, ((FingerPrint) obj).binaryzationMatrix);
        } else {
            return super.equals(obj);
        }
    }

    /**
     * 与指定的压缩格式指纹比较相似度
     *
     * @param compactValue
     * @return
     * @see #compare(FingerPrint)
     */
    public float compareCompact(byte[] compactValue) {
        return compare(createFromCompact(compactValue));
    }

    /**
     * @param hashValue
     * @return
     * @see #compare(FingerPrint)
     */
    public float compare(String hashValue) {
        return compare(new FingerPrint(hashValue));
    }

    /**
     * 与指定的指纹比较相似度
     *
     * @param hashValue
     * @return
     * @see #compare(FingerPrint)
     */
    public float compare(byte[] hashValue) {
        return compare(new FingerPrint(hashValue));
    }

    /**
     * 与指定图像比较相似度
     *
     * @param image2
     * @return
     * @see #compare(FingerPrint)
     */
    public float compare(BufferedImage image2) {
        return compare(new FingerPrint(image2));
    }

    /**
     * 比较指纹相似度
     *
     * @param src
     * @return
     * @see #compare(byte[], byte[])
     */
    public float compare(FingerPrint src) {
        if (src.binaryzationMatrix.length != this.binaryzationMatrix.length) {
            throw new IllegalArgumentException("length of hashValue is mismatch");
        }
        return compare(binaryzationMatrix, src.binaryzationMatrix);
    }

    /**
     * 判断两个数组相似度,数组长度必须一致否则抛出异常
     *
     * @param f1
     * @param f2
     * @return 返回相似度(0.0 ~ 1.0)
     */
    private static float compare(byte[] f1, byte[] f2) {
        if (f1.length != f2.length) {
            throw new IllegalArgumentException("mismatch FingerPrint length");
        }
        int sameCount = 0;
        for (int i = 0; i < f1.length; ++i) {
            {
                if (f1[i] == f2[i]) {
                    ++sameCount;
                }
            }
        }
        return (float) sameCount / f1.length;
    }

    public static float compareCompact(byte[] f1, byte[] f2) {
        return compare(uncompact(f1), uncompact(f2));
    }

    public static float compare(BufferedImage image1, BufferedImage image2) {
        return new FingerPrint(image1).compare(new FingerPrint(image2));
    }

    /**
     * @param args
     * @return void
     * @author Guoyh
     * @date 2018/10/12 15:07
     */
    public static void main(String[] args) throws Exception {
        for (int i = 18; i <= 21; i++) {
            FingerPrint fp1 = new FingerPrint(ImageIO.read(new File("G:/oss/pk/" + 18 + ".jpg")));
            FingerPrint fp2 = new FingerPrint(ImageIO.read(new File("G:/oss/pk/" + i + ".jpg")));
            System.out.println("\t" + "\t"+"G:/oss/pk/" + 18 + ".jpg"+"\t"+"与"+"\t"+"G:/oss/pk/" + i + ".jpg"+"\t"+"两张图片的相似度为:" + fp1.compare(fp2) * 100 + "%");
        }
    }
}

FingerPrint

2/3  图片对比以及结果

package com.aliyun.picture.demo;

/**
 * @BelongsProject: maven-demo
 * @BelongsPackage: com.aliyun.picture.demo
 * @Author: Guoyh
 * @CreateTime: 2018-10-12 15:05
 * @Description: 感知哈希算法(均值哈希算法)比较两图的相似性
 */

import javax.imageio.ImageIO;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.util.Arrays;
import java.io.File;

public final class FingerPrint {
    /**
     * 图像指纹的尺寸,将图像resize到指定的尺寸,来计算哈希数组
     */
    private static final int HASH_SIZE = 16;
    /**
     * 保存图像指纹的二值化矩阵
     */
    private final byte[] binaryzationMatrix;

    public FingerPrint(byte[] hashValue) {
        if (hashValue.length != HASH_SIZE * HASH_SIZE) {
            throw new IllegalArgumentException(String.format("length of hashValue must be %d", HASH_SIZE * HASH_SIZE));
        }
        this.binaryzationMatrix = hashValue;
    }

    public FingerPrint(String hashValue) {
        this(toBytes(hashValue));
    }

    public FingerPrint(BufferedImage src) {
        this(hashValue(src));
    }

    private static byte[] hashValue(BufferedImage src) {
        BufferedImage hashImage = resize(src, HASH_SIZE, HASH_SIZE);
        byte[] matrixGray = (byte[]) toGray(hashImage).getData().getDataElements(0, 0, HASH_SIZE, HASH_SIZE, null);
        return binaryzation(matrixGray);
    }

    /**
     * 从压缩格式指纹创建{@link FingerPrint}对象
     *
     * @param compactValue
     * @return
     */
    public static FingerPrint createFromCompact(byte[] compactValue) {
        return new FingerPrint(uncompact(compactValue));
    }

    public static boolean validHashValue(byte[] hashValue) {
        if (hashValue.length != HASH_SIZE) {
            return false;
        }
        for (byte b : hashValue) {
            {
                if (0 != b && 1 != b) {
                    return false;
                }
            }
        }
        return true;
    }

    public static boolean validHashValue(String hashValue) {
        if (hashValue.length() != HASH_SIZE) {
            return false;
        }
        for (int i = 0; i < hashValue.length(); ++i) {
            if (‘0‘ != hashValue.charAt(i) && ‘1‘ != hashValue.charAt(i)) {
                return false;
            }
        }
        return true;
    }

    public byte[] compact() {
        return compact(binaryzationMatrix);
    }

    /**
     * 指纹数据按位压缩
     *
     * @param hashValue
     * @return
     */
    private static byte[] compact(byte[] hashValue) {
        byte[] result = new byte[(hashValue.length + 7) >> 3];
        byte b = 0;
        for (int i = 0; i < hashValue.length; ++i) {
            if (0 == (i & 7)) {
                b = 0;
            }
            if (1 == hashValue[i]) {
                b |= 1 << (i & 7);
            } else if (hashValue[i] != 0) {
                throw new IllegalArgumentException("invalid hashValue,every element must be 0 or 1");
            }
            if (7 == (i & 7) || i == hashValue.length - 1) {
                result[i >> 3] = b;
            }
        }
        return result;
    }

    /**
     * 压缩格式的指纹解压缩
     *
     * @param compactValue
     * @return
     */
    private static byte[] uncompact(byte[] compactValue) {
        byte[] result = new byte[compactValue.length << 3];
        for (int i = 0; i < result.length; ++i) {
            if ((compactValue[i >> 3] & (1 << (i & 7))) == 0) {
                result[i] = 0;
            } else {
                result[i] = 1;
            }
        }
        return result;
    }

    /**
     * 字符串类型的指纹数据转为字节数组
     *
     * @param hashValue
     * @return
     */
    private static byte[] toBytes(String hashValue) {
        hashValue = hashValue.replaceAll("\\s", "");
        byte[] result = new byte[hashValue.length()];
        for (int i = 0; i < result.length; ++i) {
            char c = hashValue.charAt(i);
            if (‘0‘ == c) {
                result[i] = 0;
            } else if (‘1‘ == c) {
                result[i] = 1;
            } else {
                throw new IllegalArgumentException("invalid hashValue String");
            }
        }
        return result;
    }

    /**
     * 缩放图像到指定尺寸
     *
     * @param src
     * @param width
     * @param height
     * @return
     */
    private static BufferedImage resize(Image src, int width, int height) {
        BufferedImage result = new BufferedImage(width, height,
                BufferedImage.TYPE_3BYTE_BGR);
        Graphics g = result.getGraphics();
        try {
            g.drawImage(src.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
        } finally {
            g.dispose();
        }
        return result;
    }

    /**
     * 计算均值
     *
     * @param src
     * @return
     */
    private static int mean(byte[] src) {
        long sum = 0;
        // 将数组元素转为无符号整数
        for (byte b : src) {
            sum += (long) b & 0xff;
        }
        return (int) (Math.round((float) sum / src.length));
    }

    /**
     * 二值化处理
     *
     * @param src
     * @return
     */
    private static byte[] binaryzation(byte[] src) {
        byte[] dst = src.clone();
        int mean = mean(src);
        for (int i = 0; i < dst.length; ++i) {
            // 将数组元素转为无符号整数再比较
            dst[i] = (byte) (((int) dst[i] & 0xff) >= mean ? 1 : 0);
        }
        return dst;

    }

    /**
     * 转灰度图像
     *
     * @param src
     * @return
     */
    private static BufferedImage toGray(BufferedImage src) {
        if (src.getType() == BufferedImage.TYPE_BYTE_GRAY) {
            return src;
        } else {
            // 图像转灰
            BufferedImage grayImage = new BufferedImage(src.getWidth(), src.getHeight(),
                    BufferedImage.TYPE_BYTE_GRAY);
            new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(src, grayImage);
            return grayImage;
        }
    }

    @Override
    public String toString() {
        return toString(true);
    }

    /**
     * @param multiLine 是否分行
     * @return
     */
    public String toString(boolean multiLine) {
        StringBuffer buffer = new StringBuffer();
        int count = 0;
        for (byte b : this.binaryzationMatrix) {
            buffer.append(0 == b ? ‘0‘ : ‘1‘);
            if (multiLine && ++count % HASH_SIZE == 0) {
                buffer.append(‘\n‘);
            }
        }
        return buffer.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof FingerPrint) {
            return Arrays.equals(this.binaryzationMatrix, ((FingerPrint) obj).binaryzationMatrix);
        } else {
            return super.equals(obj);
        }
    }

    /**
     * 与指定的压缩格式指纹比较相似度
     *
     * @param compactValue
     * @return
     * @see #compare(FingerPrint)
     */
    public float compareCompact(byte[] compactValue) {
        return compare(createFromCompact(compactValue));
    }

    /**
     * @param hashValue
     * @return
     * @see #compare(FingerPrint)
     */
    public float compare(String hashValue) {
        return compare(new FingerPrint(hashValue));
    }

    /**
     * 与指定的指纹比较相似度
     *
     * @param hashValue
     * @return
     * @see #compare(FingerPrint)
     */
    public float compare(byte[] hashValue) {
        return compare(new FingerPrint(hashValue));
    }

    /**
     * 与指定图像比较相似度
     *
     * @param image2
     * @return
     * @see #compare(FingerPrint)
     */
    public float compare(BufferedImage image2) {
        return compare(new FingerPrint(image2));
    }

    /**
     * 比较指纹相似度
     *
     * @param src
     * @return
     * @see #compare(byte[], byte[])
     */
    public float compare(FingerPrint src) {
        if (src.binaryzationMatrix.length != this.binaryzationMatrix.length) {
            throw new IllegalArgumentException("length of hashValue is mismatch");
        }
        return compare(binaryzationMatrix, src.binaryzationMatrix);
    }

    /**
     * 判断两个数组相似度,数组长度必须一致否则抛出异常
     *
     * @param f1
     * @param f2
     * @return 返回相似度(0.0 ~ 1.0)
     */
    private static float compare(byte[] f1, byte[] f2) {
        if (f1.length != f2.length) {
            throw new IllegalArgumentException("mismatch FingerPrint length");
        }
        int sameCount = 0;
        for (int i = 0; i < f1.length; ++i) {
            {
                if (f1[i] == f2[i]) {
                    ++sameCount;
                }
            }
        }
        return (float) sameCount / f1.length;
    }

    public static float compareCompact(byte[] f1, byte[] f2) {
        return compare(uncompact(f1), uncompact(f2));
    }

    public static float compare(BufferedImage image1, BufferedImage image2) {
        return new FingerPrint(image1).compare(new FingerPrint(image2));
    }

    /**
     * @param args
     * @return void
     * @author Guoyh
     * @date 2018/10/12 15:07
     */
    public static void main(String[] args) throws Exception {
        for (int i = 2; i <= 3; i++) {
            FingerPrint fp1 = new FingerPrint(ImageIO.read(new File("G:/oss/pk/" + 2 + ".jpg")));
            FingerPrint fp2 = new FingerPrint(ImageIO.read(new File("G:/oss/pk/" + i + ".jpg")));
            System.out.println("\t" + "\t"+"G:/oss/pk/" + 2 + ".jpg"+"\t"+"与"+"\t"+"G:/oss/pk/" + i + ".jpg"+"\t"+"两张图片的相似度为:" + fp1.compare(fp2) * 100 + "%");
        }
    }
}

FingerPrint

参考:

https://blog.csdn.net/zhuason/article/details/78933250

https://blog.csdn.net/qq_37320823/article/details/80538933

https://blog.csdn.net/10km/article/details/70949272

https://blog.csdn.net/gaoxiang24/article/details/79214834

原文地址:https://www.cnblogs.com/angelye/p/9779290.html

时间: 2024-10-09 07:56:10

列举一些算法对照片、图像进行相似度对比分析比较的相关文章

视觉SLAM之RANSAC算法用于消除图像误匹配的原理

在基于特征点的视觉SLAM中,通常情况下,在特征匹配过程中往往会存在误匹配信息,使得计算获取的位姿精度低,易产生位姿估计失败的问题,因此,剔除这些错配点有很大的必要性.常会用到RANSAC算法进行消除两两匹配图像的误匹配点,如果只停留在应用的层面上很简单,直接调用opencv函数就行,看到效果时,感觉好神奇,到底怎么实现的啊,以前一直也没弄太明白,与图像结合的博客也比较少,在查阅了一些资料后,笔者似乎明白了一点,希望笔者的总结会对您的理解有帮助. 首先先介绍一下RANSAC算法(RANdom S

图像水波纹特效原理分析和实现

前段时间注意到一些软件上有图像的水波纹特效,似乎很炫,想深入了解下该效果的具体原理与实现方式,上网搜了不少些资料,都讲得不清不楚,没办法只能靠自己了.花了一整个下午先去复习了高中物理的波的知识,试着自己来推导原理并实现了下.下面的推导是我根据一些资料以及自己分析出的,如有错误,望请指出.上张效果图先: 基本原理 水波效果反映到图像上,则是像素点的偏移.因此对图像的处理就如同图像缩放一样,对于输出图像的每个点,计算其对应于原始输入图像的像素点,通过插值的方法即可计算其颜色值. 先说下关于水波的基础

将图像旋转90度

题目:给定一幅由N*N矩阵表示的图像,其中每个像素的 大小为4字节,编写一个方法,将图像旋转90度.不占用额外内存空间能否做到? 那么,该如何交换这四条边?一种做法是把上面复制到一个数组中,然后将左边移到上边,下边移到到左边,等等.这需要占用O(N)内存空间.但实际上没有必要, 更好的做法是按索引一个一个进行交换.具体做法如下: for i = 0 to n temp = top[i]; top[i] = left[i]; left[i] = bottom[i]; bottom[i] = rig

图像清晰度的评价及分析

图像清晰度的评价及分析 2016年07月28日 17:54:22 clxiaoclxiao 阅读数:17963更多 个人分类: opencv 在无参考图像的质量评价中,图像的清晰度是衡量图像质量优劣的重要指标,它能够较好的与人的主观感受相对应,图像的清晰度不高表现出图像的模糊.本文针对无参考图像质量评价应用,对目前几种较为常用的.具有代表性清晰度算法进行讨论分析,为实际应用中选择清晰度算法提供依据. (1)Brenner 梯度函数 Brenner梯度函数是最简单的梯度评价函数,它只是简单的计算相

集合相似度对比的两种计算算法

相似度对比的两种计算算法:Jaccard similarity相似性系数和Ochiai coefficient落和系数 Jaccard coefficient:A,B分别代表符合某种条件的集合:两个集合交集的大小/两个集合并集的大小,交集=并集意味着2个集合完全重合. Ochiai coefficient:A,B分别代表符合某种条件的集合:两个集合的交集大小/两个集合大小的几何平均值.是余弦相似性的一种形式. 相关参考链接:http://en.wikipedia.org/wiki/Jaccard

最短路径算法的命令式、函数式版本对比分析

C版本(来自 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)) 1 /*************************************** 2 * About: 有向图的Dijkstra算法实现 3 * Author: Tanky Woo 4 * Blog: www.WuTianQi.com 5 ***************************************/ 6 7 #include <iostream> 8 using namespace

[LeetCode][14]Longest Common Prefix解析 两种算法和底层源码的深入对比-Java实现

Q: Write a function to find the longest common prefix string amongst an array of strings. A: 这题的大概意思就是说给你一组字符串找出其中最长的哪个通用的前缀出来.这个东西不难找,但是如何找的又快又好不简单.其实这题本来就是easy题,但是却让我联想到了<数据结构与算法分析>上的一道题目,那道题目是这样的: 给一个8900个字的字典,从中间找出类似abc.bbc.abb这样单词中只有一个字母不同的单词进行

OpenCV进行图像相似度对比的几种办法

对计算图像相似度的方法,本文做了如下总结,主要有三种办法: 1.PSNR(Peak Signal to Noise Ratio)峰值信噪比,一种全参考的图像质量评价指标. 简介: http://www.cnblogs.com/vincent2012/archive/2012/10/13/2723152.html PSNR是最普遍和使用最为广泛的一种图像客观评价指标,然而它是基于对应像素点间的误差,即基于误差敏感的图像质量评价.由于并未考虑到人眼的视觉特性(人眼对空间频率较低的对比差异敏感度较高,

浅识——后向投影成像算法(BackProjection,BP) 【MATLAB代码分析】

一.什么是BP算法 由来:BP算法最初是McCorkle受计算机层析技术的启发推导而来,所谓的计算机层析:就是CT(Computer Tomograpy),这是在医院中再普遍不过的技术了. BP算法的原理:BP算法参考了"时延-叠加"的思想,在雷达应用中,其对雷达接收天线接收到的回波信号进行距离向匹配率,获取回波数据中包含的相幅信息,再通过IFFT进行逆傅里叶变换,获取收发天线组合的时延,最后累积信号相干相加得到目标函数. 1.1  BP算法 回波信号与参与电信号进行匹配滤波后,获得的