利用Opencv实现微信跳一跳脚本源码放送(C++实现嵌套python)

最近微信的跳一跳很火,无意间在QQ空间看见有人用单片机控制舵机测量距离实现微信跳一跳,于是我雅兴大发,自己也用Opencv实现一个视觉控制的微信跳一跳,百度一下,果然很多,但大多数都是python实现的,于是我自己写了一个C++实现的微信跳一跳脚本。

我是利用360手机助手中 有一个360演示,图标如下
这里写图片描述

控制手机在电脑上进行运行。那只是这样的
这里写图片描述

一、对区域截图

一开始需要截取改界面的图片加以运算,这里使用windows API对C++开放的接口,获取界面所在的位置,由于python截取屏幕简单方便程序远远超过C++,所以在截图这一块,我用C++调用了python,代码如下:

void ScreenShot(void)
{
    RECT rect;  
    HWND hwnd = ::FindWindow(NULL, L"实时演示");    //获取360演示的句柄
    GetWindowRect(hwnd, &rect);     //获取图像的位置
    char sScreenShot[64];
    sprintf(sScreenShot, "grab.exe %d %d %d %d", rect.left, rect.top+135, rect.right, rect.bottom-50);//组成字符串
    system(sScreenShot);    //调用python截取图片
}

python截图图片如下:

from PIL import ImageGrab  
import argparse

parser = argparse.ArgumentParser()   #初始化准备传参
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                    help='location for top left and bottom right')
args = parser.parse_args()
print(args.integers)        #打印出参数

def grab():
    ImageGrab.grab(bbox=(args.integers[0],args.integers[1],args.integers[2],args.integers[3])).convert("L").save(".\\helloworld.jpg")#截图 保存为helloworld.jpg

grab()  #进行截图

二、获取黑子的位置

接下来就是获取黑子所在的位置,这个可以使用Opencv提供的模板匹配matchTemplate,事先,将黑子截图保存好,之后和图像进行对比,找到最相近的区域。
C++代码如下:

Point GetNowPoint(Mat& srcImage, Mat& Tem_img)
{
    cv::Mat image_matched;
    matchTemplate(srcImage, Tem_img, image_matched, CV_TM_SQDIFF);// 匹配黑棋子
    double minVal, maxVal;
    Point minLoc, maxLoc, matchLoc;
    minMaxLoc(image_matched, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
    matchLoc = minLoc; //matchLoc是最佳匹配的区域左上角点

    return Point(matchLoc.x + Tem_img.cols*0.5, matchLoc.y + Tem_img.rows);
}

三、寻找目标位置

接下来就是检测需要跳到的位置检测,我们需要对图像做一些处理,对图像进行高斯滤波减少噪声,之后我们对他进行Canny边缘检测,实现的效果图如下
这里写图片描述

我们要找到两个点,第一个是图像最高点(即Y方向最低点),第二个是图像最靠右边点(即X方向大点)
这里写图片描述

C++代码实现如下:

Point GetNextPoint(Mat& srcImage)
{
    cv::Point point1;
    cv::Point point2;

    cv::GaussianBlur(srcImage, srcImage, cv::Size(5, 5), 0);  //高斯滤波,降低噪声
//  cv::threshold(srcImage, srcImage, 0, 255, 8);
    Canny(srcImage, srcImage, 20, 30);      //进行边缘检测
    vector<vector<Point>> contours; 
    vector<Vec4i> hierarchy;
    findContours(srcImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point()); //找到关键的角点
    //遍历每一个轮廓,把多余的轮廓去掉
    std::vector<std::vector<cv::Point> >::const_iterator it = contours.begin();
    while (it != contours.end()) {
        if (it->size()<150)
            it = contours.erase(it);
        else
            ++it;
    }
    int nYMin = srcImage.rows;
    int nXMin = srcImage.cols;
    int nYMax = 0;
    int nXMax = 0;
    int nIdY = 0;
    for (int i = 0; i < contours.size(); i++)
    {
        //contours[i]代表的是第i个轮廓,contours[i].size()代表的是第i个轮廓上所有的像素点数  
        for (int j = 0; j < contours[i].size(); j++)
        {
            if (contours[i][j].y < nYMin)
            {
                nYMin = contours[i][j].y;   //找到最低的y值
                point1 = contours[i][j];    //记录  y值最低点坐标
                nIdY = i;                   //记录哪个区域内的
            }
        }
    }
    int minY = srcImage.cols;

    for (int j = 0; j < contours[nIdY].size(); j++) //在哪个区域内继续变量 找到x最大值
    {
        if (contours[nIdY][j].x >nXMax)
        {
            nXMax = contours[nIdY][j].x;
        }
    }
    for (int j = 0; j < contours[nIdY].size(); j++)
    {//找到x中最大值上的最小值
        if (contours[nIdY][j].x == nXMax && contours[nIdY][j].y < minY)
        {
            point2 = contours[nIdY][j];         
            minY = contours[nIdY][j].y;     //记录X点的最大值
        }
    }
    return cv::Point(point1.x, point2.y);       //返回中点坐标
}

四、计算距离

通过原点坐标和目标点坐标算出距离,这个就很简单了:

int GetDistance(Point& first_point, Point& next_point)
{
    int A = first_point.x - next_point.x;
    int B = first_point.y - (next_point.y + 50);
    return int(pow(pow(A, 2) + pow(B, 2), 0.5));
}

五、计算跳跃时间

算出距离后,下面就是计算按下位置和时间,就可以了

void Jump(int&g_distance)
{
    cout << "distance:" << g_distance << endl;
    int time = g_distance*4+330;

    RECT rect;
    HWND hwnd = ::FindWindow(NULL, L"实时演示");
    GetWindowRect(hwnd, &rect);

    ::SetCursorPos(rect.left+100, rect.bottom-500);
    INPUT  Input = { 0 };       //鼠标按下
    Input.type = INPUT_MOUSE;
    Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    SendInput(1, &Input, sizeof(INPUT));

    Sleep(time);//鼠标下的时间   

    Input = { 0 };      //鼠标松开
    Input.type = INPUT_MOUSE;
    Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
    SendInput(1, &Input, sizeof(INPUT));

}

整个的工程已经描述完毕了,包括我的想法和设计,如果有更好的,欢迎交流。整个工程的下载在这里。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
跳一跳是一款非常流行的手机游戏,玩家需要通过点击屏幕,控制小人跳跃来消除方块。本课程设计将通过利用Python编程语言和图像处理库,实现跳一跳的自动运行。 首先,我们需要使用Python的图像处理库,如OpenCV或PIL,来截取手机屏幕的游戏画面。这样我们就可以获取到游戏的实时状态。 接下来,我们需要检测小人和方块的位置。可以通过图像处理的方式,识别出屏幕上的小人和方块,并获取它们的坐标信息。 然后,我们需要设计一个算法来自动计算小人跳跃的距离。可以利用小人和方块之间的距离来估算出合适的跳跃力度。 最后,我们将利用Python模拟点击屏幕的操作,控制小人跳跃。通过计算得到的跳跃力度,我们可以编写代码,实现自动点击屏幕的功能。 整个过程中,我们需要不断地截取游戏画面、识别小人和方块的位置、计算跳跃力度,并模拟点击屏幕操作。我们可以使用循环来不断重复这个过程,使得小人可以不断地自动跳跃。 通过以上步骤的实现,我们就可以让Python自动玩跳一跳了。这样,我们不需要手动操作手机屏幕,而是通过编程来控制游戏的进行。 当然,实现跳一跳的自动运行并不是一件简单的任务,需要对图像处理、算法设计和编程有较好的理解和实践能力。但是通过这样的课程设计,可以锻炼学生的编程思维和创造力,提高他们的问题解决能力和编程技术水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值