kazu22002の技術覚書

PHPer, Golang, AWS エンジニアの日々

カードの画像認識に挑戦

免許証や名刺などのカードを認識するアプリって結構あるので、どうやって作られているのか自分でも試してみました。

少し使いたいプロジェクトがあったのもあり、ネットの情報を元にどれくらいできるか挑戦です。

参考ページ

dev.classmethod.jp

qiita.com

vigne-cla.com

labs.eecs.tottori-u.ac.jp

言語選択

画像処理系の知識は多少ありますが、実装をあまりしてきていないためほぼ初心者と同じです。

そのため目的に対して、なにで実現できそうかを調べるところから始めましたが、opencv + pythonの組み合わせが多くpythonで実装を行うことにしました。

目標

やりたいことは名刺や免許証のOCR( 文字認識 )までを目標として、OCRに渡す画像を適切な部分のみ抽出するプログラムを目指して挑戦してきます。

まず画像からカード系を認識すること自体は調べたらかなり多く出てきました。実際にそのままのコードで動作するものも多いです。コードは読んでみましたが、かなり知識を必要とする部分が多い印象です。

まずopencvができることを知る。そして、画像処理のパターンを知る。というところから始めた感じです。

処理の内容

カード認識までに必要なこととしては、まずカードの矩形を認識する。ということです。

処理の流れは以下の流れが多い感じです。

  • 前処理
  • 輪郭抽出
  • 部分切り取り

前処理の部分が重要でいろんなやり方があり、輪郭を抽出しやすくするように画像処理を行います。

パターンとしてあったのは

  • ガウシアンフィルタ( ぼかす処理 )
  • ネガポジ + グレースケール + ニ値化
  • グレースケール + ニ値化

ノイズ除去をいれるパターンもあり、やろうと思えばいろいろできます。処理が増えることで計算時間も増えるためユースケースごとに処理を検討する必要はありそうですが、今回は画像で行うためある程度時間がかかる処理でも可としました。

前処理にて、状況による誤差を減らしたり、精度を高めるための工夫を入れる感じです。

輪郭抽出ではopencvの機能でfindContours関数を利用します。

docs.opencv.org

輪郭抽出の関数にもパラメータごとに抽出できる輪郭の特徴があるため、ドキュメントをみて試すことが必要ですね。

今回はCHAIN_APPROX_SIMPLEを利用してみました。

cv2.findContours(binarized, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

この段階までいけば輪郭線の抽出ができるので、あとは必要な部分のみの切り抜きになります。

ただし輪郭線自体はきれいな四角ではないため輪郭情報をそのまま切り抜くことができないので、4点を抽出して画像に切り抜く処理が入ります。

これもopencvの関数approxPolyDPを利用することで、複雑な情報を少なくすることが可能です。approxPolyDP関数は輪郭の近似を取得する関数で、情報をより少ない点で表現したい場合に利用することができます。引数に精度の値を渡すことができるため渡す値によって4点にしたりできます。

4点まで絞り込むことができたらあとは、4点から画像を作成するのみになります。

4点から画像を作成する際に、正四角形であれば問題ありませんが、画像からカードを判定するためほぼそのような状況は作れないでしょう。台形のような場合ばかりでしょう。

そのため最後に台形を四角に変換する処理が必要になります。

いわゆる射影変換を行い、必要な部分のみの画像にしていこう。という感じです。

ja.wikipedia.org

変換や回転をうまく計算して必要な部分を補完する処理になっています。

これで完成です。流れは以上です。

いやー、数学ってすごいですね。

雑記

詳細は少しずつ記事にしていきたいと思っています。コードもあるため詳細に書けると思います。

ただopencv + pythonの組み合わせはかなり楽に実装を試すことができ、実用レベルのものも作れそうだと感じています。

世の中にすでに多くの情報があるからできるだろうと思っていましたが、予想以上に動くものになってうれしいですね。

ただ商用のものはやはりレベルが高く、よく綺麗に認識できるなー。と感心することが多いですね。

webばっかりやってたので、久しぶりに脳をフル回転している感じがあり、面白かった。