Java基于相似算法实现以图搜图

一、简述

  本文主要讲如何利用图片相似性算法,基于LIRE来实现图片搜索。

二、依赖

   <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-core -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>6.3.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-queryparser -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>6.3.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-analyzers-common -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>6.3.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-math3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-math3</artifactId>
            <version>3.6.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.sangupta/jopensurf -->
        <dependency>
            <groupId>com.sangupta</groupId>
            <artifactId>jopensurf</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>

二、样例1

  Data目录下存放所有图片的样本。

package com.dearcloud.imagesearch;

import net.semanticmetadata.lire.aggregators.AbstractAggregator;
import net.semanticmetadata.lire.aggregators.BOVW;
import net.semanticmetadata.lire.builders.DocumentBuilder;
import net.semanticmetadata.lire.imageanalysis.features.global.CEDD;
import net.semanticmetadata.lire.imageanalysis.features.local.opencvfeatures.CvSurfExtractor;
import net.semanticmetadata.lire.imageanalysis.features.local.simple.SimpleExtractor;
import net.semanticmetadata.lire.indexers.parallel.ParallelIndexer;
import net.semanticmetadata.lire.searchers.GenericFastImageSearcher;
import net.semanticmetadata.lire.searchers.ImageSearchHits;
import net.semanticmetadata.lire.searchers.ImageSearcher;
import net.semanticmetadata.lire.utils.FileUtils;
import net.semanticmetadata.lire.utils.ImageUtils;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.store.FSDirectory;

import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;

public class IndexingAndSearchWithLocalFeatures {
    public static void main(String[] args) throws IOException {
        String indexPath = "D:\\以图搜图\\衬衣\\index";
        String imageData = "D:\\以图搜图\\衬衣\\Data";
        indexer(indexPath, imageData);

        String searchImage = "D:\\以图搜图\\衬衣\\search\\timg.jpg";
        String searchOutputFolder = "D:\\以图搜图\\衬衣\\output";
        search(indexPath, searchImage, searchOutputFolder);
    }

    /**
     * Indexing data using OpenCV and SURF as well as CEDD and SIMPLE.
     * @param indexFolder
     * @param imageDirectory
     */
    private static void indexer(String indexFolder, String imageDirectory) {
        // Checking if arg[0] is there and if it is a directory.
        boolean passed = false;
        // use ParallelIndexer to index all photos from args[0] into "index".
        int numOfDocsForVocabulary = 500;
        Class<? extends AbstractAggregator> aggregator = BOVW.class;
        int[] numOfClusters = new int[]{128};
        ParallelIndexer indexer = new ParallelIndexer(DocumentBuilder.NUM_OF_THREADS, indexFolder, imageDirectory, numOfClusters, numOfDocsForVocabulary, aggregator);
        indexer.setImagePreprocessor(image -> ImageUtils.createWorkingCopy(image));
        //Local
        indexer.addExtractor(CvSurfExtractor.class);
        //Simple
        indexer.addExtractor(CEDD.class, SimpleExtractor.KeypointDetector.CVSURF);

        indexer.run();
        System.out.println("Finished indexing.");
    }

    /**
     * Linear search on the indexed data.
     * @param indexPath
     * @throws IOException
     */
    public static void search(String indexPath, String searchFile, String searchOutputFolder) throws IOException {
        IndexReader reader = DirectoryReader.open(FSDirectory.open(Paths.get(indexPath)));

        // make sure that this matches what you used for indexing (see below) ...
        ImageSearcher imgSearcher = new GenericFastImageSearcher(1000, CEDD.class, SimpleExtractor.KeypointDetector.CVSURF, new BOVW(), 128, true, reader, indexPath + ".config");
        // just a static example with a given image.
        ImageSearchHits hits = imgSearcher.search(ImageIO.read(new File(searchFile)), reader);

        for (int i = 0; i < hits.length(); i++) {
            double score = hits.score(i);
            String imagePath = reader.document(hits.documentID(i)).getValues(DocumentBuilder.FIELD_NAME_IDENTIFIER)[0];
            System.out.printf("%.2f: (%d) %s\n", score, hits.documentID(i), imagePath);
        }
        String outputHtmlReport = FileUtils.saveImageResultsToHtml("search-", hits, searchFile, reader);
        System.out.println("Report:" + outputHtmlReport);
        org.apache.commons.io.FileUtils.copyFile(org.apache.commons.io.FileUtils.getFile(outputHtmlReport), org.apache.commons.io.FileUtils.getFile(searchOutputFolder, outputHtmlReport));
    }

}

三、样例2

  1、Indexer

package com.dearcloud.imagesearch;

import net.semanticmetadata.lire.builders.GlobalDocumentBuilder;
import net.semanticmetadata.lire.imageanalysis.features.global.AutoColorCorrelogram;
import net.semanticmetadata.lire.imageanalysis.features.global.CEDD;
import net.semanticmetadata.lire.imageanalysis.features.global.FCTH;
import net.semanticmetadata.lire.utils.FileUtils;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.FSDirectory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Iterator;

public class LireIndexer {
    public static void main(String[] args) throws IOException {
        String indexPath = "D:\\以图搜图\\全部\\index";
        String imageData = "D:\\以图搜图\\全部\\Data";
        index(indexPath, imageData);
    }

    private static void index(String indexFolder, String imageDirectory) throws IOException {
        // Getting all images from a directory and its sub directories.
        ArrayList<String> images = FileUtils.getAllImages(new File(imageDirectory), true);

        // Creating a CEDD document builder and indexing all files.
        GlobalDocumentBuilder globalDocumentBuilder = new GlobalDocumentBuilder(false, false);
        /*
            If you want to use DocValues, which makes linear search much faster, then use.
            However, you then have to use a specific searcher!
         */
        // GlobalDocumentBuilder globalDocumentBuilder = new GlobalDocumentBuilder(false, true);

        /*
            Then add those features we want to extract in a single run:
         */
        globalDocumentBuilder.addExtractor(CEDD.class);
        globalDocumentBuilder.addExtractor(FCTH.class);
        globalDocumentBuilder.addExtractor(AutoColorCorrelogram.class);

        // Creating an Lucene IndexWriter
        IndexWriterConfig conf = new IndexWriterConfig(new WhitespaceAnalyzer());
        IndexWriter iw = new IndexWriter(FSDirectory.open(Paths.get(indexFolder)), conf);
        // Iterating through images building the low level features
        for (Iterator<String> it = images.iterator(); it.hasNext(); ) {
            String imageFilePath = it.next();
            System.out.println("Indexing " + imageFilePath);
            try {
                BufferedImage img = ImageIO.read(new FileInputStream(imageFilePath));
                if (img == null) continue;
                Document document = globalDocumentBuilder.createDocument(img, imageFilePath);
                iw.addDocument(document);
            } catch (Exception e) {
                System.err.println("Error reading image or indexing it.");
                e.printStackTrace();
            }
        }
        // closing the IndexWriter
        iw.close();
        System.out.println("Finished indexing.");
    }
}

  2、Searcher

package com.dearcloud.imagesearch;

import net.semanticmetadata.lire.builders.DocumentBuilder;
import net.semanticmetadata.lire.imageanalysis.features.global.CEDD;
import net.semanticmetadata.lire.searchers.GenericFastImageSearcher;
import net.semanticmetadata.lire.searchers.ImageSearchHits;
import net.semanticmetadata.lire.searchers.ImageSearcher;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.store.FSDirectory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Paths;

public class LireSearcher {
    public static void main(String[] args) throws IOException {
        String indexPath = "D:\\以图搜图\\全部\\index";
        String searchImage = "D:\\以图搜图\\全部\\search\\timg.jpg";
        String searchOutputFolder = "D:\\以图搜图\\全部\\output";
        search(indexPath, searchImage, searchOutputFolder);
    }

    private static void search(String indexFolder, String searchFile, String searchOutputFolder) throws IOException {
        BufferedImage img = ImageIO.read(FileUtils.getFile(searchFile));

        IndexReader reader = DirectoryReader.open(FSDirectory.open(Paths.get(indexFolder)));
        ImageSearcher searcher = new GenericFastImageSearcher(30, CEDD.class);
        // ImageSearcher searcher = new GenericFastImageSearcher(30, AutoColorCorrelogram.class); // for another image descriptor ...

        /*
            If you used DocValues while Indexing, use the following searcher:
         */
        // ImageSearcher searcher = new GenericDocValuesImageSearcher(30, CEDD.class, ir);
        // searching with a image file ...
        ImageSearchHits hits = searcher.search(img, reader);
        // searching with a Lucene document instance ...
        // ImageSearchHits hits = searcher.search(ir.document(0), ir);
        for (int i = 0; i < hits.length(); i++) {
            String fileName = reader.document(hits.documentID(i)).getValues(DocumentBuilder.FIELD_NAME_IDENTIFIER)[0];
            System.out.println(hits.score(i) + ": \t" + fileName);
        }
        String outputHtmlReport = net.semanticmetadata.lire.utils.FileUtils.saveImageResultsToHtml("search-", hits, searchFile, reader);
        System.out.println("Report:" + outputHtmlReport);
        org.apache.commons.io.FileUtils.copyFile(org.apache.commons.io.FileUtils.getFile(outputHtmlReport), org.apache.commons.io.FileUtils.getFile(searchOutputFolder, outputHtmlReport));
    }
}

四、素材

   

    

  

五、LIRE支持的算法

  

  

### 回答1: Java实现以图搜图功能的实现主要依赖于图像处理和图像识别技术。 首先,需要使用Java的图像处理库,例如OpenCV或Java Advanced Imaging(JAI),来读取和处理图像。这些库提供了丰富的图像处理函数和算法,可以完成图像的预处理和特征提取等任务。 其次,需要使用机器学习或深度学习算法,来对图像进行特征提取和识别。可以使用Java的机器学习库,例如Weka或TensorFlow,来训练一个图像分类模型。该模型可以使用一组已知的图像样本进行训练,使其能够识别不同类型的图像。 在实际的搜索过程中,用户需要提供一个待搜索的图像。程序将使用同样的图像处理和特征提取算法,对待搜索的图像进行处理,并提取出与已知图像样本相似的特征。 最后,根据待搜索图像的特征与已知图像样本的相似度,可以通过计算两者之间的距离或相似性度量,来进行图像匹配和相似图像的搜索。模型会返回与待搜索图像最接近的已知图像样本,或者返回一组相似度较高的图像。 总结起来,Java实现以图搜图功能需要借助图像处理库和机器学习算法,对图像进行特征提取和识别。用户提供待搜索图像后,程序将对其进行处理,并通过比较特征的相似度,来到与之最接近或相似的图像。这样可以实现图像的搜索和相似图像的查。 ### 回答2: Java实现以图搜图功能可以通过以下步骤: 1. 图片特征提取:使用Java图像处理库,如OpenCV或Java Advanced Imaging(JAI),读取输入图像,并提取图像的关键特征,如颜色直方图、纹理特征或边缘特征等。这些特征可以通过计算图像的统计特性或使用深度学习算法进行提取。 2. 图像相似度计算:对于给定的检索图像,计算其与数据库中所有图像的相似度。可以使用Java相似度计算库,如Apache Commons Math,来计算两个图像特征之间的距离或相似度。常用的相似度度量包括欧氏距离、曼哈顿距离或余弦相似度等。 3. 数据库管理:将图像和其对应的特征值存储在数据库中。可以使用Java的关系型数据库,如MySQL或PostgreSQL,以及相应的JDBC驱动程序进行数据库管理。数据库的设计可以根据实际需求选择合适的表结构,包括图像文件路径、图像特征值等字段。 4. 图像搜索功能:用户输入待搜索图像,并提供图像路径或上传图像文件。程序读取输入图像,并提取其特征值。然后,程序计算输入图像与数据库中所有图像的相似度,相似度最高的图像。 5. 结果展示:将搜索结果展示给用户。可以使用Java图形化界面库,如JavaFX或Swing,创建一个用户友好的界面,显示搜索结果,并提供交互功能,如点击结果图像以显示详细信息、保存结果等。 总结起来,Java实现以图搜图功能主要涉及图像处理、特征提取、相似度计算、数据库管理和图形化界面等方面。这需要使用Java的图像处理库和相关算法,以及数据库和图形化界面的相关技术,结合数据库设计和Java编程知识来实现
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

遇君行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值