基于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
上一篇: 冷笑话短信系列一之逗你乐
下一篇: 融资16亿美元 科学家将尝试重现人类大脑