ドキュメンテーション

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

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

この例では、Computer Vision System 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}

% Location of the word in I
wordBBox = results.WordBoundingBoxes(2,:)
word =

    'MathWorks®'


wordBBox =

   173    75   376    61

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

関数 ocr で返される情報

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

% Find characters with low confidence
lowConfidenceIdx = results.CharacterConfidences < 0.5;

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

% Get confidence values
lowConfVal = results.CharacterConfidences(lowConfidenceIdx);

% Annotate image with character confidences
str      = sprintf('confidence = %f', lowConfVal);
Ilowconf = insertObjectAnnotation(I, 'rectangle', lowConfBBoxes, str);

figure;
imshow(Ilowconf);

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

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

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

I = imread('keypad.jpg');
I = rgb2gray(I);

figure;
imshow(I)

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

results.Text
ans =

    ' 
     
     '

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

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

results.Text
ans =

  0×0 empty char array

問題箇所の特定

'TextLayout' パラメーターを調整しても効果はありませんでした。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(Icorrected, BW1, 'montage');

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

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

BW2 = imbinarize(Iclean);

figure;
imshowpair(Iclean, BW2, 'montage');

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

results = ocr(BW2, 'TextLayout', 'Block');

results.Text
ans =

    '«-1 ..c2 .3
     ....4 .5 .....6
     W7 M8 M9
     -*1..o fl
     
     '

数字の隣に小さいテキストがあるため、結果には若干の「ノイズ」が含まれています。また、数字の「0」がアルファベットの「o」として誤認識されています。こうしたタイプのエラーは、形状の似ている文字が 2 つあり、関数 ocr が特定の文字の最適な分類を判断するのに十分なテキストが周りにない場合に発生します。「ノイズの多い」結果であっても、OCR の結果に locateText メソッドを使用して、元のイメージで数字の位置を見つけることができます。

locateText メソッドは正規表現をサポートするため、無関係のテキストを無視できます。

% The regular expression, '\d', matches the location of any digit in the
% recognized text and ignores all non-digit characters.
regularExpr = '\d';

% Get bounding boxes around text that matches the regular expression
bboxes = locateText(results, regularExpr, 'UseRegexp', true);

digits = regexp(results.Text, regularExpr, 'match');

% draw boxes around the digits
Idigits = insertObjectAnnotation(I, 'rectangle', bboxes, digits);

figure;
imshow(Idigits);

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

% Use the 'CharacterSet' parameter to constrain OCR
results = ocr(BW2, 'CharacterSet', '0123456789', 'TextLayout','Block');

results.Text
ans =

    ' 1 1   2   3
     5 4  5   06
      7  3  9
      4 1 0  51
     
     '

これで、結果には数字の文字セットにある文字だけが含まれるようになります。しかし、イメージ内にある数字以外のいくつかの文字も数字として誤認識されているのがわかります。これが起こるのは、数字ではない文字がいずれかの数字によく似ているときです。

キーパッドにある数字は 10 個だけであるという事実と、文字の信頼度を使用して、10 個の最適の数字を検出できます。

% Sort the character confidences
[sortedConf, sortedIndex] = sort(results.CharacterConfidences, 'descend');

% Keep indices associated with non-NaN confidences values
indexesNaNsRemoved = sortedIndex( ~isnan(sortedConf) );

% Get the top ten indexes
topTenIndexes = indexesNaNsRemoved(1:10);

% Select the top ten results
digits = num2cell(results.Text(topTenIndexes));
bboxes = results.CharacterBoundingBoxes(topTenIndexes, :);

Idigits = insertObjectAnnotation(I, 'rectangle', bboxes, digits);

figure;
imshow(Idigits);

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

状況によっては、イメージの前処理だけでは OCR で十分な結果を得られないこともあります。そうした状況で使用できる 1 つの方法は、ocr で処理する特定の領域をイメージ内に指定することです。キーパッドの例のイメージでは、こうした領域に該当するのは数字だけを含む領域です。領域は imrect を使って手動で選択できますが、処理を自動化することも可能です。テキスト検出を自動化する 1 つの方法は、「自然なイメージ内にあるテキストの自動検出と自動認識」という例で説明されています。この例では、vision.BlobAnalysis を使用してキーパッド上の数字を検出します。

% Initialize the blob analysis System object(TM)
blobAnalyzer = vision.BlobAnalysis('MaximumCount', 500);

% Run the blob analyzer to find connected components and their statistics.
[area, centroids, roi] = step(blobAnalyzer, BW1);

% Show all the connected regions
img = insertShape(I, 'rectangle', roi);
figure;
imshow(img);

キーパッド イメージの中には数多くの連結された領域があります。小さい領域にテキストが含まれる可能性は低いので、これらは vision.BlobAnalysis で返される面積の統計を使って削除できます。ここでは面積が 300 未満の領域を削除します。

areaConstraint = area > 300;

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

% Show remaining blobs 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 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 ,:);

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

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

roi(:,1:2) = roi(:,1:2) - 4;
roi(:,3:4) = roi(:,3:4) + 8;
results = ocr(BW1, roi, 'TextLayout', 'Block');

認識されたテキストは、insertObjectAnnotation を使用して元のイメージに表示できます。空白や改行文字などの終了文字を削除するには、関数 deblank を使用します。この結果ではいくつかの分類 (たとえば、数字の 8) が欠けていますが、これは追加の前処理手法を使用して訂正できます。

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

figure;
imshow(img)

vision.BlobAnalysis では、キーパッド イメージ内の数字を検出できましたが、テキスト以外に多数のオブジェクトが含まれる自然なシーンのイメージはうまく処理できない可能性があります。そうしたタイプのイメージでは、「自然なイメージ内にあるテキストの自動検出と自動認識」の例で示した手法によって、より良好なテキスト検出結果が得られることがあります。

まとめ

この例では、関数 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.