この記事、何?
機械学習でGridSearchCV近辺触ってて、精度を悩んでみたくなった。
ただ、アヤメやタイタニックと向き合うのはいまいち気が乗らない・・・
だって、スコアが良すぎたら過学習を疑ってしまうし、低くても理解や努力が足らないのか、そもそもそのくらいなものなのかがよくわからない。
というわけで、音ゲーのスクリーンショット(スクショ)で何かしてみようと。
まずは、初めて画像がらみをどうにかする初心者向けの課題として、数値分類をしようかと。
で、やったことというと・・・教師データとして数字1文字ずつの画像ファイルを作った。
スクショを94枚用意して、1枚当たり31個の数字があったので94*31=2914個の画像ファイルを作った。
全体的な方針
今回の投稿は2914個の画像ファイルに細切れにしたまでだけど、長期的には目的はこんな感じ。
Lv.1 : 決まったドット位置にでる数字を読み取る
Lv.2 : 何種類かのスクリーンパターンごとにパターンを判別したうえで数字を読み取る
Lv.3 : 決まったドット位置に出る曲名を読み取る
Lv.4 : 何種類かのスクリーンパターンごとにパターンを判別したうえで文字を読み取る
Lv.5 : 未知のパターンに対しても文字・数字を読み取る
まあ・・・キャライラストからアイドルの子を判別できたり、スマホのスクショではなく、アーケードゲームのレザルトを撮影した写真からスコアとか曲名とか取れるようになるといいなぁ・・・始めたばかりの自分には想像もつかない感じですが。
使ったもの
Windows 8 Pro
Python 3.7.1 (Anaconda)
OpenCV 3.4.1
(参考:デレステ)
■アイドルマスター シンデレラガールズ スターライトステージ
https://cinderella.idolmaster.jp/sl-stage/
方針
今回は上記でいうといわばLv.0。Lv.1の解析を目的にした準備。
Lv.1で解析させたい数字がいっぱい出る画面として、プレー後のスコア画面。
スコアとして7桁の数字が出る。
それ以外に、タイミングピッタリ(PERFECT)~駄目(MISS)までの5種類の数と、つながった数(COMBO)が出る画面。(それぞれ4桁)
それらがスクショで固定的な位置に出るから初心者向けとしてピッタリ。
Pythonで処理する前に、画像の何ドット目から何桁なのかということの位置合わせのために画像を表示してポイントしたら位置を数えてくれるツールをC#で別途作ってみた。
で、そこから得た情報がこんな。
Name | FromX | FromY | SizeX | SizeY | Digits |
---|---|---|---|---|---|
PERFECT | 772 | 344 | 132 | 44 | 4 |
GREAT | 772 | 403 | 132 | 44 | 4 |
NICE | 772 | 462 | 132 | 44 | 4 |
BAD | 772 | 521 | 132 | 44 | 4 |
MISS | 772 | 580 | 132 | 44 | 4 |
COMBO | 759 | 669 | 144 | 52 | 4 |
SCORE | 653 | 827 | 252 | 49 | 7 |
*1行目、PerfectはX=772,Y=344の位置から、132x44サイズで4桁という意味
あとはC#でこれを一つのjsonとして出力しておいて、pythonで読んでOpevCVでバラバラにしようと。
で、あとで学習させようと。
※あくまで本記事の目的はOpenCVでの分割までです。
ホントは・・・C#ももっといい感じのコードにしてアップしようかと思ったけどやっつけ感が半端ないものになったので上げられない。。。
できあがり
これで2914個の「0」とか、「3」とか書いたちっちゃいファイルができた。
import os
import json
import cv2
jfile = 'score.json'
jdata = open(jfile)
dict = json.load(jdata)
# 7種類の数ごとに繰り返す
for f in range(7):
#位置とか桁とかの読み取り
header = dict[f]['Name']
x = int(dict[f]['FromX'])
y = int(dict[f]['FromY'])
width = int(dict[f]['SizeX'])
height = int(dict[f]['SizeY'])
digits = int(dict[f]['Digits'])
#ファイルごとに繰り返す
for dirpath, dirs, files in os.walk('C:/projects/qiita_data/20190303/score'):
for name in files:
#各桁ごとに1文字ずつ切り出す
for d in range(digits):
src = cv2.imread(dirpath + '/' + name, 1)
dst = src[y:y+height, x+int(width/digits)*d:x+int(width/digits)*(d+1)]
#別フォルダに個別のファイルとして出力
cv2.imwrite('output/' + header + '_' + str(d) + '_' + name, dst)
感想
初めてOpenCV使ってみた。
画像ってそんなに簡単なコマンドで何とかなるものなのね・・・やっぱPythonすごいな。
あっ、教師デーったってことは94ファイル・・・2914個の数字を読んで書き留めないといけないのね。めんどい。。。
あと、松尾先生がしばらく前のAI関連の番組で「レシートをOCRして家計簿に落としてくれるAI」がでてた。
それ、レシートに出てくる、商品名・価格だけじゃなく、それらが「食費」なのか、「交際費」なのかとかのジャンル分けとか、
店舗名とか、スルーしてよい特売のお知らせとかの意味まで理解してカテゴライズしてた気がする。
すごいな。Lv.100?