Main Content

光学式文字認識 (OCR) を使用したテキストの認識

この例では、Computer Vision Toolbox™ の関数 ocr を使用して光学式文字認識を実行する方法を説明します。

関数 ocr を使用したテキスト認識

イメージ内のテキストの認識は、イメージ探索、文書解析、ロボット操縦など、多くのコンピューター ビジョン アプリケーションで役立ちます。関数 ocr によって、広範なアプリケーションにテキスト認識機能を簡単に追加することができます。

% Load an image.
I = imread("businessCard.png");

% Perform OCR.
results = ocr(I);

% Display one of the recognized words.
word = results.Words{2}
word = 
'MathWorks:'
% Location of the word in I
wordBBox = results.WordBoundingBoxes(2,:)
wordBBox = 1×4

   173    66   376    82

% Show the location of the word in the original image.
figure
Iname = insertObjectAnnotation(I,"rectangle",wordBBox,word);
imshow(Iname)

関数 ocr で返される情報

関数 ocr は、認識したテキスト、認識の信頼度および元のイメージでのテキストの位置を返します。この情報を使って、イメージ内で誤分類されたテキストの位置を特定できます。

% Find 5 characters with least confidences.
[~ ,idx] = sort(results.CharacterConfidences);
lowConfidenceIdx = idx(1:5);

% Get the bounding box locations of the low confidence characters.
lowConfBBoxes = results.CharacterBoundingBoxes(lowConfidenceIdx,:);

% Get recognized characters.
lowConfChars = results.Text(lowConfidenceIdx)';

% Annotate image with low confidence characters.
str      = "Character = '" + lowConfChars + "'";
Ilowconf = insertObjectAnnotation(I,"rectangle",lowConfBBoxes,str);

figure
imshow(Ilowconf)
title("Character recognitions with the least confidence")

ここでは名刺のロゴが誤ってテキストの文字として分類されています。このような種類の OCR エラーは、処理を進める前に、信頼度の値を使用して識別できます。

正確な結果を取得する際の課題

ocr は、テキストの背景が一様であり、背景が濃色でテキストが淡色の文書のような形式をもつ場合に最もよく機能します。一様ではない不均一な濃色の背景にテキストが表示されている場合、OCR で最適な結果を得るには追加の前処理手順が必要です。ここでは、キーパッド上の数字の位置を特定します。キーパッドのイメージは OCR で簡単に扱えるように見えますが、一様ではない濃色の背景上にテキストがあるため、実際にはかなり難しい処理となります。

I = imread("keypad.jpg");
I = im2gray(I);

figure
imshow(I)

% Run OCR on the image
results = ocr(I);

results.Text
ans = 
    ' 
     
     '

results.Text が空白なのは、テキストが何も認識されていないことを示します。キーパッドのイメージでは、テキストがまばらで、一様でない背景上に配置されています。この場合、ocr 内で文書のレイアウト解析に使われるヒューリスティックな方法ではイメージ内のテキスト ブロックが見つからない可能性があり、その結果テキスト認識は失敗します。こうした状況では、LayoutAnalysis パラメーターを使って自動レイアウト解析を無効にすると、結果が改善されることがあります。

% Set LayoutAnalysis to "Block" to instruct ocr to assume the image
% contains just one block of text.
results = ocr(I,LayoutAnalysis="Block");

results.Text
ans =

  0x0 empty char array

問題箇所の特定

LayoutAnalysis パラメーターを調整しても効果はありませんでした。OCR が失敗し続ける原因を把握するには、ocr 内で実行される初期の 2 値化ステップを調べる必要があります。ocrimbinarize 内の既定の "グローバル" メソッドは、いずれも Otsu 法によるイメージの 2 値化を使用するため、imbinarize を使ってこの初期の 2 値化ステップを確認できます。

BW = imbinarize(I);

figure
imshowpair(I,BW,"montage")

しきい値処理の後、バイナリ イメージにはテキストが含まれていません。ocr が元のイメージにあるテキストを一切認識できなかったのはそのためです。イメージの前処理を行い、テキストのセグメンテーションを改善することで、よりよい結果を得ることができます。この例の次の部分では、役に立つ前処理の手法を 2 つ扱います。

結果を改善するためのイメージの前処理手法

上記でテキストのセグメンテーションがうまく機能しないのは、濃いグレーに囲まれて薄いグレーのキーがあり、イメージの背景が一様でないことが原因となっています。次の前処理手法を使用すると、背景のばらつきをなくし、テキストのセグメンテーションを改善することができます。この手法の詳細については、不均一な照度の補正と前景オブジェクトの解析という表題の例を参照してください。

% Remove keypad background.
Icorrected = imtophat(I,strel("disk",15));

BW1 = imbinarize(Icorrected);

figure 
imshowpair(I,BW1,"montage")

背景のばらつきを取り除くと、バイナリ イメージ内で数字が可視化されます。しかし、キーの端にあるいくつかのアーティファクトと数字の隣にある小さいテキストが、イメージ全体の正確な OCR を引き続き妨げる可能性があります。モルフォロジー再構成を使用して追加の前処理を行うと、こうしたアーティファクトを除去して OCR 用によりクリーンなイメージを生成することができます。

% Perform morphological reconstruction and show binarized image.
marker = imerode(Icorrected,strel("line",10,0));
Iclean = imreconstruct(marker,Icorrected);

Ibinary = imbinarize(Iclean);

figure
imshowpair(Iclean,Ibinary,"montage")

次に、きれいな 2 値化イメージを反転して、OCR 用に淡色の背景に濃色のテキストを含むイメージを生成します。

BW2 = imcomplement(Ibinary);
figure
imshowpair(Ibinary,BW2,"montage")

上記の前処理手順を踏むと、背景から数字がうまく区別され、ocr で何らかの結果が得られるようになります。

results = ocr(BW2,LayoutAnalysis="block");

results.Text
ans = 
    'ww] 2 x 3
     md ud wb
     on/ wB wm?
     -* . 0 #)
     
     '

結果は、いくつかの文字以外はほとんど正確でないようです。これは、キーパッド内の文字のサイズが異なっていて、自動レイアウト解析が失敗することが原因です。

結果を改善する 1 つの方法は、イメージ内のテキストについての予備知識を活用することです。この例では、対象となるテキストに含まれている文字は、数字、*#、および ' だけです。最適のマッチを "0123456789*#" のセットからのみ選択するように ocr を制約することで、結果を改善できます。

% Use the "CharacterSet" parameter to constrain OCR
results = ocr(BW2,CharacterSet="0123456789*#");

results.Text
ans = 
    '2 3
     4
     78
     
     *0
     
     '

結果はより良くなり、指定された文字セットの文字のみが含まれるようになりました。ただし、イメージ内の対象文字のうち、認識結果のないものがまだいくつかあります。

ROI ベースの処理による結果の改善

この状況で認識結果をさらに改善するには、ocr で処理する特定の領域をイメージ内に指定します。キーパッドの例のイメージでは、こうした領域に該当するのは数字、*、および # の文字のみを含む領域です。領域は imrect を使って手動で選択できますが、処理を自動化することも可能です。テキスト領域を自動的に検出する方法の詳細については、MSER と OCR を使用したテキストの自動検出と自動認識およびAutomatically Detect and Recognize Text Using Pretrained CRAFT Network and OCRを参照してください。この例では、regionprops を使用して、キーパッド上の対象文字を検出します。

% Use regionprops to find bounding boxes around text regions and measure their area.
cc = bwconncomp(Ibinary);
stats = regionprops(cc, ["BoundingBox","Area"]);

% Extract bounding boxes and area from the output statistics.
roi = vertcat(stats(:).BoundingBox);
area = vertcat(stats(:).Area);

% Show all the connected regions.
img = insertObjectAnnotation(I,"rectangle",roi,area,"LineWidth",3);
figure;
imshow(img);

この例で最も小さい対象文字は、数字の "1" です。その領域を使用して外れ値をフィルター処理します。

% Define area constraint based on the area of smallest character of interest.
areaConstraint = area > 347;

% Keep regions that meet the area constraint.
roi = double(roi(areaConstraint,:));

% Show remaining bounding boxes after applying the area constraint.
img = insertShape(I,"rectangle",roi);
figure;
imshow(img);

領域の縦横比に基づく追加の処理を適用して、文字を 1 つ含む可能性が高い領域を識別します。これは、数字の隣に混じりこんでいる小さいテキスト文字を削除するのに役立ちます。一般に、テキストのサイズが大きいほど、ocr で認識しやすくなります。

% Compute the aspect ratio.
width  = roi(:,3);
height = roi(:,4);
aspectRatio = width ./ height;

% An aspect ratio between 0.25 and 1.25 is typical for individual characters
% as they are usually not very short and wide or very tall and skinny.
roi = roi( aspectRatio > 0.25 & aspectRatio < 1.25 ,:);

% Show regions after applying the area and aspect ratio constraints.
img = insertShape(I,"rectangle",roi);
figure;
imshow(img);

残っている領域は関数 ocr に渡すことができ、この関数は四角形の関心領域を入力として受け入れます。テキスト文字の周りにある追加の背景のピクセルも含めるため、領域のサイズは若干大きくなります。これは、背景に置かれたテキストの極性 (たとえば、濃色の背景に淡色のテキストがあるのか、淡色の背景に濃色のテキストがあるのかなど) を判断するための内部のヒューリスティックな方法を改善するのに役立ちます。

numAdditionalPixels = 5;
roi(:,1:2) = roi(:,1:2) - numAdditionalPixels;
roi(:,3:4) = roi(:,3:4) + 2*numAdditionalPixels;

LayoutAnalysis を "none" に設定して、自動レイアウト解析を無効にします。ROI 入力が手動で提供される場合、LayoutAnalysis を "block"、"word"、"textline"、"character"、または "none" に設定すると、結果が改善される可能性があります。最適なレイアウト解析値を決定するには、経験的解析が必要です。

results = ocr(BW2,roi,CharacterSet="0123456789*#",LayoutAnalysis="none");

認識されたテキストは、insertObjectAnnotation を使用して元のイメージに表示できます。空白や改行文字などの終了文字を削除するには、関数 deblank を使用します。

text = deblank({results.Text});
img  = insertObjectAnnotation(I,"rectangle",roi,text);

figure; 
imshow(img)

regionprops では、キーパッド イメージ内の数字を検出できましたが、テキスト以外に多数のオブジェクトが含まれる自然なシーンのイメージはうまく処理できない可能性があります。これらのタイプのイメージでは、Automatically Detect and Recognize Text Using Pretrained CRAFT Network and OCRの例で示した手法によって、より良好なテキスト検出結果が得られることがあります。

まとめ

この例では、関数 ocr を使用してイメージ内のテキストを認識する方法を示し、一見して OCR で簡単に扱えそうなイメージであっても良好な結果を得るには追加の前処理が必要となることを説明しました。

参照

[1] Ray Smith. Hybrid Page Layout Analysis via Tab-Stop Detection. Proceedings of the 10th international conference on document analysis and recognition. 2009.

関連するトピック