Lucene image retrieval是以图搜图的java开源框架,这几天没什么事,就读了点源码,并写了点注释,特在这分享给大家。
这里主要给出的是BOVWBuilder.java、Kmeans.java及Cluster.java。就是用词频对特征进行编码,用到是BOF(bag of feature)模型,原理就是提取N张图片的特征(比如sift),放在一起就可以得到矩阵,然后对矩阵进行kmeans聚类,就会到到若干个聚类中心;对于新来的一副图像,我们分别计算该特征点与那个聚类中心最近,这样该聚类中心的量值就加1,这样就可以编码得到与聚类中心个数想等的维数向量。
一切都从BOVWBuilder中index函数开始...
BOVWBuilder.java(包含注释)
package lmc.imageretrieval.imageanalysis.bovw;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import javax.swing.ProgressMonitor;
import lmc.imageretrieval.imageanalysis.Histogram;
import lmc.imageretrieval.imageanalysis.LireFeature;
import lmc.imageretrieval.tools.DocumentBuilder;
import lmc.imageretrieval.utils.SerializationUtils;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.MultiFields;
import org.apache.lucene.index.Term;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.Version;
public class BOVWBuilder {
IndexReader reader;
// number of documents used to build the vocabulary / clusters.
private int numDocsForVocabulary = 500;
private int numClusters = 512;
private Cluster[] clusters = null;
DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance();
private ProgressMonitor pm = null;
protected LireFeature lireFeature;
protected String localFeatureFieldName;
protected String visualWordsFieldName;
protected String localFeatureHistFieldName;
protected String clusterFile;
public static boolean DELETE_LOCAL_FEATURES = true;
/**
*
* @param reader
* @deprecated
*/
public BOVWBuilder(IndexReader reader) {
this.reader = reader;
}
/**
* Creates a new instance of the BOVWBuilder using the given reader. The numDocsForVocabulary
* indicates how many documents of the index are used to build the vocabulary (clusters).
*
* @param reader the reader used to open the Lucene index,
* @param numDocsForVocabulary gives the number of documents for building the vocabulary (clusters).
* @deprecated
*/
public BOVWBuilder(IndexReader reader, int numDocsForVocabulary) {
this.reader = reader;
this.numDocsForVocabulary = numDocsForVocabulary;
}
/**
* Creates a new instance of the BOVWBuilder using the given reader. The numDocsForVocabulary
* indicates how many documents of the index are used to build the vocabulary (clusters). The numClusters gives
* the number of clusters k-means should find. Note that this number should be lower than the number of features,
* otherwise an exception will be thrown while indexing.
*
* @param reader the index reader
* @param numDocsForVocabulary the number of documents that should be sampled for building the visual vocabulary
* @param numClusters the size of the visual vocabulary
* @deprecated
*/
public BOVWBuilder(IndexReader reader, int numDocsForVocabulary, int numClusters) {
this.numDocsForVocabulary = numDocsForVocabulary;
this.numClusters = numClusters;
this.reader = reader;
}
/**
* Creates a new instance of the BOVWBuilder using the given reader. TODO: write
*
* @param reader the index reader
* @param lireFeature lireFeature used
*/
public BOVWBuilder(IndexReader reader, LireFeature lireFeature) {
this.reader = reader;
this.lireFeature = lireFeature;
}
/**
* Creates a new instance of the BOVWBuilder using the given reader. The numDocsForVocabulary
* indicates how many documents of the index are used to build the vocabulary (clusters).
* TODO: write
*
* @param reader the index reader
* @param lireFeature lireFeature used
* @param numDocsForVocabulary the number of documents that should be sampled for building the visual vocabulary
*/
public BOVWBuilder(IndexReader reader, LireFeature lireFeature, int numDocsForVocabulary) {
this.numDocsForVocabulary = numDocsForVocabulary;
this.reader = reader;
this.lireFeature = lireFeature;
}
/**
* Creates a new instance of the BOVWBuilder using the given reader. The numDocsForVocabulary
* indicates how many documents of the index are used to build the vocabulary (clusters). The numClusters gives
* the number of clusters k-means should find. Note that this number should be lower than the number of features,
* otherwise an exception will be thrown while indexing. TODO: write
*
* @param reader the index reader
* @param lireFeature lireFeature used
* @param numDocsForVocabulary the number of documents that should be sampled for building the visual vocabulary
* @param numClusters the size of the visual vocabulary
*/
public BOVWBuilder(IndexReader reader, LireFeature lireFeature, int numDocsForVocabulary, int numClusters) {
this.numDocsForVocabulary = numDocsForVocabulary;
this.numClusters = numClusters;
this.reader = reader;
this.lireFeature = lireFeature;
}
protected void init() {
localFeatureFieldName = lireFeature.getFieldName();
visualWordsFieldName = lireFeature.getFieldName() + DocumentBuilder.FIELD_NAME_BOVW;
localFeatureHistFieldName = lireFeature.getFieldName()+ DocumentBuilder.FIELD_NAME_BOVW_VECTOR;
clusterFile = "./clusters-bovw" + lireFeature.getFeatureName() + ".dat";
}
/**
* Uses an existing index, where each and every document should have a set of local features. A number of
* random images (numDocsForVocabulary) is selected and clustered to get a vocabulary of visual words
* (the cluster means). For all images a histogram on the visual words is created and added to the documents.
* Pre-existing histograms are deleted, so this method can be used for re-indexing.
*
* @throws java.io.IOException
*/
public void index() throws IOException {
init();
df.setMaximumFractionDigits(3);
// find the documents for building the vocabular