splatoon画像認識について
プライベートマッチの自動ボイスチャット振り分けbot
最近Discordを使ってボイスチャットをしながらSplatoonをしている。そこでSplatoonは4vs4の対抗戦のためボイスチャットもチームごとに分けたい。
そこで手動で映るのは面倒なので自動化した。その備忘録。
実装は .NET Core 2.1(C#) + OpenCVSharp + Discord.NETでやった。OpenCVSharpが非Win環境でうまく動かず、当初の思惑から外れてしまって少し残念。
ikanopu - Github
名前認識
次のような画像が来るので、名前とDiscord IDをうまく結び付けられればあとはDiscord側のAPIをうまいこと叩いてあげればうまくいきそうである。
ただ、すでに書いてある枠を見てもらえればわかるが、枠は微妙に傾いてあるため元画像とのxorなどではうまくいかない。((傾き補正まで含めて実装すればうまくいきそうではある))
そこで局所特徴量を比較することで実装した。
画像取得
OpenCVのVideoCaptureは、USBデバイスなどから画像を取得することができる。便利。
/ikanopu/Service/ImageProcessingService.cs#L61
追加でUSB以外のネットワークエンドポイントを指定したストリームも見れるようにしてある。
背景の削除
名前はほぼ白で書いているので、Grayscale→しきい値固定の2値化処理でうまくいく。
/ikanopu/Core/ImageUtil.cs#L128
特徴量抽出
AKAZE,FAST等有名所をいくつか試したが、解像度があまり高くないことや街中写真から看板を見つけるようなマッチングとは少々勝手が異なるようでうまくいかず。結局周辺への重み付けをよしなにやっているBRISKが一番いい成果を上げた。
詳細はわたしよりも大学の講義テキストに準じたpdfをGoogleで調べたほうが参考になる。
/ikanopu/Core/ImageUtil.cs#L152
こんなに簡単にできていいのだろうか…OpenCV様様である。
特徴識別
まず事前に登録した画像との特徴量の結果、具体的にはKeyPointの数と2画像間の距離を一通り計算する。
これをいい感じな評価関数でマッチングしてあげればよいのだが、人間が行うような手法をそのまま落とし込んでしまっているので参考にはならなそう。実際には動かしながら実装としきい値を決め打ちしている。
行っている処理は以下の通り。
1.取得した画像の特徴量を計算
2.すでに保存されている画像との特徴量差分を一通り計算する
抽出するメソッドから一部切り出した。distanceはmatches(KeyPoint対応のリスト)からその距離の平均を計算している。
またkeypointDiffという変数で、特徴点数の差分もペナルティとして勘定に入れている。
これを入れないと、特徴点数が異様に多い画像と少ない画像で比較を行った際のmatchesが全体的に小さい値を推移するからである。
/ikanopu/Core/ImageUtil.cs#L177
3. 2.項の結果から、飛び抜けたものを抽出
細かいことは雑なコメントに書いてあるが、まとめると「正規分布のはずれにあるものを採用する」だけである。
/ikanopu/Core/ImageUtil.cs#L207
なんとも人間味溢れた処理だが、そんなこんなで先の画像認識が実現する。
実運用時に認識を誤る場合「もともと登録された画像と異なる特徴を持っている」ので、追加登録することで認識精度を改善することができる。なんとも運用でカバーな話だ。
Discord.NETでのボイスチャンネルの移動
以下の処理でうまく行った。GuildUserを取得することがミソ(単純にユーザ取得しても、ギルドに対する処理は行えない。)
それにしてもDiscord.NETはかなり洗練されたライブラリだった。
/ikanopu/Module/PuModule.cs#L565
※ギルドに属するユーザーの編集権限が必要である。
まとめ
けっこう面倒な課題だったような気がするが、原始的な実装でうまく動いて正直自分でも驚いている。
ikanopuに並行して2つに分けた両チームのボイスチャンネル音声をMixするbotもプロ両名(@taniho_0707, @tokoro10g)を中心に開発され、観戦者は双方の駆け引きと指揮を聞けるようになってより楽しめるようになった。
スプラトゥーンは音・ビジュアル・ゲームシステム等どれをとっても完成度が高く、ユーザーを楽しませてくれる素晴らしいゲームだと思う。