スマブラーが動画から数値を認識させてみた(前編)

# はじめに
スマブラー(~~本業はシステムエンジニア~~)がスマブラの動画からキャラクターが受けたダメージを認識させ、それをグラフに描画するものを作りました。スマブラのレート対戦ではVIP(上位3%)ですが、システムエンジニアとしては逆VIP(下位3%)です。(特に機械学習は最近勉強し始めました)

短くまとめるのが難しそうなので、前編、後編(もしかしたら中編も)で分けました。
前編ではTesseract OCRを使ったキャラクター名とダメージの認識の実装について
後編ではOpenCVを使ったダメージ(数字)の輪郭抽出と、機械学習を使ったダメージ認識の実装について書く予定です。

Qiita初投稿なので、至らない点があると思います。
なにかありましたらコメントをお願いします(厳しいご指摘もお待ちしてます！！:D)

# 作ったもの
下記のような画面(動画ファイル)の下部に表示されているダメージを認識させてグラフに描画させました。

### Input
![sample_Moment.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483308/b98a8f88-8c0e-2bf0-d5f3-b3dd1716e039.jpeg)

### Output
![beta1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483308/2bbd81e4-2cbe-50cb-bf01-d100e6acd8bc.png)

# 開発環境
ＯＳ　　　：Windows10 Home 64 bit
言語　　　：Python 3.7.4
エディタ　：Atom 1.40.0
ソース管理：Github

# 実装
`車輪の再発明はするな by えらいひと`　
という有り難いお言葉をどこかでQiitaことがあるので、まずはオープンソースで画像から文字を認識してくれるものを探してみて、一番最初に見つけた、『Tesseract OCR』というものを使ってみました。

## tesseract
私はWindowsを使用しているので、下記の記事を参考にインストールしました。
[Tesseract OCRの始め方](https://qiita.com/Utage/items/29b4dc9e87b0f9dfd481)

## pyocr
Tesseract OCR自体は、画像を入力として与えると文字列を返してくれるツール(OCR)のようで、そのままではPython上では動かせません。
そのため、OCRをpython上で動かすためのpyocrをインストールします。
インストールは簡単で、下記のようにpipコマンドを打つだけです。

``` :コマンドプロンプト
pip install pyocr
```
インストールが終わったら実際にpython上で動かしてみます。
※私の環境では環境変数をいじらないと上手くpyocrがTesseractを認識してくれなかったので、下記の記事を参考に環境変数を追加しました。
[tesseractでOCR@Windows7](https://qiita.com/maitake9116/items/bcf0e519b06e846f0baf)

### キャラクター名(アルファベット)の認識
```python:sample.py
import pyocr
import cv2
import os
import sys
from PIL import Image

# read OCR tools
tools = pyocr.get_available_tools()
if len(tools) == 0:
    print("No OCR tool found")
    sys.exit(1)

# select pyocr.tesseract
tool = tools[0]

# input image file
root_dir = os.path.split(__file__)[0]
image_luci = os.path.join(root_dir, 'data/lucina.png')
image_bayo = os.path.join(root_dir, 'data/bayonetta.png')

image = cv2.imread(image_luci, 0)
lucina = tool.image_to_string(
    Image.fromarray(image),
    builder=pyocr.builders.TextBuilder(tesseract_layout=6)
)

image = cv2.imread(image_bayo, 0)
bayonetta = tool.image_to_string(
    Image.fromarray(image),
    builder=pyocr.builders.TextBuilder(tesseract_layout=6)
)

# output
print('期待値：BAYONETTA 実行結果：{}'.format(bayonetta))
print('期待値：LUCINA    実行結果：{}'.format(lucina))
```

### Input
![bayonetta.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483308/46e8a9ce-7a30-6763-085a-213ef30d50ec.png)
![lucina.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483308/f939dac3-fde8-8341-6a3b-2a58b89191e5.png)

### Output
```
期待値：BAYONETTA 実行結果：BAYONETTA
期待値：LUCINA    実行結果：LUCINA
[Finished in 0.714s]
```

キャラクター名を認識するには実用できそうです。
では肝心なダメージの認識はどうでしょうか。

### ダメージ(数値)の認識
```python:sample.py
import pyocr
import cv2
import os
import sys
from PIL import Image

# read OCR tools
tools = pyocr.get_available_tools()
if len(tools) == 0:
    print("No OCR tool found")
    sys.exit(1)

# select pyocr.tesseract
tool = tools[0]

# read image file
root_dir = os.path.split(__file__)[0]

image_135_5 = os.path.join(root_dir, 'data/135_5.png')
image_6 = os.path.join(root_dir, 'data/6.png')

image = cv2.imread(image_135_5, 0)
damage_135_5 = tool.image_to_string(
    Image.fromarray(image),
    builder=pyocr.builders.TextBuilder(tesseract_layout=6)
)

image = cv2.imread(image_6, 0)
damage_6 = tool.image_to_string(
    Image.fromarray(image),
    builder=pyocr.builders.TextBuilder(tesseract_layout=6)
)

# output
print('期待値：135.5 実行結果：{}'.format(damage_135_5))
print('期待値：135.5 実行結果：{}'.format(damage_6))
```

### Input
![135_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483308/079daec6-83a1-df6e-71a5-071dda45beb0.png)

![damage6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483308/732df9e9-816f-30e3-37e6-0eac08bf4324.png)

### Output
```
期待値：135.5 実行結果：
期待値：6     実行結果：GB
[Finished in 0.712s]
```

# 結論
キャラクター名の認識では、背景がグレーになっているため、Tesseractが有用でしたが
ダメージの認識では背景がゲームのバックグラウンドの影響をかなり受けるため、難しそうです。
詳しい内容は次回の記事で書きますが、まずは背景の情報量を落とす必要がありそうです。
(いろいろ試した結果、機械学習させました...)