200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 微信跳一跳辅助程序开发 基于C++与opencv图像识别

微信跳一跳辅助程序开发 基于C++与opencv图像识别

时间:2019-01-04 01:43:42

相关推荐

微信跳一跳辅助程序开发 基于C++与opencv图像识别

趁着期末这段时间,课程不多,在学习opencv,闲来无事,看到网上有大神用python实现了Wechat的跳一跳的辅助外挂,看了大概原理,似乎跟我最近学的opencv好像很沾边,但是鄙人实在不懂Python,于是想着用C++就把它给实现了。原文链接:/wangshub/wechat_jump_game,感兴趣的同学们可以看一下大神版本。

步入正题

先说原理,我这里直接copy大神的:

将手机点击到《跳一跳》小程序界面,用 ADB 工具获取当前手机截图,并用 ADB 将截图传上来,靠棋子的颜色来识别棋子,靠底色和方块的色差来识别棋盘(重点),用 ADB 工具点击屏幕一跳。

开发环境:

所谓工欲善必先利其器,鄙人的平台是win7 64位+vs+opencv 3.4+adb工具+荣耀4X(分辨率:720x1280),只对此分辨率作适配过,其它的我试了一下,不可行,等考完试我再适配。环境配置网上很多,这里就不浪费时间了。adb工具直接放到工程文件夹下即可。

前提准备工作:把手机用数据线连到电脑,装好驱动,打开开发者模式,打开USB调试,下载adb工具,这里最好配个环境变量。不配也行,打开cmd命令窗口,转到adb目录,键入 adb devices 命令(坑爹的魅族手机,它就是连接不了,不得不借用同学的备用手机荣耀4x来测试),如下:

连接成功之后,开始写代码了

打开vs,新建工程键入头文件这些这些不多说了,同学们都会,

1.使用system命令,截图,并传上来,用imread读入到变量scree去

system("adb shell screencap -p /sdcard/autojump.jpg");//截图system("adb pull /sdcard/autojump.jpg"); //上传到电脑Mat scree = imread("autojump.jpg");//读入

2.对图像进行处理,分两步,一是先找出棋子的位置,二是找到物体的中心位置

1).找棋子。找规律,发现的棋子的颜色在游戏中好像是独一无二的,利用这点,我们很容易找到棋子的位置,用ps拾取棋子底部的RGB三个通道颜色(注意了,opencv的储存通道的顺序是BGR)作为参考点,然后从图像下方(逐行逐个像素)往上扫描(为什么是从下往上?因为我们要的是棋子的下方,如果是上方,找的是棋子的脑袋),如果扫描到的点的各通道的数值与参考点的作对比,如果各点的误差的值的和少于20(数值根据需要适当的调),那么认为是找到了。代码如下:

Point ptc, ptm;//存储棋子底下与物体中心的坐标

void draw_color(Mat &img){int average = 0;int channels = img.channels();int nRows = img.rows;int nCols = img.cols* channels;int i = (int)nRows * 1 / 3;//不用整个图像都扫描,高的1/3就行int b_color = 102;//定义棋子蓝色通道值int g_color = 54;//定义棋子绿色通道值int r_color = 53;//定义棋子红色通道值int man_x = 0;int man_y = 0;int fla = 0;for (man_y = i + 350; man_y>i + 100; man_y--){for (man_x = 99; man_x < nCols - 99; man_x += 3){if ((abs((int)img.at<uchar>(man_y, man_x) - b_color) +abs((int)img.at<uchar>(man_y, man_x + 1) - g_color) +abs((int)img.at<uchar>(man_y, man_x + 2) - r_color)) < 20) //判断{ptm.x = (int)man_x / 3.0;//记录坐标,因为opencv存储图像点是以三通道存储的,所以除以3ptm.y = man_y - 5;//下移,防止找到背景点的bugfla = 1;break;}}if (fla)break;}draw_garry(img, ptm.x);//调用另外一下函数,由另外的函数去找物体顶面上的中点}

2).找到棋子的坐标坐标之后,我们要找物体的顶面上的中点。分两步,1是找物体的顶面的上界,2是找物体的顶面的下界。

首先从图像上方往下扫描,大概屏幕往下的1/4开始找,因为这部分区域基本上是背景,无其它的颜色,所以利用这点,我们以此处的第一行为参考,把一行中每一点的像素值加起来,与第一行作对比,如果比参考值大或者小于某个数值(适当的调整),则认为是有物体了(先把图像转换为灰度比较好处理)。然后再往右扫描,以第一个像素点作对比,然后比较他们的绝对差,大于某个值,就是找到了

代码如下

Mat img;cvtColor(thr, img, COLOR_RGB2GRAY);int sum = 0;int average = 0;int channels = img.channels();int nRows = img.rows;int nCols = img.cols* channels;int k = 0;int f = 0;Rect r1;Rect r2;Point pt1, pt2;int stat_y = (int)(nRows*(2.0 / 6.0));pt2.x = nCols;pt1.x = 0;pt1.y = 0;pt2.y = 0;int i;int j;//找出物体的第一行//扫描每一行,如果下一行与第一行的像素总和相差正负30个,那么就不是纯色,有物体了for (i = stat_y; i < nRows; ++i){for (j = 0; j<nCols; j++){sum += img.at<uchar>(i, j);//把一行的像素值加起来}if (sum != 0)if (k == 0){f = sum;k = 1;}if (sum <f - 30|| sum>f + 30)//如果这行与参考行的像素值相差正负30,那么认为是有物体{average = 1;break;}if (average)break;sum = 0;}

//找出有物体的第一行后//接着找出非背景的第一点int fl = i + 273;//物体最大不会高于273行int i_x = 0;int i_y = 0;int kk = 0;for (; i < fl; ++i){for (j = 0; j<nCols-1; j++){//如果前一点与后一点的像素值相差大于5,那么就是找到了kk = abs((int)img.at<uchar>(i, j) - (int)img.at<uchar>(i, j+1));//为了防止棋子的脑袋超过物体,所以先找出棋子的x轴方向的位置,//如果这时找出的第一点与棋子的坐标相接近,则继续找if (abs(j - man_xx) < 30)continue;if (kk>5){i_x = j;i_y = i;pt1.x = i_x;pt1.y = i_y;break;}}if (i_x != 0)break;}

同理,嗯嗯,我很喜欢这词,每当用这个词的时候可以省略好多字好多言语。我们取上界那个点的颜色作参考点,由下往上找,就能找到下界的点了

int n;int n_x = 0;int n_y = 0;//找出物体的下界,以便求中点for (n = fl; n >= i; n--){//用上面找到物体的那一点的像素值来判断,相差不大于10就是找到了if (abs((int)img.at<uchar>(i+1, j) - (int)img.at<uchar>(n, j)) < 10){pt2.x = j;pt2.y = n;break;}}

上下界的点找到之后,物体的顶面的中点就很容易计算出来了

ptc.x = j;ptc.y = (int)((n - i) /2) + i;//计算物体顶面中点

3.计算物体顶面中点到棋子底部的距离,不多说,两点距离公式,并乘上系数0.5再除以0.25,就是按压时间。

//计算人到物体中心距离//两点距离公式,距离再乘以0.5再除以0.25就是按压时间int S = (int)sqrt((ptc.x - ptm.x)*(ptc.x - ptm.x) + (ptc.y - ptm.y)*(ptc.y - ptm.y))*0.5 / 0.25;

4.发送命令:adb shell input swipe 320 420 320 410,在坐标320,410到坐标320,410模拟滑到时间S毫秒,也就是按压S毫秒啦啦。

char ch[50] = { " " };//把按压时间与命令放到一个字符串上sprintf(ch, "adb shell input swipe 320 410 310 410 %d", S);//用system命令输入system(ch);

所有代码:

main.cpp文件

#include "header.h"int main(){cout << "微信跳一跳辅助程序,彬彬移植于网络大神的python的版本\n此版本是用C++与opencv定的还有很多bug\n";cout << "请确保打开了手机微信跳一跳 y or n?\n";getchar();while(1){system("adb shell screencap -p /sdcard/autojump.jpg");system("adb pull /sdcard/autojump.jpg");Mat scree = imread("autojump.jpg");draw_color(scree);Sleep(1500);//延时,不能太快}system("pause");return 0;}

gray.cpp文件

#include "header.h"Point ptc, ptm;//存储棋子底下与物体中心的坐标/************找出棋子的底下的坐标*****************///判断当前点与人物底下的颜色相似//对应的通道像素值作差取绝对值//即参考的红色通道值-扫描点的红色通道点等三个通道分别减取绝对值//然后相加,如果少于20,那就认为这两点颜色相同//记录坐标************************************************/void draw_color(Mat &img){int average = 0;int channels = img.channels();int nRows = img.rows;int nCols = img.cols* channels;int i = (int)nRows * 1 / 3;//不用整个图像都扫描,高的1/3就行int b_color = 102;//定义棋子蓝色通道值int g_color = 54;//定义棋子绿色通道值int r_color = 53;//定义棋子红色通道值int man_x = 0;int man_y = 0;int fla = 0;for (man_y = i + 350; man_y>i + 100; man_y--){for (man_x = 99; man_x < nCols - 99; man_x += 3){if ((abs((int)img.at<uchar>(man_y, man_x) - b_color) +abs((int)img.at<uchar>(man_y, man_x + 1) - g_color) +abs((int)img.at<uchar>(man_y, man_x + 2) - r_color)) < 20) //判断{ptm.x = (int)man_x / 3.0;//记录坐标,因为opencv存储图像点是以三通道存储的,所以除以3ptm.y = man_y - 5;//下移,防止找到背景点的bugfla = 1;break;}}if (fla)break;}draw_garry(img, ptm.x);}void draw_garry(Mat &thr,int man_xx){Mat img;cvtColor(thr, img, COLOR_RGB2GRAY);int sum = 0;int average = 0;int channels = img.channels();int nRows = img.rows;int nCols = img.cols* channels;int k = 0;int f = 0;Rect r1;Rect r2;Point pt1, pt2;int stat_y = (int)(nRows*(2.0 / 6.0));pt2.x = nCols;pt1.x = 0;pt1.y = 0;pt2.y = 0;int i;int j;//找出物体的第一行//扫描每一行,如果下一行与第一行的像素总和相差正负30个,那么就不是纯色,有物体了for (i = stat_y; i < nRows; ++i){for (j = 0; j<nCols; j++){sum += img.at<uchar>(i, j);//把一行的像素值加起来}if (sum != 0)if (k == 0){f = sum;k = 1;}if (sum <f - 30|| sum>f + 30)//如果这行与参考行的像素值相差正负30,那么认为是有物体{average = 1;break;}if (average)break;sum = 0;}//找出有物体的第一行后//接着找出非背景的第一点int fl = i + 273;//物体最大不会高于273行int i_x = 0;int i_y = 0;int kk = 0;for (; i < fl; ++i){for (j = 0; j<nCols-1; j++){//如果前一点与后一点的像素值相差大于5,那么就是找到了kk = abs((int)img.at<uchar>(i, j) - (int)img.at<uchar>(i, j+1));//为了防止棋子的脑袋超过物体,所以先找出棋子的x轴方向的位置,//如果这时找出的第一点与棋子的坐标相接近,则继续找if (abs(j - man_xx) < 30)continue;if (kk>5){i_x = j;i_y = i;pt1.x = i_x;pt1.y = i_y;break;}}if (i_x != 0)break;}int n;int n_x = 0;int n_y = 0;//找出物体的下界,以便求中点for (n = fl; n >= i; n--){//用上面找到物体的那一点的像素值来判断,相差不大于10就是找到了if (abs((int)img.at<uchar>(i+1, j) - (int)img.at<uchar>(n, j)) < 10){pt2.x = j;pt2.y = n;break;}}ptc.x = j;ptc.y = (int)((n - i) /2) + i;//计算物体中点//计算人到物体中心距离//两点距离公式,距离再乘以0.5再除以0.25就是按压时间int S = (int)sqrt((ptc.x - ptm.x)*(ptc.x - ptm.x) + (ptc.y - ptm.y)*(ptc.y - ptm.y))*0.5 / 0.25;char ch[50] = { " " };//把按压时间与命令放到一个字符串上sprintf(ch, "adb shell input swipe 320 410 310 410 %d", S);//用system命令输入system(ch);cout << "\n" << ch << endl;}

头文件

#define _CRT_SECURE_NO_WARNINGS//关闭安全检查,须放到最前面#include <opencv2/opencv.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iostream>#include <Windows.h>#include <cmath>using namespace cv;using namespace std;void draw_color(Mat &img);void draw_garry(Mat &img, int x);//找出物体的中心位置

逐个添加进工程即可,至少分辨率的适配,调下里面那些数据就好, adb工具搜索下载即可。

希望期末考试不挂科不挂科

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。