Java图片上查找图片算法
之前用按键精灵写过一些游戏辅助,里面有个函数叫FindPic,就是在屏幕范围查找给定的一张图片,返回查找到的坐标位置。
现在,Java来实现这个函数类似的功能。
算法描述:
- 屏幕截图,得到图A,(查找的目标图片为图B);
- 遍历图A的像素点,根据图B的尺寸,得到图B四个角映射到图A上的四个点;
- 得到的四个点与图B的四个角像素点的值比较。如果四个点一样,执行步骤4;否则,回到步骤2继续;
- 进一步对比,将映射范围内的全部点与图B全部的点比较。如果全部一样,则说明图片已找到;否则,回到步骤2继续;
这里,像素之间的比较是通过BufferedImage对象获取每个像素的RGB值来比较的。如下,将BufferedImage转换为int二维数组:
/**
* 根据BufferedImage获取图片RGB数组
* @param bfImage
* @return
*/
public static int[][] getImageGRB(BufferedImage bfImage) {
int width = bfImage.getWidth();
int height = bfImage.getHeight();
int[][] result = new int[height][width];
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
//使用getRGB(w, h)获取该点的颜色值是ARGB,而在实际应用中使用的是RGB,所以需要将ARGB转化成RGB,即bufImg.getRGB(w, h) & 0xFFFFFF。
result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF;
}
}
return result;
}
比较两个像素点的RGB值是否相同,是通过异或操作比较的(据说比==效率更高),如果异或操作后得到的值为0,说明两个像素点的RGB一样,否则不一样。
下面附上算法完整java代码:
package com.jebysun.test.imagefind; import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException; import javax.imageio.ImageIO;
/**
* 屏幕上查找指定图片
* @author Jeby Sun
* @date 2014-09-13
* @website http://www.jebysun.com
*/
public class ImageFindDemo { BufferedImage screenShotImage; //屏幕截图
BufferedImage keyImage; //查找目标图片 int scrShotImgWidth; //屏幕截图宽度
int scrShotImgHeight; //屏幕截图高度 int keyImgWidth; //查找目标图片宽度
int keyImgHeight; //查找目标图片高度 int[][] screenShotImageRGBData; //屏幕截图RGB数据
int[][] keyImageRGBData; //查找目标图片RGB数据 int[][][] findImgData; //查找结果,目标图标位于屏幕截图上的坐标数据 public ImageFindDemo(String keyImagePath) {
screenShotImage = this.getFullScreenShot();
keyImage = this.getBfImageFromPath(keyImagePath);
screenShotImageRGBData = this.getImageGRB(screenShotImage);
keyImageRGBData = this.getImageGRB(keyImage);
scrShotImgWidth = screenShotImage.getWidth();
scrShotImgHeight = screenShotImage.getHeight();
keyImgWidth = keyImage.getWidth();
keyImgHeight = keyImage.getHeight(); //开始查找
this.findImage(); } /**
* 全屏截图
* @return 返回BufferedImage
*/
public BufferedImage getFullScreenShot() {
BufferedImage bfImage = null;
int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
try {
Robot robot = new Robot();
bfImage = robot.createScreenCapture(new Rectangle(0, 0, width, height));
} catch (AWTException e) {
e.printStackTrace();
}
return bfImage;
} /**
* 从本地文件读取目标图片
* @param keyImagePath - 图片绝对路径
* @return 本地图片的BufferedImage对象
*/
public BufferedImage getBfImageFromPath(String keyImagePath) {
BufferedImage bfImage = null;
try {
bfImage = ImageIO.read(new File(keyImagePath));
} catch (IOException e) {
e.printStackTrace();
}
return bfImage;
} /**
* 根据BufferedImage获取图片RGB数组
* @param bfImage
* @return
*/
public int[][] getImageGRB(BufferedImage bfImage) {
int width = bfImage.getWidth();
int height = bfImage.getHeight();
int[][] result = new int[height][width];
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
//使用getRGB(w, h)获取该点的颜色值是ARGB,而在实际应用中使用的是RGB,所以需要将ARGB转化成RGB,即bufImg.getRGB(w, h) & 0xFFFFFF。
result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF;
}
}
return result;
} /**
* 查找图片
*/
public void findImage() {
findImgData = new int[keyImgHeight][keyImgWidth][2];
//遍历屏幕截图像素点数据
for(int y=0; y<scrShotImgHeight-keyImgHeight; y++) {
for(int x=0; x<scrShotImgWidth-keyImgWidth; x++) {
//根据目标图的尺寸,得到目标图四个角映射到屏幕截图上的四个点,
//判断截图上对应的四个点与图B的四个角像素点的值是否相同,
//如果相同就将屏幕截图上映射范围内的所有的点与目标图的所有的点进行比较。
if((keyImageRGBData[0][0]^screenShotImageRGBData[y][x])==0
&& (keyImageRGBData[0][keyImgWidth-1]^screenShotImageRGBData[y][x+keyImgWidth-1])==0
&& (keyImageRGBData[keyImgHeight-1][keyImgWidth-1]^screenShotImageRGBData[y+keyImgHeight-1][x+keyImgWidth-1])==0
&& (keyImageRGBData[keyImgHeight-1][0]^screenShotImageRGBData[y+keyImgHeight-1][x])==0) { boolean isFinded = isMatchAll(y, x);
//如果比较结果完全相同,则说明图片找到,填充查找到的位置坐标数据到查找结果数组。
if(isFinded) {
for(int h=0; h<keyImgHeight; h++) {
for(int w=0; w<keyImgWidth; w++) {
findImgData[h][w][0] = y+h;
findImgData[h][w][1] = x+w;
}
}
return;
}
}
}
}
} /**
* 判断屏幕截图上目标图映射范围内的全部点是否全部和小图的点一一对应。
* @param y - 与目标图左上角像素点想匹配的屏幕截图y坐标
* @param x - 与目标图左上角像素点想匹配的屏幕截图x坐标
* @return
*/
public boolean isMatchAll(int y, int x) {
int biggerY = 0;
int biggerX = 0;
int xor = 0;
for(int smallerY=0; smallerY<keyImgHeight; smallerY++) {
biggerY = y+smallerY;
for(int smallerX=0; smallerX<keyImgWidth; smallerX++) {
biggerX = x+smallerX;
if(biggerY>=scrShotImgHeight || biggerX>=scrShotImgWidth) {
return false;
}
xor = keyImageRGBData[smallerY][smallerX]^screenShotImageRGBData[biggerY][biggerX];
if(xor!=0) {
return false;
}
}
biggerX = x;
}
return true;
} /**
* 输出查找到的坐标数据
*/
private void printFindData() {
for(int y=0; y<keyImgHeight; y++) {
for(int x=0; x<keyImgWidth; x++) {
System.out.print("("+this.findImgData[y][x][0]+", "+this.findImgData[y][x][1]+")");
}
System.out.println();
}
} public static void main(String[] args) {
String keyImagePath = "D:/key.png";
ImageFindDemo demo = new ImageFindDemo(keyImagePath);
demo.printFindData();
} }
这种算法是精确比较,只要有一个像素点有差异,就会找不到图片。当然,如果想指定一个比较的精确度,我也有个思路,就是在算法步骤4比较映射范围内全部像素点的时候做个统计,如果90%的点都相同,那就是说精确度是0.9。
另外,可能还要考虑效率问题,不过,我在我的应用场景中并不太在意效率。如果有朋友看到这篇文章,对这个话题有更好的想法,请留言。
Java图片上查找图片算法的更多相关文章
- [转]jquery 鼠标放在图片上显示图片的放大镜效果jqzoom_ev-2.3
本文转自:http://blog.csdn.net/weizengxun/article/details/6768183 鼠标放在图片上显示图片的放大镜效果使用jqzoom实现,本例版本2.3 效果图 ...
- 2019-3-16-win10-uwp-鼠标移动到图片上切换图片
title author date CreateTime categories win10 uwp 鼠标移动到图片上切换图片 lindexi 2019-03-16 14:43:46 +0800 201 ...
- java 文件上传(图片上传)
1.FTP工具类 代码如下: package com.taotao.common.utils; import java.io.File; import java.io.FileInputStream; ...
- spring mvc 图片上传,图片压缩、跨域解决、 按天生成文件夹 ,删除,限制为图片代码等相关配置
spring mvc 图片上传,跨域解决 按天生成文件夹 ,删除,限制为图片代码,等相关配置 fs.root=data/ #fs.root=/home/dev/fs/ #fs.root=D:/fs/ ...
- Django中怎么做图片上传--图片展示
1.首先是html页面的form表单的三大属性,action是提交到哪,method是提交方式,enctype只要有图片上传就要加这个属性 Django框架自带csrf_token ,所以需要在前端页 ...
- SpringBoot图片上传(五) 上一篇的新版本,样式修改后的
简单描述:一次上传N张图片(N可自定义):上传完后图片回显,鼠标放到已经上传的图片上后,显示删除,点击后可以删除图片,鼠标离开后,图片恢复. 效果:一次上传多个图片后的效果 上传成功: 鼠标悬浮到图片 ...
- C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi
C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...
- rails使用bootstrap3-wysiwyg可视化编辑器并实现自定义图片上传插入功能
之前在rails开发中使用了ckeditor作为可视化编辑器,不过感觉ckeditor过于庞大,有很多不需要的功能,而且图片上传功能不好控制不同用户可以互相删除图片,感觉很不好.于是考虑更改可视化编辑 ...
- android 加载自定义图片并在图片上绘图
来源:毕设 关键词:Bitmap Canvas //毕设中需要自定义室内地图,并且在地图上绘制轨迹 //此处是一个测试Demo,实现图片的加载和记录手指在屏幕上的运动轨迹 图片的载入 使用系统提供的内 ...
随机推荐
- 测试使用markdonw写博客
# 欢迎使用 Cmd Markdown 编辑阅读器 ------ 我们理解您需要更便捷更高效的工具记录思想,整理笔记.知识,并将其中承载的价值传播给他人,**Cmd Markdown** 是我们给出的 ...
- 【CV论文阅读】Deep Linear Discriminative Analysis, ICLR, 2016
DeepLDA 并不是把LDA模型整合到了Deep Network,而是利用LDA来指导模型的训练.从实验结果来看,使用DeepLDA模型最后投影的特征也是很discriminative 的,但是很遗 ...
- 网易互娱2017实习生招聘游戏研发工程师在线笔试第二场 C
偶尔碰到这题,简单数位DP题,然而我已生疏了…… 这次算是重新想到的,看来对DP的理解有增进了…… dp[i][j][k],表示前i为,mod为j,是否出现2.3.5的剩下的数位可组成的数字.答案就是 ...
- Network problem solving flow chart
来自为知笔记(Wiz)
- VMWare9下基于Ubuntu12.10搭建Hadoop-1.2.1集群—整合Zookeeper和Hbase
VMWare9下基于Ubuntu12.10搭建Hadoop-1.2.1集群-整合Zookeeper和Hbase 这篇是接着上一篇hadoop集群搭建进行的.在hadoop-1.2.1基础之上安装zoo ...
- 安装Nginx须要系统的辅助软件(linux)
安装Nginx须要系统的辅助软件(linux): yum -y install make gcc gcc-c++ ncurses-devel yum -y install zlib zlib-deve ...
- HTTP请求库——axios源码阅读与分析
概述 在前端开发过程中,我们经常会遇到需要发送异步请求的情况.而使用一个功能齐全,接口完善的HTTP请求库,能够在很大程度上减少我们的开发成本,提高我们的开发效率. axios是一个在近些年来非常火的 ...
- dotNet Core初学之创建第一个dotNetCore项目
首先创建解决方案dotNetCrazy 一.创建项目 1.这里选择.Net Core 选择ASP.NET Core Web 应用程序 名称暂且叫CoreCrazy 这里我们选择 web应用程序(模型视 ...
- 系统的BIOS与系统安装
今天偶尔看到个介绍电脑BIOS的与各种本子安装系统的介绍:(记录一下) 网络地址:http://blog.sina.com.cn/s/blog_4a1faae60102dyek.html
- 内容可编辑且随内容自增长的div
<!DOCTYPE HTML> <html> <head> <title></title> <meta http-equiv=&quo ...