欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于OpenCV的微信跳一跳外挂

程序员文章站 2022-10-20 10:55:42
摘要:微信跳一跳是时下热门的微信小游戏,基本原理是根据按压屏幕的时间控制棋子跳过的距离,使其跳到下一个方块上;现利用Android adb工具,PC端获取实时截图,使用OpenCV库分析图片计算距离,从而计算按压时间传回手机。 环境:Ubuntu18.04、OpenCV3.4.0 步骤: 1、获取A ......

摘要:微信跳一跳是时下热门的微信小游戏,基本原理是根据按压屏幕的时间控制棋子跳过的距离,使其跳到下一个方块上;现利用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

效果图:

基于OpenCV的微信跳一跳外挂

具体代码如下:

  1 #include "cv.h"
  2 #include "highgui.h"
  3 #include <iostream>
  4 #include <unistd.h>
  5 #include <stdio.h>
  6 using namespace std;
  7 using namespace cv;
  8 CvPoint find_chess_point(IplImage* src, IplImage* mode)
  9 {
 10     //模式匹配
 11     IplImage* result;
 12     CvPoint MinLocation, MaxLocation;
 13     double MinValue, MaxValue;
 14     int iwidth = src->width - mode->width + 1;
 15     int iheight = src->height - mode->height + 1;
 16     result = cvCreateImage(cvSize(iwidth, iheight), 32, 1);
 17     cvMatchTemplate(src, mode, result, CV_TM_CCOEFF);
 18     cvMinMaxLoc(result, &MinValue, &MaxValue, &MinLocation, &MaxLocation, NULL);
 19     return cvPoint(MaxLocation.x + (int)mode->width/2, MaxLocation.y + mode->height);
 20 }
 21 CvPoint find_next_point(IplImage* src, CvPoint chess_point, int mode = 0)
 22 {
 23     IplImage* tmp = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
 24     cvCvtColor(src, tmp, CV_BGR2GRAY);
 25     cvEqualizeHist(tmp, tmp);
 26     IplImage* dst = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
 27     cvCanny(src, dst, 50, 100, 3);
 28     //cvNamedWindow("doCany");
 29     //cvShowImage("doCany", dst);
 30     CvPoint next_point;
 31     if(chess_point.x < 500)//分左右,如果棋子在左侧,目标方块则在右侧
 32     {
 33         /*遍历轮廓上顶点*/
 34         unsigned char *pixel = (unsigned char *)dst->imageData;//指向首地址
 35         for(int row = 0; row < 300 ; ++row)//行扫描
 36         {
 37             for(int col = 500; col < 1000; ++col)//列扫描
 38             {
 39                 if(pixel[row*dst->width + col] == 255)//灰度图Canny边缘处理后轮廓为白色255
 40                 {
 41                     next_point.x = col;
 42                     if(mode == 1)
 43                     {
 44                         /*这是根据chess与target的连线与水平夹角总是30度,只知道横坐标和角度即可算出纵坐标*/
 45                         next_point.y = (int) (chess_point.y - (chess_point.x - next_point.x)/1.732); //根号3
 46                         return next_point;
 47                     }
 48                     /*找到上顶点后,开始遍历右顶点*/
 49                     for(int col_=999; col_ > 500; --col_)//最右列向左遍历
 50                     {
 51                         for(int row_=0; row_ < 400; ++row_)//从上向下遍历
 52                         {
 53                             if(pixel[row_*dst->width + col_] == 255)
 54                             {
 55                                 /*找到右顶点*/
 56                                 next_point.y = row_;
 57                                 cvLine(dst, chess_point, next_point, Scalar(255, 255, 255));
 58                                 cvShowImage("line", dst);
 59                                 cvWaitKey(100);
 60                                 return next_point;
 61                             }
 62                         }
 63                     }
 64                 }
 65             }
 66         }
 67     }
 68     else
 69     {
 70         /*遍历轮廓上顶点*/
 71         unsigned char *pixel = (unsigned char* )dst->imageData;//指向首地址
 72         for(int row = 0; row < 300 ; ++row)//行扫描
 73         {
 74             for(int col = 0; col < 500; ++col)//列扫描
 75             {
 76                 if(pixel[row*dst->width + col] == 255)
 77                 {
 78                     next_point.x = col;
 79                     if(mode == 1)
 80                     {
 81                         /*这是根据chess与target的连线与水平夹角总是30度,只知道横坐标和角度即可算出纵坐标, 这个方法效果好*/
 82                         next_point.y = (int) (chess_point.y - (chess_point.x - next_point.x)/1.732); //根号3
 83                         return next_point;
 84                     }
 85                     /*找到上顶点后,开始遍历右顶点*/
 86                     for(int col_=499; col_ > 0; --col_)//最正中间列向左遍历
 87                     {
 88                         for(int row_=0; row_ < 400; ++row_)//从上向下遍历
 89                         {
 90                             if(pixel[row_*dst->width + col_] == 255)
 91                             {
 92                                 /*找到右顶点*/
 93                                 next_point.y = row_;
 94                                 cvLine(dst, chess_point, next_point, Scalar(255, 255, 255));
 95                                 cvShowImage("line", dst);
 96                                 cvWaitKey(100);
 97                                 return next_point;
 98                             }
 99                         }
100                     }
101                 }
102             }
103         }
104     }
105     return next_point;
106 }
107 
108 IplImage* cut_src_img(IplImage* src)
109 {
110     //SetImageROI
111     cvSetImageROI(src, cvRect(40, 700, 1040, 400));//取决于手机分辨率,可以在上一行resize后,其他地方不需要修改
112     cvSaveImage("roi.jpg",src);
113     return cvLoadImage("roi.jpg", 1);
114 }
115 
116 float calculate_distance(CvPoint chess_point, CvPoint next_point)
117 {
118     float distance;
119     distance = sqrt(pow(abs(chess_point.x - next_point.x), 2) + pow(abs(chess_point.y - next_point.y), 2));
120     return distance;
121 }
122 void jump_one_jump(float distance, float parameter)
123 {
124     char jump[50];
125     RNG rng;
126     sprintf(jump, "adb shell input swipe %d %d %d %d %d", rng.uniform(400, 700), rng.uniform(1500, 1600), rng.uniform(400, 700), rng.uniform(1500, 1700), (int)(distance * parameter));
127     system(jump);
128 }
129 int main(int argc, char** argv)
130 {
131     IplImage* roi_image = NULL;
132     IplImage* chess_mode = cvLoadImage("jump.png", 1);
133     float distance;
134     CvPoint chess_point, next_point;
135     cvNamedWindow("line",1);
136     for(;;)
137     {
138         system("rm -rf screenshot.png && rm -rf roi.jpg");
139         system("adb shell /system/bin/screencap -p /sdcard/screenshot.png");
140         sleep(0.2);
141         system("adb pull /sdcard/screenshot.png . >/dev/null");//把adb pull命令的shell提示重定向
142         sleep(0.2);
143         IplImage* src = cvLoadImage("screenshot.png", 1);
144         roi_image = cut_src_img(src);//取截图中间部分
145         chess_point = find_chess_point(roi_image, chess_mode);//match找到chess坐标
146         next_point = find_next_point(roi_image, chess_point, 1);//像素点遍历找到target坐标,mode=1效果好
147         //cvLine(roi_image, chess_point, next_point, Scalar(0, 255, 255));
148         //cvShowImage("line",roi_image);
149         //cvWaitKey(100);
150         distance = calculate_distance(chess_point, next_point);//计算距离
151         jump_one_jump(distance, 1.4);
152         sleep(1);
153     }
154     return 0;
155 }

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