はじめに
概要
本記事では、OCRを実施する簡単なWebアプリケーションを紹介します。
コードは全てGithubにアップしております。
OCRとは
OCRとは「Optical Character Recognition」の略で、光学式文字認識を指します。
今回のデモアプリでは、Clientのブラウザからサーバに画像ファイルをアップロードする事で、画像内から文字列を読み取ります。
PaddleOCRとは
80言語以上をサポートしているPythonの軽量OSSライブラリです。
トレーニング済みのモデルが公開されてるため、すぐにOCRを試すことができます。
本編
アーキテクチャ
フロントからバックエンドに画像を投げ、バックエンドで非同期にOCRを実行します。実行ステータスはバックエンドのPostgreSQLで管理し、フロントはポーリングで実行完了を待ちます。
フロントエンド
Next.js + React
バックエンド
KtorのWebアプリ + PythonのOCRロジック実行環境
環境
OSは一応Windowsですが、Linuxでも動作すると思います。
主なフレームワーク/ライブラリのみ記載します。
フロントエンド
- Next.js / React: 14.2.15
- typescript: 5
- tailwind css: 3.4.14
バックエンド
- ktor: 2.3.12
- exposed: 0.53.0
- postgres: 14.6
(下記よりpython環境) - python: 3.9.6
- PaddleOCR: 2.7.0.3
- paddlepaddle: 2.5.2
- loguru: 0.7.2
ソースコード
GithubのRepositoryを参照ください。
OCRロジックは、バックエンドのリソースに含まれるocr_demo.pyに実装してます。このファイル単体でもOCRを試せます。
フロントエンド
バックエンド
OCRロジック
def run_ocr(img_path):
# 画像パスからnumpy配列へ
img = Image.open(img_path).convert('L')
np_img = np.asarray(img)
paddleOCR = PaddleOCR(
use_gpu=False, # GPUは使用しない
lang = "en", # 今回は英語の学習モデル
det_limit_side_len=img.size[1], # 画像の圧縮防止
max_text_length = 20, # 検知する文字列長
show_log=False
)
result = paddleOCR.ocr(img=np.asarray(np_img), det=True, rec=True, cls=False)
if not result or result[0] is None:
logger.debug(f'not detected.')
return
# 検知文字列を画像に入力
output_img = cv2.cvtColor(np_img.copy(), cv2.COLOR_BGR2RGB)
for detection in result[0]:
top_left = tuple([int(i) for i in detection[0][0]])
bottom_right = tuple([int(i) for i in detection[0][2]])
bottom_left = tuple([int(i) for i in detection[0][3]])
found_text = detection[1][0]
output_img = cv2.rectangle(output_img, top_left, bottom_right, (0, 255, 0), 1)
output_img = cv2.putText(output_img, found_text, top_left, cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 1, cv2.LINE_AA)
# 結果画像保存
output_img = cv2.cvtColor(output_img, cv2.COLOR_RGB2BGR)
cv2.imwrite(img_path, output_img)
Demo
躓いた点
PaddleOCRの実行環境構築に苦戦しました。
python・paddleocr・paddlepaddleのバージョンで、互換性の無い組合わせがあります。
本家のGithubに従っても良いのですが、私は下記の組合せで動作確認してます。
※python 3.9.6
python -m pip install paddleocr==2.7.0.3
python -m pip install paddlepaddle==2.5.2 -i https://mirror.baidu.com/pypi/simple
蛇足
今回の仕様/コードでは、フロント・バックを分けてNext.jsを用いる意味が全くないのですが・・・
この構成をサッと試せる環境を作っておきたかったです。