准备材料:
1. adb工具(版本新点)比如 platform-tools-latest-windows.zip
2.opencv基于C++ 的开发环境
3.一部装有最新微信的安卓智能机
实现原理:根据分析跳一跳界面截图,可以获知几个重要信息
1.背景单调,但是渐变色 会自动变色
2.棋子形状固定,不随时间变化
3.棋子跳转的距离与按压的时间成线性关系
4.每步跳转的倾斜角是30°。
5.下一步的物块必定比其它物块高
6.将每步截图以中心建立坐标系,发现一个重要特点
(1)棋子只会在左下与右下区域
(2)棋子如果在左下区域 下一步必定在右上区域;反之亦然
(3)每步中心点连线必过整个截图的中心
根据如此多的特点 我们便可以着手进行辅助开发,首先要熟悉一下安卓的调试工具ADB,其具体指令方式不做过多介绍,给出网址有全面的介绍 https://github.com/mzlogin/awesome-adb 程序中只用了两个指令
截图:adb exec-out screencap -p >sc1.png 这个指令是直接截图保存到电脑端
触摸按压:adb shell input swipe 500 500 500 500 500 这个其实是滑动指令 这5个500 分别是 按压的起始位置x y 和松开的结束位置 x y 最后一个参数是按压的时间单位 ms
具体手机与PC的连接不做过多介绍,明显是使用开发者选项,打开USB调试模式
接下来便是程序的重点
1.获取一张屏幕截图,并读取。根据ADB指令读取到一帧图像,读入程序。根据这个游戏的工作方式我们很清楚的了解到辅助工具只要计算出来两点的距离 然后转换成跳跃的按压时间就行了。因此我们就其实只需要获取两个坐标点: 棋子 与下一步
2.如何获取棋子的坐标点: 我根据毛星云书本附带例程中的模板匹配 很轻松的就稳定的获取到了棋子坐标
Mat g_resultImage; Mat Mode = imread("mode.png");//读取棋子模板 用作模板匹配 Point findmode(Mat &SrcImg) { //Mat SrcImg = imread("G:\\src4.png"); int g_nMatchMethod = 0; matchTemplate(SrcImg, Mode, g_resultImage, g_nMatchMethod); normalize(g_resultImage, g_resultImage, 0, 1, NORM_MINMAX, -1, Mat()); //【4】通过函数 minMaxLoc 定位最匹配的位置 double minValue; double maxValue; Point minLocation; Point maxLocation; Point matchLocation; minMaxLoc(g_resultImage, &minValue, &maxValue, &minLocation, &maxLocation, Mat()); //cout <获取到棋子坐标比较容易,但是下一步的坐标中心点 一直没有很好的注意获取, 这里就不说我的程序的发展历程,直接展示V3.0版实现的方式,根据重要信息5 我们可以考虑逐行遍历的方式来获得物块的最高点 这个点肯定接近物块中心,其实还可以发现这个点的横坐标与目标点x坐标几乎是一样的。
但是怎么遍历呢 ,这里有两种方案,(1)根据分析背景可知,背景是渐变色,每行的背景色数值是一样的 ,所以我们可以嵌套for进行判断 如果下一个像素点与这个点不一样 ,那么它就是物块上的点 ,找到物块最高点坐标 寻找结束
( 2)方案2使用漫水填充将背景填充0(即去除), 然后同样遍历像素点找到有数据的坐标 ,此坐标即为物块最高点
做到这步其实已经可以勉强使这个工具工作了,但是每次的目标点不是很准,拿不到高分,想拿到连续跳到中点的高分 就要继续利用发现到的重要信息 4 和 6.3
目标点与棋子当前坐标是成30°的 那么我在刚刚已经获取到了目标点的x坐标,利用初中的一元一次方程知识 我不就可以获知到经过棋子坐标点获得这个函数 利用已知坐标x 即可求出更加准确的目标点的y 坐标
circles; Point center1, center2,CenterPoint(540,960); Mat SrcImg,SrcImgC,desImg,TLImg,TRImg,MaskImg; Point findmode(Mat &SrcImg);//寻找棋子 Point findNextStep(Mat &SrcImg);//寻找下一步 int _tmain(int argc, _TCHAR* argv[]) { bool state = 1, jumpstat = 1; int num=0; while (state) { system(PC);//获取一张截图 //system("cls");//CMD清屏 SrcImg = imread("sc1.png");//读取截取的图像 //SrcImg = imread("C:\\Users\\cheng\\Desktop\\QQ图片20180217232802.jpg"); if (SrcImg.empty())//检测是否读到 { cout <<"Can't read image " <
540)//棋子在右半侧 { TLImg = SrcImg(Range(400, 960), Range(0, 540)).clone(); center2=findNextStep(TLImg)+Point(0,400); } else { TRImg = SrcImg(Range(400, 960), Range(540, 1080)).clone(); center2 = findNextStep(TRImg) + Point(540, 400); } center2.y = CenterPoint.y - 0.5*abs(center2.x - CenterPoint.x);//路径倾斜30° circle(SrcImg, center2, 10, Scalar(255, 255, 0), -1); resize(SrcImg, SrcImg, SrcImg.size() / 4);//重设尺寸为了显示 //circle(SrcImg, Point(SrcImg.cols, SrcImg.rows) / 2, 5, Scalar(0, 0, 0), 2); line(SrcImg, Point(0, SrcImg.rows / 2), Point(SrcImg.cols, SrcImg.rows / 2), Scalar(0)); line(SrcImg, Point(SrcImg.cols / 2, 0), Point(SrcImg.cols / 2, SrcImg.rows), Scalar(0)); center1 = center2 - center1; int length = sqrt(pow(center1.x, 2) + pow(center1.y, 2)); if (length <150 || center2.x==300)length = 222;//距离太近会造成错误检测 printf("第%03d次跳跃。",num++); std::cout <<"GetLength" < (i,j) != Vec3b(0,0,0) && j>10) { NextStep = Point(j,i); return NextStep; } } } // return NextStep; }
第一次写博客,希望大家支持,完整示例程序见链接文件。在1080x1920手机上能够完美运行,一般跑500分以上完全没问题。
附完整示例程序:http://download.csdn.net/download/qq_34901073/10254240