Help us understand the problem. What is going on with this article?

画像からOCRテキスト出すやつを高速化する

環境

  • Windows 10
  • Python 3.7.1 (Anaconda3-2018.12-Windows-x86_64)
  • PyOCR
  • Tesseract OCR 4.0.0

画像をOCRするやつの並列化版

前回の画像をOCRして検索用のテキストファイルを作るだとシングルスレッドで処理するので遅かった。

標準ライブラリに入っているPoolというやつを使うとmapするときに並列処理できるらしいので、それに合わせてOCR処理を書き換えた。

pyocrとTesseract OCRが並列で呼び出しても問題ないIFになっているかどうか不安だったが、OCRする度にTesseract OCRを新たに呼び出す設計で問題なかった(少なくとも上記環境では)。

from PIL import Image
import sys

import pyocr
import pyocr.builders
import glob
import os

from multiprocessing import Pool
import multiprocessing as multi

def ocrimage(file):
    tools = pyocr.get_available_tools()
    if len(tools) == 0:
        print("No OCR tool found")
        sys.exit(1)
    # The tools are returned in the recommended order of usage
    tool = tools[0]
    print("Will use tool '%s'" % (tool.get_name()))
    # Ex: Will use tool 'libtesseract'

    langs = tool.get_available_languages()
    print("Available languages: %s" % ", ".join(langs))
    lang = langs[0]
    print("Will use lang '%s'" % (lang))
    ocrtext = tool.image_to_string(
        Image.open(file),
        lang="jpn",
        builder=pyocr.builders.TextBuilder(tesseract_layout=6)
    )
    return ocrtext

if __name__ == '__main__':

    njobs = 1
    if multi.cpu_count() > 2:
        njobs = multi.cpu_count() - 1

    ocrtext = ""
    filelist = []
    for p in glob.glob('./**', recursive=True): # ディレクトリとファイル取得
           if os.path.isfile(p):
               # ファイルの場合
               name,ext = os.path.splitext(p)
               if ".jpg" == ext or ".png" == ext or ".gif" == ext:
                   filelist.append(p)

    # 並列処理                
    process = Pool( njobs )
    ocrtexts = process.map(ocrimage, filelist)
    process.close()

    for index, p in  enumerate(filelist):
        ocrtext += p + ":\n" + ocrtexts[index] + "\n\n"

    f = open('ocrtext.txt', 'w', encoding='utf-8')
    f.write(ocrtext)
    f.close()

前回はRyzen7 2700X(8コア16スレッド)で1スレッドしか使ってなかったので約2500個の画像に1時間ぐらい掛かっていたが、今回のコードで10分程度に高速化した。

HyperThreadingなどのSMTはCPUの空きパイプラインを活用して5-20%程度性能を改善するらしいのだが、実コア数を超えた時点でPCの動作が重くなる。

multi.cpu_count()が返すのはどうも論理コア数らしいので、実コア数に合わせたい感はある。

論理コア数を全部使い切られるとPCが大変重くなって作業できなくなるので一応-1している。

余談だが、if __name__ == '__main__':を忘れたせいで1時間半損した。

2/27追記: なんか"UnicodeEncodeError: 'cp932' codec can't encode character ..."とエラーが出た。
書き込み時のエンコーディング指定忘れが原因だった。ちゃんとencoding='utf-8'をつけましょう…。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした