質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Tesseract

Tesseractは、Googleが提供しているオープンソースのOCRエンジンです。機械学習があり60以上の言語に対応でき、日本語の文字認識も可能です。さらに精度を上げることもできます。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

0回答

4006閲覧

OCR時に,大きさの違う文字が認識できない。

TsumaW

総合スコア10

Tesseract

Tesseractは、Googleが提供しているオープンソースのOCRエンジンです。機械学習があり60以上の言語に対応でき、日本語の文字認識も可能です。さらに精度を上げることもできます。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/11/17 08:20

前提・実現したいこと

レシートを読み込み,合計金額を抽出したいです。

python3系でtesseractを用いてOCRし,レシートの内容をテキストファイルにしようとしていたのですが,合計という文字がどうしても認識できません。
文字が潰れない限りで2値化も行っているのですが,そもそも元のレシートにおいて合計という文字が他の文字より大きく横長に書いてあることが多いためだと思います。実際,部首とそれ以外のところが別の文字として認識されてしまいます。

発生している問題・エラーメッセージ

文字認識した結果が以下のようになります。
""""
小 計 \③⑥0
刊 - が か ト * 社 ざ \①0
畑 言 一 \ ③ ⑤ 0
"""
畑言 一というところが本来,合計,と表示されるところです。

該当のソースコード

import cv2
import matplotlib.pyplot as plt
import numpy as np
import os

#画像を表示させる関数
def show_img(img):
plt.figure()
tmp = np.tile(img.reshape(img.shape[0],img.shape[1], -1),reps=3)
plt.imshow(tmp)
plt.show()

#画像をトリミングする関数の定義
def transform_by4(img, points):
""" 4点を指定してトリミングする。 """
points = sorted(points, key=lambda x:x[1]) # yが小さいもの順に並び替え。
top = sorted(points[:2], key=lambda x:x[0]) # 前半二つは四角形の上。xで並び替えると左右も分かる。
bottom = sorted(points[2:], key=lambda x:x[0], reverse=True) # 後半二つは四角形の下。同じくxで並び替え。
points = numpy.array(top + bottom, dtype='float32') # 分離した二つを再結合。
width = max(numpy.sqrt(((points[0][0]-points[2][0])**2)*2), numpy.sqrt(((points[1][0]-points[3][0])**2)*2))
height = max(numpy.sqrt(((points[0][1]-points[2][1])**2)*2), numpy.sqrt(((points[1][1]-points[3][1])**2)*2))
dst = numpy.array([
numpy.array([0, 0]),
numpy.array([width-1, 0]),
numpy.array([width-1, height-1]),
numpy.array([0, height-1]),
], numpy.float32)

trans = cv2.getPerspectiveTransform(points, dst) # 変換前の座標と変換後の座標の対応を渡すと、透視変換行列を作ってくれる。 return cv2.warpPerspective(img, trans, (int(width), int(height))) # 透視変換行列を使って切り抜く。

def convert(im, filename):
im = cv2.imread(im)
im_size = im.shape[0] * im.shape[1]

#輪郭を抽出して切り取るための二値化
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imwrite(filename + "_gray.jpg", im_gray)
print(filename + "_gray.jpg")

im_blur = cv2.fastNlMeansDenoising(im_gray) #画像のノイズ除去 im_th = cv2.adaptiveThreshold(im_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 15, 5) #画像の二値化 show_img(im_th) cv2.imwrite(filename + "_th.jpg", im_th) print (filename+'_th.jpg')

#輪郭を抽出
img, cnts, hierarchy = cv2.findContours(im_th, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) #輪郭はリスト内にnumpy配列で出力される
cnts.sort(key = cv2.contourArea, reverse=True ) #面積の大きい順のsort
cnt = cnts[1]
img = cv2.drawContours(img, [cnt], -1, (0,255,0), 3)
cv2.imwrite(filename+"_drawcont.jpg", img)
im_line = im.copy()
print("finish")

warp = None flag = 1 for c in cnts[1:]: arclen = cv2.arcLength(c, True) #輪郭の長さを検出 approx = cv2.approxPolyDP(c, 0.02*arclen, True) #輪郭を近似 #近似した上で四角い輪郭に対して処理 if len(approx) == 4: cv2.drawContours(im_line, [approx], -1, (0,0,255), 2) if flag: print(approx) warp = approx.copy() flag = 0 #一番大きな輪郭をwarpに組み込む else: cv2.drawContours(im_line, [approx], -1, (0, 255, 0), 2) for pos in approx: cv2.circle(im_line, tuple(pos[0]), 4, (255,0,0)) #レシートっぽい輪郭の面積を算出 #一定以上の大きさならトリミング area = cv2.contourArea(warp) print("area = ", area) if area > im_size//5: print("now cutting.....") im_rect = transform_by4(im, warp[:,0,:]) #レシートの輪郭で切り取る。 cv2.imwrite(filename+'_rect.jpg', im_rect) else: return im #切り取ったら画像を表示する plt.figure() plt.imshow(im_line) cv2.imwrite(filename+'_line.jpg', im_line) print("warp = \n",warp[:, 0, :]) print(filename + '_rect.jp') #今度は文字抽出のためのグレースケール化 im_rect_gray = cv2.cvtColor(im_rect, cv2.COLOR_BGR2GRAY) cv2.imwrite(filename + "_rect_gray.jpg", im_rect_gray) print(filename + "_rect_gray.jpg") show_img(im_rect_gray) #2値化 im_rect_blur = cv2.fastNlMeansDenoising(im_rect_gray) im_rect_th = cv2.adaptiveThreshold(im_rect_blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) rect_th_filename = "{:s}_rect_th.jpg".format(filename) cv2.imwrite(rect_th_filename, im_rect_th) print (filename+'_rect_th.jpg') show_img(im_rect_th) return (im_rect_th)

#実際に文字認識を行う
from PIL import Image
import sys
import pyocr
import pyocr.builders

def detect_txt(file):

tools = pyocr.get_available_tools() if len(tools) == 0: print("No OCR tool found") sys.exit(1) tool = tools[0] txt = tool.image_to_string( # ここでOCRの対象や言語,オプションを指定する Image.open('reciet1_rect_th.jpg'), lang='jpn', builder=pyocr.builders.TextBuilder() ) txt = open("out.txt").read().replace('\', '¥') print(txt)

#実行
if name == 'main':
detect_txt(convert("./reciet1.jpg", "reciet1"))

python

補足情報(FW/ツールのバージョンなど)

独学で勉強している初心者であり,teratailなどの質問場所を利用するのも初めてなので,ルールなど詳しくないのでご無礼ありましたら申し訳ございません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2018/11/17 14:29

現状ではコードが読めません。質門を編集して、<code>ボタン、’’’の枠の中にコードを貼り付けてください
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問