每張圖片均可以生成顏色分佈的直方圖(color histogram)。若是兩張圖片的直方圖很接近,就能夠認爲它們很類似。java
任何一種顏色都是由紅綠藍三原色(RGB)構成的,因此上圖共有4張直方圖(三原色直方圖 + 最後合成的直方圖)。函數
若是每種原色均可以取256個值,那麼整個顏色空間共有1600萬種顏色(256的三次方)。針對這1600萬種顏色比較直方圖,計算量實在太大了,所以須要採用簡化方法。能夠將0~255分紅四個區:0~63爲第0區,64~127爲第1區,128~191爲第2區,192~255爲第3區。這意味着紅綠藍分別有4個區,總共能夠構成64種組合(4的3次方)。this
任何一種顏色必然屬於這64種組合中的一種,這樣就能夠統計每一種組合包含的像素數量。code
上圖是某張圖片的顏色分佈表,將表中最後一欄提取出來,組成一個64維向量(7414, 230, 0, 0, 8, …, 109, 0, 0, 3415, 53929)。這個向量就是這張圖片的特徵值或者叫」指紋」。圖片
因而,尋找類似圖片就變成了找出與其最類似的向量。這裏用皮爾遜相關係數算出。get
下面貼出代碼it
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。其性質以下:io
當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爲高度線性相關。class
調用代碼以下import
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); } }
你能夠用下面幾張圖片試試哦:)