基于OpenCV的微信跳一跳外挂

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

效果图:

具体代码如下:

  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

猜你喜欢

转载自www.cnblogs.com/luoyijie/p/9164263.html