CLOVA OCRのInvoice OCR APIで読み取った範囲を描画する

2022.01.25

前回の記事では読み取ったデータを整形してテーブル風に表示させていました。

今回は読み取ったデータに入っている座標情報を使い、読み取ったデータを線で囲ってみようと思います。

やってみる

APIの結果には必ず読み取った情報の座標が格納されます。

subTotalPriceの例 )

"subTotalPrice": [
            {
              "confidence": 0.9999915361397882,
              "coordinates": {
                "bottom_left": [
                  2208,
                  2703
                ],
                "bottom_right": [
                  2344,
                  2703
                ],
                "top_left": [
                  2208,
                  2660
                ],
                "top_right": [
                  2344,
                  2660
                ]
              },
              "isConfident": true,
              "value": 830000
            }
]

coordinatesというオブジェクトに情報を読み取った座標(単位は、ピクセル) が格納されます 。

この座標を使って読み取った箇所をPythonを使って線で囲っていきます。

Webページで線で囲った状態を表示することを想定し、PDFを画像に変換後、OCRをかけて結果を取得する流れにします。

Pythonのライブラリをインストール

PDFを画像に変換するために、pdf2imageをインストールします。

pip3 install pdf2image

pdf3imageを使うにはpopplerもインストールする必要があるので、プラットフォームに応じたやり方でインストールします。

How to install を参照。

recipientInfo(請求先情報)を描画

(読み取り前)

この請求書をInvoice OCR APIで読み込んだところ、 recipientInfo は以下のように返ってきました

{ 'address': [ { 'confidence': 0.9970708195227984,
                 'coordinates': { 'bottom_left': [83, 674],
                                  'bottom_right': [371, 674],
                                  'top_left': [83, 637],
                                  'top_right': [371, 637]},
                 'isConfident': False,
                 'value': '東京都品川区西品川1-1'}],
  'companyName': [ { 'confidence': 0.9990133529424299,
                     'coordinates': { 'bottom_left': [91, 569],
                                      'bottom_right': [332, 569],
                                      'top_left': [91, 532],
                                      'top_right': [332, 532]},
                     'isConfident': False,
                     'value': 'クローバ株式会社'}],
  'department': [ { 'confidence': 0.9984980259534468,
                    'coordinates': { 'bottom_left': [86, 601],
                                     'bottom_right': [270, 601],
                                     'top_left': [86, 566],
                                     'top_right': [270, 566]},
                    'isConfident': False,
                    'value': 'ITシステム部'}],
  'personName': [ { 'confidence': 0.993760210940338,
                    'coordinates': { 'bottom_left': [292, 602],
                                     'bottom_right': [446, 602],
                                     'top_left': [292, 563],
                                     'top_right': [446, 563]},
                    'isConfident': False,
                    'value': 'ご担当者'}],
  'postalCode': [ { 'confidence': 0.7979394908056896,
                    'coordinates': { 'bottom_left': [88, 640],
                                     'bottom_right': [215, 640],
                                     'top_left': [88, 611],
                                     'top_right': [215, 611]},
                    'isConfident': False,
                    'value': '〒141-0033'}]}

coordinatesが座標情報で、

  • top_left : 左上座標の配列(left, top)
  • top_right : 右上座標の配列(right, top)
  • bottom_left : 左下座標の配列(left, bottom)
  • bottom_right : 右下座標の配列(right, bottom)

となっています。

この座標をOpenCVで使って線だけの矩形を描画します。

例)

pt1 = (150, 100)
pt2 = (350, 200)
color = (0,0,0)
cv2.rectangle(img, pt1, pt2, color, 3, cv2.LINE_4)

pt1は左上頂点の座標、pt2は右下頂点の座標ですので、 APIの結果データからtop_leftbottom_rightを利用します。

(読み取り後)

ちゃんと描画できていますね。

使用したサンプルコードは以下になります。

サンプルコード

from pdf2image import convert_from_path
import json
import requests
import cv2
import pprint

pp = pprint.PrettyPrinter(indent=2)

file = "LINE_CLOVA OCR_請求書サンプル.pdf"
file_path = "./bill/sample/" + file
img_path ="./bill/sample/images/"

## PDFを画像に変換
convert_from_path(file_path, output_folder=img_path,fmt='png',output_file="sample_")

## CLOVA ORCからPDF読み取り結果を取得
apikey = '<< Your API KEY>>'
url = 'https://<< YOUR API URL>>'
files = {'file': open(img_path + "sample_0001-1.png", 'rb')}
headers = { 'x-linebrain-apigw-api-key': apikey }
res = requests.post(
    url,
    files = files,
    headers = headers)
json_dict = json.loads(res.text)
pp.pprint(json_dict[0]['result']['recipientInfo'])

## 座標を指定して長方形を描画(recipientInfo)
img = cv2.imread(img_path + "sample_0001-1.png")

for k in json_dict[0]['result']['recipientInfo']:
    #bottom_left = json_dict[0]['result']['recipientInfo'][k][0]['coordinates']['bottom_left']
    bottom_right = json_dict[0]['result']['recipientInfo'][k][0]['coordinates']['bottom_right']
    top_left = json_dict[0]['result']['recipientInfo'][k][0]['coordinates']['top_left']
    #top_right = json_dict[0]['result']['recipientInfo'][k][0]['coordinates']['top_right']

    cv2.rectangle(img,
                pt1=(top_left[0], top_left[1]),
                pt2=(bottom_right[0], bottom_right[1]),
                color=(255, 0, 0),
                thickness=3,
                lineType=cv2.LINE_4)

    cv2.imwrite(img_path + 'sample_after.png', img)

取れる情報全部描画

座標情報をもとに全て長方形で囲ってみると上記のようになりました。

最後に

今回はCLOVA Invoice OCR のAPIの情報から読み取った箇所を長方形で囲って描画してみました。

座標情報から画像に線で囲ってあげるとどこを読み取ったかが一目でわかるので、OCRの結果を使ったアプリなんかでは使えそうですね。