検証環境:8年前のMacBook Air
この記事はGoogle Colabでカードゲームを攻略するAIを作るシリーズのPart 3です。
- Part 1:Google Colabの基礎 + RustバイナリをColabで動かす
- https://qiita.com/hiyokoko/items/e24061c12d1cf3ff4f00
- Part 2:強化学習 + 20万エピソードの結果
- https://qiita.com/hiyokoko/items/e1160172b370ad7ebac0
Part 2で強化学習側はうまく動いた。次の課題は「実際のゲーム画面からカード情報を自動取得すること」。スクショからカードを認識させようと2週間格闘した。結果は完全に失敗。何がダメだったか正直に書く。
目指していたパイプライン
カード画像(JPG)
↓ OpenCV
カード名を認識
↓ TOMLと紐付け
効果・コストを取得
↓ RL環境
盤面を評価(良い手 / 悪い手)
理屈の上ではシンプル。実際はボロボロだった。
OpenCVでやろうとしたこと
GitHubから取得したマスター画像(約300種類)と、スマホのスクショから切り抜いたカード画像をテンプレートマッチングで照合する方法を試みた。
img = cv2.imread("card.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(...)
result = cv2.matchTemplate(input_card, template, cv2.TM_CCOEFF_NORMED)
一見シンプルだが、ことごとく失敗した。
やらかした3つのミス
6時間以上デバッグして見えてきた問題点。
ミス1:画像サイズを統一していなかった
マスター画像とスクショ切り抜きのサイズが微妙に違った。数ピクセルのズレでもテンプレートマッチングの精度は大きく落ちる。
ミス2:閾値が厳しすぎた
if score > 0.99: # これほぼ通らない
人間の目には同一に見える画像でも、レンダリングの違いで0.95を下回ることがある。3pxのズレが致命的だった。
ミス3:カラー画像のまま比較していた
マスターJPGとスクショの色味が微妙に違うだけで精度が落ちる。グレースケールに変換してから比較するのが正解。
全部試した
- ✅ テンプレートマッチング → 精度悪い
- ✅ ORB特徴量マッチング → 装飾フォントに弱くて失敗
- ✅ Gemini Visionに画像を投げる → 「このカードはわかりません」
- ✅ Claude Opusに投げる → 同じ回答
- ✅ Colabで2日間実験 → 解決せず
根本的な問題は、このゲームのカードがオリジナルで、どのAIモデルも学習していないこと。マスターデータとスクショの間にある「目には見えない微差」が、全てのアプローチを壊した。
結局わかったこと
諦めたのは正解だったが、得たものはある。
性能の良いPCが使えるなら、この問題はわりと簡単に解決できる。画面を常時キャプチャしてリアルタイム処理すればいい。テンプレートマッチングすら不要になる。
今回うまくいかなかった理由はアプローチが悪かったのではなく、8年前のMacBook Airでどこまでできるか限界まで削った結果だった。ハードウェアに起因する限界というのも、立派な知見だと思う。
まとめ
2週間・複数アプローチ・カード認識ゼロ。でも「なぜ失敗したか」は完全に理解できた。
同じことを試す人へ:画像サイズを統一する、グレースケール変換を先にやる、閾値は0.95以下にする。そしてオリジナルカードにVision AIは期待しないこと
英語版の記事と並行して書いているので次回余裕があれば、Rust側のゲームエンジン実装についても書くかもしれません。