OpenVINO™ を使用した手書きの中国語と日本語の OCR

この Jupyter ノートブックはオンラインで起動でき、ブラウザーのウィンドウで対話型環境を開きます。ローカルにインストールすることもできます。次のオプションのいずれかを選択します。

Binder Google Colab GitHub

このチュートリアルでは、手書きの中国語 (簡体字) と日本語の光学文字認識 (OCR) を実行します。ラテン・アルファベットを使用した OCR チュートリアルは、ノートブック 208 で入手できます。このモデルは、一度に 1 行のシンボルのみを処理できます。

このノートブックで使用されているモデルは、handwritten-japanese-recognition-0001handwritten-simplified-chinese-0001 です。モデル出力を読み取り可能なテキストとしてデコードするには、kondate_nakayosiscut_ept 文字リストが使用されます。どちらのモデルもOpen Model Zoo で入手できます。

目次

# Install openvino-dev package
%pip install -q "openvino>=2023.1.0"
%pip install -q matplotlib numpy
Note: you may need to restart the kernel to use updated packages.
Note: you may need to restart the kernel to use updated packages.

インポート

from collections import namedtuple
from itertools import groupby

import cv2
import matplotlib.pyplot as plt
import numpy as np
import openvino as ov

# Fetch `notebook_utils` module
import urllib.request
urllib.request.urlretrieve(
    url='https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/main/notebooks/utils/notebook_utils.py',
    filename='notebook_utils.py'
)
from notebook_utils import download_file

設定

このノートブックで使用されるすべての定数とフォルダを設定します

# Directories where data will be placed.
base_models_dir = "models"
data_folder = "data"
charlist_folder = f"{data_folder}/text"

# Precision used by the model.
precision = "FP16"

ファイルをグループ化するには、コレクションを定義する必要があります。これには namedtuple を使用します。

Language = namedtuple(
    typename="Language", field_names=["model_name", "charlist_name", "demo_image_name"]
)
chinese_files = Language(
    model_name="handwritten-simplified-chinese-recognition-0001",
    charlist_name="chinese_charlist.txt",
    demo_image_name="handwritten_chinese_test.jpg",
)
japanese_files = Language(
    model_name="handwritten-japanese-recognition-0001",
    charlist_name="japanese_charlist.txt",
    demo_image_name="handwritten_japanese_test.png",
)

言語を選択

選択に応じて、下のセルのコード行を変更する必要があります。

日本語のテキストに対して OCR を実行するには、language = "japanese" を設定します。中国語の場合は、language = "chinese" を設定します。

# Select the language by using either language="chinese" or language="japanese".
language = "chinese"

languages = {"chinese": chinese_files, "japanese": japanese_files}

selected_language = languages.get(language)

モデルのダウンロード

画像と文字リストに加えて、モデルファイルをダウンロードする必要があります。以下のセクションには、中国語または日本語のモデルをダウンロードするセルがあります。

ノートブックを初めて実行すると、モデルがダウンロードされます。これには、数分かかる場合があります。

utils パッケージの download_file 関数を使用すると、ディレクトリー構造が自動的に作成され、選択したモデルファイルをダウンロードできます。

path_to_model = download_file(
                                        url=f'https://storage.openvinotoolkit.org/repositories/open_model_zoo/2023.0/models_bin/1/{selected_language.model_name}/{precision}/{selected_language.model_name}.xml',
    directory=base_models_dir
)
_ = download_file(
    url=f'https://storage.openvinotoolkit.org/repositories/open_model_zoo/2023.0/models_bin/1/{selected_language.model_name}/{precision}/{selected_language.model_name}.bin',
    directory=base_models_dir
)
models/handwritten-simplified-chinese-recognition-0001.xml:   0%|          | 0.00/108k [00:00<?, ?B/s]
models/handwritten-simplified-chinese-recognition-0001.bin:   0%|          | 0.00/32.9M [00:00<?, ?B/s]

モデルをロードして実行

すべてのファイルがダウンロードされ、言語が選択されたら、ネットワークを読み取ってコンパイルし、推論を実行します。モデルへのパスは、選択した言語に基づいて定義されます。

core = ov.Core()
model = core.read_model(model=path_to_model)

推論デバイスの選択

OpenVINO を使用して推論を実行するためにドロップダウン・リストからデバイスを選択します

import ipywidgets as widgets

device = widgets.Dropdown(
    options=core.available_devices + ["AUTO"],
    value='AUTO',
    description='Device:',
    disabled=False,
)

device
Dropdown(description='Device:', index=1, options=('CPU', 'AUTO'), value='AUTO')
compiled_model = core.compile_model(model=model, device_name=device.value)

入力レイヤーと出力レイヤーに関する情報を取得

モデルが読み込まれたので、入力レイヤーと出力レイヤー (形状) に関する情報を取得します。

recognition_output_layer = compiled_model.output(0)
recognition_input_layer = compiled_model.input(0)

画像のロード

次に、画像を読み込みます。モデルは入力として単一チャネルの画像を想定しているため、画像はグレースケールで読み取られます。

入力画像を読み込んだ後、必要な入力レイヤーの高さと現在の画像の高さのスケール比の計算に必要な情報を取得します。下のセルでは、文字の比率を維持し、入力された形状に合うように、画像のサイズが変更され、パディングされます。

# Download the image from the openvino_notebooks storage based on the selected model.
file_name = download_file(
    "https://storage.openvinotoolkit.org/repositories/openvino_notebooks/data/data/image/" + selected_language.demo_image_name,
    directory=data_folder
)

# Text detection models expect an image in grayscale format.
# IMPORTANT! This model enables reading only one line at time.

# Read the image.
image = cv2.imread(filename=str(file_name), flags=cv2.IMREAD_GRAYSCALE)

# Fetch the shape.
image_height, _ = image.shape

# B,C,H,W = batch size, number of channels, height, width.
_, _, H, W = recognition_input_layer.shape

# Calculate scale ratio between the input shape height and image height to resize the image.
scale_ratio = H / image_height

# Resize the image to expected input sizes.
resized_image = cv2.resize(
                                        image, None, fx=scale_ratio, fy=scale_ratio, interpolation=cv2.INTER_AREA
)

# Pad the image to match input size, without changing aspect ratio.
resized_image = np.pad(
    resized_image, ((0, 0), (0, W - resized_image.shape[1])), mode="edge"
)

# Reshape to network input shape.
input_image = resized_image[None, None, :, :]
data/handwritten_chinese_test.jpg:   0%|          | 0.00/42.1k [00:00<?, ?B/s]

入力画像を視覚化

前処理が終わったら画像を表示できます。

plt.figure(figsize=(20, 1))
plt.axis("off")
plt.imshow(resized_image, cmap="gray", vmin=0, vmax=255);
../_images/209-handwritten-ocr-with-output_22_0.png

文字リストを準備

モデルが読み込まれ、画像が準備できました。残っている要素は、ダウンロードされる文字リストのみです。使用する前に、文字リストの先頭に空白記号を追加する必要があります。これは中国モデルと日本モデルの両方で予想されます。

# Download the image from the openvino_notebooks storage based on the selected model.
used_charlist_file = download_file(
    "https://storage.openvinotoolkit.org/repositories/openvino_notebooks/data/data/text/" + selected_language.charlist_name,
    directory=charlist_folder
)
data/text/chinese_charlist.txt:   0%|          | 0.00/15.8k [00:00<?, ?B/s]
# Get a dictionary to encode the output, based on model documentation.
used_charlist = selected_language.charlist_name

# With both models, there should be blank symbol added at index 0 of each charlist.
blank_char = "~"

with used_charlist_file.open(mode="r", encoding="utf-8") as charlist:
    letters = blank_char + "".join(line.strip() for line in charlist)

推論の実行

推論を実行します。compiled_model() 関数は、モデル入力と同じ順序の入力のリストを受け取ります。次に、出力テンソルから出力を取得します。

# Run inference on the model
predictions = compiled_model([input_image])[recognition_output_layer]

出力データを処理

モデルの出力は W x B x L 形式です。

  • W - 出力シーケンス長

  • B - バッチサイズ

  • L - Kondate と Nakayosi でサポートされているシンボル間の信頼度分布。

より人間が読みやすい形式にするには、最も確率の高いシンボルを選択します。最も高い確率を持つと予測されるインデックスのリストを保持する場合、CTC デコードの制限により、同時シンボルを削除してから空白を削除します。

最後に、文字リスト内の対応するインデックスからシンボルを取得します。

# Remove a batch dimension.
predictions = np.squeeze(predictions)

# Run the `argmax` function to pick the symbols with the highest probability.
predictions_indexes = np.argmax(predictions, axis=1)
# Use the `groupby` function to remove concurrent letters, as required by CTC greedy decoding.
output_text_indexes = list(groupby(predictions_indexes))

# Remove grouper objects.
output_text_indexes, _ = np.transpose(output_text_indexes, (1, 0))

# Remove blank symbols.
output_text_indexes = output_text_indexes[output_text_indexes != 0]

# Assign letters to indexes from the output array.
output_text = [letters[letter_index] for letter_index in output_text_indexes]