前阵子在阮一峰的博客上看到了这篇《相似图片搜索原理》博客,就有一种冲动要将这些原理实现出来了。

Google "相似图片搜索":你可以用一张图片,搜索互联网上所有与它相似的图片。

打开Google图片搜索页面:

点击使用上传一张angelababy原图:

点击搜索后,Google将会找出与之相似的图片,图片相似度越高就越排在前面。如:

这种技术的原理是什么?计算机怎么知道两张图片相似呢?

根据Neal Krawetz博士的解释,实现相似图片搜素的关键技术叫做"感知哈希算法"(Perceptualhash algorithm),它的作用是对每张图片生成一个"指纹"(fingerprint)字符串,然后比较不同图片的指纹。结果越接近,就说明图片越相似。

以下是一个最简单的Java实现:

预处理:读取图片

  1. File inputFile = newFile(filename);
  2. BufferedImage sourceImage = ImageIO.read(inputFile);//读取图片文件

第一步,缩小尺寸。

将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。

  1. int width= 8;
  2. intheight = 8;
  3. // targetW,targetH分别表示目标长和宽
  4. int type= sourceImage.getType();// 图片类型
  5. BufferedImagethumbImage = null;
  6. double sx= (double) width / sourceImage.getWidth();
  7. double sy= (double) height / sourceImage.getHeight();
  1. // 将图片宽度和高度都设置成一样,以长度短的为准
  2. if (b) {
  3. if(sx > sy) {
  4. sx= sy;
  5. width= (int) (sx * sourceImage.getWidth());
  6. }else {
  7. sy= sx;
  8. height= (int) (sy * sourceImage.getHeight());
  9. }
  10. }
  11. // 自定义图片
  12. if (type== BufferedImage.TYPE_CUSTOM) { // handmade
  13. ColorModelcm = sourceImage.getColorModel();
  14. WritableRasterraster = cm.createCompatibleWritableRaster(width,height);
  15. booleanalphaPremultiplied = cm.isAlphaPremultiplied();
  16. thumbImage= new BufferedImage(cm, raster, alphaPremultiplied, null);
  17. } else {
  18. // 已知图片,如jpg,png,gif
  19. thumbImage= new BufferedImage(width, height, type);
  20. }
  21. // 调用画图类画缩小尺寸后的图
  22. Graphics2Dg = target.createGraphics();
  23. //smoother than exlax:
  24. g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
  25. g.drawRenderedImage(sourceImage,AffineTransform.getScaleInstance(sx, sy));
  26. g.dispose();

第二步,简化色彩。

将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。

  1. int[]pixels = new int[width * height];
  2. for (inti = 0; i < width; i++) {
  3. for(int j = 0; j < height; j++) {
  4. pixels[i* height + j] = rgbToGray(thumbImage.getRGB(i, j));
  5. }
  6. }
  7. /**
  8. * 灰度值计算
  9. * @param pixels 彩色RGB值(Red-Green-Blue 红绿蓝)
  10. * @return int 灰度值
  11. */
  12. public static int rgbToGray(int pixels) {
  13. // int _alpha =(pixels >> 24) & 0xFF;
  14. int _red = (pixels >> 16) & 0xFF;
  15. int _green = (pixels >> 8) & 0xFF;
  16. int _blue = (pixels) & 0xFF;
  17. return (int) (0.3 * _red + 0.59 * _green + 0.11 * _blue);
  18. }

第三步,计算平均值。

计算所有64个像素的灰度平均值。

  1. int avgPixel= 0;
  2. int m = 0;
  3. for (int i =0; i < pixels.length; ++i) {
  4. m +=pixels[i];
  5. }
  6. m = m /pixels.length;
  7. avgPixel = m;

第四步,比较像素的灰度。

将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。

  1. int[] comps= new int[width * height];
  2. for (inti = 0; i < comps.length; i++) {
  3. if(pixels[i] >= avgPixel) {
  4. comps[i]= 1;
  5. }else {
  6. comps[i]= 0;
  7. }
  8. }

第五步,计算哈希值。

将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。

 =  = 8f373714acfcf4d0

  1. StringBufferhashCode = new StringBuffer();
  2. for (inti = 0; i < comps.length; i+= 4) {
  3. intresult = comps[i] * (int) Math.pow(2, 3) + comps[i + 1] * (int) Math.pow(2, 2)+ comps[i + 2] * (int) Math.pow(2, 1) + comps[i + 2];
  4. hashCode.append(binaryToHex(result));//二进制转为16进制
  5. }
  6. StringsourceHashCode = hashCode.toString();

得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hammingdistance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。

  1. int difference = 0;
  2. int len =sourceHashCode.length();
  3. for (inti = 0; i < len; i++) {
  4. if(sourceHashCode.charAt(i) != hashCode.charAt(i)) {
  5. difference++;
  6. }
  7. }

你可以将几张图片放在一起,也计算出他们的汉明距离对比,就可以看看两张图片是否相似。

这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。

实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。

以上内容大部分直接从阮一峰的网站上复制过来,想看原著的童鞋可以去在最上面的链接点击进去看。

提供源码下载,源码下载链接:http://download.csdn.net/detail/luohong722/3965112

参考链接:神奇的图像处理算法, 11款相似图片搜索引擎推荐,以图搜图将不再是难事,http://insidesearch.blogspot.com/2011/07/teaching-computers-to-see-image.html

Google 以图搜图 - 相似图片搜索原理 - Java实现的更多相关文章

  1. Google 以图搜图 - 相似图片搜索原理 - Java实现 (转)

    前阵子在阮一峰的博客上看到了这篇<相似图片搜索原理>博客,就有一种冲动要将这些原理实现出来了. Google "相似图片搜索":你可以用一张图片,搜索互联网上所有与它相 ...

  2. 使用 selenium 实现谷歌以图搜图爬虫

    使用selenium实现谷歌以图搜图 实现思路 原理非常简单,就是利用selenium去操作浏览器,获取到想要的链接,然后进行图片的下载,和一般的爬虫无异. 用到的技术:multiprocessing ...

  3. 以图搜图(一):Python实现dHash算法(转)

    近期研究了一下以图搜图这个炫酷的东西.百度和谷歌都有提供以图搜图的功能,有兴趣可以找一下.当然,不是很深入.深入的话,得运用到深度学习这货.Python深度学习当然不在话下. 这个功能最核心的东西就是 ...

  4. 以图搜图之模型篇: 基于 InceptionV3 的模型 finetune

    在以图搜图的过程中,需要以来模型提取特征,通过特征之间的欧式距离来找到相似的图形. 本次我们主要讲诉以图搜图模型创建的方法. 图片预处理方法,看这里:https://keras.io/zh/prepr ...

  5. [No000007]搜索引擎以图搜图的原理

    之前,Google把"相似图片搜索"正式放上了首页. 你可以用一张图片,搜索互联网上所有与它相似的图片.点击搜索框中照相机的图标. 一个对话框会出现. 你输入网片的网址,或者直接上 ...

  6. php 以图搜图

    感知哈希算法count < =5 匹配最相似count > 10 两张不同的图片var_dump(ImageHash::run('1.jpg’, '2.jpg’)); <?php c ...

  7. 谷歌百度以图搜图 "感知哈希算法" C#简单实现

    /// <summary> /// 感知哈希算法 /// </summary> public class ImageComparer { /// <summary> ...

  8. 如何使用 js 实现相似图片搜索

    如何使用 js 实现相似图片搜索 以图搜图 https://www.google.com/imghp?hl=en https://www.google.com/imghp?hl=zh https:// ...

  9. Google图片搜索

    本博文的主要内容有 .Google图片搜索的介绍 .Google图片之普通搜索    .Google图片之高级搜索 1.Google图片搜索的介绍   Google的图片搜索,不仅通过关键字查找拥有特 ...

随机推荐

  1. P6 EPPM R16.1安装与配置指南(二)

    P6 EPPM R16.1安装与配置指南(一) http://www.cnblogs.com/endv/p/5634620.html P6 EPPM R16.1安装与配置指南(二) 环境变量配置 新建 ...

  2. [爬虫学习笔记]用于提取网页中所有链接的 Extractor 模块

            Extractor的工作是从下载的网页中将它包含的所有URL提取出来.这是个细致的工作,你需要考虑到所有可能的url的样式,比如网页中常常会包含相对路径的url,提取的时候需要将它转换 ...

  3. 不经意间网易开源镜像去掉了FreeBSD的镜像

    http://mirrors.163.com/ FreeBSD已经到了这么不招人待见的地步了么? 网易曾经可是FreeBSD的大户啊.

  4. hadoop pipes wordcount compile

    http://devel.cs.stolaf.edu/projects/bw/wiki.real/index.php/Hadoop_Reference,_January_2011 http://guo ...

  5. [PHP] java读取PHP接口数据

    和安卓是一个道理,读取json数据 PHP文件: <?php class Test{ //日志路径 const LOG_PATH="E:\phpServer\Apache\logs\\ ...

  6. iOS App上线的秘密

    App上线需要准备几个证书:首先是是CSR证书,要创建这个证书需要在自己电脑上找到钥匙串访问(在应用程序->其他 里面).钥匙串访问->证书助理->从证书颁发机构请求证书如下: 创建 ...

  7. java微信开发(wechat4j)——发送客服消息

    微信支持主动发送客服消息.如果你要实现此功能,需要使用CustomerMsg类. 获得access_token access_token请求之后有一个过期时间,微信平台建议你使用一个中控服务器来定时刷 ...

  8. EF数据库初始化策略及种子数据的添加

    EF数据库初始化策略及种子数据的添加 CreateDatabaseIfNotExists 判断当前数据库连接字符串对应的数据库是否存在,若不存在则根据代码定义的model进行创建 DropCreate ...

  9. Windows Azure 上传 VM

    One of the great features of Windows Azure is VHD mobility. Simply put it means you can upload and d ...

  10. Android Studio利用Gradle删除没有使用到的资源和代码文件

    一.打包时忽略无用资源 我们在打包的时候默认会把没有用到的资源(比如图片)也打包成app,徒增了应用的大小.现在我们可以利用Gradle来优雅的去除没有用到的资源文件了! 就是在gradle中配置sh ...