はじめに
概要
本記事では、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を用いる意味が全くないのですが・・・
この構成をサッと試せる環境を作っておきたかったです。
