Opencv

スマフォゲーをOpenCVで操作出来ないか試してみた



FFGMや時のドラゴン等のスタミナ要素が無いゲームをやっているとひたすら同じ作業の繰り返しで、レベル上げがめんどくさくなってくる
OpenCVを使って画像判別しながらスマフォ操作すればいいんじゃないかといろいろ試してみた


Android Opencvを使うためにいろいろインストール

・JDK
・JRE
・Eclipse
・Android SDK
・Android Development Tool (ADT)
・OpenCV packege for Android

なんとかEcliseを使ってAndroid上でOpencvを実行することに成功!

しかし、ゲームアプリ上でタッチイベントがうまく動かない・・・
Google先生に確認すると、Androidはセキュリティ上、他のアプリを操作出来ないようになっているとのこと

仕方がないからWindowsのOpencv使ってADB SHELLからスマフォ操作することにした

流れは、

スマフォのスクリーンショットを撮影、保存

画像をPCに移動

予め作成しておいた目的の画像(おまかせボタン)がマッチングしたらそのボタンの座標を取得しTap命令をPCからスマフォに送る



#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>


int main(int argc, char *argv[])
{
    int key, tap_x, tap_y;
    FILE *file;
   
    // テンプレート画像
    cv::Mat tmp_img = cv::imread("omakase.png", 1);
    if (tmp_img.empty()) return -1;

    while (1){
        system("adb shell screencap -p /sdcard/screen.png");
        system("adb pull /sdcard/screen.png");

        // 探索画像
        cv::Mat search_img = cv::imread("screen.png", 1);
        if (search_img.empty()) continue;

        cv::Mat result_img;

        // テンプレートマッチング
        cv::matchTemplate(search_img, tmp_img, result_img, CV_TM_CCOEFF_NORMED);

        // 最大のスコアの場所を探す
        cv::Rect roi_rect(0, 0, tmp_img.cols, tmp_img.rows);
        cv::Point max_pt;
        double maxVal;
        cv::minMaxLoc(result_img, NULL, &maxVal, NULL, &max_pt);

        // マッチング度合で処理を変更
        if (maxVal < 0.6) continue;

        // 最大スコアの場所
        roi_rect.x = max_pt.x;
        roi_rect.y = max_pt.y;
        // 最大スコアの中央値
        tap_x = max_pt.x + tmp_img.cols / 2;
        tap_y = max_pt.y + tmp_img.rows / 2;
        // 最大スコアの結果を表示
        std::cout << "(TAP_X=" << tap_x << ",TAP_Y=" << tap_y << ", x=" << max_pt.x << ", y=" << max_pt.y << "), score=" << maxVal << std::endl;

        // 探索結果の場所に矩形を描画
        cv::rectangle(search_img, roi_rect, cv::Scalar(0, 0, 255), 3);

        // 結果の画像を表示
        cv::namedWindow("result", CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO);
        cv::imshow("result", search_img);

        char *passbuf = "adb shell input touchscreen tap %d %d",tap_x,tap_y;
        printf(passbuf);
       

        key = cvWaitKey(1);

        if (key == 'q') {

            break;
        }
        else if (key == 's'){
            cv::imwrite("output.png", search_img);
        }
    }
}

screen













































スマフォのスクリーンショット(生画像)


omakase



おまかせ攻撃画像



一番苦労したのは変数をadb shellで指定するところ
当初、tap_x,tap_yと変数をそのまま指定していたがうまく代入されず、グーグル先生の指導のもと%dに代入してprintfすれば行けることを発見した

後は状況に応じて、判別する画像、その際の動作を組み込めば自動レベルアップを簡単に実行することが出来るだろう


次回はOpenCVではない番外編
UWSCで同じようにスマフォを操作してみる