簡單說兩句:
筆主利用這個七夕前后兩天的寂寞時光,用JAVA磨了一個簡單的圖像相似度計算小程序,就在剛才終於糾結完畢,輸出了1.0版本,小小的滿足了一下可憐的虛榮心..→_→
使用最簡單最基礎的感知哈希算法,算法原理戳這里,絕對比筆主講的要好:
http://www.ruanyifeng.com/blog/2011/07/principle_of_similar_image_search.html
UI設計圖:
實際運行效果圖:
關鍵算法:
1 // 全流程 2 public static void main(String[] args) throws IOException { 3 // 獲取圖像 4 File imageFile = new File("c:/1.jpg"); 5 Image image = ImageIO.read(imageFile); 6 // 轉換至灰度 7 image = toGrayscale(image); 8 // 縮小成32x32的縮略圖 9 image = scale(image); 10 // 獲取灰度像素數組 11 int[] pixels = getPixels(image); 12 // 獲取平均灰度顏色 13 int averageColor = getAverageOfPixelArray(pixels); 14 // 獲取灰度像素的比較數組(即圖像指紋序列) 15 pixels = getPixelDeviateWeightsArray(pixels, averageColor); 16 // 獲取兩個圖的漢明距離(假設另一個圖也已經按上面步驟得到灰度比較數組) 17 int hammingDistance = getHammingDistance(pixels, pixels); 18 // 通過漢明距離計算相似度,取值范圍 [0.0, 1.0] 19 double similarity = calSimilarity(hammingDistance); 20 } 21 22 // 將任意Image類型圖像轉換為BufferedImage類型,方便后續操作 23 public static BufferedImage convertToBufferedFrom(Image srcImage) { 24 BufferedImage bufferedImage = new BufferedImage(srcImage.getWidth(null), 25 srcImage.getHeight(null), BufferedImage.TYPE_INT_ARGB); 26 Graphics2D g = bufferedImage.createGraphics(); 27 g.drawImage(srcImage, null, null); 28 g.dispose(); 29 return bufferedImage; 30 } 31 32 // 轉換至灰度圖 33 public static BufferedImage toGrayscale(Image image) { 34 BufferedImage sourceBuffered = convertToBufferedFrom(image); 35 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); 36 ColorConvertOp op = new ColorConvertOp(cs, null); 37 BufferedImage grayBuffered = op.filter(sourceBuffered, null); 38 return grayBuffered; 39 } 40 41 // 縮放至32x32像素縮略圖 42 public static Image scale(Image image) { 43 image = image.getScaledInstance(32, 32, Image.SCALE_SMOOTH); 44 return image; 45 } 46 47 // 獲取像素數組 48 public static int[] getPixels(Image image) { 49 int width = image.getWidth(null); 50 int height = image.getHeight(null); 51 int[] pixels = convertToBufferedFrom(image).getRGB(0, 0, width, height, 52 null, 0, width); 53 return pixels; 54 } 55 56 // 獲取灰度圖的平均像素顏色值 57 public static int getAverageOfPixelArray(int[] pixels) { 58 Color color; 59 long sumRed = 0; 60 for (int i = 0; i < pixels.length; i++) { 61 color = new Color(pixels[i], true); 62 sumRed += color.getRed(); 63 } 64 int averageRed = (int) (sumRed / pixels.length); 65 return averageRed; 66 } 67 68 // 獲取灰度圖的像素比較數組(平均值的離差) 69 public static int[] getPixelDeviateWeightsArray(int[] pixels,final int averageColor) { 70 Color color; 71 int[] dest = new int[pixels.length]; 72 for (int i = 0; i < pixels.length; i++) { 73 color = new Color(pixels[i], true); 74 dest[i] = color.getRed() - averageColor > 0 ? 1 : 0; 75 } 76 return dest; 77 } 78 79 // 獲取兩個縮略圖的平均像素比較數組的漢明距離(距離越大差異越大) 80 public static int getHammingDistance(int[] a, int[] b) { 81 int sum = 0; 82 for (int i = 0; i < a.length; i++) { 83 sum += a[i] == b[i] ? 0 : 1; 84 } 85 return sum; 86 } 87 88 // 通過漢明距離計算相似度 89 public static double calSimilarity(int hammingDistance){ 90 int length = 32*32; 91 double similarity = (length - hammingDistance) / (double) length; 92 93 // 使用指數曲線調整相似度結果 94 similarity = java.lang.Math.pow(similarity, 2); 95 return similarity; 96 }
UI部分的代碼就不公開了,成品下載地址如下(使用JDK1.5):
http://download.csdn.net/detail/u011088871/7711833
解壓后打開 run.bat 批處理文件就可以跑起來了 :)