java指纹识别+谷歌图片识别技术(采用Hash方法)

2023-11-15

 

转载自:http://blog.csdn.net/yjflinchong/article/details/7469213

java指纹识别+谷歌图片识别技术

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


写了图片识别的一个demo

提供源码下载,免费下载地址:http://download.csdn.net/detail/yjflinchong/4239243

去试试效果吧

要源码的,请留下邮箱。我尽量发到各位邮箱中。

本人三年JAVA开发,寻求牛人加入Q群53141769


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

打开Google图片搜索页面:


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


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


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

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

 

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

 

预处理:读取图片

BufferedImage source = ImageHelper.readPNGImage(filename);// 读取文件

第一步,缩小尺寸。

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

/**
	 * 生成缩略图 <br/>
	 * 保存:ImageIO.write(BufferedImage, imgType[jpg/png/...], File);
	 * 
	 * @param source
	 *            原图片
	 * @param width
	 *            缩略图宽
	 * @param height
	 *            缩略图高
	 * @param b
	 *            是否等比缩放
	 * */
	public static BufferedImage thumb(BufferedImage source, int width,
			int height, boolean b) {
		// targetW,targetH分别表示目标长和宽
		int type = source.getType();
		BufferedImage target = null;
		double sx = (double) width / source.getWidth();
		double sy = (double) height / source.getHeight();

		if (b) {
			if (sx > sy) {
				sx = sy;
				width = (int) (sx * source.getWidth());
			} else {
				sy = sx;
				height = (int) (sy * source.getHeight());
			}
		}

		if (type == BufferedImage.TYPE_CUSTOM) { // handmade
			ColorModel cm = source.getColorModel();
			WritableRaster raster = cm.createCompatibleWritableRaster(width,
					height);
			boolean alphaPremultiplied = cm.isAlphaPremultiplied();
			target = new BufferedImage(cm, raster, alphaPremultiplied, null);
		} else
			target = new BufferedImage(width, height, type);
		Graphics2D g = target.createGraphics();
		// smoother than exlax:
		g.setRenderingHint(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_QUALITY);
		g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
		g.dispose();
		return target;
	}



第二步,简化色彩。

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

// 第二步,简化色彩。
		// 将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。
		int[] pixels = new int[width * height];
		for (int i = 0; i < width; i++) {
			for (int j = 0; j < height; j++) {
				pixels[i * height + j] = ImageHelper.rgbToGray(thumb.getRGB(i, j));
			}
		}



第三步,计算平均值。

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

	// 第三步,计算平均值。
		// 计算所有64个像素的灰度平均值。
		int avgPixel = ImageHelper.average(pixels);



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

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

// 第四步,比较像素的灰度。
		// 将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。
		int[] comps = new int[width * height];
		for (int i = 0; i < comps.length; i++) {
			if (pixels[i] >= avgPixel) {
				comps[i] = 1;
			} else {
				comps[i] = 0;
			}
		}



第五步,计算哈希值。

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

// 第五步,计算哈希值。
		// 将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。
		StringBuffer hashCode = new StringBuffer();
		for (int i = 0; i < comps.length; i+= 4) {
			int result = 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));
		}



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

	for (int i = 0; i < hashCodes.size(); i++)
        {
		    int difference = hammingDistance(sourceHashCode, hashCodes.get(i));
		    System.out.print("汉明距离:"+difference+"     ");
		    if(difference==0){
		    	System.out.println("source.jpg图片跟example"+(i+1)+".jpg一样");
		    }else if(difference<=5){
		    	System.out.println("source.jpg图片跟example"+(i+1)+".jpg非常相似");
		    }else if(difference<=10){
		    	System.out.println("source.jpg图片跟example"+(i+1)+".jpg有点相似");
		    }else if(difference>10){
		    	System.out.println("source.jpg图片跟example"+(i+1)+".jpg完全不一样");
		    }
        }



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

 

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

 

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


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


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java指纹识别+谷歌图片识别技术(采用Hash方法) 的相关文章

  • 使用 Java 的 OpenId 提供者/服务器

    我正在尝试使用 OpenId 服务增强现有的 Java Web 应用程序 以便登录用户可以使用我的 Web 应用程序作为 OpenId 提供程序登录另一个启用 OpenId 的应用程序 My first attempt was to use
  • 如何找出已使用的 JAR?

    在更大的项目中 我们可能会使用大量的 JAR 如何找出项目 而不是整个项目 中的某个模块 包正在使用哪些 JAR 有什么工具 技术等吗 较大的项目通常使用类似的构建工具maven http maven apache org or ant h
  • Encog - 如何加载神经网络的训练数据

    The NeuralDataSet我在实际中看到的对象除了 XOR 之外什么都没有 它只是两个小数据数组 我无法从文档中找出任何内容MLDataSet 似乎所有内容都必须立即加载 但是 我想循环遍历训练数据 直到到达 EOF 然后将其算作
  • 如何使 java.text.NumberFormat 将 0.0d 格式设置为“0”而不是“+0”?

    需要带符号的结果 0 0d 除外 IE 123 45d gt 123 45 123 45d gt 123 45 0 0d gt 0 我调用format setPositivePrefix 在 DecimalFormat 的实例上 强制结果中
  • java.lang.IllegalArgumentException:比较方法违反了其一般契约[重复]

    这个问题在这里已经有答案了 您好 下面是我的比较器的比较方法 我不确定出了什么问题 我在堆栈溢出上查找了其他类似标题的问题和答案 但不确定我的方法出了什么问题 但我不断收到 java lang IllegalArgumentExceptio
  • 如何在 Java 中用 \n 替换 \\n

    我有一个string test first n middle n last 现在我想更换所有 n by n 我试过了test replaceAll n n and test replaceAll n n 但它们不起作用 有人有解决办法吗 T
  • 关于java中同步的问题;何时/如何/到什么程度

    我正在开发我的第一个多线程程序 并在同步的几个方面陷入困境 我已经浏览了 oracle sun 主页上的多线程教程 以及这里的一些关于 SO 的问题 所以我相信我知道什么是同步 然而 正如我提到的 有几个方面我不太确定如何弄清楚 我以明确问
  • 具有 JPA、PostgreSQL 和 NULL 值的 JodaTime

    我试图将 JPA 的 JodaTime DateTime 字段保留到 PostgreSQL 但遇到了指向数据库 NULL 值的空指针的问题 我正在使用 NetBeans 7 beta 2 IDE 持久性实现是 EclipseLink 2 2
  • 设置 MetaspaceSize 的指南 - java 8

    64 位服务器的 MetaspaceSize 默认值是多少 我在官方文档中没有找到它 我观察到 在服务器 JVM 进程中 GC 频率有时会变高并持续增长 如果我重新启动服务几次 它就会恢复稳定 我认为这是由于 JRE 升级造成的 JVM 堆
  • Android 3.1 USB 主机 - BroadcastReceiver 未收到 USB_DEVICE_ATTACHED

    我经历过USB 主机的描述和示例位于developer android com http developer android com guide topics usb host html检测连接和分离的 USB 设备 如果我在清单文件中使用
  • EDITLogBack Syslog 不工作 java

    我写了一个简单的项目来在 Ubuntu 中运行日志 方法如下example https examples javacodegeeks com enterprise java logback logback syslog example 应用
  • 如何在给定目标索引数组的情况下对数组进行就地排序?

    你如何对给定的数组进行排序arr in place给定目标索引数组ind 例如 var arr A B C D E F var ind 4 0 5 2 1 3 rearrange arr ind console log arr gt B E
  • 如何自定义 JFrame 上的标题栏?

    我想在我的 Java Swing 桌面应用程序中拥有一个自定义的标题栏 最好的方法是什么 我可以通过在 JFrame 的构造函数中使用以下代码来使用 Swing 标题栏 this setUndecorated true this getRo
  • 如何求解:T(n) = T(n - 1) + n

    我已经解决了以下问题 T n T n 1 n O n 2 现在 当我解决这个问题时 我发现界限非常松散 我是否做错了什么 或者只是这样 您还需要一个递归关系的基本情况 T 1 c T n T n 1 n 为了解决这个问题 您可以首先猜测一个
  • Android 改造参数化@Headers

    我正在使用 OAuth 每次发出请求时都需要将 OAuth 令牌放入标头中 我看到 Header注释 但是有没有办法让它参数化 以便我可以在运行时传入 这是概念 Header Authorization OAuth var api vers
  • 重构 google 的 NetworkBoundResource 类以使用 RxJava 而不是 LiveData

    谷歌的android架构组件教程here https developer android com topic libraries architecture guide html有一部分解释了如何抽象通过网络获取数据的逻辑 在其中 他们使用
  • 为什么我们在同一台服务器上使用多个应用程序服务器实例

    我想这是有充分理由的 但我不明白为什么有时我们会在同一物理服务器上放置例如 5 个具有相同 Web 应用程序的实例 这与多处理器架构的优化有关吗 JVM 或其他允许的最大内存限制 嗯 过了很长一段时间我又看到这个问题了 一台机器上的多个 J
  • Java并发锁和条件的使用

    我可以用object wait object notify and synchronized blocks解决生产者消费者类型的问题 同时我可以使用locks and conditions from java util concurrent
  • 在 O(n) 时间内找到 n x n 矩阵中的局部最小值

    所以 这不是我的家庭作业问题 而是取自 coursera 算法和数据结构课程的未评分作业 现已完成 You are given an n by n grid of distinct numbers A number is a local m
  • Android,Volley请求,响应阻塞主线程

    使用 Volley 处理较大响应时会发生一些不好的事情 String url AppHelper DOMAIN service pages profile update json this infoTextView setText getS

随机推荐

  • 【详解】指针与函数传参——多图、多例子(c语言)

    前言 在用c语言实现链表时 会有很多朋友无法理解明明传了指针到函数中 函数中对指针改变却无法影响原函数中指针的位置 事实上 这是因为你对形参和实参的关系理解还不够透彻 通过这篇文章 我将告诉你指针传参时 函数的形参到底该选择怎样的类型接收
  • jquery——zTree, 完美好用的树插件

  • 记一次udp服务性能优化经历

    目录 概述 磁盘io 网络io 减少重复计算 减少内存复制 减少互斥锁 概述 手上有个go项目 接收udp信息 主要是syslog和snmp trap 并查询设备信息 将信息结构化 设备ip名称 匹配了什么规则之类的 后发送到kafka和e
  • 哈夫曼编码的实现

    2 哈夫曼编码的实现 对教材P167中习题5 18 编码实现哈夫曼编码树 并对 Chapter Graphs surveys the most important graph processing problems including de
  • org.hibernate.UnknownEntityTypeException: Unable to locate persister:xxx类

    看了网上其他人的解决办法 发现出现的错误跟我的并不相同 基本就是没有引入映射文件 或者映射文件路径错误 我的错误是抽取了一个公共的dao 其中 get方法应该传入get x class id 而我写入的是类名 所以运行时总是提示找不到这个类
  • 51单片机学习笔记-12LCD1602液晶屏

    12 LCD1602液晶屏 toc 注 笔记主要参考B站江科大自化协教学视频 51单片机入门教程 2020版 程序全程纯手打 从零开始入门 注 工程及代码文件放在了本人的Github仓库 12 1 LCD1602介绍 LCD1602 Liq
  • ArcSDE 日志文件表(二)

    基于会话的或独立的日志文件组成的池 Pools of log file tables 以下为ArcGIS10 1中文帮助 归地理数据库管理员所有的日志文件池 地理数据库管理员可以创建可由其他用户检出和使用的日志文件池 这些日志文件可以是基于
  • spark性能优化调优指导性文件

    1 让我们看一下前面的核心参数设置 num executors 10 20 executor cores 1 2 executor memory 10 20 driver memory 20 spark default parallelis
  • Linux常用命令与JavaWeb开发环境的搭建

    文章目录 前言 一 系统信息以及查看文件 1 1系统信息 1 2查看文件 二 查看进程和防火墙的开关 三 搭建Java Web开发环境 3 1JDK 3 2Tomcat 3 3Mysql 总结 前言 Linux 特点 免费 开源 免费 安全
  • 继电器驱动电路原理及注意事项

    继电器驱动电流一般需要20 40mA或更大 线圈电阻100 200欧姆 因此要加驱动电路 1 晶体管用来驱动继电器 必须将晶体管的发射极接地 具体电路如下 NPN晶体管 PNP晶体管 NPN晶体管驱动时 当晶体管T1基极被输入高电平时 晶体
  • 导入数据的几种方法

    采用标准python类库导入数据 读取文件 from csv import reader import numpy as np filename pima csv with open filename rt as raw data read
  • centOS7服务器搭建

    一 安装jdk 运行代码 yum search jdk 1 查询当前云服务器里面通过yum可以安装哪些jdk 以这个jdk1 8的版本为例 运行代码 yum y install java 1 8 0 openjdk 2 安装jdk1 8版本
  • obj(判断对象中是否包含某个key属性)

    key in obj 不包含 obj hasOwnProperty key 包含
  • 纯代码构建Swift工程

    有些东西很简单 但是我还是把它记录了下来 使用Storyboard创建一个新的项目后 应用程序从闪屏 到主窗口 再到第一个界面经过的文件分别是 LaunchScreen storyboard gt Main storyboard gt Vi
  • NBIoT与LoRa技术详解及竞争态势分析

    物联网的无线通信技术很多 主要分为两类 一类是Zigbee WiFi 蓝牙 Z wave等短距离通信技术 另一类是LPWAN low power Wide Area Network 低功耗广域网 即广域网通信技术 LPWA又可分为两类 一类
  • 计算机视觉领域经典模型汇总(RCNN、YOLO等)

    一 RCNN系列 1 RCNN RCNN是用于目标检测的经典方法 其核心思想是将目标检测任务分解为两个主要步骤 候选区域生成和目标分类 候选区域生成 RCNN的第一步是生成可能包含目标的候选区域 RCNN使用传统的计算机视觉技术 特别是选择
  • linux中tmp文件在哪,Linux系统中/tmp文件夹

    在Linux系统中 tmp文件夹里面的文件会被清空 至于多长时间被清空 如何清空的 可能大家知识的就不多了 所以 今天我们就来剖析一个这两个问题 在RHEL CentOS Fedora 系统中 本次实验是在RHEL6中进行的 1 tmpwa
  • 数字后端dbGet使用方法合集

    以下资料是我之前写过的 芯片数字后端中Innovus Encounter dbGet命令使用方法的介绍 整理了一下 做成合集 方便大家查询 点击标题就可以选择文章查看 会直接挂在公众号的主页菜单栏里的 后端资料 里 感觉好的话 请多多推广喔
  • java报错:Connection reset by peer: socket write error

    用java做excel导出时 报错 ClientAbortException java net SocketException Connection reset by peer socket write error 大致出现问题的原因如下
  • java指纹识别+谷歌图片识别技术(采用Hash方法)

    转载自 http blog csdn net yjflinchong article details 7469213 java指纹识别 谷歌图片识别技术 前阵子在阮一峰的博客上看到了这篇 相似图片搜索原理 博客 就有一种冲动要将这些原理实现