以前画像をJSONリクエストに乗せる方法を紹介しました。今回はHTTPリクエストで画像をもらい、TesseractOCRの実行結果を返却するAPIを作る方法を紹介します。シンプルなAPIなのでflaskで実装します。
Dockerfile
日本語可なTesseractをインストールするDockerfileの一例です。ついでにflaskも入れるので後述のrequirements.txtが必要になります。API部分はtesseract_api.pyで実装しています。
FROM python:3.7
USER root
ENV PYTHONUNBUFFERED 1
RUN apt-get update && \
apt-get -y install locales \
vim less \
libboost-all-dev \
tesseract-ocr \
tesseract-ocr-jpn \
libtesseract-dev
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
### create and into workdir
RUN mkdir /flask
WORKDIR /flask
ADD requirements.txt /flask/
RUN pip install -r requirements.txt
RUN pip install pytesseract pyocr
ADD ./tesseract_api.py /flask/
CMD FLASK_APP=/flask/tesseract_api.py flask run --host=0.0.0.0 --debugger --reload
必要ライブラリ
requirements.txt は下記になります。※numpyは文字列化した画像を復元する際に使用するので、用途によっては不要です。
numpy
opencv-python
Flask
Tesseract API の実装
画像とTesseractOCRを実行したい矩形の座標領域、矩形領域の連番が下記フォーマットで渡されて、矩形領域に文字が含まれているか判定するAPIを実装します。(tesseract_api.py)
{“image” : “画像の文字列”, “rectangles” : [rect( = [x, y, width, height, uid] )}
画像差分から記入箇所判定で紙が歪んでいた場合は記入箇所以外にも差分として検出してしまうことが多いので、検出箇所に文字があるか判定する用途で作成したものです。これは抜粋なので本来はTesseractのオプションをJSONで指定したりヘルスチェックを入れたりする必要はあると思います。
from flask import Flask, request, json, jsonify
import base64
import numpy as np
import cv2
import pytesseract
from collections import namedtuple
import logging
# 矩形領域IDに文字があるか判定結果を格納するフォーマット
DetectResult = namedtuple('Result', ('uid', 'has_text'))
app = Flask(__name__)
# JSONにUnicode文字が含まれる可能性がある場合必要
app.config['JSON_AS_ASCII'] = False
api_logger = logging.getLogger('werkzeug')
@app.route('/text_detect', methods=['POST'])
def text_detect():
app.logger.debug('text_detect')
# 文字列から画像の復元
posted = json.loads(request.get_json())
img_as_text = posted['image']#.encode('utf-8')
img_binary = base64.b64decode(img_as_text.encode('utf-8'))
img_array = np.frombuffer(img_binary, dtype=np.uint8)
img_from_text = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
rectangles = posted['rectangles']
api_logger.info('rectangles:' + str(rectangles))
# オプションは本来リクエストで変更したほうが良いが入力チェックは大変そう
config = ('-l eng+jpn --oem 1 --psm 7')
res_rectangles = []
for rect in rectangles:
x, y, width, height, uid = rect.values()
clip_img = img_from_text[y:y+height, x:x+width]
# Tesseract の呼び出し
text = pytesseract.image_to_string(clip_img, config=config)
if text == '':
res_rectangles.append(DetectResult(uid, False))
else:
res_rectangles.append(DetectResult(uid, True))
res_json = json.dumps(res_rectangles)
app.logger.debug(res_json)
return jsonify(json.loads(res_json))
これだけでTesseract OCRを実行するAPIサーバがどこにでも立てることができます。(実際のAPI実装はもっと真面目にやるべきです)。flaskも今回初めて使いましたが、かなり直感的で学習コスト少なくAPIが実装できそうな感じです。(ただしXXS対策などセキュリティは考慮してないのでそこは別)。
ちなみにnamedtupleはクラスにするほどでもないけど、ちょっとしたオブジェクトを作りたいときに結構便利です。「テスト駆動 Python」で初めて知りました。立ち読みレベルで理解できるので興味がある方は読んでみてください。(Amazonのリンク貼れるようにしようかな)