背景
プレイ中のゲーム画面を画像分析させたりできないかなぁと思っていた所、思っていたよりかなり簡単に実装できたので記事にしました。
使用技術
- Python
- Pillow(画像を扱うためのライブラリ)
- OpenCV(画像解析用ライブラリ)
実際の例
今回は例として、テトリスを画像分析してみることにします。
import cv2
import numpy as np
from PIL import Image, ImageGrab
import time
# 1.テトリスブロックのテンプレート画像ファイルのパス
block_templates = ['block_I.png', 'block_J.png', 'block_L.png', 'block_O.png', 'block_S.png', 'block_T.png', 'block_Z.png']
def capture_screen():
"""スクリーンショットを取得してOpenCV形式に変換"""
screenshot = ImageGrab.grab()
image_np = np.array(screenshot)
return cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR)
def detect_blocks(frame, templates):
"""画像内のテトリスブロックを検出"""
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
detected_blocks = []
for template_path in templates:
template = cv2.imread(template_path, cv2.IMREAD_GRAYSCALE)
w, h = template.shape[::-1]
result = cv2.matchTemplate(gray_frame, template, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
if max_val > 0.8: # 一致度が高い場合
detected_blocks.append((template_path, max_loc, (w, h)))
return detected_blocks
while True:
# 2.ゲーム画面をキャプチャ
frame = capture_screen()
# 3.ブロックを検出
blocks = detect_blocks(frame, block_templates)
# 4.検出結果を表示
for block in blocks:
template_path, (x, y), (w, h) = block
print(f"Detected {template_path} at position ({x}, {y})")
# 5.検出したブロックを矩形で囲む
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 6.キャプチャした画像を表示(デバッグ用)
cv2.imshow('Detected Blocks', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
time.sleep(5) # 5秒ごとに実行
cv2.destroyAllWindows()
コードの説明
1. テトリスブロックのテンプレート画像ファイルのパス
2. ゲーム画面をキャプチャ
今開いているPCの画面全体のスクリーンショットを取ります。
3. ブロックを検出
テンプレートマッチングにかけ、各ブロックに一致する箇所の一覧を取得します。
4. 検出結果を表示
ブロックが存在した座標をシェルに出力します。
5. 検出したブロックを矩形で囲む
ブロックを色つきの長方形の枠で囲い視覚的に分かるようにします。
6. キャプチャした画像を表示(デバッグ用)
最後に画面上に、画像分析の結果を出力します。
私の環境では、いい感じに表示できなかったので調整は必要です。
感想
難しい部分をライブラリがやってくれているおかげで、かなりシンプルなコードで実現することができました。
応用すれば、結構できそうなことがありそうだなと思いました。