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

标签: lire lucene image | 发表时间:2013-04-09 11:07 | 作者:fengzhe0411
出处:http://blog.csdn.net

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

LIRE官网: http://www.semanticmetadata.net/lire/

包和源码: http://code.google.com/p/lire/

基本使用示例: http://www.semanticmetadata.net/wiki/doku.php?id=start

API: http://www.itec.uni-klu.ac.at/lire/nightly/api/index.html

本文不讨论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;
    }

    @Override
    public 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 afterwards
            if (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的倒排优势(对于高维数据还真不知道怎么利用倒排表)。对于大规模的数据速度估计够呛,好在lire的作者也意识到了这一点, http://www.semanticmetadata.net/2013/03/20/large-image-data-sets-with-lire-some-new-numbers/作者表示正在把LSH算法(Locality sensitive hashing)集成进去,LSH对于这种高维数据的相似检索速度可以说是质的飞跃。


自己做的一些实验,大概13万张图片,用的CEDD特征,索引文件只用了不到30M的大小,检索速度没测,目测1秒以内。

左上第一张图片就是输入图片。


作者:fengzhe0411 发表于2013-4-9 11:07:42 原文链接
阅读:25 评论:0 查看评论

相关 [lire lucene image] 推荐:

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

- - CSDN博客云计算推荐文章
众说周知,lucene是一个开源的强大的索引工具,但是它仅限于文本索引. 基于内容的图像检索(CBIR)要求我们利用图像的一些基本特征(如颜色纹理形状以及sift,surf等等)搜索相似的图片,LIRE(Lucene Image Retrieval)是一款基于lucene的图像特征索引工具,它能帮助我们方便的对图像特征建立索引和搜索,作者也在不断加入新的特征供用户使用.

lucene排序

- - 开源软件 - ITeye博客
排序是对于全文检索来言是一个必不可少的功能,在实际运用中,排序功能能在某些时候给我们带来很大的方便,比如在淘宝,京东等一些电商网站我们可能通过排序来快速找到价格最便宜的商品,或者通过排序来找到评论数最高或卖的最好的商品,再比如在Iteye里的博客栏里,每天都会以降序的方式,来显示出最新发出的几篇博客,有了排序,我们就能在某些时候很方便快速的得到某些有效信息,所以说排序功能,无处不在 ^_^.

Java MongoDB : Save image example(译)

- - 数据库 - ITeye博客
原文出自:http://www.mkyong.com/mongodb/java-mongodb-save-image-example/. 返回目录: http://ysj5125094.iteye.com/blog/2192754  . 译:在本教程中,我们将向你展示如何通过  GridFS API 保存一个图片到MongoDB.

转换 Vmware Image to Virtualbox Image 或者 导入 Vmware Imagee into Virtu

- - 操作系统 - ITeye博客
VirtualBox can run VMs created by VMware Workstation or Server for this you need to import vmdk files using the following procedure. 来源: http://www.ubuntugeek.com/howto-convert-vmware-image-to-virtualbox-image.html.

[原]Lucene系列-facet

- - 文武天下
facet:面、切面、方面. 个人理解就是维度,在满足query的前提下,观察结果在各维度上的分布(一个维度下各子类的数目). 如jd上搜“手机”,得到4009个商品. 其中品牌、网络、价格就是商品的维度(facet),点击某个品牌或者网络,获取更细分的结果. 点击品牌小米,获得小米手机的结果,显示27个.

[原]Lucene系列-FieldCache

- - 文武天下
域缓存,加载所有文档中某个特定域的值到内存,便于随机存取该域值. 当用户需要访问各文档中某个域的值时,IndexSearcher.doc(docId)获得Document的所有域值,但访问速度比较慢,而且只能获得Stored域的值. FieldCache能获得域值数组,根据docId random access域值.

Lucene 使用教程

- - 行业应用 - ITeye博客
1 lucene简介 . 1.1 什么是lucene . Lucene是一个全文搜索框架,而不是应用产品. 因此它并不像 http://www.baidu.com/ 或者google Desktop那么拿来就能用,它只是提供了一种工具让你能实现这些产品. 1.2 lucene能做什么 . 要回答这个问题,先要了解lucene的本质.

Lucene 4.x 之 IndexReader

- - zzm
在Lucene 3.x时代,《Lucene In Action》是一本相当不错的参考书,书中详细介绍了Lucene各种高级使用技术,对于开发者来说非常实用. 但是近期Lucene升级到了4.x版本,在性能等各方面有了很大的提高,值得在新项目中使用. 然而Lucene 4.x中的API相比3.x来说有了很大的改变,《Lucene In Action》中的很多内容都已经过时了,并且由于4.x推出的时间不长,还没有比较好的文档来对用法进行说明,这个系列文章就是想记录下自己使用Lucene 4.x的经验体会,供大家参考使用.

IE中Image .onload方法问题

- 红茶 - WEB前端开发
因为IE会缓存图片,第2次加载的图片,不是从服务器上传过来的,而是从缓冲区里加载的. 先写onload方法,再指定这张图片的URL,这样就正常了. 所以,不是IE没有触发onload事件,而是因为加载缓冲区的速度太快,以至于没有运行到img.onload的时候,onload事件已经触发了.

图片处理 javax.imageio.IIOException: Unsupported Image Type

- - zzm
用ImageIO处理图片:. ps或其他软件处理过的图片保存为jpg格式时,默认的模式是CMYK模式(这是给印刷机用的). 在图像-->模式中改为RGB模式才是显示器用的. 解决办法:方法一:通知用户修改图片格式为RGB. 已有 0 人发表留言,猛击->> 这里<<-参与讨论. —软件人才免语言低担保 赴美带薪读研.