JAVA图片相似度判断(1)颜色分布法

原创
2017/12/12 14:21
阅读数 1W

每张图片都可以生成颜色分布的直方图(color histogram)。如果两张图片的直方图很接近,就可以认为它们很相似。

任何一种颜色都是由红绿蓝三原色(RGB)构成的,所以上图共有4张直方图(三原色直方图 + 最后合成的直方图)。

如果每种原色都可以取256个值,那么整个颜色空间共有1600万种颜色(256的三次方)。针对这1600万种颜色比较直方图,计算量实在太大了,因此需要采用简化方法。可以将0~255分成四个区:0~63为第0区,64~127为第1区,128~191为第2区,192~255为第3区。这意味着红绿蓝分别有4个区,总共可以构成64种组合(4的3次方)。

任何一种颜色必然属于这64种组合中的一种,这样就可以统计每一种组合包含的像素数量。

上图是某张图片的颜色分布表,将表中最后一栏提取出来,组成一个64维向量(7414, 230, 0, 0, 8, …, 109, 0, 0, 3415, 53929)。这个向量就是这张图片的特征值或者叫”指纹”。

于是,寻找相似图片就变成了找出与其最相似的向量。这里用皮尔逊相关系数算出。

下面贴出代码

package com;

import java.util.Map;
import java.util.HashMap;
import java.awt.image.BufferedImage;

public class ImageColorHistogramSimilarity {

    public double colorHistogramSimilarity(BufferedImage src1, BufferedImage src2) {
        int[] array1 = this.colorHistogramSimilarity(src1);
        int[] array2 = this.colorHistogramSimilarity(src2);
        double sumX = 0.0;
        double sumY = 0.0;
        double sumX_Sq = 0.0;
        double sumY_Sq = 0.0;
        double sumXY = 0.0;
        int N = 64;
        for (int i = 0; i < 64; i++) {
            int x = array1[i];
            int y = array2[i];
            sumX += x;
            sumY += y;
            sumX_Sq += Math.pow(x, 2);
            sumY_Sq += Math.pow(y, 2);
            sumXY += x * y;
        }

        double numerator = sumXY - sumX * sumY / N;
        double denominator = Math.sqrt((sumX_Sq - sumX * sumX / N)
                * (sumY_Sq - sumY * sumY / N));

        // 分母不能为0
        if (denominator == 0) {
            return 0;
        }

        return numerator / denominator;
    }

    private String getRange(int color) {
        if (color >= 0 && color <= 63) {
            return "0";
        } else if (color >= 64 && color <= 127) {
            return "1";
        } else if (color >= 128 && color <= 191) {
            return "2";
        } else if (color >= 192 && color <= 255) {
            return "3";
        }
        return null;
    }

    public int[] colorHistogramSimilarity(BufferedImage src) {
        int width = src.getWidth();
        int height = src.getHeight();
        Map<String, Integer> imageHistogram = new HashMap<String, Integer>();
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int rgb = src.getRGB(j, i);
                int r = (rgb >> 16) & 0xff;//取出次高位(16-23)红色分量的信息
                int g = (rgb >> 8) & 0xff;//取出中位(8-15)绿色分量的信息
                int b = rgb & 0xff;//取出低位(0-7)蓝色分量的信息
                String key = this.getRange(r) + this.getRange(g) + this.getRange(b);

                Integer count = imageHistogram.get(key);
                if (count == null) {
                    imageHistogram.put(key, 1);
                } else {
                    imageHistogram.put(key, count + 1);
                }
            }
        }
        int[] result = new int[64];
        String key = "";
        int idx = 0;
        for (int r = 0; r < 4; r++) {
            for (int g = 0; g < 4; g++) {
                for (int b = 0; b < 4; b++) {
                    key = String.valueOf(r) + String.valueOf(g) + String.valueOf(b);
                    Integer count = imageHistogram.get(key);
                    if (count == null) {
                        result[idx] = 0;
                    } else {
                        result[idx] = count;
                    }
                    idx++;
                }
            }
        }
        return result;
    }
}

得到相关系数的值介于–1与+1之间,即–1≤r≤+1。其性质如下:

当r>0时,表示两变量正相关,r<0时,两变量为负相关。
当|r|=1时,表示两变量为完全线性相关,即为函数关系。
当r=0时,表示两变量间无线性相关关系。
当0<|r|<1时,表示两变量存在一定程度的线性相关。且|r|越接近1,两变量间线性关系越密切;|r|越接近于0,表示两变量的线性相关越弱。
一般可按三级划分:|r|<0.4为低度线性相关;0.4≤|r|<0.7为显著性相关;0.7≤|r|<1为高度线性相关。

调用代码如下

public class Test {


    public static void main(String[] args) throws IOException {
        BufferedImage image1 = ImageIO.read(new File("C:/timg.jpg"));
        BufferedImage image2 = ImageIO.read(new File("C:/timg4.jpg"));
        ImageColorHistogramSimilarity is = new ImageColorHistogramSimilarity();
        double rate = is.colorHistogramSimilarity(image1,image2);
        System.out.println(rate);
    }


}

你可以用下面几张图片试试哦:)

展开阅读全文
加载中

作者的其它热门文章

打赏
1
1 收藏
分享
打赏
3 评论
1 收藏
1
分享
返回顶部
顶部