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,实现图片的加载和记录手指在屏幕上的运动轨迹 图片的载入 使用系统提供的内 ...
随机推荐
- go-import下划线的作用
原文:http://studygolang.com/articles/4356 ------------------------------------------------------------ ...
- 剑指Offer面试题29(java版):数组中出现次数超过一半的数字
题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 比如输入一个长度为9的数组{1,2,3,2.2,2.5,4,2}.因为数字2在数组中出现5次,超过数组长度的一半,因此输出2. 解 ...
- WEB端应该使用DataTable/DataSet吗?
有一次和同事讨论起具体的技术细节,同事说不要用什么实体类,从数据库访问到的数据,直接用DataTable.DataSet 就好.理由是,从获取到的数据集转换成实体类,有一定的性能损耗. 呵呵,性能.我 ...
- http ssl
http ssl
- G. 铁路修复计划 最小生成树
G. 铁路修复计划 二分答案,改变边的权值,找最小生成树即可. 类似的思想还可以用在单度限制最小生成树和最优比例生成树上. #include<iostream> #include<c ...
- bzoj 1575: [Usaco2009 Jan]气象牛Baric【dp】
完了不会dp了 设f[i][j]为以i结尾,有j个时的最优值,辅助数组g[i][j]为s选了i和j,i~j中的误差值 转移是f[j][i]=min(f[k][i-1]+g[k][j]) #includ ...
- 【BZOJ2525】[Poi2011]Dynamite(二分,树形dp)
[BZOJ2525][Poi2011]Dynamite Description Byteotian Cave的结构是一棵N个节点的树,其中某些点上面已经安置了炸.药,现在需要点燃M个点上的引线引爆所有 ...
- array_column() 函数[二维数组转为一维数组]
array_column() 函数 输出数组中某个键值的集合[二维数组转为一位数组] <?php // 表示由数据库返回的可能记录集的数组 $a = array( array( 'id' =&g ...
- P4451 [国家集训队]整数的lqp拆分
#include <bits/stdc++.h> using namespace std; typedef long long LL; inline LL read () { LL res ...
- Get 和 Post 使用篇(1)
1.Post 请求发送方式 实例: const string sResponseEncoding = "gb2312"; //测试文本信息 string postText = &q ...