使用图像的类似图像搜索

我正在开展一个项目,其中将检查两个图像的相似性,如“Google Image Search by image”。

我搜索了谷歌以及各种网站,包括stackoverflow,并了解了各种技术,如直方图,筛选,傅里叶变换,像素抓取等。

事情太复杂了,我无法理解成为这个领域的初学者。

我的问题是:

  1. 我从哪里开始? 是否有任何书籍或网站提供有关如何实际使用这些技术的教程?

  2. 是否有可以为此目的实施的新技术?

我想开始通过颜色搜索图像,然后如果可能的话可能会有其他属性。

首选语言是Java。

这个主题有一个类似的主题,但它是几年前写的。

为了这个目的,我已经为http://sourceforge.net/projects/imgndxr/提供了一个名为Images相似搜索器的工具作为免费软件。

它使用两个库:

  • LIRE: http : //www.semanticmetadata.net/lire/

LIRE(Lucene Image REtrieval)库提供了一种基于颜色和纹理特征检索图像和照片的简单方法。 LIRE为基于内容的图像检索(CBIR)创建了Lucene图像特征索引。 有几种不同的低级function,例如MPEG-7 ScalableColor,ColorLayout和EdgeHistogram,Auto Color Correlogram,PHOG,CEDD,JCD,FCTH等等。 此外,LIRE提供了用于搜索索引和结果浏览的简单和扩展方法。 LIRE使用基于散列的近似索引可以很好地扩展到数百万个图像。 LIRE库和LIRE Demo应用程序以及所有源代码均在Gnu GPL许可下提供。

  • LUCENE: http : //lucene.apache.org/core/

Apache LuceneTM是一个完全用Java编写的高性能,function齐全的文本搜索引擎库。 它是一种适用于几乎所有需要全文搜索的应用程序的技术,尤其是跨平台搜索。

Apache Lucene是一个可供免费下载的开源项目。 请使用右侧的链接访问Lucene。

这取决于您的使用案例。 图像是通用的,还是在类似的照明条件和视角下拍摄的?


可以根据模型的复杂性对方法进行分类。 从本质上讲,我们可以区分直接与基于特征的方法。

直接(或基于强度)方法试图通过基于重叠区域中的强度差异最小化误差函数来(迭代地)估计相似性。 每个图像必须表示具有相同比例,视角等的完全相同的场景,以便重叠它们。 可以通过计算和方差(SSD)或ZSSD,相关系数(CC),互信息(MI)和相关比(RC)来实现相似性测量。

直接方法可以用于例如检查新video压缩算法的工作情况。 看看下面的文章:

http://docs.opencv.org/trunk/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.html


另一方面,我们可以谈论基于特征的方法。 他们尝试在点,线或其他几何实体之间建立对应关系以估计相机参数。 当图像的结构单元(像素)不包含有关其内容的足够信息时,它们可能很有用。 因此,基于特征的方法试图用数学特征(n维向量)表示图像内容,然后使用分类器来比较这些特征以获得关于它们的相似性的度量。

通过将图像调整为8×8缩略图,然后获取每个图像中相应像素之间的8位RGB色差的均方误差,我得到了满意的结果。

步骤1.创建缩略图:

BufferedImage img = ImageIO.read(src); Image thumbnail = img.getScaledInstance(8, 8, Image.SCALE_AREA_AVERAGING); 

检查https://community.oracle.com/docs/DOC-983611 ,了解为什么我选择较慢的SCALE_AREA_AVERAGING不是更新,更快的方法。

步骤2.使用Java转换Image到BufferedImage的toBufferedImage方法Image缩略图 转换为BufferedImage 。 将结果放入List

步骤3.计算均方误差

此方法采用两个尺寸相同的缩略图大小的图像并返回差异。 零意味着图像非常相似:

 public static double compare(BufferedImage img1, BufferedImage img2) { int width1 = img1.getWidth(); int width2 = img2.getWidth(); int height1 = img1.getHeight(); int height2 = img2.getHeight(); if ((width1 != width2) || (height1 != height2)) { throw new IllegalArgumentException("Error: Images dimensions mismatch"); } int diff2 = 0; for (int i = 0; i < height1; i++) { for (int j = 0; j < width1; j++) { int rgb1 = img1.getRGB(j, i); int rgb2 = img2.getRGB(j, i); int r1 = (rgb1 >> 16) & 0xff; int g1 = (rgb1 >> 8) & 0xff; int b1 = (rgb1) & 0xff; int r2 = (rgb2 >> 16) & 0xff; int g2 = (rgb2 >> 8) & 0xff; int b2 = (rgb2) & 0xff; diff2 += Math.pow(r1 - r2, 2) + Math.pow(g1 - g2, 2) + Math.pow(b1 - b2, 2); } } return diff2 * 1.0 / (height1*width1); } 

步骤4.实施搜索

这通过简单地找到具有最小差异的图像来工作。 根据您的使用情况,您可能还需要设置一个阈值,高于该阈值不会返回任何图像。 在我的应用程序中,始终向用户显示最佳匹配,以便用户可以决定它是否是正确的图像,因此不需要硬编码阈值。

 public BufferedImage findImage(List haystack, BufferedImage needle) { double lastDiff = Double.MAX_VALUE; BufferedImage winner = null; for(BufferedImage candidate: haystack) { double diff = compare(candidate, needle); if(diff < lastDiff) { lastDiff = diff; winner = candidate; } } return winner; }