#きっかけ
手書き文字認識API(Tegaki.ai)を使ってみました。ルールベースのOCRではなく、AIで手書き文字をデータ化したOCRのようです。認識率99.22%。
サービスの詳細は、HPを参照して欲しい。わくわくする。
本投稿で必要なことだけ説明すると、Tegaki.aiは手書き画像の認識、読取結果取得をAPIで提供していて、そのAPIコールに必要な画像は自分で用意する必要があります。
画像の傾きの補正や、ノイズ除去をすることにより、読取精度が上がりやすいとのことなので、OpenCVで画像補正してみました。
#まずはTegaki.ai使ってみる
Tegaki.aiは有料サービスですが、無料トライアルで使えるみたいなので、早速申し込み。
無料トライアルが使えるようになったので、
まずは、手書き文字認識用の画像を自分で用意しました。
これから手書き文字認識されると思うと、いつもより丁寧に文字を書いてしまいますねw
Tegaki.aiにリクエストを投げて結果を受け取ると、99%の認識率。
画像補正しなくても読取精度が高い結果となりました。誤読された文字も、人間でも読めないかもなーと感じる文字でしたので、まぁよしとしましょう。
次に、業務で使っている手書き書類を使って、tegaki.aiに投げると98%の認識率。
ただ、FAX受信した紙の場合、88%の認識率と精度が低かった。
ここで、FAX受信すると少し縮小されるため、読取位置がずれてしまうのではないか?と仮定して、
FAXの前と後でスキャンした画像の
罫線をぴったりあわせたいと考えました。
結論からいうと、2つの画像を罫線をぴったり合わせることができ、88%→95%まで精度をあげることができました。その過程を本投稿で説明します。
残りの5%は、やはり人間でも読めないような文字や、罫線をはみ出している文字でした。
#実際につかった画像の一部
#Tegaki.aiで提供されているTegaki-editorでデザイン
tegaki-editorでデザインすると、リクエスト用の画像が容易に準備できる。
緑が「単線」フィールド。1行読取
赤が「チェックボックス」フィールド。○囲みや、レ点を読取
「ボックスキャラクター」フィールドもあるが、2018/3時点では数字とカナのみの対応とのこと。
あらかじめデザインした「テンプレート画像」、「読取画像」それぞれの罫線のがぴったり合わないと、読取精度が落ちると思われます。
#OpenCVでやったこと
OpenCVを使って、次のような画像補正をしてみた。
・紙をスキャンするときに傾いてしまう→傾き補正(水平に)
・縮小される→リサイズ
※上下逆、手書き文字のかすれ、ノイズ、などの対策はしていない。
#環境
OpenCV3.1
python3.5
#画像補正
##傾き
こちらを参考にしました。
ほぼコピペです。
1.cv2.Canny() でエッジ検出
2.cv2.HoughLinesP()で直線検出
3.水平方向の直線の平均角度を取る
4.直線が水平になるように画像全体を回転
の処理をしています。
今回使用した画像は紙をスキャンしたものですが、スキャンしたときに書類が斜めだと、黒い背景ができますよね。
参考)スキャン画像の左下。
これを直線としてカウントしてしまうと、
3.水平方向の直線の平均角度を取る
で平均角度が適性ではないことがあったので、
唯一変更したのが、if文にarg != 0
を追記したことです。
ファイル名:degree.py
import cv2
import numpy as np
import math
import sys
from scipy import ndimage
def get_degree(img):
l_img = img.copy()
gray_image = cv2.cvtColor(l_img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray_image,50,150,apertureSize = 3)
minLineLength = 200
maxLineGap = 30
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
sum_arg = 0;
count = 0;
for line in lines:
for x1,y1,x2,y2 in line:
arg = math.degrees(math.atan2((y2-y1), (x2-x1)))
HORIZONTAL = 0
DIFF = 20
#arg != 0を条件に追加し、傾きの平均を0に寄りにくくした。
if arg != 0 and arg > HORIZONTAL - DIFF and arg < HORIZONTAL + DIFF :
sum_arg += arg;
count += 1
if count == 0:
return HORIZONTAL
else:
return (sum_arg / count) - HORIZONTAL;
if __name__ == "__main__":
read_file = sys.argv[1]
img = cv2.imread(read_file)
arg = get_degree(img)
rotate_img = ndimage.rotate(img, arg)
cv2.imwrite('degree.jpg', rotate_img)
実行してみる
> python degree.py input.jpg
degree.jpgというファイル名で出力されます。
一旦、ここまでで投稿。
次回リサイズ