- 浏览: 260415 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
sunshine_bean:
第四行改进下URL=`svn info |grep &quo ...
linux判断是否需要svn up的脚本 -
leokelly001:
设置请求头,user-agent就行了
android使用豆瓣API出现500错误及解决方法 -
貌似掉线:
txy7121 写道HandlerFactory和AntiCo ...
大谈android安全2——Activity劫持的防范程序 -
txy7121:
HandlerFactory和AntiConstants这两个 ...
大谈android安全2——Activity劫持的防范程序 -
貌似掉线:
hyc_willie 写道关注着你的框架,希望能见到它的发布 ...
androidkit——Android开发框架
上一篇只是提到了在PC端利用android sdk里面的工具进行截图,接下来这一篇将补充一点关于上一篇的内容,然后介绍一下程序的整个结构,以及如何进行《天天连萌》里面的图像识别和消除的搜索算法。
一、补充上篇的内容
首先补充一下上一篇忘了提及的内容。
在使用chimpchat时,需要添加几个jar包。这方面网上的资料很少,不过功夫不负有心人,嘿嘿。
需要添加的jar包如下:
以上jar包都可以在android sdk里面的tools/lib目录中找到。
二、程序的设计
在这个程序里面我主要写了4个java文件:
三、图像识别及转换。
首先先截一张游戏界面的图。游戏里的方块是分布在中心的一个10*5(方块大小)的区域中的。所以先截下图,通过工具取得它的4个边的边距。以我的手机为例,它是800*480的分辨率的,截的图是竖屏的,左边距为48,右边距为72,上边距及下边距为115。每个游戏方块为57*72。如下图所示:
所以在Robot.java需要定义以上相关常量,代码如下:
上面定义的常量当中还有CORNER_WIDTH及CORNER_HEIGHT,这是因为有时有些方块会有道具标示,或者是是“*2”的分数提示,所以截取小图进行图像识别的时候还要避开这一点。然后上面提到的数组行列数,这里的数组不是取得的图像的数组。而是为了便于比较计算,将每个图像对应一个int数字,bomb或为空时为0。它的行及列分别为12和7,而不是10和5,是因为考虑到连连看的规则而加上的外围边界。如下图所示:
然后还要定义两个成员变量,一个表示取得的方块矩阵,一个表示对应的数字矩阵,代码如下:
从截屏取得的大图中获取方块小图代码如下:
上面代码中的+3及-3,是为了不计算方块的边界,可看情况修改,因为当游戏中出现提示时,方块的边框是有流动动画的,它如果被计算在内的话也会影响图像识别。
取得图之后,我们可以通过计算每个图像对应的hash值,然后对每种图像定义一个值,这样在游戏开始后,通过汉明距离算法就可以把图像转换为一个二维数组,进行连连看的方块消除搜索。当然 ,采用这一算法,需要先截得包含这些方块图像的游戏界面,然后计算出它们各自的hash值,进行存储。除去bomb,共有28种方块图像,多进行几次游戏就可以全截取到了。关于图片转换为hash值及进行相似判断的代码将在后面给出。
下面贴上将方块图片转换为int二维数组的代码,其中image是截取的屏幕的大图,然后取得小图边计算它的hash值,再调用distance判断是哪个图像方块:
上面的mImgHash是一个ImageHash对象,也是我定义的实现汉明距离算法的类。GAME_IMAGE存储了每个方块图像对应的hash值,是之前计算得到的,定义如下:
在遍历GAME_IMAGE数组进行每个方块的相似识别时,通常距离小于5的都可以认为是相似图片,在这里会比较与哪一个图片的hash距离最小是因为取得的方块图片都较小,为避免识别错误需要对每个图片都进行距离判断(因为一开始我取的识别精度并不是5,而是8,极少数情况下会有图片识别错误)。
最后附上汉明距离算法的代码:
一、补充上篇的内容
首先补充一下上一篇忘了提及的内容。
在使用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 <a target="_blank" href= * "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=XTAuOSVzPDM5LzI0OR0sLHM_MjA" * style="text-decoration:none;"><img src= * "http://rescdn.qqmail.com/zh_CN/htmledition/images/function/qm_open/ico_mailme_01.png" * /></a> */ 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版“天天连萌”刷高分(四)——模拟按键及程序优化
2014-01-22 00:14 1711这一系列文章,没想到从去年10月份以来,写了三篇我就忘了写了, ... -
利用电脑玩Android版“天天连萌”刷高分(三)——连连看消除搜索
2013-10-29 17:02 1183差点忘了写接下来的这两篇博客了,这篇如果接不上上一篇,请勿见怪 ... -
利用电脑玩Android版“天天连萌”刷高分(一)——截图
2013-10-20 11:22 3410这几周微信游戏“天天 ... -
在PC端进行android截屏的多种方法
2013-10-18 11:01 3596昨晚意外的发现在PC端进行截屏的方法相当多,在android ... -
Java获取照片EXIF信息
2013-10-16 17:40 1556目前最简单易用的EXIF信息处理的Java包是Drew Noa ... -
近期计划
2013-09-01 20:02 1233在上一篇(http://maosidiao ... -
Android开源游戏引擎之Angle(二)——开始前的准备
2013-09-01 12:04 2508在上一篇博客(http://mao ... -
Android开源游戏引擎之Angle(一)——概述
2013-08-31 19:26 6044Angle是一个Android平台上 ... -
设置tabWidget标题的字体大小及颜色
2013-03-27 13:47 9461/* * @(#)TextAppearenceUtil ... -
一一对应的键值对象
2013-03-22 13:19 3058最近写程序需要用到一种结构,像HashMap的,但是却是一对一 ... -
桌面小部件AppWidget的使用
2013-02-23 13:49 1726在android平台中,显示在HOME界面的一些挂件,即桌面小 ... -
android使用actionbar与fragment
2013-01-16 23:12 2294android使用actionbar中的tab,及fragme ... -
android使用豆瓣API出现500错误及解决方法
2013-01-10 18:56 6291为团队做一个图书管理的应用,涉及到扫描ISBN然后查询图书信息 ... -
DES加密及解密封装
2012-12-20 23:40 1586/* * @(#)CipherUtil.java ... -
MD5加密封装
2012-12-20 23:38 1539/* * @(#)DigestUtil.java ... -
进入程序的动画IntroActivity增强版
2012-12-11 10:19 1474这是对上一次谈到的android程序进入前的动画的封装(详见: ... -
androidkit发布0.5.3alpha版
2012-12-07 09:26 1314androidkit是一个用于android应用层开发的工具包 ... -
使用Zxing及豆瓣API
2012-12-06 20:30 2399本文原创,转载请注明原文地址:http://maosidiao ... -
androidkit——减少android开发代码的工具包
2012-11-16 22:25 2226androidkit是我学android开发以来,慢慢在封装的 ... -
windows平台下用java解析apk包
2012-11-09 20:05 2386抽空把以前写的解析apk包的工具,重新写了一个,也解决了以前许 ...
相关推荐
《Android游戏星座连萌》是一款深受玩家喜爱的休闲益智类手机游戏,它结合了星座元素和连连看的玩法,为玩家带来独特的娱乐体验。在深入探讨这款游戏之前,我们需要了解Android平台的基础知识以及游戏开发的相关技术...
天天连萌源码
【标题】"安卓Android源码——星座连萌.zip" 提供的是一个基于Android平台开发的休闲游戏“星座连萌”的源代码。这个压缩包中包含了应用程序的可执行文件(星座连萌.apk)以及可能的其他开发资源或配置文件(xzlm)...
基于Java实现的天天连萌游戏自动玩+源码,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用~ 基于Java实现的天天连萌游戏自动玩+源码,适合毕业设计、课程设计、项目...
【标题】"安卓Android源码——精典源码之星座连萌"是一个关于安卓应用程序开发的项目,重点在于分析和理解其源代码。这个项目的目的是为开发者提供一个学习和研究Android应用开发的实例,特别是针对游戏开发的部分。...
【标题】"安卓Android源码——[安卓开源]星座连萌.7z" 提供的是一个基于Android平台的开源项目,名为“星座连萌”。这个项目可能是为了展示Android应用程序的开发技术,或者是教学材料,让开发者能够理解并学习...
《安卓Android源码——娱乐项目安卓星座连萌》是一个针对Android平台开发的娱乐应用源代码,旨在提供一种轻松有趣的星座连连看游戏体验。这个项目的源码对于学习Android应用开发,尤其是游戏开发的开发者来说,是一...
【安卓Android源码——[安卓开源]星座连萌】是一个以星座为主题的开源安卓游戏项目,其源码可供开发者学习和研究。在这个项目中,我们可以深入理解Android应用开发的基本流程、UI设计、游戏逻辑以及Android平台上的...
【Android 星座连萌】是一款基于Android平台的毕业设计项目,主要展示了移动应用开发的基本技术和设计理念。这个项目可以作为Android编程初学者深入理解和实践Android应用开发的一个实例,同时也是对毕业设计者展示...
《Android应用源码解析——以“星座连萌”为例》 在移动开发领域,Android作为全球最广泛使用的操作系统之一,其应用开发对于学生和开发者来说是至关重要的技能。本篇文章将深入探讨一个名为“星座连萌”的Android...
《Android应用源码之星座连萌》是一款基于Android平台的休闲游戏,它的源代码提供了深入理解Android应用开发的宝贵资源。这款应用可能结合了星座知识、消除类游戏玩法以及萌系元素,旨在吸引广大用户群体,尤其是...
这个压缩包文件“Android应用源码娱乐项目安卓星座连萌.zip”显然包含了开发一个基于Android平台的娱乐应用的源代码,特别是一个与星座相关的游戏——星座连连萌。从描述来看,“源码参考,欢迎下载”,这表明这个...
总的来说,这个压缩包提供了一个完整的小游戏——"心动连萌"的源代码,对学习游戏开发的程序员而言是一份宝贵的资源。通过深入研究源码,可以了解到游戏开发中的基本架构、数据结构、算法应用、游戏循环、事件处理、...
Android应用源码娱乐项目安卓星座连萌
《星座连萌》是一款基于Android平台的休闲游戏,其源码是学习Android开发,特别是对于初学者和进行毕业设计的学生来说,极具参考价值。通过分析和研究这份源码,我们可以深入理解Android应用开发的各个环节,包括但...