摘要:微信跳一跳是时下热门的微信小游戏,基本原理是根据按压屏幕的时间控制棋子跳过的距离,使其跳到下一个方块上;现利用Android adb工具,PC端获取实时截图,使用OpenCV库分析图片计算距离,从而计算按压时间传回手机。

环境:Ubuntu18.04、OpenCV3.4.0

步骤:

1、获取Android截图,并传到PC端

adb shell /system/bin/screencap -p /sdcard/screenshot.png

adb pull /sdcard/screenshot.png .

2、程序读入图片并获取ROI

cvLoadImage("screenshot.png", 1);

cvSetImageROI(src, cvRect(0, 600, 1080, 900));

2、对ROI进行模板匹配,找到chess坐标

cvMatchTemplate(src, mode, result, CV_TM_CCOEFF);

3、对ROI灰度处理并边缘检测

cvCvtColor(src,srcGray, CV_BGR2GRAY);

cvCanny( srcGray, dst, 50, 100, 3);

4、对边缘检测结果进行遍历像素点,获取最上与最右(左)的像素 点坐标,从而得出下一方块中心点。

5、计算两个点坐标距离乘相应系数得到时间。

adb shell input swipe  400 400 400 400  time

效果图:

具体代码如下:

 #include "cv.h"
#include "highgui.h"
#include <iostream>
#include <unistd.h>
#include <stdio.h>
using namespace std;
using namespace cv;
CvPoint find_chess_point(IplImage* src, IplImage* mode)
{
//模式匹配
IplImage* result;
CvPoint MinLocation, MaxLocation;
double MinValue, MaxValue;
int iwidth = src->width - mode->width + ;
int iheight = src->height - mode->height + ;
result = cvCreateImage(cvSize(iwidth, iheight), , );
cvMatchTemplate(src, mode, result, CV_TM_CCOEFF);
cvMinMaxLoc(result, &MinValue, &MaxValue, &MinLocation, &MaxLocation, NULL);
return cvPoint(MaxLocation.x + (int)mode->width/, MaxLocation.y + mode->height);
}
CvPoint find_next_point(IplImage* src, CvPoint chess_point, int mode = )
{
IplImage* tmp = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, );
cvCvtColor(src, tmp, CV_BGR2GRAY);
cvEqualizeHist(tmp, tmp);
IplImage* dst = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, );
cvCanny(src, dst, , , );
//cvNamedWindow("doCany");
//cvShowImage("doCany", dst);
CvPoint next_point;
if(chess_point.x < )//分左右,如果棋子在左侧,目标方块则在右侧
{
/*遍历轮廓上顶点*/
unsigned char *pixel = (unsigned char *)dst->imageData;//指向首地址
for(int row = ; row < ; ++row)//行扫描
{
for(int col = ; col < ; ++col)//列扫描
{
if(pixel[row*dst->width + col] == )//灰度图Canny边缘处理后轮廓为白色255
{
next_point.x = col;
if(mode == )
{
/*这是根据chess与target的连线与水平夹角总是30度,只知道横坐标和角度即可算出纵坐标*/
next_point.y = (int) (chess_point.y - (chess_point.x - next_point.x)/1.732); //根号3
return next_point;
}
/*找到上顶点后,开始遍历右顶点*/
for(int col_=; col_ > ; --col_)//最右列向左遍历
{
for(int row_=; row_ < ; ++row_)//从上向下遍历
{
if(pixel[row_*dst->width + col_] == )
{
/*找到右顶点*/
next_point.y = row_;
cvLine(dst, chess_point, next_point, Scalar(, , ));
cvShowImage("line", dst);
cvWaitKey();
return next_point;
}
}
}
}
}
}
}
else
{
/*遍历轮廓上顶点*/
unsigned char *pixel = (unsigned char* )dst->imageData;//指向首地址
for(int row = ; row < ; ++row)//行扫描
{
for(int col = ; col < ; ++col)//列扫描
{
if(pixel[row*dst->width + col] == )
{
next_point.x = col;
if(mode == )
{
/*这是根据chess与target的连线与水平夹角总是30度,只知道横坐标和角度即可算出纵坐标, 这个方法效果好*/
next_point.y = (int) (chess_point.y - (chess_point.x - next_point.x)/1.732); //根号3
return next_point;
}
/*找到上顶点后,开始遍历右顶点*/
for(int col_=; col_ > ; --col_)//最正中间列向左遍历
{
for(int row_=; row_ < ; ++row_)//从上向下遍历
{
if(pixel[row_*dst->width + col_] == )
{
/*找到右顶点*/
next_point.y = row_;
cvLine(dst, chess_point, next_point, Scalar(, , ));
cvShowImage("line", dst);
cvWaitKey();
return next_point;
}
}
}
}
}
}
}
return next_point;
} IplImage* cut_src_img(IplImage* src)
{
//SetImageROI
cvSetImageROI(src, cvRect(, , , ));//取决于手机分辨率,可以在上一行resize后,其他地方不需要修改
cvSaveImage("roi.jpg",src);
return cvLoadImage("roi.jpg", );
} float calculate_distance(CvPoint chess_point, CvPoint next_point)
{
float distance;
distance = sqrt(pow(abs(chess_point.x - next_point.x), ) + pow(abs(chess_point.y - next_point.y), ));
return distance;
}
void jump_one_jump(float distance, float parameter)
{
char jump[];
RNG rng;
sprintf(jump, "adb shell input swipe %d %d %d %d %d", rng.uniform(, ), rng.uniform(, ), rng.uniform(, ), rng.uniform(, ), (int)(distance * parameter));
system(jump);
}
int main(int argc, char** argv)
{
IplImage* roi_image = NULL;
IplImage* chess_mode = cvLoadImage("jump.png", );
float distance;
CvPoint chess_point, next_point;
cvNamedWindow("line",);
for(;;)
{
system("rm -rf screenshot.png && rm -rf roi.jpg");
system("adb shell /system/bin/screencap -p /sdcard/screenshot.png");
sleep(0.2);
system("adb pull /sdcard/screenshot.png . >/dev/null");//把adb pull命令的shell提示重定向
sleep(0.2);
IplImage* src = cvLoadImage("screenshot.png", );
roi_image = cut_src_img(src);//取截图中间部分
chess_point = find_chess_point(roi_image, chess_mode);//match找到chess坐标
next_point = find_next_point(roi_image, chess_point, );//像素点遍历找到target坐标,mode=1效果好
//cvLine(roi_image, chess_point, next_point, Scalar(0, 255, 255));
//cvShowImage("line",roi_image);
//cvWaitKey(100);
distance = calculate_distance(chess_point, next_point);//计算距离
jump_one_jump(distance, 1.4);
sleep();
}
return ;
}

代码链接:https://files.cnblogs.com/files/luoyijie/jump2.0.tar.gz

最新文章

  1. 几种常见的Shell
  2. 使用Aspose.Cells读取Excel
  3. iOS PCH文件
  4. 剑指offer五:
  5. HDMI之CEC DDC学习笔记(可能有误)
  6. JSON 转javabean 利器
  7. 01传智_jbpm与OA项目_整体项目架构
  8. linux 下find命令 --查找文件名
  9. 如何分离数据库 (SQL Server Management Studio)
  10. python--参数列表的分拆
  11. innerHTML与innerText的PK
  12. sql求和涉及到null值
  13. UIScrollView上面放一个UIScrollView或者UITableView拖动时候 View出现一闪一闪解决办法
  14. LeetCode 145. Binary Tree Postorder Traversal 二叉树的后序遍历 C++
  15. CentOS7+CDH5.14.0安装CDH错误排查: HiveServer2 该角色的进程已退出。该角色的预期状态为已启动
  16. Hive环境搭建及测试
  17. java中去除字符串(String)中的换行字符(\r \n \t)
  18. 【Mybatis】一对多实例
  19. hibernate 中,出现了错误 &quot;node to traverse cannot be null!&quot; 如何改正
  20. ORA:01745 无效的主机 绑定变量名

热门文章

  1. java笔记--BigDecimal的使用
  2. struts文件上传——文件过大时错误提示的配置问题说明
  3. python读取xml文件报错ValueError: multi-byte encodings are not supported
  4. Java List详解,面试中应该如何解答关于List的问题
  5. linux mint gcc 编译第一个c程序
  6. SOJ 4309 Sum of xor 异或/思维
  7. 基于session和cookie的登录验证(CBV模式)
  8. G、CSL 的训练计划【BFS 贪心】(“新智认知”杯上海高校程序设计竞赛暨第十七届上海大学程序设计春季联赛)
  9. HTML5 FormData对象
  10. Kali-linux使用OpenVAS