python

Qt6 Python 画像より文字抽出 OCR

Qt6 Python 画像より文字抽出 PYOCR OpenCV

事前作業

Pyocr

PyocrはGoogleが開発したOCRエンジンを使用してOCRを行うライブラリです。

インストール

pyocrと日本語のocrエンジンをダウンロードします。

pip install pyocr
apt install tesseract-ocr libtesseract-dev tesseract-ocr-jpn

下記のコマンドを実行してjpnと表示されたらインストール成功です。

!tesseract --list-langs

OpenCVとは

OpenCVとは、画像処理・画像解析のために開発されたオープンソースのライブラリで、Python、C++など様々な言語で利用できます。

OpenCVを使うことでエッジや輪郭の抽出、物体検出などの画像処理をPythonで簡単に行えます。

OpenCVを利用する前にインストールする必要があります。

例えば、下記のようなコマンドでインストールしてから使ってみてください。

pip install opencv-python

OpenCVでマウスクリックした場所の座標を取得する方法

それでは、OpenCVを使って画像の特定の場所の座標を取得する方法を説明します。

以下の2つの機能を順番に使います。

  1. OpenCVを使って画像を表示する
  2. OpenCVで表示した画像のクリックされた座標を取得する

Qt6Creatorでプロジェクト ImageToTextを作成

form.ui は、pyside6-uic form.ui -o ui_form.py を実行して ui_form.py を作成します。

form.ui

imagetotext.py

# This Python file uses the following encoding: utf-8
import sys
import os

from PySide6.QtWidgets import QApplication, QWidget,QFileDialog
from PIL import Image
import pyocr

import cv2
import numpy as np

# Important:
# You need to run the following command to generate the ui_form.py file
#     pyside6-uic form.ui -o ui_form.py, or
#     pyside2-uic form.ui -o ui_form.py
from ui_form import Ui_ImageToText

class ImageToText(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_ImageToText()
        self.ui.setupUi(self)

        self.ui.pushButton.clicked.connect(self.file_open)
        self.ui.pushButton_2.clicked.connect(self.file_save)
        self.ui.pushButton_3.clicked.connect(self.end)
        self.ui.pushButton_4.clicked.connect(self.henkan)
        self.ui.pushButton_5.clicked.connect(self.clear)

        self.setStyleSheet("background-color:lightblue")
        #cv2画像の倍率
        self.ui.lineEdit_7.setText("0.15")
        self.ui.lineEdit_8.setText("6")
        self.ui.lineEdit_9.setText("jpn")

    def file_open(self):   #画像選択、OCR処理

            # インストール済みのTesseractのパスを通す
            path_tesseract = "C:\\Program Files\\Tesseract-OCR"
            if path_tesseract not in os.environ["PATH"].split(os.pathsep):
              os.environ["PATH"] += os.pathsep + path_tesseract

            # 押したときの動作(ファイル選択ダイアログを開く)
            self.fileName = QFileDialog.getOpenFileName(None,"ファイルを選択してください。")
            #ファイル名が選択されていたらいろいろ表示
            if self.fileName[0] != "":
               #ファイル名をセット
               self.ui.lineEdit.setText(self.fileName[0])
               def onMouse(event, x, y, flags, params):
                   if event == cv2.EVENT_LBUTTONDOWN:
                    print(x, y)
                    xy = str(x) + "," + str(y) + ","
                    xyz = self.ui.lineEdit_2.text()
                    xy2 = xyz + xy
                    self.ui.lineEdit_2.setText(xy2)
                    pos = self.ui.lineEdit_2.text().split(',')
                    print(pos)
                    l=len(pos)
                    if l>4:
                       self.ui.lineEdit_3.setText(pos[l-5])
                       self.ui.lineEdit_4.setText(pos[l-4])
                       self.ui.lineEdit_5.setText(pos[l-3])
                       self.ui.lineEdit_6.setText(pos[l-2])

               # Pillowで画像ファイルを開く日本語のファイル名のため
               pil_img = Image.open(self.fileName[0])
               # PillowからNumPyへ変換
               img = np.array(pil_img)
               # カラー画像のときは、RGBからBGRへ変換する
               if img.ndim == 3:
                 img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

               #img = cv2.imread(self.fileName[0])

               #倍率で表示する
               ritu=float(self.ui.lineEdit_7.text())
               img_fs=cv2.resize(img,None,fx=ritu,fy=ritu)

               cv2.imshow('image', img_fs)
               cv2.setMouseCallback('image', onMouse)
               cv2.waitKey(0)

    def henkan(self):   #画像選択、OCR処理
           tools = pyocr.get_available_tools()
           assert(len(tools) != 0)
           tool = tools[0]

           #対応言語取得
           langs = tool.get_available_languages()
           print("対応言語:",langs) # ['eng', 'jpn', 'osd']

           # 原稿画像の読み込み
           img_org = Image.open(self.fileName[0])
           img_box = Image.open(self.fileName[0])

           pos = self.ui.lineEdit_2.text().split(',')
           l=len(pos)
           if l>4:
             # 番号の部分を切り抜き
             ritu=float(self.ui.lineEdit_7.text())
             x1=int(self.ui.lineEdit_3.text())/ritu
             y1=int(self.ui.lineEdit_4.text())/ritu
             x2=int(self.ui.lineEdit_5.text())/ritu
             y2=int(self.ui.lineEdit_6.text())/ritu
             img_box = img_org.crop((x1, y1, x2, y2))

           opt = int(self.ui.lineEdit_8.text())
           gen = self.ui.lineEdit_9.text()

           text = tool.image_to_string(
           img_box,
           lang=gen,
           builder=pyocr.builders.TextBuilder(tesseract_layout=opt) # ここが重要
           )
           self.ui.textEdit.setText(text)

    def file_save(self):    #ファイル保存
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName , _ = QFileDialog.getSaveFileName(self,"Save File", "", "All Files(*);;Text Files(*.txt)", options = options)
        if fileName:
            with open(fileName, 'w') as f:
                f.write(self.ui.textEdit.toPlainText())

    def clear(self):
        self.ui.lineEdit_2.setText("")
        self.ui.lineEdit_3.setText("")
        self.ui.lineEdit_4.setText("")
        self.ui.lineEdit_5.setText("")
        self.ui.lineEdit_6.setText("")

    def end(self):
        self.close()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    widget = ImageToText()
    widget.show()
    sys.exit(app.exec())

実行画面

画面選択ボタンを押下して画像ファイルを選択します。画像が表示されます。倍率で表示サイズを変更できます。規定は、0.15倍です。

抽出したい領域をマウスで始点と終点を指定します。選択画像座標に値が設定されます。文字抽出ボタンを押下。内容が表示されます。テキスト保存ボタンでファイル保存できます。選択座標なしの場合は、全体が対象となります。

ページセグメンテーションモードについて 

特定の画像に特化したレイアウト解析をするためのオプションを指定する。このオプションを指定した場合、画像の種類によっては文字認識の結果が改善される可能性がある。

オプション説明
0文字角度の識別と書字系のみの認識(OSD)のみ実施(outputbase.osdが出力され、OCRは行われない)
1OSDと自動ページセグメンテーション
2OSDなしの自動セグメンテーション(OCRは行われない)
3OSDなしの完全自動セグメンテーション(デフォルト)
4可変サイズの1列テキストを想定する
5縦書きの単一のテキストブロックとみなす
6単一のテキストブロックとみなす(5と異なる点は横書きのみ)
7画像を1行のテキストとみなす
8画像を単語とみなす
9円の中に記載された1単語とみなす(例:①、⑥など)
10画像を1文字とみなす
11まだらなテキスト。特定の順序でなるべく多くの単語を検出する(角度無し)
12文字角度検出を実施(OSD)しかつ、まだらなテキストとしてなるべく多くの単語を検出する
13Tesseract固有の処理を回避して1行のテキストとみなす

Tesseractのダウンロード

LinuxやMacではレポジトリからインストールできますが、Windowsについてはドイツのマンハイム大学図書館提供のインストーラーを利用できます。マンハイム大学図書館はTesseractで歴史的な新聞の文字認識を行っています。

Home · UB-Mannheim/tesseract Wiki · GitHubのページにアクセスしてWindows用のインストーラーをダウンロードします。32bit版と64bit版があります

-python

PAGE TOP