薬剤師のプログラミング学習日記

プログラミングやコンピュータに関する記事を書いていきます

数字認識を使って棚卸を自動化するアプリケーションを作る

機械学習ライブラリにおける画像分類のチュートリアルなどで目にすることが多い手書き数字認識ですが、実際の業務で行う棚卸で利用することができそうだと考え、あれこれ試行錯誤してやってみました。とりあえず実用で使えるレベルで形になったので、書いていきたいと思います。


手書き数字認識とは

手書きの数字画像が0~9のどの数字であるかを正しく分類しようというタスクです。
下図はMNISTという数字画像と正解ラベルがセットになっているデータセットの数字画像の例です。このデータセットの訓練用画像で学習を行い、学習したモデルでテスト用画像をどれだけ正しく分類できるかを計測する、といった使い方をします。

<MNIST画像データセットの例>
f:id:enokisaute:20210101114414p:plain

手書きの数字(文字)というのは人によって個性(くせ)があったり、国や地域によっても書き方が異なる場合があるようです。たとえば「7」だと1画で書かれたものもあれば、長い縦棒部分に短い横棒が入っているものがあったりします。
このような違いがあっても、人が「7」だと認識するのは難しいことではありませんが、プログラムがこれらの違いを吸収して「7」を正しく認識できるかというところに難しさがあります。

作成するアプリケーションの概要

私の職場での棚卸作業の流れはだいたい次のようになっています。

  1. 採用薬マスタからExcelVBAで棚卸記入用紙を作成、印刷する
  2. 実際に在庫を数えて用紙に記入する
  3. 用紙に書かれた在庫数をPCに手作業で入力する
  4. ExcelVBAで集計・在庫金額を出して提出用のフォーマットに整形する
自動化する部分

上の作業の内、今回自動化するのは3番目の「用紙に書かれた在庫数をPCに手作業で入力する」部分です。
もう少し具体的に言うと、コピー機でスキャンして画像データにした後、書いてある数字部分をコンピュータ(学習した画像識別モデル)に読ませることで人間が行っていた入力作業を自動化する、ということです。
入力作業自体は数十枚程度のことですが、この自動化によって、手間と時間を節約しようというのが今回作成するアプリケーションの目的*1です。

このような自動化を行うための工程は、以下のように分けられます。

<スキャンした画像データ>
f:id:enokisaute:20201231101103p:plain
   
<手書き数字の切り出し(1文字ずつに分解)>
f:id:enokisaute:20201231102418p:plain
   
<数字認識>
f:id:enokisaute:20210101163307p:plain
   
<読み取った数字の入力>
f:id:enokisaute:20201231110138p:plain

ひと言でいうと、OCR(光学文字認識:画像データのテキスト部分を認識して文字データに変換する機能)をやってみたい、ということになるでしょうか。
しかし、今回作成するアプリケーションはGoogleドライブなどで使える写真のOCRとは以下の点で異なります。
数字が書かれている場所は決まっており、対象領域が限定されているので画像データのどこに数字があるかを探す必要はありません。また、書かれている文字も郵便番号のように0~9の数字だけとわかっているので、写真のOCRに比べると難易度的にはそれほど難しくはない・・・はずですが、それなりに苦労した点もありました。

精度を決めるポイント

アプリケーションを作成する上で要所となるのは次の2点です。

  • 手書き数字の切り出し
  • 数字認識(学習したモデルによる数字の分類)

MNISTデータセットにおいては、シンプルなCNN(畳み込みニューラルネットワーク)を使っても現在は99%以上の精度で分類できるようなので、「数字認識」の部分にはアプリケーションの精度向上の潜在的な伸びしろはほぼありません。
要するに、アプリケーション全体の精度を決めるのは「手書き数字の切り出し」部分の工程であり、ここに注力すべきということになります。理屈の上では、この部分がほぼ完璧に機能すれば、コンピュータに99%に近い精度で手書き数字を入力させることができるはず、というわけです。

OpenCVによる画像データの前処理

OpenCVとはオープンソースの画像・映像を処理するライブラリで、もともとはC/C++で開発されたものだそうですが、JavaやPythonなどの言語でも使うことが可能です。
ライブラリでは画像のサイズ変更や回転、ノイズの除去や輪郭の抽出、グレースケール変換など様々な高度な機能が提供されており、「手書き数字の切り出し」工程では主に以下のような処理でOpenCVを使用しました。

  • スキャナーで読み込んだ画像を回転して水平にする
  • 切り出し枠の正確な座標を得る
  • 枠線を消して数字だけを浮かび上がらせる

これらの処理について書いた記事のリンクを貼っておきます。
こちらの記事では実行環境やスキャナー設定の情報も書いています。
www.yakupro.info
こちらはマスク処理による背景の消去と数字の切り出しです。
www.yakupro.info
切り出した数字画像の前処理について
www.yakupro.info




手書き数字データの収集と使用したモデル

手書き数字の分類はSVM(サポートベクターマシン)や多層ニューラルネットワーク等でも行うことができますが、実用に耐える精度を目指したので画像に対して認識率の高い結果を出す深層学習(ディープラーニング)を行うCNN(畳み込みニューラルネットワーク)を使用しました。
学習のための画像データは前述したようにMNISTデータセットを使用しましたが、このデータセットである程度学習した後、自前でデータを収集してそちらを使った学習も行いました。
この辺の試行錯誤についても、自分の勉強した復習を兼ねて少しずつ書いていければと思っています。

参考

・Coursera Machine Learning Application example: Photo OCR
ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
カラー図解 Raspberry Piではじめる機械学習 基礎からディープラーニングまで (ブルーバックス)
・今すぐ試したい! 機械学習・深層学習(ディープラーニング) 画像認識プログラミングレシピ

*1:ちょっと良く言いすぎかも。正直に言うと、数字認識を使って何か作ってみたい、が先でした。