見出し画像

画像からの文字抽出がうまく読み込めない場合は、画像処理して読み取り精度を上げる(pytesseract, python)

画像ファイルから文字を抽出する際の精度を上げたく、今回は事前に画像処理を実施し、読み取りやすい状態にした上で、文字の抽出処理を検討していこうかと思います。

以前に作成した、画像ファイルから文字を抽出する記事は以下です。
これらの文字抽出機能の読み取り精度を上げていきます。

写真アプリで数パターン画像加工し、上手く読み込めたパターンの画像処理をロジック化

検証段階で、画像処理のプログラミングをすると労力がかかってしまうので、mac標準の写真アプリで数パターン画像処理をしたものを文字抽出処理を実施していきたいと思います。

写真アプリで数パターン画像加工したもので、文字抽出検証

フリーの請求書フォーマットがありましたので、こちらを使用させて頂き、検証していきたいと思います。

1.ノーマル(加工なし)

請 求 書
サンプル株式会社 御中 No 1001
請求日 2022/4/30
下記のとおり、御請求申し上げます。 サンプル株式会社
件名 サンプルプロジェクト 〒100-000
支払期限 02747| 東京都千代田区千代田1-1-1
あん サンプル銀行 本店 普通 1111111 サンプルビル3階
サンプル (カ TEL : 03-0000-0000
担当: サンプル太郎
154,000 円 (税込)
摘要 EE 単位 単価 金額
サンプル1 1|10,000 10,000
サンプル2 1| 式 10,000 10,000
サンプル3 1|10,000 10,000
サンプル4 1| 式 10,000 10,000
サンプル5 1|10,000 10,000
サンプル6 1| 式 10,000 10,000
サンプル7 1|10,000 10,000
サンプル8 1| 式 10,000 10,000
サンプル9 1|10,000 10,000
ユエキュレーア1 ィ ード ィ4n nn 44n nnn

2.露出を半分下げる

請 求 書
サンプル株式会社 御中 No 1001
請求日 2022/4/30
下記のとおり、御請求申し上げます。 サンプル株式会社
Ia必コ サンプルプロジェクト 〒100-000
支払期限 AUM247な| 東京都千代田区千代田1-1-1
あん サンプル銀行 本店 普通 1111111 サンプルビル3階
サンプル (カ TEL : 03-0000-0000
担当: サンプル太郎
154,000 円 (税込)
摘要 1 単位 単価 金額
サンプル1 1|10,000 10,000
サンプル2 1| 式 10,000 10,000
サンプル3 1|10,000 10,000
サンプル4 1| 式 10,000 10,000
サンプル5 1|10,000 10,000
サンプル6 1| 式 10,000 10,000
サンプル7 1|10,000 10,000
サンプル8 1| 式 10,000 10,000
サンプル9 1|10,000 10,000
ユエキュレーアjj 10 ィ ード 4n nnn ィ4n nnn

3.コントラストを最大に上げる

請 求 書
サンプル株式会社 御中 No
請求日 2022/4/30
下記のとおり、御請求申し上げます。 サンプル株式会社
igコ サンプルプロジェクト 〒100-000
支払期限 04がな 東京都千代田区千代田1-1-1
シリ サンプル銀行 本店 普通 1111111 サンプルビル3階
サンプル (カ TEL : 03-0000-0000
担当: サンプル太郎
154,000 円 (税込)
摘要 ye 単位 単価 に
サンプル1 1| 式 10.000 10,000
サンプル2 1|10.000 10.000
サンプル3 1| 式 10.000 10,000
サンプル4 1|10.000 10.000
サンプル5 1| 式 10.000 10,000
サンプル6 1|10.000 10.000
サンプル7 1| 式 10.000 10,.000
サンプル8 1|10.000 10.000
サンプル9 1| 式 10.000 10,.000
オキキュレーデョゴイ 和イ ード 4nロnnn 4n nnn

4.コントラストを半分上げる

請 求 書
にに| 計
サンプル株式会社 御中 No 1001
請求日 2022/4/30
下記のとおり、御請求申し上げます。 サンプル株式会社
件名 サンプルプロジェクト 〒100-000
支払期限 AM24:なが 東京都千代田区千代田1-1-1
振込先 サンプル銀行 本店 普通 1111111 サンプルビル3階
サンプル (カ TEL : 03-0000-0000
担当: サンプル太郎
154,000 円 (税込)
摘要 数量 単位 Ei
サンプル1 1|10,000 10,000
サンプル2 1| 式 10,.000 10,000
サンプル3 1|10,000 10,000
サンプル4 1| 式 10,000 10,000
サンプル5 1|10,000 10,000
サンプル6 1| 式 10,000 10,000
サンプル7 1|10,000 10,000
サンプル8 1| 式 10,000 10,000
サンプル9 1|10,000 10,000
ユエキュレーアデ 1 ィ ード 4n nn ィ4n nnn

検証結果(画像加工すると読み取れるようになることもある)

「摘要、数量、単位、単価、金額」の行に着目すると、画像加工なしで読み込めなかった「数量」が、「コントラストを半分上げる」の画像処理をすることで、読み込むことが出来ましたが、逆に「金額」が読み込めなくなりました

ノーマル:摘要 EE 単位 単価 金額
露出を半分下げる:摘要 1 単位 単価 金額
コントラストを最大に上げる:摘要 ye 単位 単価 に
コントラストを半分に上げる:摘要 数量 単位 Ei

事前の画像加工処理だけでは、上手く読み取れないので別案を検討していきます。


各画像処理パターンで読み取った文字列に誤字がある場合は、不採用とする

「EE、1、ye、数量」の行では、「数量」を採用してもらいたく、各画像処理パターンで読み取った文字列に誤字がある場合は、不採用とするチェックロジックを組み込めば、「数量」が採用されるのではないか?という見立てのもと、このチェックロジックをChatGPTに作ってもらおうと思います。

プロンプト

pythonで、文字が誤字であるかを確認する
形態素解析を行う
以下文字列が対象
EE、1、ye、数量

ChatGPTの回答

形態素解析を使って文字列が誤字であるかを確認するコードを作成します。形態素解析を行うためにjanomeライブラリを使用します。

from janome.tokenizer import Tokenizer

# 対象の文字列リスト
strings = ["EE", "1", "ye", "数量"]

# 文字列が誤字かどうかを確認する関数
def is_typo(string):
    tokenizer = Tokenizer()
    tokens = tokenizer.tokenize(string)
    # 形態素解析した結果が一般的な日本語の構造に適合しているかどうかをチェック
    for token in tokens:
        # 品詞を取得して、名詞であるかどうかを確認(名詞であれば一般的な日本語の単語とみなす)
        if '名詞' not in token.part_of_speech:
            return True  # 名詞以外の品詞が見つかった場合は誤字とみなす
    return False

# 各文字列について誤字であるかどうかを確認
for string in strings:
    if is_typo(string):
        print(f'"{string}" は誤字の可能性があります。')
    else:
        print(f'"{string}" は誤字ではありません。')

結果

上記のコードを実行すると、次のような結果が得られます:

"EE" は誤字の可能性があります。
"1" は誤字の可能性があります。
"ye" は誤字の可能性があります。
"数量" は誤字ではありません。

各画像処理パターンで読み取った文字列同士を比較し、一致するものが一番多い文字列を採用する

上記の誤字チェックロジックでは数値はチェックNGとされてしまいますが、数値も読み取り対象として存在しますので、誤字チェックロジックで、すべてチェックNGの場合は、各画像処理パターンで読み取った文字列同士を比較し、一致するものが一番多い文字列を採用するロジックをChatGPTに作ってもらおうと思います。

プロンプト

以下配列について、各インデックス同士で値を比較し、一致するものが一番多い値を、別の配列に格納していく
結果について示す

array1 = ['aa', 'b', 3, 4, 'a5']
array2 = ['aa', 'b', 0, 4, 'a5']
array3 = [1, 'b', 3, 0, 5]
array4 = ['aa', 2, 3, 4, 0]
array5 = [1, 0, 3, 4, 'a5']

ChatGPTの回答

与えられた配列について、各インデックス同士で値を比較し、一致するものが一番多い値を別の配列に格納する方法と結果について示します。

from collections import Counter

# 5つの配列を用意する
array1 = ['aa', 'b', 3, 4, 'a5']
array2 = ['aa', 'b', 0, 4, 'a5']
array3 = [1, 'b', 3, 0, 5]
array4 = ['aa', 2, 3, 4, 0]
array5 = [1, 0, 3, 4, 'a5']

# 配列をリストにまとめる
arrays = [array1, array2, array3, array4, array5]

# 新しい配列を作成する
result_array = []

# 各インデックスごとに多数決を行う
for i in range(len(array1)):
    # すべての配列のi番目の要素を集める
    elements = [array[i] for array in arrays]
    # 最も多い要素を見つける
    most_common_element = Counter(elements).most_common(1)[0][0]
    # 結果の配列に追加する
    result_array.append(most_common_element)

# 結果を表示
print(f"一致する数が最も多い配列: {result_array}")

結果

一致する数が最も多い配列: ['aa', 'b', 3, 4, 'a5']

画像のコントラストと露出を変更するロジック

最後に、画像のコントラストと露出を変更するロジックをChatGPTに教えてもらおうと思います。冒頭では写真アプリで画像加工していたものを、ロジック化しその工程を自動化していくイメージとなります。

プロンプト

pytesseract
コントラストを変更するやり方と
露出を変更するやり方

ChatGPTの回答

Pythonで画像処理を行うためには、OpenCVなどのライブラリを使用することが一般的です。PytesseractはOCR(光学式文字認識)ライブラリであり、画像のコントラストや露出を変更する機能は直接提供していません。ですが、OpenCVを使って画像を変更することができます。

以下に、OpenCVを使用して画像のコントラストと露出を変更する方法を示します。

import cv2

# 画像を読み込む
image = cv2.imread('input_image.jpg')

# コントラストを変更する
alpha = 1.5  # コントラストの倍率(1より大きい値でコントラストが上がる)
adjusted_image_contrast = cv2.convertScaleAbs(image, alpha=alpha, beta=0)

# 露出を変更する
beta = 50  # 露出の調整量(正の値で明るく、負の値で暗くなる)
adjusted_image_exposure = cv2.convertScaleAbs(image, alpha=1, beta=beta)

# 変更した画像を表示する
cv2.imshow('Adjusted Contrast', adjusted_image_contrast)
cv2.imshow('Adjusted Exposure', adjusted_image_exposure)
cv2.waitKey(0)
cv2.destroyAllWindows()

このコードでは、alphaパラメータを使ってコントラストを変更し、betaパラメータを使って露出を変更しています。必要に応じて、alphabetaの値を調整してください。また、最後のcv2.imshow()cv2.imwrite()を使って画像を表示したり、保存したりすることができます。

おわりに

最後まで読んで頂き、ありがとうございます!

今回は、「事前に画像処理をすることで、読み取り精度が上がるか?」を検討してみましたが、整理すると結構ステップが多く大変な気がするのと、画像加工ロジックが多いと処理が重たくなる気もします。

それと、試した画像加工では一部日付箇所が読み込めないものがあったので、別の学習データを取り込む作戦の方が良さそうな気もしています。

画像加工のやり方ももっとあるので、もっと効率良いやり方がないかは今後も検証していきたいと思います。

おまけ

最近、ChatGPTを使用し、色々なことを模索しています。
もしよければ、以下の記事も見て頂けると嬉しいです!



この記事が気に入ったらサポートをしてみませんか?