android-auto-play-opencv 最近分かったこと

08_備忘録

android appの自動操作していて、感じたことを適当に書きます。

■まずはエラーにならず完了することが大切

結局自動化が目的でやってるので、時間がかかってでもエラーなく終わること。

それが最も重要。精神的にも。

そうしておけば寝ている間に必要なことはやってくれる。これ大事。

以下のようなコードを走るようにしておいて、たまに再起動をかけると最後まで走るようになる。

当然、広告の回避策とかは別で必要

def restart(aapo, package_name, app_class_name):
    print("restart")
    aapo.end(f"{package_name}")
    time.sleep(10)
    aapo.start(f"{package_name}{app_class_name}")
    time.sleep(3)
    capture(aapo)

■機械学習を使ってできることは増えるが、学習データを使用する場面を選ぶ必要がある

例えば、広告回避策として、一定時間たつと×ボタンを押してほしいけど、いろんな場所に×が来たり、形が微妙に違ったりして困るものだ。

そういう時に×の位置を探すように指示することができる。

まずは学習させるデータをいくつか用意する。とりあえずは10~20でいい。

必要なら後から追加できる。

そこから以下のようなコードで学習データを作る

import cv2
import numpy as np

def prepare_training_data(image_path):
    # 画像の読み込み
    image = cv2.imread(image_path)

    # グレースケールに変換
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # 学習データに追加
    training_data.append({
        'image': gray
    })

# テンプレートマッチングを使用して画像内の座標を検出する関数
def detect_coordinates(image, template):
    result = cv2.matchTemplate(image, template['image'], cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    print(f"テンプレートマッチングの結果: {max_loc} (類似度: {max_val})")
    return max_loc

def detect_coordinates_center(image, template):
    result = cv2.matchTemplate(image, template['image'], cv2.TM_CCOEFF_NORMED)
    _, max_val, _, max_loc = cv2.minMaxLoc(result)

    # テンプレート画像の中心座標を計算
    template_center = (template['image'].shape[1] // 2, template['image'].shape[0] // 2)

    # 検出された位置の左上座標から中心座標に変換
    detected_center = (max_loc[0] + template_center[0], max_loc[1] + template_center[1])

    return detected_center


# ■学習

# 学習データの初期化
training_data = []

# 例として、いくつかの正解画像と座標を用意する

prepare_training_data('close_1.png')
prepare_training_data('close_2.png')
prepare_training_data('close_3.png')
prepare_training_data('close_4.png')
prepare_training_data('close_5.png')
prepare_training_data('close_6.png')
prepare_training_data('close_7.png')
prepare_training_data('close_8.png')
prepare_training_data('close_12.png')
prepare_training_data('close_13.png')
prepare_training_data('close_14.png')
prepare_training_data('close_15.png')
prepare_training_data('close_16.png')

# 別の画像や座標を追加する場合、prepare_training_dataを再度呼び出してください

# 学習データを保存
np.save('training_data.npy', training_data)


# ■実力確認

# 学習データの読み込み
training_data = np.load('training_data.npy', allow_pickle=True)
# print(training_data)

# 新しい画像の読み込み
new_image_path = 'test_image.png'
new_image = cv2.imread(new_image_path)
new_gray = cv2.cvtColor(new_image, cv2.COLOR_BGR2GRAY)

# 最も類似度が高い座標を初期化
best_coordinates = None
best_similarity = -1

# 学習データを使用して座標を検出
for template in training_data:
    coordinates = detect_coordinates_center(new_gray, template)
    result = cv2.matchTemplate(new_gray, template['image'], cv2.TM_CCOEFF_NORMED)
    _, max_val, _, _ = cv2.minMaxLoc(result)

    # 最も類似度が高い座標を更新
    if max_val > best_similarity:
        best_similarity = max_val
        best_coordinates = coordinates

# 結果を表示
print(f"最も類似度が高い中心座標 {best_coordinates} に対応する画像が検出されました。")

上記の学習データを用いて検出させる。

そんでもって、結局どういうコードを埋め込むかというと。。。以下

×ボタンの中央をタップするように誘導する関数も一応別にしておく

def ad_x_machine_lerning(aapo):#実際に実行させるコードはこっち
    # 学習データの読み込み
    training_data = np.load('training_data.npy', allow_pickle=True)

    new_image = get_screenshot()
    new_image = new_image[:380, :]  # y < 380の範囲のみを取得
    new_gray = cv2.cvtColor(new_image, cv2.COLOR_BGR2GRAY)
    # 最も類似度が高い座標を初期化
    best_coordinates = None
    best_similarity = -1
    # 学習データを使用して座標を検出
    for template in training_data:
        coordinates = detect_coordinates_center(new_gray, template)#画像の中央をタップさせる
        result = cv2.matchTemplate(new_gray, template['image'], cv2.TM_CCOEFF_NORMED)
        _, max_val, _, _ = cv2.minMaxLoc(result)
        x, y = coordinates#追加

        # 最も類似度が高い座標を更新
        if max_val > best_similarity and y < 380:#条件追加
            best_similarity = max_val
            best_coordinates = coordinates

    # 結果を表示
    print(f"最も類似度が高い中心座標 {best_coordinates} に対応する画像が検出されました。")
    x, y = best_coordinates

    # xとyの値を出力
    print(f"xの値: {x}")
    print(f"yの値: {y}")
    if y < 380:#画面上部で見つかった場合のみ対応
        aapo.touchPos(x, y)

def detect_coordinates_center(image, template):
    result = cv2.matchTemplate(image, template['image'], cv2.TM_CCOEFF_NORMED)
    _, max_val, _, max_loc = cv2.minMaxLoc(result)

    # テンプレート画像の中心座標を計算
    template_center = (template['image'].shape[1] // 2, template['image'].shape[0] // 2)

    # 検出された位置の左上座標から中心座標に変換
    detected_center = (max_loc[0] + template_center[0], max_loc[1] + template_center[1])

    return detected_center

ただし、利用場所には留意が必要、広告でないところでこのコードを走らせると、最も類似度が高い箇所でどこかをタップするので、確実に広告の画面だとわかっているときにしか使用できない。

まぁそのあたりは工夫してくれ。

上記のコードは私なりの工夫がされている。大体、広告のXボタンは画面の上部に表示されることが多く、y座標が380未満の範囲でしか探さないように制限を掛けている。

■ポイントや決済情報が含まれる画面は対外キャプチャできない

paypayとかd払い、楽天payのようなQRコード決済の画面は普通キャプチャできない。

画像で決済出来てしまうと問題があるための対策と思う。

こういったアプリにおいて自動化の目的はほぼないと思うので、問題にならないことが多いが、どうしても自動化したい箇所がある場合、キャプチャをせずに座標指定とtime.sleepだけで対処する。

目隠しでアプリ操作してるのと同じ。

そういうアプリはバーコードがある画面だけがキャプチャできない仕様になっていることが多いが、中には、決済と全く関係のない画面でも、すべての画面でキャプチャできないアプリもあった。

確認方法は簡単で、確認したいアプリを開いて、自動操作をしてみたい画面でscreenShotを取って、画像が真っ黒だとそこはキャプチャできない画面。

コメント

タイトルとURLをコピーしました