OpenCV + C++ 实现微信跳一跳小人自动跳动 (VS2015)

LZQ plus

发布于 2018.03.10 13:57 阅读 3161 评论 0

前言

因为自己手太残,平均跳30来分就over了,最近又在捣鼓OpenCV所以干脆基于OpenCV写一个程序刷分来并总结一下最近学的内容。

之前写过一个版本,那个也就跳120来分就不行了,所以昨天进行优化了一下,效果挺好。网上开发语言都是Python,也没C++,所以在这里整理一下思路和代码,分享一下(对,我就是活雷锋)。

 

准备

    先:配置好OpenCV3. 都没问题,还有adb.exe 配置好。

开发环境:VS 2015(什么都可以,只要配置到OpenCV可以使用就行)。

需要零件:可以跳一跳的Android手机一部,脑子。

 

思路

1、获取到手机上跳一跳的画面。

2、找到起跳点位置 à A

3、找到目标点位置 à B

4、计算A B两点的距离,计算出模拟按屏时间的长短。

5adb 传输模拟按屏时间命令,完成跳跃。

 

具体实现

1、获取手机画面,并改变大小改成原图的一半。(我的测试手机是1280*720的)

Mat getNextImg() {

       system("adb shell screencap -p /sdcard/next.png");

       system("adb pull /sdcard/next.png");

       Mat nextImg, reImg;

       nextImg = imread("next.png");

       resize(nextImg, reImg, Size(nextImg.cols / 2, nextImg.rows / 2));

       return reImg;

}

2、找到起跳点位置 A,这里有较详细说明 à OpenCV模板匹配

Point getStartMaxPoint(Mat nextImg, Mat temp) {

       Mat  player;

       matchTemplate(nextImg, temp, player, TM_CCOEFF_NORMED);

       double min_val = 0, max_val = 0;

       Point min_loc, max_loc, now_loc;

       minMaxLoc(player, &min_val, &max_val, &min_loc, &max_loc);

       rectangle(nextImg,

              Point(0, 0),

              Point(nextImg.cols, nextImg.rows / 4),

              CV_RGB(0, 0, 0),

              -1,8,0);

       rectangle(nextImg,

              Point(0, nextImg.rows * 3 / 4),

              Point(nextImg.cols, nextImg.rows),

              CV_RGB(0, 0, 0),

              -1, 8, 0);

       return max_loc;

}

 

3、获取目标点B,比较麻烦,分两小步写。

①、先判断下一步是否识别到加分的那个小圆点,如果有就获取小圆点的中心坐标 即:目标点B的坐标;如果没有就执行第②步。

②、将源图像进行高斯模糊、边缘化处理。然后从上向下行遍历,从右到左列遍历,得到目标区域的最顶部坐标和最右边的坐标。从而得到目标点。下面是简易的执行原理图。

Point findTargetPoint(Mat img) {

       //开始遍历行数

       int startRow = img.rows / 4 + 5;

       //结束遍历行数

       int rows = startRow + img.rows / 5 + 10;

       int cols = img.cols * img.channels();

       Point top, right;

       right.x = 0; right.y = 0;

       bool topPonit = false;

       // 找上边的顶点

       for (int i = startRow; i < rows; i++) {

              uchar* data = img.ptr<uchar>(i);

              int temporaryX = 0;

              for (int j = cols; j > 0; j--) {

                     if (data[j] != 0) {

                            temporaryX++;

                            if (!topPonit) {

                                   top.x = j;

                                   top.y = i;

                                   topPonit = true;

                            }

                     }

                     if (temporaryX > 1) {

                            top.x = top.x - (temporaryX / 2);

                            top.y = i;

                            temporaryX = 0;

                     }

              }

              //一旦找到,循环结束

              if(topPonit){

                     break;

              }

       }

       //找右边的顶点

       for (int i = top.y; i < rows; i++) {

              uchar* data = img.ptr<uchar>(i);

              for (int j = cols; j > top.x; j--) {

                     if (data[j] != 0) {

                            if (j > right.x) {

                                   right.x = j;

                                   right.y = i;

                            }

                     }

              }

       }

       return Point(top.x, right.y);

}

4、计算A B两点距离,随机生成模拟按屏位置坐标,计算模拟按屏时间,adb命令传入手机,完成跳跃。其中2.12的那个地方根据实际情况调节

d = sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y)) * 2;

cout << "实际距离:" << d << endl;

int pressX = random(10, next.cols * 2);

int pressY = random(next.cols*2/5, next.cols *8/5);

char* str1 = "adb shell input swipe";

char cmd[100];

float time = d * 2.12;

sprintf(cmd, "%s %d %d %d %d %d", str1, pressX, pressY, pressX, pressY, (int)time);

cout << "cmd:" << cmd << endl;

system(cmd);

 

大体思路就是这样,这一版本是按“j”键完成跳跃,按“e”键结束,想要实现自动跳(源码里没有,下边有思路)就是在while{…}里作文章。

	while (true)
	{

		char key = waitKey(50);
		if (key == 'j') {
			automatic = true;
		}

		if (automatic) {
            .........................
              别的细节操作,源码里有
            .........................
			int anTime = random(15, 22);
			char command = waitKey(time + anTime * 100);
			if (command == 'e') {
				automatic = false;
				cout << "*********以结束程序运行**********" << endl;
				break;
			}
		}

	}

微信有防作弊机制,这个程序反防作弊机制也还可以(只要别太过分),本来想看看到底能跳多久,直到跳到下图,再跳就扣分了……对,就是能一直跳,膨胀了。

下面的是全部代码的网盘连接。(好人就是我)

连接:https://pan.baidu.com/s/1KYDoOahorYUT7fPszRFqwg

密码:n8ud