上一篇只是提到了在PC端利用android sdk里面的工具进行截图,接下来这一篇将补充一点关于上一篇的内容,然后介绍一下程序的整个结构,以及如何进行《天天连萌》里面的图像识别和消除的搜索算法。

一、补充上篇的内容

首先补充一下上一篇忘了提及的内容。

在使用chimpchat时,需要添加几个jar包。这方面网上的资料很少,不过功夫不负有心人,嘿嘿。

需要添加的jar包如下:

chimpchat.jar

common.jar

ddmlib.jar

guava-13.0.1.jar

以上jar包都可以在android sdk里面的tools/lib目录中找到。

二、程序的设计

在这个程序里面我主要写了4个java文件:

Main.java 只有一个main方法,程序的入口。

Robot.java,程序的核心部分,进行游戏截图、图像转换为数组,搜索消除等。里面包含一个LianlianKan的内部类,它是用于搜索可以消除的方块的工具类。

Point.java,表示在数组中的坐标位置的对象。

ImageHash.java,图像识别的算法类,采用汉明距离算法进行图片相似检测。

三、图像识别及转换。

首先先截一张游戏界面的图。游戏里的方块是分布在中心的一个10*5(方块大小)的区域中的。所以先截下图,通过工具取得它的4个边的边距。以我的手机为例,它是800*480的分辨率的,截的图是竖屏的,左边距为48,右边距为72,上边距及下边距为115。每个游戏方块为57*72。如下图所示:

所以在Robot.java需要定义以上相关常量,代码如下:

/**

* 主要操作类,进行截图,识别,转换,消除,按键等。

*

* @author Geek_Soledad

* "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=XTAuOSVzPDM5LzI0OR0sLHM_MjA"

* style="text-decoration:none;">

* "http://rescdn.qqmail.com/zh_CN/htmledition/images/function/qm_open/ico_mailme_01.png"

* />

*/

public class Robot {

/**

* 屏幕宽,视手机而修改

*/

private static final int SCREEN_WIDTH = 480;

/**

* 屏幕高,视手机而修改

*/

private static final int SCREEN_HEIGHT = 800;

/**

* 左边距,视手机而修改

*/

private static final int PADDING_LEFT = 48;

/**

* 右边距,视手机而修改

*/

private static final int PADDING_RIGHT = 72;

/**

* 上边距,视手机而修改

*/

private static final int PADDING_TOP = 115;

/**

* 下边距,视手机而修改

*/

private static final int PADDING_BOTTOM = 115;

/**

* 游戏方块列数

*/

private static final int BOX_COL = 5;

/**

* 游戏方块行数

*/

private static final int BOX_ROW = 10;

/**

* 图片宽

*/

private static final int IMAGE_WIDTH = (SCREEN_WIDTH - PADDING_LEFT - PADDING_RIGHT) / BOX_COL;

/**

* 图片高

*/

private static final int IMAGE_HEIGHT = (SCREEN_HEIGHT - PADDING_TOP - PADDING_BOTTOM)

/ BOX_ROW;

/**

* 截除的边角宽,视手机而修改

*/

private static final int CORNER_WIDTH = 24;

/**

* 截除的边角高,视手机而修改

*/

private static final int CORNER_HEIGHT = 27;

/**

* 数组行数

*/

private static final int CODE_ROW = 12;

/**

* 数组列数

*/

private static final int CODE_COL = 7;

// ...

}

上面定义的常量当中还有CORNER_WIDTH及CORNER_HEIGHT,这是因为有时有些方块会有道具标示,或者是是“*2”的分数提示,所以截取小图进行图像识别的时候还要避开这一点。然后上面提到的数组行列数,这里的数组不是取得的图像的数组。而是为了便于比较计算,将每个图像对应一个int数字,bomb或为空时为0。它的行及列分别为12和7,而不是10和5,是因为考虑到连连看的规则而加上的外围边界。如下图所示:

然后还要定义两个成员变量,一个表示取得的方块矩阵,一个表示对应的数字矩阵,代码如下:

private BufferedImage images[][] = new BufferedImage[BOX_ROW][BOX_COL];

/**

* 表示图片的数组,为12 * 7个。 图片共有10*5个单位,但是在进行路径计算的时候还要考虑四周,所以是12 * 7 个单位。

*/

private int imageCodes[][];

从截屏取得的大图中获取方块小图代码如下:

for (int i = 0; i < images.length; i++) {

for (int j = 0; j < images[i].length; j++) {

images[i][j] = image.getSubimage(j * IMAGE_WIDTH + PADDING_LEFT + 3, i

* IMAGE_HEIGHT + PADDING_TOP + 3, IMAGE_WIDTH - CORNER_WIDTH - 3,

IMAGE_HEIGHT - CORNER_HEIGHT - 3);

}

}

上面代码中的+3及-3,是为了不计算方块的边界,可看情况修改,因为当游戏中出现提示时,方块的边框是有流动动画的,它如果被计算在内的话也会影响图像识别。

取得图之后,我们可以通过计算每个图像对应的hash值,然后对每种图像定义一个值,这样在游戏开始后,通过汉明距离算法就可以把图像转换为一个二维数组,进行连连看的方块消除搜索。当然 ,采用这一算法,需要先截得包含这些方块图像的游戏界面,然后计算出它们各自的hash值,进行存储。除去bomb,共有28种方块图像,多进行几次游戏就可以全截取到了。关于图片转换为hash值及进行相似判断的代码将在后面给出。

下面贴上将方块图片转换为int二维数组的代码,其中image是截取的屏幕的大图,然后取得小图边计算它的hash值,再调用distance判断是哪个图像方块:

/**

* 通过获取的截图设置num数组

*/

public void setNum(BufferedImage image) {

imageCodes = new int[CODE_ROW][CODE_COL];

for (int i = 0; i < images.length; i++) {

for (int j = 0; j < images[i].length; j++) {

images[i][j] = image.getSubimage(j * IMAGE_WIDTH + PADDING_LEFT + 3, i

* IMAGE_HEIGHT + PADDING_TOP + 3, IMAGE_WIDTH - CORNER_WIDTH - 3,

IMAGE_HEIGHT - CORNER_HEIGHT - 3);

String hash = mImgHash.getHash(images[i][j]);

int minDis = Integer.MAX_VALUE;

for (int k = 0; k < GAME_IMAGE.length; k++) {

int dis = mImgHash.distance(GAME_IMAGE[k], hash);

if (dis <= 8 && dis < minDis) {

imageCodes[i + 1][j + 1] = k + 1;

minDis = dis;

if (minDis <= 0) {

break;

}

}

}

// System.out.print(imageCodes[i + 1][j + 1] + "\t");

}

// System.out.println();

}

}

上面的mImgHash是一个ImageHash对象,也是我定义的实现汉明距离算法的类。GAME_IMAGE存储了每个方块图像对应的hash值,是之前计算得到的,定义如下:

public class Robot {

/**

* 表示每个方块图像的HASH值

*/

private static final String[] GAME_IMAGE = {

"0110000100110010101000110111110000010010101001110"/* 煎蛋 */,

"0000001100000000011110100101100110111100000110000"/* 紫猫 */,

"0010000101010101010100101110100000110101001101111"/* 白菜 */,

"0000001001101001100011100110101110010100000010011"/* 茄子 */,

"1001100100000101001100100111001100101110110100010"/* 兔子 */,

"1000010001000101111010100100100011010010111011000"/* 莲藕 */,

"0010010010100100101100110101100011011010010010001"/* 红虾 */,

"1000000000101000100010111000110000011001111011100"/* 玉米 */,

"0001100001100101101001010100111001101010110101100"/* 闪电 */,

"0000000000100001010100011111101010010000000100000"/* 狐狸 */,

"1100000101000000011110111011010011011100001100000"/* 白云 */,

"1000011000110101100000110100010001110011001100000"/* 菠萝 */,

"1000111001100101101010110100100001110110101011000"/* 草莓 */,

"0000000001110011100001000011001110111001001100110"/* 蘑菇 */,

"1111011000110100111001110100000101011000011100111"/* 蓝鼠 */,

"1000000000001000111100110000110011110000011011101"/* 太阳 */,

"1001100000001101100010111000110001010001110011100"/* 月亮 */,

"1011100000001110100100101100010100101001011011010"/* 雪人 */,

"1000011001101101011000111100101001111100011001100"/* 熊猫 */,

"1000000000000001010100001110101010111000010100000"/* 黄熊 */,

"1000000110100011001110111001100110001100001001011"/* 彩虹 */,

"1010100000001001001000101001010111011000111001000"/* 雪花 */,

"1000110001110001100010100000100111010100010010000"/* 西瓜 */,

"1000001101011000011110110001010011001001010110110"/* 香蕉 */,

"0001100000001101000001000000001100001001110100000"/* 蓝果实 */,

"1000100011101111010001000110001000000010010100110"/* 葡萄 */,

"0000100000011100110000101010100000111000101000111"/* 红果实 */,

"1001100000110001000110110011001110001011000110011"/* 黄梨 */, };

// ...

}

在遍历GAME_IMAGE数组进行每个方块的相似识别时,通常距离小于5的都可以认为是相似图片,在这里会比较与哪一个图片的hash距离最小是因为取得的方块图片都较小,为避免识别错误需要对每个图片都进行距离判断(因为一开始我取的识别精度并不是5,而是8,极少数情况下会有图片识别错误)。

最后附上汉明距离算法的代码:

* @(#)ImageHash.java Project:lianmeng

* Date-Time:2013-10-11 下午7:40:20

*

* Copyright (c) 2013 CFuture09, Institute of Software,

* Guangdong Ocean University, Zhanjiang, GuangDong, China.

* All rights reserved.

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package pw.msdx.lianmengassistant;

import java.awt.Graphics2D;

import java.awt.color.ColorSpace;

import java.awt.image.BufferedImage;

import java.awt.image.ColorConvertOp;

/*

* pHash-like image hash.

* Author: Elliot Shepherd (elliot@jarofworms.com

* Based On: http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html

*

* Optimize by Geek_Soledad.

*/

public class ImageHash {

private int size = 8;

private int smallerSize = 8;

public ImageHash() {

initCoefficients();

}

public ImageHash(int size, int smallerSize) {

this.size = size;

this.smallerSize = smallerSize;

initCoefficients();

}

public int distance(String s1, String s2) {

int counter = 0;

for (int k = 0; k < s1.length(); k++) {

if (s1.charAt(k) != s2.charAt(k)) {

counter++;

}

}

return counter;

}

// Returns a 'binary string' (like. 001010111011100010) which is easy to do

// a hamming distance on.

public String getHash(BufferedImage img) {

/*

* 1. Reduce size. Like Average Hash, pHash starts with a small image.

* However, the image is larger than 8x8; 32x32 is a good size. This is

* really done to simplify the DCT computation and not because it is

* needed to reduce the high frequencies.

*/

img = resize(img, size, size);

/*

* 2. Reduce color. The image is reduced to a grayscale just to further

* simplify the number of computations.

*/

img = grayscale(img);

double[][] vals = new double[size][size];

for (int x = 0; x < img.getWidth(); x++) {

for (int y = 0; y < img.getHeight(); y++) {

vals[x][y] = getBlue(img, x, y);

}

}

/*

* 3. Compute the DCT. The DCT separates the image into a collection of

* frequencies and scalars. While JPEG uses an 8x8 DCT, this algorithm

* uses a 32x32 DCT.

*/

double[][] dctVals = applyDCT(vals);

/*

* 4. Reduce the DCT. This is the magic step. While the DCT is 32x32,

* just keep the top-left 8x8. Those represent the lowest frequencies in

* the picture.

*/

/*

* 5. Compute the average value. Like the Average Hash, compute the mean

* DCT value (using only the 8x8 DCT low-frequency values and excluding

* the first term since the DC coefficient can be significantly

* different from the other values and will throw off the average).

*/

double total = 0;

for (int x = 0; x < smallerSize; x++) {

for (int y = 0; y < smallerSize; y++) {

total += dctVals[x][y];

}

}

total -= dctVals[0][0];

double avg = total / (double) ((smallerSize * smallerSize) - 1);

/*

* 6. Further reduce the DCT. This is the magic step. Set the 64 hash

* bits to 0 or 1 depending on whether each of the 64 DCT values is

* above or below the average value. The result doesn't tell us the

* actual low frequencies; it just tells us the very-rough relative

* scale of the frequencies to the mean. The result will not vary as

* long as the overall structure of the image remains the same; this can

* survive gamma and color histogram adjustments without a problem.

*/

StringBuilder hash = new StringBuilder();

for (int x = 0; x < smallerSize; x++) {

for (int y = 0; y < smallerSize; y++) {

if (x != 0 && y != 0) {

hash.append(dctVals[x][y] > avg ? "1" : "0");

}

}

}

return hash.toString();

}

private BufferedImage resize(BufferedImage image, int width, int height) {

BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

Graphics2D g = resizedImage.createGraphics();

g.drawImage(image, 0, 0, width, height, null);

g.dispose();

return resizedImage;

}

private ColorConvertOp colorConvert = new ColorConvertOp(

ColorSpace.getInstance(ColorSpace.CS_GRAY), null);

private BufferedImage grayscale(BufferedImage img) {

colorConvert.filter(img, img);

return img;

}

private static int getBlue(BufferedImage img, int x, int y) {

return (img.getRGB(x, y)) & 0xff;

}

// DCT function stolen from

// http://stackoverflow.com/questions/4240490/problems-with-dct-and-idct-algorithm-in-java

private double[] c;

private void initCoefficients() {

c = new double[size];

for (int i = 1; i < size; i++) {

c[i] = 1;

}

c[0] = 1 / Math.sqrt(2.0);

}

private double[][] applyDCT(double[][] f) {

int N = size;

double[][] F = new double[N][N];

for (int u = 0; u < N; u++) {

for (int v = 0; v < N; v++) {

double sum = 0.0;

for (int i = 0; i < N; i++) {

for (int j = 0; j < N; j++) {

sum += Math.cos(((2 * i + 1) / (2.0 * N)) * u * Math.PI)

* Math.cos(((2 * j + 1) / (2.0 * N)) * v * Math.PI) * (f[i][j]);

}

}

sum *= ((c[u] * c[v]) / 4.0);

F[u][v] = sum;

}

}

return F;

}

}

利用电脑玩android版天天连萌刷高分 二,利用电脑玩Android版“天天连萌”刷高分(二)——图像识别...相关推荐

  1. 刺激战场电脑版android,逍遥安卓模拟器像端游操控玩《绝地求生刺激战场》电脑版...

    <绝地求生刺激战场>电脑版可以像绝地求生端游一样操控吗?可以在电脑上像绝地求生端游一样用鼠标键盘玩吗?逍遥安卓模拟器是目前小编测试过电脑上玩<绝地求生刺激战场>手游还原绝地求生 ...

  2. n9009+android+4.4.2,三星N9009 (Galaxy Note 3 电信版 Android 4.4)救砖教程 救砖包 刷回官方系统支持OTA升级...

    奇兔ROM市场小编在这给大家分享一下三星N9009 (Galaxy Note 3 电信版 Android 4.4)救砖教程和三星N9009 (Galaxy Note 3 电信版 Android 4.4 ...

  3. 锤子T1(Smartisan T1 4G)版刷成3G版,即sm705运行sm701的CM11 Android 4.4.4ROM

    对于喜欢折腾的人来说买锤子T系列真实不明智的选择,但是我是罗粉,对于锤子安卓内核版本的不升级政策很是不满,我承认Smartisan OS确实很好用,用了iOS后才知道锤子的系统真好,高效贴心真心替用户 ...

  4. 锤子T1(Smartisan T1 4G)版刷成3G版,即sm705运行sm701的CM11 Android 4.4.4ROM 1

    对于喜欢折腾的人来说买锤子T系列真实不明智的选择,但是我是罗粉,对于锤子安卓内核版本的不升级政策很是不满,我承认Smartisan OS确实很好用,用了iOS后才知道锤子的系统真好,高效贴心真心替用户 ...

  5. Android 13 第一个开发者版本来了,网友直呼:Android 12 还没玩透!

    整理 | 苏宓 出品 | CSDN(ID:CSDNnews) 2 月 10 日,Google 宣布 Android 13 首个预览版面向开发者开放,此版本重点聚焦隐私和安全.提供开发者生产力.应用兼容 ...

  6. 自走棋电脑版_手游版《自走棋》上线试玩

    自走棋测试服最近已经陆续开放内部测试,经过了一番试玩之后,发现和电脑版还是有一些区别,大体上还是能够保持一致的很期待公测之后的版本.例如10金币吃1利息,连胜奖励,连败奖励,升级经验5金币,刷新商店2 ...

  7. 魅族 刷机android 6.0,乐视X800+安卓6.0.1 魅族Flyme6刷机包 最新6.7.12.29R版 紫火20180510更新...

    本包是乐视X800+适配版,属于安卓6.0系列,论坛的另外一个Flyme是5.0版本的,大家区别开来,不要胡乱互刷,否则会出现问题, 安卓6.0系统的flyme正式停止更新.:请关注安卓7.1的Fly ...

  8. android刷windows教程视频,蓝魔i9s安卓版刷Windows 8.1系统固件视频教程

    本文介绍的蓝魔I9s安卓版刷windows 8.1系统固件的方法主要来自蓝魔贴吧"蓝魔i9s Windows8 with Bing固件"一文,不过因为视频也是第一次刷机制作,在中途 ...

  9. 百度android模拟器下载地址,百度手机助手电脑版怎么下载 安卓模拟器电脑版下载地址...

    最近在朋友圈非常流行的手游百度手机助手已经开放下载了,不过不少玩家都觉得手机上玩百度手机助手手机屏幕太小,操作不方便,画面不够清晰炫酷.那么如何在电脑上运行百度手机助手这款手游呢?小编现在就推荐一款百 ...

  10. 微信Mac 3.0.0内测版上线!终于可以用电脑刷朋友圈了!!

    微信Mac版客户端终于支持查看朋友圈啦!!!微信是一款运行在OS X上的 社交聊天工具,微信mac版支持跨通信运营商,跨操作系统平台通过网络快速发送免费语音短信.视频.图片和文字,还能发送各种类型的文 ...

最新文章

  1. TCP三次握手(建立连接)/四次挥手(关闭连接)
  2. 使得守护进程一次执行一个
  3. 无监督学习典例:聚类
  4. JSX详解React的事件绑定事件参数的传递
  5. Luogu P1280 Niko的任务【线性dp】By cellur925
  6. 计算机程序的思维逻辑 (54) - 剖析Collections - 设计模式
  7. [单反六]查看快门数
  8. Django_RBAC_demo2 升级版权限控制组件
  9. MOQL—筛选器(Selector)(二)
  10. Oracle查看表空间使用率
  11. 《Python与硬件项目案例》— 基于Python与指纹模块AS608的指纹识别签到考勤系统(上篇)(期末大作业、课程设计、毕业设计、结课项目)
  12. java的第一个代码模型,简单的java类
  13. 判断三点方向(顺时针或逆时针)
  14. layui使用formselect4完成的下拉框多选,拼音搜索
  15. java 天猫项目_2018最新Java前后端练手项目【模仿天猫前端】
  16. 用“大数据”预防职务犯罪
  17. 浏览器相关及知识积累
  18. 数据挖掘学习笔记:标称属性(名词性)的邻近性度量
  19. 今天事真多 哎呦我去了!
  20. 疫情致美国10万家餐厅倒闭或长期关闭;温德姆酒店集团上半年大中华区签署38个项目 | 美通企业日报...

热门文章

  1. COM in Wine(1)——COM基本概念
  2. 服务器证书如果不被网站信任怎么办?
  3. Microsoft Visual C++ 14.0 is required.
  4. Android 音频管理器AudioManager类介绍
  5. 合唱队形(c++DP)
  6. 宏定义是什么?为什么要进行宏定义?宏定义的格式
  7. 我的JavaScript学习之路四:JavaScript数据类型之Number类型(1)
  8. 学习基于html和JavaScript的滑动图片拼图验证源码
  9. Ceres Solver (ubuntu 安装)
  10. lch 儿童围棋课堂 初级篇1 ( (李昌镐 著))