画像から文字認識！精度100%のロジックをウイイレを題材に解説

# ウイイレのデータ解析自動化してくよ！ part3

どうも[ヤジュン](https://qiita.com/junya0001000/items/ccb673ba7c07a57e6d8a#%E8%87%AA%E5%B7%B1pr)です！

本記事はシリーズもので、Part3です。よかったら一緒に読んでもらえたらと思います。
1. [Part1の記事](https://qiita.com/junya0001000/items/ccb673ba7c07a57e6d8a)は、試合結果画像から文字データを抽出する文字認識ソフトの作成
2. [part2の記事](https://qiita.com/junya0001000/items/d97e1d3596b85892e767)は、抽出データをグラフ化するソフトの作成

ソフトはPythonで書いています。[■参考URL](https://qiita.com/junya0001000/items/8f519cdb3846fcec397a#%E5%8F%82%E8%80%83url)

## ■宣伝
* [ウイイレのイベント告知用Bot](https://twitter.com/PESeventBOT)作成したので、利用してもらえたら幸いです。
* コンテンツ発信のおかげか、eスポーツ人材の紹介サイトに登録させてもらえました。[ﾘﾝｸ](https://esports-select.com/)
* 今後、解析ソフトと連動した取り組みをYoutube上でする予定です。[ﾘﾝｸ](https://www.youtube.com/user/junya090400)

## ■はじめに
* 今までの活動で、データ抽出からグラフ解析までのソフトを作成し、新しい機能追加を目指していました！

        「もっとデータを集めて新たな解析をしよう！」
        「ウイイレの攻略法を導きだそう！」
    
    しかし、ある問題が開発効率を大きく下げてました...それは
    
    #### **作成した文字認識ソフトの精度が95%だったのです！**

![](https://i.imgur.com/xLGsl9G.png)
![](https://i.imgur.com/VrdEhax.png)

### ▼精度95%がダメな理由
* データ解析のフローを載せました 
    「②文字データ抽出」精度が95%ということは、残5%のエラーを修正しなくてはいけません。
    1試合分のデータで数箇所直す感じです。
    
    仮に解析サービスを、顧客10人に6か月続けるとします。
    プロや配信者をターゲットとし、年2000試合のデータが来ると仮定します。
    
        10人 x 2000試合（1年） x 0.5(半年) = 10000試合分
    
    1試合数個の修正でも、10000試合分だと破綻しますね。。。
    したがって、**データ抽出精度100％は必須要件なのです。**
    
    
![](https://i.imgur.com/eonWaRW.png)

## ■ゴール
* 「ウイイレの試合結果画像からのデータ抽出精度を100%にする」をゴールとしました。

## ■方法
### ▼方法 : OCR
* 最初は[OCR](https://kotobank.jp/word/OCR-1931)をベースとして、精度100%にする取り組みをしました.
    OCRは画像に含まれる文字から、文字データを抽出する技術です。
    結論から言うと、性能は達成できませんでした。
    **ただ、OCRを使いたいエンジニア向けに私の経験を残しておきます。**
    
    OCRの精度は、以下の因子によって構成されます。

         ①入力データのノイズ
         ②ツール・ライブラリの性能
         ③動作モード
         ④出力結果からのノイズ削除
    
#### ①入力データ
* PS4からの付属のスクリーンショット機能で、画像を取得しているので画質等の改善は難しいです。  
    OCRは、物体から特徴量を抽出するので、入力データの品質は重要です.

#### ②ツール・ライブラリの性能
---
* Part1から採用していたのは、[tesseract-ocr](https://github.com/tesseract-ocr/tesseract/wiki)です。  
    無料のライブラリで、pythonで利用されることも多く、参考にできるサイトがたくさんあります。  
    
---


* 次に検討したのは、[Google Vision API](https://cloud.google.com/vision/?hl=ja&utm_source=google&utm_medium=cpc&utm_campaign=japac-JP-all-ja-dr-bkws-all-all-trial-b-dr-1008074&utm_content=text-ad-none-none-DEV_c-CRE_285865409470-ADGP_Hybrid+%7C+AW+SEM+%7C+BKWS+~+T1+%7C+BMM+%7C+ML+%7C+M:1+%7C+JP+%7C+ja+%7C+Vision+%7C+API+%7C+en-KWID_43700016119073988-kwd-154107679017&userloc_1009288&utm_term=KW_%2Bgoogle%20%2Bvision%20%2Bapi&gclid=Cj0KCQiAkePyBRCEARIsAMy5SctboKWtsTtMGinWFY2UB6glu5SBsspKPxXs3o6MKp25rJ0cb18Ih0caAtheEALw_wcB)です。  
なんと、ツール紹介ページでデモ実行ができる神仕様！さすがGoogle様や。。。入社したかった。。。  
    早速、ウイイレの試合結果画像を突っ込んでみました。
    
![](https://i.imgur.com/o3mjOGy.png)
![](https://i.imgur.com/lpgiLAi.png)
![](https://i.imgur.com/6p8Z3aX.png)

* かっこいいUIですね！タブ毎に情報が出されます。

        Labal
        Logos
        Web
        Text
        Properties
        Safe Search
* 注目するのは「Text」タブで、画像からの文字データを認識しています。
    **結論から言うと期待する性能はなさそうです。**
    文字として認識した場所は、緑色で枠どられていますが、「クロス本数」などの数字データは認識してません。
    （ロゴからサッカーチームを特定するのは個人的に感動した！）

---- 

* 他のライブラリも考えましたが、Google先生の性能をベースに考えると無駄な可能性が高いです。  
    素直に、Tesseractで開発を進めることにしました。

-----

#### ③動作モード
* OCRのライブラリには、[動作モード](https://blog.machine-powers.net/2018/08/02/learning-tesseract-command-utility/)の指定ができます。
    解析対象は、「１文字なのか？」「文字列なのか？」「縦書きか？」「横書きか？」「数字なのか？」「アルファベットなのか？」などを指定するのです。
    
    出力結果が数字でなかったりした場合は、動作モードを変えて再実行するようにします。

#### ④出力結果からのノイズ削除
* 最終的に出てくる文字列に、「.」や[|]などのノイズがあることもあります。
    そのため、文字列から数字データ以外の文字を削除するようにソフトを書きます。

    **これだけやった結果が、認識精度95%なのです。。。**
    実際の出力結果が見たい人は[■結果](https://qiita.com/junya0001000/items/8f519cdb3846fcec397a#%E7%B5%90%E6%9E%9C--%E5%87%BA%E5%8A%9B%E7%B5%90%E6%9E%9C)
    

### ▼方法 : Template Matching
* **さあ真打登場！**  
    [Template Matching](https://www.yukisako.xyz/entry/template-matching)は、ある画像から特定の画像を探すという画像処理の一つです。ライブラリは[Opencv](https://www.sejuku.net/blog/113292)を使います。
    入力データである「ウイイレ試合結果」は、Template Matchingにとって有利な特徴を持っています。
 詳細は以下の通り。

        回転しない
        ゆがまない
        各データの位置は統一
        フォントも統一
        サイズも統一

#### ・前準備
* 特徴を知ったところで、どんどん進んでいきましょう！  
    Template Matching用データとしてウイイレの試合結果から「数字データ画像」を集めます。
    （面倒くさいです!!）  
![](https://i.imgur.com/7aWvXFt.png)

#### ・デモプレイ
* 集めた画像データをTemplateとして、Template Matchingを実行します。
    使用した関数は[cv2.matchTemplate()](https://docs.opencv.org/2.4/modules/imgproc/doc/object_detection.html)です。
    数字が小さいほど緑色、大きいほど赤色の枠で囲まれるデモコードを書いて実行します。
    確実にGoogle Vision APIの性能を超えてますね！！
    
    枠が表示された場所に、該当する数字があるとしてデータを保存します。
    その際、場所によって「どのパラメータの数字か」を判断させることで、画像からデータを抽出する仕組みです。
    
![](https://i.imgur.com/Um9AXEy.jpg)

#### ・検出感度
* この欄は、エンジニア向けに技術的な話を書いておきます。
    Template Matchingにとって、エンジニアを悩ませるのが「検出感度」です。
    「検出感度」によって変わるのは、[偽陽性と偽陰性](http://canscreen.ncc.go.jp/yougo/11.html)です。
    今回のソフトを例にすると
    
        偽陽性：本当は数字が「ない」場所で、数字が「ある」と判定してしまうこと
        偽陰性：本当は数字が「ある」場所で、数字が「ない」と判定してしまうこと
    
    これを調整できるのが「検出感度」です。
    
        「偽陽性と偽陰性の両方がなくなるように検出感度調整すればいいじゃん！」
    
    と思われるかもしれませんが、大抵無理です！
    理由は、「偽陽性と偽陰性がある検出感度の区間は被っていることが多い」からです。
    
![](https://i.imgur.com/0we9jPc.png)

* では、どうするのか？
    **検出感度を「偽陽性か偽陰性のうち片方しかない」ように設定するのです。**
    あとは結果から偽物を発見・排除するようにソフトを書きます。
    仮に、偽陽性と偽陰性が共存する感度だと、コードが複雑になります。
    
    ちなみに、今回のソフトは偽陽性側に振っています。
    オブジェクト数（数字の数）が不定なので、偽陰性は検出はできないからです。
    
          ▼偽陰性を検出するためのロジック▼
          あるはずの数字の数　- 検出できた数字の数 = 差分があれば偽陰性あり


## ■結果
* 以下の5枚を入力画像として、ソフトを実行してみました。

### ▼結果 : 入力画像
![](https://i.imgur.com/Z4IsfqT.jpg)
![](https://i.imgur.com/zKpHsE9.jpg)
![](https://i.imgur.com/QW2M3Lk.jpg)
![](https://i.imgur.com/028dsyc.jpg)
![](https://i.imgur.com/kQYEvdx.jpg)

### ▼結果 : 出力結果
* 出力データはCSVで出ます。
    差分がわかりやすいように、「改善したOCRソフト」の結果も載せて比較します。
    正解データと比較して、誤っているセルは色付きで表示させています。
    
     **正答率100%を達成できました！！わーい（祝）**
     
![](https://i.imgur.com/LomCeXc.png)
![コメント 2020-02-29 181509.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572321/81fd2934-8587-d627-8b45-22c90770a909.png)



## ■おわりに
* ここまで読んでくれてありがとうございます！
    文字認識精度を100%にできたので、データ抽出からグラフ作成まで完全自動化できました！
    これで、何試合でも解析可能です♪
    
    あと、偽陽性/偽陰性を考慮したソフト設計は、エンジニアの方にも勉強になったのではないでしょうか？
    誰かのお役に立ててたら幸いです。
    
    今後も、ソフトへの機能追加・性能改善を進めていきます。
    part4をお楽しみに！

## ■参考URL
1. [Python + OpenCVで遊んでみる(OCR編)](https://itport.cloud/?p=8326)
1. [NumPy配列ndarrayの次元数、形状、サイズ（全要素数）を取得](https://note.nkmk.me/python-numpy-ndarray-ndim-shape-size/)
1. [Google Cloud Vision APIを試してみる](https://qiita.com/jkshr/items/7b4495cd80b40ae1173b)
1. [テンプレートマッチング](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_template_matching/py_template_matching.html)
1. [Pythonでリスト（配列）の要素を削除する](https://note.nkmk.me/python-list-clear-pop-remove-del/)
1. [絶対値を求めるabs関数の使い方](https://dot-blog.jp/news/python-abs-function/)