おはよう君需要なし

求不得苦な日々

Pokemon Go個体値判別アプリを作りました【Android・画像処理】

はじめに

ポケモンGoがめちゃくちゃ流行っていますが(もう流行ってないけど)、ポケモンを育てるにあたってそのモンスターの個体値を把握しておくことは ジム戦でも有利になるなど、とても大切なことだと思います。

最近のアップデートではチームのリーダーが個体値を判定してくれる機能が実装されるなど、個体値を知ることは公式も認める大切なことです。

なぜ作ろうと思ったか

作り始めた当時から、個体値の判別サービスというものは既に存在していました。SilphRoadのIV Raterなどはとても有名ですね。

thesilphroad.com

しかしこのサービス、ポケモンのレベルをあらわす円弧の角度を手動で入力する必要がありました。

f:id:yoh_mar28:20160905183652p:plain

円弧の入力はトレーナーのレベルが上がるほど細かい調整が必要とされ、手入力は面倒くさいだけでなく誤差にも繋がります。(しかも後々わかったんですが、Silphroadの円弧は誤差を含んでいます)

画像処理でできるアプローチ

というわけで、スクリーンショットから自動でモンスターの個体値を推定するプログラムを書いてみることにしました。画像処理についてはある程度知識があるので、組めるだろうという気がしていたのです。

輝度による二値化

基本的にポケモンGoの文字や円弧などの白い部分は(255,255,255)の色で構成されています。なので輝度値で二値化して必要なリージョンを切り出して処理を行う、ということは容易でした。

ラベリング

f:id:yoh_mar28:20160905191244p:plain

リージョンの切り出しについてはラベリングを使用しています。

qiita.com

ちなみに、こういうQiita記事があるんですけど、ただ和訳しただけだし内容間違えてるし正直迷惑でしかない。

JPGのノイズ

これには本当に悩まされました。当初リプライで個体値を返してくれるTwitterbot形式でのサービスを考えたのですが、Twitterの画像添付時にかかる自動的な圧縮がノイズになり、プログラムがろくに動かなくなってしまいました。

f:id:yoh_mar28:20160905185108p:plain

結果として、アプリ形式で提供するのであればpngスクリーンショットを得ることができるので、bot形式をやめるというアプローチ(笑)で解決しましたが、とても苦しいものがありますね。

HOG特徴量による文字のマッチング

f:id:yoh_mar28:20160905185423p:plain

数字のマッチングにHOG特徴量が応用できるのではないかと考えました。

f:id:yoh_mar28:20160905190051p:plain

結果としては上々ですが、所詮ここで用意したデータというのはCPの数字にしか適用できず、HPでは別途用意せねばならないことや、フォントの機種依存などを考えると頭が痛かったのでやめました。

tesseractによるOCR

github.com

tesseractはGoogleがかつて開発していたこともあって、とても強力なライブラリです。ポケモンの種類(名前)にはこのOCRライブラリを使用しました。前述のHOG特徴量を使用することも検討したんですが、日本語以外の言語に対応する場合にこちらの方が用意であることを考えてこちらにしました。

プリセットの学習データは余分なものが含まれすぎていて、却ってノイズになりやすかったため、別途学習データを作成しました。

ハフ変換による円弧の検出

f:id:yoh_mar28:20160905191102p:plain

円弧の検出にはハフ変換が有効です。

f:id:yoh_mar28:20160905191731p:plain

ハフ変換の前には細線化をすると結果の向上が見られました。

sites.google.com

細線化についてはこれを使って検討してみましたが、円弧が十分の長さを持っていないと(レベルが低いとダメ)正しく検出できない問題や、そもそもこの実装がLGPLになっていることなどからやめました。

苦労した部分

円弧とレベルの対応

円弧がレベルを表す、というのは知っていたのですが、具体的な角度については諸説あり、実際の値とずれてしまっていました。そこで1ずつレベルを上げ、レベルと円弧の角度の対応を推定しました。

f:id:yoh_mar28:20160905202735g:plain

Anroid用にライブラリをビルド

当初、アプリはWebAPIとして提供する予定だったので、Androidで使用できるかどうかという調査をせずにtesseractだ何だと取り入れてしまいました。

しかし、通信のオーバーヘッドがバカにならないレベルで大きいということがわかり、ネイティブで処理をさせようという方針になりました。TesseractやOpenCVのビルドについて、ここに書いてしまうととても長くなってしまうので需要があれば書きたいと思います。

まぁ言いたいことは、XamarinもといMonoは最強で、WindowsC#からCのライブラリを呼ぶような感覚でAndroidアプリを作ることができました。

他との比較

他のアプリと比べたところ、たぶんOCRエンジンの初期化で起動は遅いですが、判定は最速だと思います。まぁネイティブで実装してますから・・・

しかし、出力される情報はたぶん最小だと思います(笑。個体値しかまだ出せません・・・

おわりに

今回はVisual Studioを使って一本Androidアプリをはじめて作ってみたわけですが、構想から1ヶ月もリリースまでにかかりました。

初アプリということもあり、Androidの作法もわからない状態からスタートしましたが、他のアクティビティからフォーカスを奪わないオーバーレイ表示やネイティブライブラリの呼び出しなど、いろんなことを学べて楽しかったです。

このアプリにちょっとでも興味を持ってくださった方は「博士課程Go」で検索してみてください。まだベータ版ですが一応使えるようにしてあります。