相似图片搜索--哈希特征值

相似图片搜索–哈希特征值

简介

搜索方法是计算出每一个图片的特征值,然后进行对比。目前的搜索速度较慢,之后可以加入线程池等使搜索速度得到极大的提升,欢迎大家指点。
    ~~~    

思路

从文件夹读取图片
压缩图片
色彩处理
得到灰度值
计算哈希值
比较哈希值

    ~~~    

实现方法

    ~~~    

从文件夹读取图片

给定文件夹路径
递归得到当前文件架下的所有文件
判断是否为jpg文件
加入队列

递归得到文件

public static ArrayList<File> getallfile(File file, ArrayList<File> allfilelist) {
	if (file.exists()) {
		// 判断文件是否是文件夹,如果是,开始递归
		if (file.isDirectory()) {
			File f[] = file.listFiles();
			for (File file2 : f) {
				getallfile(file2, allfilelist);
			}
		} else {
			allfilelist.add(file);
		}
	}
	return allfilelist;
}

    ~~~    

将图片路径放入队列

public Vector<String> getFileByDirectory(String filepath, String endFileName) {
	File file = new File(filepath);

	ArrayList<File> files = new ArrayList<File>();
	// 拿到所有文件
	ArrayList<File> allFiles = getallfile(file, files);
	Vector<String> imagePathArray=new Vector<String>();

	for (int i = 0; i < allFiles.size(); i++) {
	
		if (allFiles.get(i).getName().endsWith(endFileName)) {// 筛选特定的文件
						
			String icon=allFiles.get(i).getAbsolutePath();
			imagePathArray.add(icon);
		}
	}
	return imagePathArray;
}

压缩图片

将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。


public static BufferedImage thumb(BufferedImage source, int width, int height, boolean b) {
	//返回此 ColorSpace 的颜色空间类型
	int type = source.getType();
	BufferedImage target = null;
	//计算缩小倍数 sx=8/原宽度  sy=8/原高度
	double sx = (double) width / source.getWidth();
	double sy = (double) height / source.getHeight();



	// 没有识别出图像类型,因此它必定是一个自定义图像。需要做处理
	if (type == BufferedImage.TYPE_CUSTOM) {
		ColorModel cm = source.getColorModel();
		WritableRaster raster = cm.createCompatibleWritableRaster(width, height);
		boolean alphaPremultiplied = cm.isAlphaPremultiplied();
		target = new BufferedImage(cm, raster, alphaPremultiplied, null);
	} else
		target = new BufferedImage(width, height, type);

	Graphics2D g = target.createGraphics();

	g.setRenderingHint(RenderingHints.KEY_RENDERING,
			RenderingHints.VALUE_RENDER_QUALITY);
	//从图像空间到用户空间的转换。
	g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
	g.dispose();
	return target;
}




色彩处理

/将缩小后的图片,转为64级灰度。转换以后,所有像素点总共只有64种颜色。之后比较灰度,做出色彩标记。
灰度转换

int[] pixels = new int[width * height];
for (int i = 0; i < width; i++) {
	for (int j = 0; j < height; j++) {
		pixels[i * height + j] = ImageHelper.rgbToGray(thumb.getRGB(i, j));
	}
}

/**
 * 灰度转化
 * @param pixels 原数组
 * @return
 */
public static int rgbToGray(int pixels) {
	// int _alpha = (pixels >> 24) & 0xFF;
	int _red = (pixels >> 16) & 0xFF;
	int _green = (pixels >> 8) & 0xFF;
	int _blue = (pixels) & 0xFF;
	return (int) (0.3 * _red + 0.59 * _green + 0.11 * _blue);
}



计算所有64个像素的灰度平均值。

// 计算所有64个像素的灰度平均值。
int avgPixel = ImageHelper.average(pixels);

public static int average(int[] pixels) {
	float m = 0;
	for (int i = 0; i < pixels.length; ++i) {
		m += pixels[i];
	}
	m = m / pixels.length;
	return (int) m;
}

标记颜色
将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。


int[] comps = new int[width * height];
for (int i = 0; i < comps.length; i++) {
	if (pixels[i] >= avgPixel) {
		comps[i] = 1;
	} else {
		comps[i] = 0;
	}
}

计算哈希值

将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。

StringBuffer hashCode = new StringBuffer();
for (int i = 0; i < comps.length; i+= 4) {
	int result = comps[i] * (int) Math.pow(2, 3) + comps[i + 1] * (int) Math.pow(2, 2) + comps[i + 2] * (int) Math.pow(2, 1) + comps[i + 2];
	hashCode.append(binaryToHex(result));
}

比较哈希值

/**
 * 计算"汉明距离"(Hamming distance)。
 * 如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。(总共64位)
 * @param sourceHashCode 源hashCode
 * @param hashCode 与之比较的hashCode
 */
public static int hammingDistance(String sourceHashCode, String hashCode) {
	int difference = 0;
	int len = sourceHashCode.length();
	
	for (int i = 0; i < len; i++) {
		if (sourceHashCode.charAt(i) != hashCode.charAt(i)) {
			difference ++;
		} 
	}
	
	return difference;
}

参考资料

相似图片搜索原理 – 阮一峰
相似图片搜索

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值