u++の備忘録

【Python&遊戯王デュエルリンクス】スクリーンショットから初期手札の「バランス」を自動取得するスクリプト

11月6日のアップデートで、スキル「バランス」に一定のランダム性が付与されたそうです。どの程度のランダム性が付与されたかを調べるため現在、モンスター10枚・魔法5枚・罠5枚デッキで「バランス」を使ってデュエルを始めた際の初期手札のスクリーンショットをひたすら取り続けています。

(オートで回している隙間時間を使って)その集計を簡略化するべく、スクリーンショットの画像から初期手札のモンスター・魔法・罠の割合を自動取得するプログラムを書きました。
github.com

手法

  1. 画像から、手札の1枚ずつの領域を取り出す
  2. それぞれの領域内のRGB値の平均を導出し特徴量とする
  3. 全てのデータ(特徴量+各ラベル)からKmeans法でモンスター・魔法・罠に分類する
  4. 集計して棒グラフを出力する
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import cv2
from sklearn.cluster import KMeans
from collections import Counter
import matplotlib.pyplot as plt
import numpy as np

img_dirs = ['img']
CARD_NUM = 4
CLASS_NUM = 3
img_data = []

def convertImgToRGB(img):
    for card in range(CARD_NUM):
        trim_img = img[1180:1200,(80 + 113 * card):(193 + 113 * card)]
        averages = trim_img.mean(0).mean(0)
        img_data.append(averages)

def imgImport():
    for i, d in enumerate(img_dirs):
        files = os.listdir('./'+d)    
        for f in files:
            img = cv2.imread('./' + d + '/' + f)
            convertImgToRGB(img)

def createBarplot(counter):
    labels = []
    cnts = []
    for label, cnt in counter.most_common():
        labels.append(label)
        cnts.append(cnt)
    left = np.array([(i+1) for i in range(len(cnts))])
    height = np.array(cnts)
    plt.bar(left, height, tick_label=labels, align="center")

def converRGBToCollection(img_data):
    pred = KMeans(n_clusters = CLASS_NUM).fit_predict(img_data)
    pred.resize(int(len(pred)/CARD_NUM), CARD_NUM)
    pred = list(pred)
    for i in range(len(pred)):
        pred[i].sort()
        pred[i] = str(pred[i])
    counter = Counter(pred)
    createBarplot(counter)

imgImport()
converRGBToCollection(img_data)

画像処理のイメージ

github.com

Kmeans法の結果

f:id:upura:20171110090559p:plain

from mpl_toolkits.mplot3d import Axes3D
def plotRGBVectors(img_data):
    pred = KMeans(n_clusters = CLASS_NUM).fit_predict(img_data)
    x = []
    y = []
    z = []
    for i in range(len(pred)):
        x.append(img_data[i][0])
        y.append(img_data[i][1])
        z.append(img_data[i][2])
    fig = plt.figure()
    ax = Axes3D(fig)
    ax.set_xlabel("X-axis")
    ax.set_ylabel("Y-axis")
    ax.set_zlabel("Z-axis")
    ax.set_xlim(0, 256)
    ax.set_ylim(0, 256)
    ax.set_zlim(0, 256)
    ax.scatter(x, y, z, "o", c=pred)
    plt.show()

plotRGBVectors(img_data)

スクリーンショット募集

データ量が大事なので、同条件でのスクリーンショットを下記フォルダにアップロードいただけると大変ありがたいです。
https://drive.google.com/drive/folders/1N4kV_Mu0qq--IEJO0EwoLKBk4ygD_r3M?usp=sharing