在对大批量数据进行图像处理的时候,比如说我提取SIFT特征,数据集为10W张图片,一个SIFT特征点是128维,一张图片提取出500个特征点,这样我们在处理的时候就是对5000万个128维的数据进行处理,这样处理所需要的耗时太长了,不符合实际生产的需要。我们需要用一种方法降低运算量,比如说降维。

  看了一些论文,提到的较多的方法是LSH(Locality Sensitive Hash),就是局部敏感哈希。我们利用LSH方法在5000万个特征点中筛选出极少量的我们需要的特征点,在对这些极少量的数据进行计算,就可以得到我们想要的结果啦。

 package com.demo.lsh;

 import com.demo.config.Constant;
import com.demo.dao.FeatureDao;
import com.demo.dao.FeatureTableDao;
import com.demo.dao.HashTableDao;
import com.demo.entity.HashTable;
import com.demo.utils.MD5Util;
import com.demo.utils.MathUtil;
import org.opencv.core.Mat;
import org.springframework.util.StringUtils; import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*; public class LSH {
//维度大小,例如对于sift特征来说就是128
private int dimention = Constant.DIMENTION;
//所需向量中元素可能的上限,譬如对于RGB来说,就是255
private int max = Constant.MAX;
//哈希表的数量,用于更大程度地削减false positive
private int hashCount = Constant.HASHCOUNT;
//LSH随机选取的采样位数,该值越小,则近似查找能力越大,但相应的false positive也越大;若该值等于size,则为由近似查找退化为精确匹配
private int bitCount = Constant.BITCOUNT;
//转化为01字符串之后的位数,等于max乘以dimensions
private int size = dimention * max;
//LSH哈希族,保存了随机采样点的INDEX
private int[][] hashFamily;
private HashTableDao hashTableDao;
/**
* 构造函数
*/
public LSH(HashTableDao hashTableDao) {
this.hashTableDao = hashTableDao;
dimention = Constant.DIMENTION;
max = Constant.MAX;
hashCount = Constant.HASHCOUNT;
bitCount = Constant.BITCOUNT;
size = dimention * max;
hashFamily = new int[hashCount][bitCount];
generataHashFamily();
} /**
* 生成随机的投影点 ,在程序第一次执行时生成。投影点可以理解为后面去数组的索引值
*/
private void generataHashFamily() {
if (new File("/home/fanxuan/data/1.txt").exists()) {
try {
InputStream in = new FileInputStream("/home/fanxuan/data/1.txt");
ObjectInputStream oin = new ObjectInputStream(in);
hashFamily = (int[][]) (oin.readObject());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}else {
Random rd = new Random();
for (int i = 0; i < hashCount; i++) {
for (int j = 0; j < bitCount; j++) {
hashFamily[i][j] = rd.nextInt(size);
}
}
try {
OutputStream out = new FileOutputStream("/home/fanxuan/data/1.txt");
ObjectOutputStream oout = new ObjectOutputStream(out);
oout.writeObject(hashFamily);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} //将向量转化为二进制字符串,比如元素的最大范围255,则元素65就被转化为65个1以及190个0
private int[] unAray(int[] data) {
int unArayData[] = new int[size];
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i]; j++) {
unArayData[i * max + j] = 1;
}
}
return unArayData;
} /**
* 将向量映射为LSH中的key
*/
private String generateHashKey(int[] list, int hashNum) {
StringBuilder sb = new StringBuilder();
int[] tempData = unAray(list);
int[] hashedData = new int[bitCount];
//首先将向量转为二进制字符串
for (int i = 0; i < bitCount; i++) {
hashedData[i] = tempData[hashFamily[hashNum][i]];
sb.append(hashedData[i]);
}
//再用常规hash函数比如MD5对key进行压缩
MessageDigest messageDigest = null;
try{
messageDigest = MessageDigest.getInstance("MD5");
}catch (NoSuchAlgorithmException e) { }
byte[] binary = sb.toString().getBytes();
byte[] hash = messageDigest.digest(binary);
String hashV = MD5Util.bufferToHex(hash);
return hashV;
} /**
* 将Sift特征点转换为Hash存表
*/
public void generateHashMap(String id, int[] vercotr, int featureId) {
for (int j = 0; j < hashCount; j++) {
String key = generateHashKey(vercotr, j);
HashTable hashTableUpdateOrAdd = new HashTable();
HashTable hashTable = hashTableDao.findHashTableByBucketId(key);
if (hashTable != null) {
String featureIdValue = hashTable.getFeatureId() + "," + featureId;
hashTableUpdateOrAdd.setFeatureId(featureIdValue);
hashTableUpdateOrAdd.setBucketId(key);
hashTableDao.updateHashTableFeatureId(hashTableUpdateOrAdd);
} else {
hashTableUpdateOrAdd.setBucketId(key);
hashTableUpdateOrAdd.setFeatureId(String.valueOf(featureId));
hashTableDao.insertHashTable(hashTableUpdateOrAdd);
}
}
} // 查询与输入向量最接近(海明空间)的向量
public List<String> queryList(int[] data) {
List<String> result = new ArrayList<>();
for (int j = 0; j < hashCount; j++) {
String key = generateHashKey(data, j);
result.add(key);
HashTable hashTable = hashTableDao.findHashTableByBucketId(key);
if (!StringUtils.isEmpty(hashTable.getFeatureId())) {
String[] str = hashTable.getFeatureId().split(",");
for (String string : str) {
result.add(string);
}
}
}
return result;
} }

  

 package com.demo.config;

 public class Constant {
//维度大小,例如对于sift特征来说就是128
public static final int DIMENTION = 128;
//所需向量中元素可能的上限,譬如对于RGB来说,就是255
public static final int MAX = 255;
//哈希表的数量,用于更大程度地削减false positive
public static final int HASHCOUNT = 12;
//LSH随机选取的采样位数,该值越小,则近似查找能力越大,但相应的false positive也越大;若该值等于size,则为由近似查找退化为精确匹配
public static final int BITCOUNT = 32;
}

  简单的介绍下代码,构造函数LSH()用来建立LSH对象,hashTableDao为数据表操作对象,不多说;因为局部敏感哈希依赖与一套随机数,每次产生的结果都不一致,所以我们需要在程序第一次运行的时候将随机数生成并固定下来,我采用的方法是存放在本地磁盘中,也可以存放在数据库中。generateHashMap()方法为数据训练函数,int[] vercotr为特征向量,其他两个参数为我需要的标志位。queryList()方法是筛选方法。

  感谢http://grunt1223.iteye.com/blog/944894的文章。

Java实现LSH(Locality Sensitive Hash )的更多相关文章

  1. 从NLP任务中文本向量的降维问题,引出LSH(Locality Sensitive Hash 局部敏感哈希)算法及其思想的讨论

    1. 引言 - 近似近邻搜索被提出所在的时代背景和挑战 0x1:从NN(Neighbor Search)说起 ANN的前身技术是NN(Neighbor Search),简单地说,最近邻检索就是根据数据 ...

  2. Locality Sensitive Hash 局部敏感哈希

    Locality Sensitive Hash是一种常见的用于处理高维向量的索引办法.与其它基于Tree的数据结构,诸如KD-Tree.SR-Tree相比,它较好地克服了Curse of Dimens ...

  3. LSH(Locality Sensitive Hashing)原理与实现

    原文地址:https://blog.csdn.net/guoziqing506/article/details/53019049 LSH(Locality Sensitive Hashing)翻译成中 ...

  4. Locality Sensitive Hashing,LSH

    1. 基本思想 局部敏感(Locality Senstitive):即空间中距离较近的点映射后发生冲突的概率高,空间中距离较远的点映射后发生冲突的概率低. 局部敏感哈希的基本思想类似于一种空间域转换思 ...

  5. [Algorithm] 局部敏感哈希算法(Locality Sensitive Hashing)

    局部敏感哈希(Locality Sensitive Hashing,LSH)算法是我在前一段时间找工作时接触到的一种衡量文本相似度的算法.局部敏感哈希是近似最近邻搜索算法中最流行的一种,它有坚实的理论 ...

  6. 局部敏感哈希-Locality Sensitive Hashing

    局部敏感哈希 转载请注明http://blog.csdn.net/stdcoutzyx/article/details/44456679 在检索技术中,索引一直须要研究的核心技术.当下,索引技术主要分 ...

  7. 局部敏感哈希算法(Locality Sensitive Hashing)

    from:https://www.cnblogs.com/maybe2030/p/4953039.html 阅读目录 1. 基本思想 2. 局部敏感哈希LSH 3. 文档相似度计算 局部敏感哈希(Lo ...

  8. 转:locality sensitive hashing

    Motivation The task of finding nearest neighbours is very common. You can think of applications like ...

  9. 转: memcached Java客户端spymemcached的一致性Hash算法

    转自:http://colobu.com/2015/04/13/consistent-hash-algorithm-in-java-memcached-client/ memcached Java客户 ...

随机推荐

  1. ibatis工作原理

    摘要: iBATIS 通过 SQL Map 将 Java 对象映射成 SQL 语句和将结果集再转化成 Java 对象,与其他 ORM 框架相比,既解决了 Java 对象与输入参数和结果集的映射,又能够 ...

  2. Loadrunder之脚本篇——关联函数对话框详解

    Insert->New Step,打开Add Step对话框 选择函数web_reg_save_param,点击OK,打开关联函数设置窗口 说明: Parameter Name 此处设置存放参数 ...

  3. Linux Shell基础 Shell的输入重定向和输出重定向

    概述 在 Linux 中输入设备指的是键盘,输出设备指的是显示器.在 Linux 中,所有的内容都是文件,计算机硬件也是文件,标准输入设备(键盘)和标准输出设备(显示器)也是文件.这些设备的设备文件名 ...

  4. Nginx配置指令的执行顺序

    rewrite阶段 rewrite阶段是一个比较早的请求处理阶段,这个阶段的配置指令一般用来对当前请求进行各种修改(比如对URI和URL参数进行改写),或者创建并初始化一系列后续处理阶段可能需要的Ng ...

  5. java 程序的使用

    Java程序可以在任何安装有Java平台的系统上运行,运行的时候语法如下: java -jar <program.jar>   -jar这个参数是必须有的,后面跟你的java程序,例如我们 ...

  6. php数组函数-array_keys()

    array_keys()函数返回包含数组中所有键名的一个新数组 如果提供了第二个参数,则返回键值为该值得键名 如果strict参数指定为true,则php会使用全等(===)来严格检查键值的 数据类型 ...

  7. Android电容屏(一)【转】

    本文转载自:http://blog.csdn.net/xubin341719/article/details/7820492 关键词:Android  电容屏 tp  ITO 平台信息:内核:linu ...

  8. Java 重写equals()与hashCode()方法

    List对象的contains方法实际上也是调用的equals()方法来进行逐条对比的. 示例代码: package com.imooc.collection; /** * 课程类 */ public ...

  9. VK Cup 2017 - Qualification 1 C 贪心

    是一道很有趣的题目 给出地图和起始点 与要求的步数k 要求走k步 正好回到起始点 输出字典序最小的移动路径 DLRU这样 可以想到DU LR都是相同数量的 于是k必须是一个偶数 然后走了弯路QAQ 从 ...

  10. 利用Xshell从windows上传文件到linux

    1.首先,打开你的xshell客户端. 2.我用的是ubuntu 所以用 apt-get install lrzsz 命令来安装这个上传软件. 安装成功以后,可以使用rz上传,sz下载. 然后等待上传 ...