私的AI研究会 > Tesseract6
基本編での検証をもとに実用的な AI開発に向けて、文字認識エンジン「Tesseract」(テッセラクト)を使用した「OCR アプリケーション」を開発する。
問題点 | 考えられる解決方法 | 実現レベル | 現状 |
不要なページがある(納品書など) | タイトル項目から「請求書」以外を除外する | ○ | 事前に排除 |
画像に傾きがある | 傾き補正をする(画像の大きさと座標調整に難あり) | ○ | 前処理対応、未実装 |
西暦以外の日付の場合 | 対応すると将来的な変更対応が必要になる | ◎ | 「令和」のみ実装 |
同じ帳票が複数ある場合 | 請求書番号などがあればチェックできる。ない場合は人的対応? | ○ | 未対応 |
PDFフォーマットの処理 | 含まれる帳票をページごとにフォルダに画像ファイルとして作成していく | ◎ | 対応済 事前に別処理で |
CSV 出力の2重登録 | 「ファイル名」で除外 | ◎ | 対応済 同じ帳票で別ファイル名の場合は対応不可 |
案件が複数項目ある場合がある | △ | 一つの案件名で代用 | |
タイトル(請求書)が装飾されている | 読めない場合は別の「請求」関連箇所で代用 | ○ | |
文字の認識精度の向上 | 学習モデルの変更 項目ごとに文字種別を制限する | ○ | 別途対策 |
# よくある誤読をヒューリスティックに訂正(日付) def replace_day_strings(self, text): DAY_REPLACE_PAIR = ( (u']', u'1'), (u'}', u'1'), (u'ー', u'1'), (u'仔', u'年'), (u'El', u'日'), (u'E|', u'日'), (u'E', u'日'), (u'口', u'日'), (u'曰', u'日'), (u'Z', u'2'), (u'O', u'0'), (u'〇', u'0'), (u'I', u'1'), (u'l', u'1'), (u'80日', u'30日'), (u'80 日', u'30日'), (u'信和', u'令和') ) for before, after in DAY_REPLACE_PAIR: text = text.replace(before, after) return text
# 文字列が年月日かどうかを調べる(「令和」対応) out: 文字列 error='' def get_str2date(self, text): string = '' text = re.sub('[,.、]', '', text) text = self.replace_day_strings(text) result = self.get_str2num(text) if len(result) == 3: if int(result[0]) < 2000: text = self.remove_space(text) result = self.get_str2num(text) if len(result) != 3: text = self.remove_space(text) result = self.get_str2num(text) if len(result) == 3: if text.find('令和') == 0: reiwa = int(result[0]) + 2018 result[0] = str(reiwa) string = self.checkDate(result[0], result[1], result[2]) elif len(result) == 2: if text.find('令和元年') == 0: result.insert(0, 2019) string = self.checkDate(result[0], result[1], result[2]) else: if self.logf: print('[{}:get_str2date()] Invalid string error !!'.format(MODULE_NAME)) return string
# よくある誤読をヒューリスティックに訂正(キー文字列) def replace_key_strings(self, text): text = self.remove_space(text) KEY_REPLACE_PAIR = ( (u'講求書', u'請求書'), (u'講求', u'請求') ) for before, after in KEY_REPLACE_PAIR: text = text.replace(before, after) return text
# 文字列から数字を取り出す out: 数字のリスト error=空のリスト def get_str2num(self, text): result = re.findall(r"\d+", text) return result # 文字列から金額を取り出す out: 文字列 error='' def get_str2mony(self, text): text0 = self.remove_space(text) money = '' if len(text0) > 0: txt = re.sub('[,.、]', '', text0) if len(txt) > 0: result = self.get_str2num(txt) if len(result) == 1: money = str(result[0]) return money
(py37) $ cd ~/workspace_py37/tryocr (py37) $ python3 mylib_text.py get_str2date(): 信和 元 年 8 月 31 日 → 2019/08/31 get_str2date(): 2020 年 06 月 80 日 → 2020/06/30 get_str2num(): 2022年1月17日 → ['2022', '1', '17'] get_str2num(): 年月日 → [] [TextConvert:checkDate()] Invalid string error !! checkDate(): 2022 2 31 → checkDate(): 2022 1 31 → 2022/01/31 get_str2date(): 2022年1月17日 → 2022/01/17 [TextConvert:checkDate()] Invalid string error !! get_str2date(): 2022年2月31日 → get_str2date(): 2月31日 → get_str2date(): 20,22年1月31日 → 2022/01/31 get_str2date(): 令和元年1月2日 → 2019/01/02 get_str2date(): 令和4年2月14日 → 2022/02/14 get_str2date(): 令 和 元 年 8 月 31 日 → 2019/08/31 get_str2date(): 2021 12 31 → 2021/12/31 get_str2date(): 令 和 3 年 12 月 31 日 → 2021/12/31 get_str2mony(): \8,500 → 8500 get_str2mony(): abc月日 → get_str2mony(): 590, 000 → 590000 get_str2mony(): \637, 200 → 637200 get_str2mony(): 615、600 → 615600 get_str2mony(): 1, 259, 020 → 1259020 get_str2mony(): 526.845 → 526845 get_str2mony(): 2,070, 490 → 2070490 get_str2mony(): 2, 277, 939 → 2277939 remove_space(): 請 求 書 → 請求書 replace_key_strings(): 講 求 書 → 請求書
アプリケーションで必要となるファイル操作を検証する。
# ファイルパスからファイル一覧を得る def get_file_list(self, dirpass): result = sorted(glob.glob(dirpass)) if self.logf: print('File list: ', result) return result # ファイルパスから拡張子で選択したファイル一覧を得る def get_file_list_sel(self, dirpass, sel_ext): flist = sorted(glob.glob(dirpass)) result = [] for name in flist: for ext in sel_ext: if ext == os.path.splitext(name)[1]: result.append(name) if self.logf: print('Select list: ', result) return result
# ファイルを移動する XXXX/XXXXX.xxx ←→ XXXX-err/XXXXX.xxx def move_file(self, filename): fname = os.path.basename(filename) fpath = os.path.dirname(filename) if fpath[-4:] == '-err': tgtpath = fpath[0:-4] if not os.path.exists(tgtpath): os.mkdir(tgtpath) tgt = tgtpath + '/' + fname else: tgtpath = fpath + '-err' if not os.path.exists(tgtpath): os.mkdir(tgtpath) tgt = tgtpath + '/' + fname shutil.move(filename,tgt) if self.logf: print('Move file {} → {}'.format(filename,tgt))
(py37) $ cd ~/workspace_py37/tryocr (py37) $ python3 mylib_file.py File list: ['/home/mizutu/workspace_py37/tryocr/tmp/AXIA.pdf'] Deprecation: 'getImageList' removed from class 'Page' after v1.19 - use 'get_images'. Deprecation: 'extractImage' removed from class 'Document' after v1.19 - use 'extract_image'. Image file: /home/mizutu/workspace_py37/tryocr/tmp/AXIA/AXIA_0000_00.jpeg Image file: /home/mizutu/workspace_py37/tryocr/tmp/AXIA/AXIA_0001_00.jpeg Image file: /home/mizutu/workspace_py37/tryocr/tmp/AXIA/AXIA_0002_00.jpeg Image file: /home/mizutu/workspace_py37/tryocr/tmp/AXIA/AXIA_0003_00.jpeg Image file: /home/mizutu/workspace_py37/tryocr/tmp/AXIA/AXIA_0004_00.jpeg