图片相似原理 - Java实现
前阵子在阮一峰的博客上看到了这篇《相似图片搜索原理》博客,就有一种冲动要将这些原理实现出来了。
Google "相似图片搜索":你可以用一张图片,搜索互联网上所有与它相似的图片。
打开Google图片搜索页面:
点击使用上传一张原图:
点击搜索后,Google将会找出与之相似的图片,图片相似度越高就越排在前面。如:
这种技术的原理是什么?计算机怎么知道两张图片相似呢?
根据Neal Krawetz博士的解释,实现相似图片搜素的关键技术叫做"感知哈希算法"(Perceptualhash algorithm),它的作用是对每张图片生成一个"指纹"(fingerprint)字符串,然后比较不同图片的指纹。结果越接近,就说明图片越相似。
以下是一个最简单的Java实现:
预处理:读取图片
File inputFile = newFile(filename); BufferedImage sourceImage = ImageIO.read(inputFile);//读取图片文件
第一步,缩小尺寸。
将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。
int width= 8; intheight = 8; // targetW,targetH分别表示目标长和宽 int type= sourceImage.getType();// 图片类型 BufferedImagethumbImage = null; double sx= (double) width / sourceImage.getWidth(); double sy= (double) height / sourceImage.getHeight(); // 将图片宽度和高度都设置成一样,以长度短的为准 if (b) { if(sx > sy) { sx= sy; width= (int) (sx * sourceImage.getWidth()); }else { sy= sx; height= (int) (sy * sourceImage.getHeight()); } } // 自定义图片 if (type== BufferedImage.TYPE_CUSTOM) { // handmade ColorModelcm = sourceImage.getColorModel(); WritableRasterraster = cm.createCompatibleWritableRaster(width, height); booleanalphaPremultiplied = cm.isAlphaPremultiplied(); thumbImage= new BufferedImage(cm, raster, alphaPremultiplied, null); } else { // 已知图片,如jpg,png,gif thumbImage= new BufferedImage(width, height, type); } // 调用画图类画缩小尺寸后的图 Graphics2Dg = target.createGraphics(); //smoother than exlax: g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.drawRenderedImage(sourceImage,AffineTransform.getScaleInstance(sx, sy)); g.dispose();
第二步,简化色彩。
将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。
int[]pixels = new int[width * height]; for (inti = 0; i < width; i++) { for(int j = 0; j < height; j++) { pixels[i* height + j] = rgbToGray(thumbImage.getRGB(i, j)); } } /** * 灰度值计算 * @param pixels 彩色RGB值(Red-Green-Blue 红绿蓝) * @return int 灰度值 */ public static int rgbToGray(int pixels) { // int _alpha =(pixels >> 24) & 0xFF; int _red = (pixels >> 16) & 0xFF; int _green = (pixels >> 8) & 0xFF; int _blue = (pixels) & 0xFF; return (int) (0.3 * _red + 0.59 * _green + 0.11 * _blue); }
第三步,计算平均值。
计算所有64个像素的灰度平均值。
int avgPixel= 0; int m = 0; for (int i =0; i < pixels.length; ++i) { m +=pixels[i]; } m = m /pixels.length; avgPixel = m;
第四步,比较像素的灰度。
将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。
int[] comps= new int[width * height]; for (inti = 0; i < comps.length; i++) { if(pixels[i] >= avgPixel) { comps[i]= 1; }else { comps[i]= 0; } }
第五步,计算哈希值。
将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。
== 8f373714acfcf4d0
StringBufferhashCode = new StringBuffer(); for (inti = 0; i < comps.length; i+= 4) { 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]; hashCode.append(binaryToHex(result));//二进制转为16进制 } StringsourceHashCode = hashCode.toString();
得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hammingdistance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。
int difference = 0; int len =sourceHashCode.length(); for (inti = 0; i < len; i++) { if(sourceHashCode.charAt(i) != hashCode.charAt(i)) { difference++; } }
你可以将几张图片放在一起,也计算出他们的汉明距离对比,就可以看看两张图片是否相似。
这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。
实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。
以上内容大部分直接从阮一峰的网站上复制过来,想看原著的童鞋可以去在最上面的链接点击进去看。
提供源码下载,源码下载链接:http://download.csdn.net/detail/luohong722/3965112
图片相似原理 - Java实现相关推荐
- 图片浏览器java程序_图片浏览器用java实现
该程序实现了图片的缩放以及浏览 package graphics; /** * 图片的缩放功能实现: *为什么图片不能无限放大,因为Thread的run方法不断在调整. *必须选择jpg或png的图片 ...
- 对接天猫接口之获取宝贝主图和购买宝贝对应的SKU图片(Java实现)
获取宝贝主图,Java实现如下: public static String getDownloadImgURL(String auctionId) throws Exception { ...
- java 图片处理 图片缩略图,java怎么生成图片缩略图,缩小图片,高清图片缩小
java如何生成图片缩略图,缩小图片,高清图片缩小 可以把图片缩小到理想的倍数,也可以根据自己的需要来具体规定图片转化后的大小 对于类型为jpg的图片来说,只需要三个参数就能转化得到自己想要的图片 参 ...
- 使用Thumbnails压缩或放大图片大小(java)
首先看下缩放图片的核心代码,其实只有一行而已 //ins表示ByteArrayInputStream形式的图片 //scale中的数据就是缩小或者放大的比例,比如小于1则表示压缩,大于1表示放大 // ...
- java script的图片隐藏,java和javascript中过滤掉img形式的字符串不显示图片的方法...
本文实例讲述了java和javascript中过滤掉img形式的字符串不显示图片的方法.分享给大家供大家参考.具体实现方法如下: 1. javascript过滤掉和形式的字符串 复制代码代码如下: 过 ...
- 生成最简单的验证码图片的Java代码
后端代码: package priv.lwx.servlet.sl.web; /*** description** @author liaowenxiong* @date 2022/3/25 09:5 ...
- 生成验证码图片的Java代码
文章目录 验证码演示代码 请求资源路径为什么要添加一个随机数的参数 验证码演示代码 package priv.lwx.javaex.servlet_demo.web.servlet.response; ...
- java如何叠加图片_图片叠加效果Java代码实现
本文实例为大家分享了Java实现图片叠加效果展示的具体代码,供大家参考,具体内容如下 import java.awt.AlphaComposite; import java.awt.Graphics2 ...
- java 判断图片合适,Java 判断图片色彩
package cardshibie; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOut ...
- 批量压缩图片软件 JAVA
批量压缩图片软件 - CompressImages 软件介绍: CompressImages是一款批量压缩图片的软件,它能够将指定文件夹(含子目录)中的所有图片文件进行压缩,并且是在图片不失真的前提下 ...
最新文章
- 软件工程硕士和计算机硕士论文题目,计算机硕士毕业论文答辩自述
- mac mysql ip访问不了_解决mysql中只能通过localhost访问不能通过ip访问的问题
- 什么能在main()函数之前或之后执行
- php项目课题,php课题
- 怎么实现注解_通透!一口气搞懂注解到底怎么用
- java异常代码分析
- P3512 [POI2010]PIL-Pilots(单调队列+二分)
- 经典论文阅读记录-持续更新
- 海明码计算(校验码)
- 软考软件设计师下午真题-面向对象的程序设计与实现-享元设计模式(2021年下半年试题六))Java代码讲解
- mysql字段动态扩展_数据库动态扩展字段
- r语言和python混合_jupyter notebook同时使用python和R语言
- android 锤子桌面壁纸,锤子桌面使用技巧|锤子桌面 1.5.1 安卓版_久友下载站_壁纸美化...
- 制造执行系统(MES)软件可以增加收入,创造更快的周转时间,提高制造商的质量
- Excel中如何使用字符串提取函数LEFT
- obs64位捕获yy开播伴侣
- 元数据是什么意思_中国股市:股票分红10转10股派5元,你看懂是什么意思了吗?...
- python计算差商_用Python求函数的差商
- 写出10以内的奇偶数php,幼儿园中班科学活动“认识奇数偶数”
- Matlab:Matlab编程语言应用之三维绘图可视化(基础知识点基本函)的使用方法简介、案例实现(三维曲线图机械阻尼振动三维等高线图等案例)之详细攻略
热门文章
- Linux -shell 基础
- github优秀代码锦集
- 如何计算机网络打印机,电脑如何连接网络打印机?网络打印机的连接教程
- 打印机脱机了怎么恢复打印
- 3.Orangepi PC2 使用busybox制作文件系统
- Linux禁用搜狗输入法的简繁切换快捷键
- 回归分析结果表格怎么填_excel回归分析结果解读
- UGUI 实现屏幕外怪物的指示箭头
- [小传]任正非:高中三年的理想只是吃个白面馒头 [zz.IS2120]
- python中[::-1][1:2][1::2]的用法