zoukankan      html  css  js  c++  java
  • 列举一些算法对照片、图像进行相似度对比分析比较

    首先: 图片如下

               

                                           18.jpg                                                                                    19.jpg

               

                                           20.jpg                                                                                    21.jpg

                            2.jpg

                            3.jpg

    算法以及对比结果

    一、获取灰度像素的比较数组、获取两个图的汉明距离、通过汉明距离计算相似度,取值范围 [0.0, 1.0]

    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("	" + "	"+"G:/oss/pk/" + 18 + ".jpg"+"	"+"与"+"	"+"G:/oss/pk/" + i + ".jpg"+"	"+"两张图片的相似度为:" + 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("	" + "	"+"G:/oss/pk/" + 2 + ".jpg"+"	"+"与"+"	"+"G:/oss/pk/" + i + ".jpg"+"	"+"两张图片的相似度为:" + 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("	"+"G:/oss/pk/" + 18 + ".jpg"+"	"+"与"+"	"+"G:/oss/pk/" + i + ".jpg"+"	"+"两张图片的相似度为:" + 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("	"+"G:/oss/pk/" + 2 + ".jpg"+"	"+"与"+"	"+"G:/oss/pk/" + i + ".jpg"+"	"+"两张图片的相似度为:" + 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 + "	" + " PK " + imgPath2 + "	" + "相似像素数量:" + "	" + xiangsi + "	" + "不相似像素数量:" + "	" + busi + "	" + "相似率:" + "	" + 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 + "	" + " PK " + imgPath2 + "	" + "相似像素数量:" + "	" + xiangsi + "	" + "不相似像素数量:" + "	" + busi + "	" + "相似率:" + "	" + 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('
    ');
                }
            }
            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("	" + "	"+"G:/oss/pk/" + 18 + ".jpg"+"	"+"与"+"	"+"G:/oss/pk/" + i + ".jpg"+"	"+"两张图片的相似度为:" + 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('
    ');
                }
            }
            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("	" + "	"+"G:/oss/pk/" + 2 + ".jpg"+"	"+"与"+"	"+"G:/oss/pk/" + i + ".jpg"+"	"+"两张图片的相似度为:" + fp1.compare(fp2) * 100 + "%");
            }
        }
    }
    FingerPrint

    通过分析比较:算法方案1、2、4比较适用于图像相似性比较

           算法方案 3 比较适用于图像“找茬”比较

    参考:

    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

  • 相关阅读:
    python join()阻塞的用法
    python远程批量执行命令
    python多进程,以及进程池并发
    python生产者消费者模型
    python如何保证多个线程同时修改共享对象时不出错!
    python多线程,多进程
    python paramiko模拟ssh登录,实现sftp上传或者下载文件
    python初识1
    验证码的作用和实现原理
    网络应用软件结构-----CS与BS结构(网络基本知识小结)
  • 原文地址:https://www.cnblogs.com/angelye/p/9779290.html
Copyright © 2011-2022 走看看