LIRE(Lucene Image Retrieval)相似图像索引和搜索机制

众说周知,lucene是一个开源的强大的索引工具,但是它仅限于文本索引。基于内容的图像检索(CBIR)要求我们利用图像的一些基本特征(如颜色纹理形状以及sift,surf等等)搜索相似的图片,LIRE(Lucene Image Retrieval)是一款基于lucene的图像特征索引工具,它能帮助我们方便的对图像特征建立索引和搜索,作者也在不断加入新的特征供用户使用。如果你熟悉lucene,那么用LIRE提取特征建立索引是非常方便的。

LIRE官网:

包和源码:

基本使用示例:?id=start

API:

本文不讨论API的调用方法,我粗略的读了下lire的源码,在这里对它的机制做个简单的说明。

LireFeature是图像特征的接口,具体的特征提取,距离计算,表示都有各自实现的类。值得一提的是,LIRE的作者实现了非常多的特征提取方法,而且都是java实现的,也没有借助opencv等工具,在此之前我能看到的sift特征提取都是c或者c++实现的。

public interface LireFeature {public void extract(BufferedImage bimg);public byte[] getByteArrayRepresentation();public void setByteArrayRepresentation(byte[] in);public void setByteArrayRepresentation(byte[] in, int offset, int length);public double[] getDoubleHistogram();float getDistance(LireFeature feature);java.lang.String getStringRepresentation();void setStringRepresentation(java.lang.String s);}

DocumentBuilder是建立Document的接口类,Document就是lucene中的文档,它建立的文档包含了图像的某个特征和图像的标识字符串两个Field。

public Document createDocument(BufferedImage image, String identifier) throws FileNotFoundException;ChainedDocumentBuilder可以建立将多个特征综合起来的文档。

DocumentBuilderFactory是DocumentBuilder的工厂类,由它初始化各个特征的DocumentBuilder。

通过调用createDocument就能返回每个图像对应特征和标识的文档,用lucene的IndexWriter就能将它写入索引文件。

SimpleResult是单个搜索的结果,它包含3个成员变量,分别是距离(相似度),文档和索引号。它实现了Comparable接口,排序的方法是按照相似度的由高到底排序,如果相似度一样,就按照索引号在前的排在前面。

public class SimpleResult implements Comparable<SimpleResult> {private float distance;private Document document;private int indexNumber = 0;public int compareTo(SimpleResult o) {int compareValue = (int) Math.signum(distance – ((SimpleResult) o).distance);if (compareValue==0 && !document.equals(o.document)) {return (int) Math.signum(indexNumber-o.indexNumber);}return compareValue;}@Overridepublic boolean equals(Object obj) {// it’s not the same if it’s not the same class.if (! (obj instanceof SimpleResult)) return false;// it’s the same if the document is the same, regardless of the distance.else return (document.equals(((SimpleResult)obj).document) && indexNumber == ((SimpleResult)obj).indexNumber);}}

ImageSearcherFactory是搜索的工厂类,由它初始化各个特征的搜索类。

这里主要讲一下GenericFastImageSearcher类,很多特征都能通过它来搜索,它的成员变量maxHits为搜索结果的个数,TreeSet<SimpleResult> docs是排序的搜索结果,float maxDistance搜索结果中的最大距离。

protected float findSimilar(IndexReader reader, LireFeature lireFeature) throws IOException {maxDistance = -1f;overallMaxDistance = -1f;// clear result set …docs.clear();// Needed for check whether the document is deleted.Bits liveDocs = MultiFields.getLiveDocs(reader);Document d;float tmpDistance;int docs = reader.numDocs();for (int i = 0; i < docs; i++) {if (reader.hasDeletions() && !liveDocs.get(i)) continue; // if it is deleted, just ignore it.d = reader.document(i);tmpDistance = getDistance(d, lireFeature);assert (tmpDistance >= 0);// calculate the overall max distance to normalize score afterwardsif (overallMaxDistance < tmpDistance) {overallMaxDistance = tmpDistance;}// if it is the first document:if (maxDistance < 0) {maxDistance = tmpDistance;}// if the array is not full yet:if (this.docs.size() < maxHits) {this.docs.add(new SimpleResult(tmpDistance, d, i));if (tmpDistance > maxDistance) maxDistance = tmpDistance;} else if (tmpDistance < maxDistance) {// if it is nearer to the sample than at least on of the current set:// remove the last one …this.docs.remove(this.docs.last());// add the new one …this.docs.add(new SimpleResult(tmpDistance, d, i));// and set our new distance border …maxDistance = this.docs.last().getDistance();}}return maxDistance;}从它的findSimilar方法可以看出,它的实现是线性检索的,也就是从头到尾遍历所有文档,并且维护一个maxHits大小的TreeSet,TreeSet里面放的是距离最小的maxHits个搜索结果。如果有不理解此过程的童鞋,,可以参考一下“TOP N搜索算法”。

public ImageSearchHits search(BufferedImage image, IndexReader reader) throws IOException {logger.finer("Starting extraction.");LireFeature lireFeature = null;SimpleImageSearchHits searchHits = null;try {lireFeature = (LireFeature) descriptorClass.newInstance();// Scaling image is especially with the correlogram features very important!BufferedImage bimg = image;if (Math.max(image.getHeight(), image.getWidth()) > GenericDocumentBuilder.MAX_IMAGE_DIMENSION) {bimg = ImageUtils.scaleImage(image, GenericDocumentBuilder.MAX_IMAGE_DIMENSION);}lireFeature.extract(bimg);logger.fine("Extraction from image finished");float maxDistance = findSimilar(reader, lireFeature);searchHits = new SimpleImageSearchHits(this.docs, maxDistance);} catch (InstantiationException e) {logger.log(Level.SEVERE, "Error instantiating class for generic image searcher: " + e.getMessage());} catch (IllegalAccessException e) {logger.log(Level.SEVERE, "Error instantiating class for generic image searcher: " + e.getMessage());}return searchHits;}search方法返回的是ImageSearchHits,它就是ArrayList<SimpleResult> results;并且利用findSimilar遍历时最大的distance做了个归一化操作,result.setDistance(1f – result.getDistance() / maxDistance);作用就是将距离变成了相似度(0到1),并且数值越大就越相似。

开上一部车,装着我们的故事,

LIRE(Lucene Image Retrieval)相似图像索引和搜索机制

相关文章:

你感兴趣的文章:

标签云: