旋转不变的感知哈希

时间:2022-05-04
本文章向大家介绍旋转不变的感知哈希,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
package com.imageretrieval.features;

import com.imageretrieval.utils.ImageUtil;

/**
 * 旋转不变的感知哈希<br>
 * @author VenyoWang
 *
 */
public class RHash {

	public static void main(String[] args) {
		String hash = getFeatureValue("");
		String hash1 = getFeatureValue("");
		System.out.println(hash);
		System.out.println(hash1);
		System.out.println(calculateSimilarity(hash, hash1));
	}

	public static String getFeatureValue(String imagePath) {
		// 缩小尺寸,简化色彩
		int[][] grayMatrix = getGrayPixel(imagePath, 8, 8);
		// 缩小DCT,计算平均值
		int[][] newMatrix = new int[8][8];
		double average = 0;
		for(int i = 0; i < 8; i++){
			for(int j = 0; j < 8; j++){
				newMatrix[i][j] = grayMatrix[i][j];
				average += grayMatrix[i][j];
			}
		}
		average /= 64.0;
		return getFeature(newMatrix, average);
	}
	
	/**
	 * 旋转不变性<br>
	 * @return
	 */
	private static String getFeature(int[][] matrix, double average) {
		// 半径
		String featureValue = "";
		int[] r = {2, 4, 6, 8};
		for(int i = 0; i < 4; i++){
			// 正方形左上角的点的下标
			int start = (8 - r[i]) / 2;
			int feature = 0;
			for(int j = start; j < start + r[i]; j++){
				feature = matrix[start][j] < average ? feature<<1 : (feature<<1)+1;
			}
			for(int j = start + 1; j < start + r[i]; j++){
				feature = matrix[j][start + r[i] - 1] < average ? feature<<1 : (feature<<1)+1;
			}
			for(int j = start + r[i] - 2; j >= start; j--){
				feature = matrix[start + r[i] - 1][j] < average ? feature<<1 : (feature<<1)+1;
			}
			for(int j = start + r[i] - 2; j > start; j--){
				feature = matrix[j][start] < average ? feature<<1 : (feature<<1)+1;
			}
			featureValue += getMinFeature(feature, 4 * (r[i] - 1));
		}
		return featureValue;
	}
	
	private static String getMinFeature(int feature, int bitNum) {
		// 位数为bitNum的情况下的最大值
		int max = 1;
		for(int i = 1; i < bitNum; i++){
			max = (max << 1) + 1;
		}
		int min = feature;
		for(int i = 0; i < bitNum - 1; i++){
			feature = (feature>>1 | feature<<(bitNum - 1)) & max;
			if(feature < min) min = feature;
		}
		String result = "";
		for(int i = 0; i < bitNum; i++){
			if(min % 2 == 0){
				result = "0" + result;
			}
			else {
				result = "1" + result;
			}
			min >>= 1;
		}
		return result;
	}

    public static int[][] getGrayPixel(String imagePath, int width, int height) {
		BufferedImage bi = null;
		try {
			bi = resizeImage(imagePath, width, height, BufferedImage.TYPE_INT_RGB);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		int minx = bi.getMinX();
		int miny = bi.getMinY();
		int[][] matrix = new int[width - minx][height - miny];
		for (int i = minx; i < width; i++) {
			for (int j = miny; j < height; j++) {
				int pixel = bi.getRGB(i, j);
				int red = (pixel & 0xff0000) >> 16;
				int green = (pixel & 0xff00) >> 8;
				int blue = (pixel & 0xff);
				int gray = (int) (red * 0.3 + green * 0.59 + blue * 0.11);
				matrix[i][j] = gray;
			}
		}
		return matrix;
	}

    public static BufferedImage resizeImage(String srcImgPath, int width, int height, int imageType)
			throws IOException {
		File srcFile = new File(srcImgPath);
		BufferedImage srcImg = ImageIO.read(srcFile);
		BufferedImage buffImg = null;
		buffImg = new BufferedImage(width, height, imageType);
		buffImg.getGraphics().drawImage(srcImg.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
		return buffImg;
	}

    /**
	 * 用于计算pHash的相似度<br>
	 * 相似度为1时,图片最相似
	 * @param str1
	 * @param str2
	 * @return
	 */
	public static double calculateSimilarity(String str1, String str2) {
		int num = 0;
		for(int i = 0; i < 64; i++){
			if(str1.charAt(i) == str2.charAt(i)){
				num++;
			}
		}
		return ((double)num) / 64.0;
	}
}