初心者による初心者のためのPOKECON自動化【実践編】

1.はじめに

この記事は”初心者による初心者のためのPOKECON自動化【基礎編】”、”初心者による初心者のためのPOKECON自動化【構造編】”の続きとなります。まだ読んでいないという方は、ぜひ以下のリンクからどうぞ!

さて、今回は表題の通りPOKECONプログラムを実際に作成していきます!ぜひみなさんも一緒にトライしてみてください。
なお、作成手順などはすべてWindows10を基準に説明することをご了承ください。また、作成や実行の過程で何らかの動作などの不具合によって不利益が生じたとしても、こちらは責任を負いかねます。

2. Pythonファイルの作成

これをしなければプログラム作成は始まりません。
おそらくWindows10ではPythonファイルをデフォルトで作成する機能は標準で備わっていないため、自分で作成します。作成手順については、以下を参考にしてみてください。

  1. エクスプローラーの「表示」からファイル名拡張子のチェックボックスにチェックを入れる。

  2. デスクトップなどの適当な場所にテキストファイルを作成する。

  3. ファイル名を適当に変更し、拡張子を".py"に変更する。

テキストファイル作成直後。これを…
こんな感じに変更してみてください。

ソースコードエディタを利用している人は、作成したファイルを右クリックして「プログラムから開く」>「(ソースコードエディタ名)」の順に開けばまっさらな編集画面が表示されるはずです。

3.今回実現したい動作

今回実現したい動作を示します。動作の目的は、「手持ちのポケモンから、指定したポケモンを検出すること」です。

  1. メニューのポケモンアイコンが左上に表示される、かつカーソルがすでに左上にある状態で、メニューが開けるフィールド画面からスタート。

  2. Xでメニューを開き、ポケモンアイコンをAで選択する。

  3. Aを適切な間隔で2回押し、ポケモンのステータス画面を開く。

  4. あらかじめ用意したポケモンの名前の画像を利用して画像認識を行い、一致した場合は動作終了(しない場合は5.へ)。

  5. ↓ボタンを押し、次のポケモンを表示してしばらく待った後4.へ。

  6. 12回動作を行っても目標のポケモンを認識できなかった場合に対しては、無限動作回避のためエラー文を表示してプログラムを終了する。

動作のイメージは湧きましたか?それでは、早速プログラムを作成してみましょう。

4. 認識対象画像(テンプレート)の準備

認識対象のポケモン名の画像である”target.png”を用意します。
まずはPOKECONを起動し、Switch側は目標のポケモンの名前を表示させた画面にしておきます。この状態でCaptureボタンを押すと、”PokeCon/Poke-Controller-Modified/SerialController/Captures”に画面のキャプチャが保存されます。

Captureボタンの場所。ココを押すとCapturesフォルダに保存される

この画像ファイルのファイル名を”target.png”に変更し、ポケモン名の部分を写真やペイントなどのアプリでトリミングしてください。これを”PokeCon/Poke-Controller-Modified/SerialController/Template/”に配置すれば、画像の準備は完了です。

トリミングの様子。ポケモン名の部分が切り取れたら上書き保存してTemplateフォルダへ

実際にプログラムを作成しているときに複数のテンプレートが必要だと分かった場合には、この手順を繰り返して画像を集めます。今回はこのテンプレートしか使わないので、用意するのは1回だけでOKです。

5. ソースコードの記述

改めて、記述するプログラムの動作を確認しておきましょう。先ほどイメージした動作と照らし合わせてみてください。必要に応じて、実機で動作を確認してみるといいかもしれません。

今回のプログラムの処理の概要

では、前回の記事の通りに実際に記述していきましょう。
まずは、使うライブラリから記載していくんでしたね。今回は画像認識とボタンの押下設定さえできれば動作の実現が可能なので、以下の2つのライブラリをインポートしましょう。

from Commands.PythonCommandBase import PythonCommand, ImageProcPythonCommand
from Commands.Keys import KeyPress, Button, Direction, Stick, Hat

次は、クラスやプログラム名の記述でした。名前やクラス名はおのおのお任せします。

class Pokemonfind(ImageProcPythonCommand):
    NAME = "ポケモン特定(実践編)"

そして、初期化のメソッドの設定です。ここではカメラ設定の継承に加えて、あえて画像認識の閾値を初期化してみます。

    def __init__(self, cam):
        super().__init__(cam)  #カメラ設定の継承

        self.Find_Threshold = 0.85  #ポケモン認識の閾値

さらに、メインの処理メソッドの設定を記述しましょう。ここでは勉強のために、ポケモンの認識部分は自作メソッド”pokemonfind”を作成してやってみます(作成については後述)。なお、前回の記事で書き忘れていましたが、POKECONで自作メソッドを呼び出すときは先頭に”self.”を付けないとほぼエラーで停止するので、付けるのを忘れないようにしましょう。

    def do(self):
        num = 12 #ポケモン認識のために↓ボタンを押す限界の回数

        print("ポケモン特定(実践編)スタート")

        self.press(Button.X, duration=0.2, wait=1.5)  #メニューを開く
        self.press(Button.A, duration=0.2, wait=1.5)  #ポケモンアイコンを選択する
        self.press(Button.A, duration=0.2, wait=1.0)  
        self.press(Button.A, duration=0.2, wait=2.0)  #「つよさをみる」からステータス画面へ

        self.pokemonfind(Find_num=num) #numをpokemonfindの引数Find_numとして指定

        self.finish() #プログラムの終了

最後に、自作メソッドの記述です。ここで、記述する処理の概要は以下のように考えているものとします。

  • 無限動作回避のため、変数 i の値が”i<Find_num”を満たさなくなった瞬間にwhileループを脱出します。なお、Find_numはメインの処理部から引数として渡ってきた数で、上記ソースコードの11行目から分かるように変数num(=12)が引き渡されています。

  • ”target.png”を閾値”self.Find_Threshold”で認識したら、成功した旨をprint文によって出力し、繰り返しの際に用いるwhileループからbreakコマンドで脱出させます。認識できない場合は↓ボタンを押して、変数 i に1を加えた後にwhileループを継続します。

  • 12回繰り返し動作が行われてしまった場合のために、if文でエラーの旨を表示するかの条件分岐を記述します。12回以内に目標のポケモンを発見できた場合には、条件文の”i == 12”が満たされない(つまりFalseになる)ので、ここはスルーとなる仕組みです。

ちなみに、ほかにもループの記述方法はあるので、余力のある方はぜひトライしてみてください。この一連の処理が終わると、上記のメインの処理メソッドに帰っていきます。帰った直後の処理は”self.finish()”ですから、ここでプログラムが終了します。

    def pokemonfind(self , Find_num = 0): #ここではFind_numが0だが、引数により更新される
        i = 0

        while i < Find_num: #iがFind_num(=12)より小さいときだけ、以下の処理を繰り返す
            if self.isContainTemplate('target.png' , threshold=self.Find_Threshold , use_gray=True , show_value=True):
                #target.png(目的ポケモンの画像)を認識したら以下を実行
                print("目標のポケモンを発見しました!")
                break  #whileループを強制終了
            else:
                print("目標のポケモンを検出できません。次のポケモンに移行します")
                self.press(Direction.DOWN, duration=0.2, wait=0.5)  #target.png(目的ポケモンの画像)を認識しなかったら↓ボタンを押す
                i = i + 1

        if i == 12: #iが12であるとき(すなわち12回認識しても発見できなかったとき)
            print("目標のポケモンは存在しない可能性があります。") #エラー文表示

では、これを通しで見てみましょう。タブスペースによるインデントに注目してみてください。こんな感じになりましたか?

from Commands.PythonCommandBase import PythonCommand, ImageProcPythonCommand
from Commands.Keys import KeyPress, Button, Direction, Stick, Hat

class Pokemonfind(ImageProcPythonCommand):
    NAME = "ポケモン特定(実践編)"

    def __init__(self, cam):
        super().__init__(cam)  #カメラ設定の継承

        self.Find_Threshold = 0.85  #ポケモン認識の閾値

    def do(self):
        num = 12 #ポケモン認識のために↓ボタンを押す限界の回数

        print("ポケモン特定(実践編)スタート")

        self.press(Button.X, duration=0.2, wait=1.5)  #メニューを開く
        self.press(Button.A, duration=0.2, wait=1.5)  #ポケモンアイコンを選択する
        self.press(Button.A, duration=0.2, wait=1.0)  
        self.press(Button.A, duration=0.2, wait=2.0)  #「つよさをみる」からステータス画面へ

        self.pokemonfind(Find_num=num) #numをpokemonfindの引数Find_numとして指定

        self.finish() #プログラムの終了

    def pokemonfind(self , Find_num = 0): #ここではFind_numが0だが、引数により更新される
        i = 0

        while i < Find_num: #iがFind_num(=12)より小さいときだけ、以下の処理を繰り返す
            if self.isContainTemplate('target.png' , threshold=self.Find_Threshold , use_gray=True , show_value=True):
                #target.png(目的ポケモンの画像)を認識したら以下を実行
                print("目標のポケモンを発見しました!")
                break  #whileループを強制終了
            else:
                print("目標のポケモンを検出できません。次のポケモンに移行します")
                self.press(Direction.DOWN, duration=0.2, wait=0.5)  #target.png(目的ポケモンの画像)を認識しなかったら↓ボタンを押す
                i = i + 1

        if i == 12: #iが12であるとき(すなわち12回認識しても発見できなかったとき)
            print("目標のポケモンは存在しない可能性があります。") #エラー文表示

確認できたら、このプログラムを、画像認識を利用するプログラムを入れる場所である”PokeCon/Poke-Controller-Modified/SerialController/Commands/PythonCommands/ImageProcessingOnly/”に移動させ、POKECONを再起動してみましょう。きっと変数NAMEに代入した文字列がプログラム名として表示されているはずです。POKECONがエラーで起動しない場合には、以下の5点を確認してみてください。

  • コメントアウト部分を除き、全角文字や全角スペースが含まれていないか

  • アルファベットの大文字、小文字は間違えていないか

  • アルファベットのスペルは間違えていないか

  • 各行のインデントのレベルは合っているか

  • かっこやコロンの不足はないか

必要に応じて、【基礎編】の4.1.10部分にあるエラーに関してのサイトを参照するといいかもしれません。
ここまで来たら後は実行・微調整のフェーズです!

6. 実行・微調整

では、数回ボタンを押してArduinoをコントローラとして認識させ、3.の動作イメージ1.で確認した条件になっていることを確認してください。
確認が取れたら、作成したプログラムを選択してStartを押してみましょう!きっとこんな動作になるはず。ちなみに、この動画の後半では目標のポケモンを入れないときの動作も含まれています。対象のポケモンがいない場合にどのような動作になるか確認してみましょう。

動作環境は各人で異なりますので、動作に違いが出る可能性は十分にあります。こんな感じの動作にならなかったときは、ボタンの押下時間や待機時間、閾値などを変更してリトライしてみましょう。プログラム作成では、試行錯誤のとき以上に勉強になる機会はありません。
ちなみに、画像認識時に出る以下のログは画像認識の一致率を表示しているので、閾値調整のときに確認するといいでしょう。

target.png ZNCC value: 0.4792815148830414   #このときの一致率は47.928…%

ここまで大丈夫だったら、あなたはもう1人前のPOKECONプログラマーです!あとは自分の好きなプログラムを自由に作ってみてください。

【参考】今回作成したプログラムなど

以下のzipファイルには、今回作成にあたって使用した
・pokemonfind.py(プログラム)
・target.png(画像フォルダ)
が含まれています。参考としてご活用ください。パスワードには、今回の記事内で用意していた画像ファイル名を拡張子付きで入れてください。

7. おわりに

長々とお付き合いいただきありがとうございました!以上で”初心者による初心者のためのPOKECON自動化【実践編】”は終了です。
これまでの記事では基礎的な知識のみを紹介してきましたが、配布されているPOKECONプログラムなどを見てみると、紹介してこなかった知識を使っているものも多々あります。そんなときには、ぜひ一度インターネットなどを利用して調べてみてください。意外と同じような問題に直面している方は多いもので、大体の場合はここで問題解決が可能です。
しかし、「1時間考えたけどわかんねぇよ、あほ4ね!」という場合には制作者様に質問してみるのも手です。ただし、質問の際には円滑なやりとりを行えるように配慮する必要があります。そのため、質問する前に予め以下のサイトに記載されていることを参考にするとよいでしょう。

この点に注意して、READMEなどをよく確認した上でしっかりマナーを守り質問すれば、きっと親身に教えてくださるはずです。実際に私も制作過程でお世話になりました。

最後になりますが、この記事がプログラム作成に挑戦する方々の一助になりますと幸いです。ではでは。

8. Special Thanks!!

  • じゃんきー様(https://twitter.com/junky_poke_ )
     プログラムの質問に関する箇所で、Poke-Controller Guideのリンクの提供をいただきました。ありがとうございました!

9. 編集履歴

  • 2022/09/14:記事のアップロード

いいなと思ったら応援しよう!