web-dev-qa-db-ja.com

pythonおよびopencvを使用して画像内のテキスト領域を検出します

python 2.7およびopencv 2.4.9を使用して画像のテキスト領域を検出し、その周囲に長方形領域を描画したい。下のサンプル画像に示すように。

私は画像処理が初めてなので、どのようにこれを行うかのアイデアが高く評価されます。

building blueprint with labeled rooms

27
User9412

画像内のテキストを検出する方法は複数あります。

この質問はこちら をご覧になることをお勧めします。あなたのケースにも答えられるかもしれません。 Pythonではありませんが、コードはc ++からpythonに簡単に変換できます(APIを見て、c ++からpythonにメソッドを変換するだけで、難しくはありません。私自身の別の問題のために)。ここでの解決策はあなたの場合にはうまくいかないかもしれませんが、試してみることをお勧めします。

私がこれについて行くとしたら、次のプロセスを実行します。

画像の準備:編集するすべての画像が提供した画像とほぼ同じで、実際のデザインがさまざまなグレー色で構成され、テキストが常に黒である場合。最初に、黒ではない(または既に白である)コンテンツをすべて白くします。そうすると、黒いテキストだけが残ります。

# must import if working with opencv in python
import numpy as np
import cv2

# removes pixels in image that are between the range of
# [lower_val,upper_val]
def remove_gray(img,lower_val,upper_val):
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    lower_bound = np.array([0,0,lower_val])
    upper_bound = np.array([255,255,upper_val])
    mask = cv2.inRange(gray, lower_bound, upper_bound)
    return cv2.bitwise_and(gray, gray, mask = mask)

黒色のテキストだけが用意できたので、目標はそれらのボックスを取得することです。前に述べたように、これについてはさまざまな方法があります。

ストローク幅変換(SWT)

テキスト領域を見つける一般的な方法: "ストローク幅変換を使用した自然シーンでのテキストの検出" Boris Epshtein、Eyal Ofek、Yonatan Wexlerに示されているように、ストローク幅変換を使用してテキスト領域を検索できます。正直に言うと、これが私が信じているほど速くて信頼できるなら、この方法は以下のコードよりも効率的な方法です。ただし、上記のコードを使用して設計図を削除することはできますが、そのmayはswtアルゴリズムの全体的なパフォーマンスに役立ちます。

ここにcライブラリがあります アルゴリズムを実装していますが、非常に未加工であり、ドキュメントは不完全であると記載されています。明らかに、このライブラリをpythonで使用するにはラッパーが必要になりますが、現時点では公式のものは提供されていません。

リンクしたライブラリは CCV です。これは、アルゴリズムを再作成するのではなく、アプリケーションで使用するためのライブラリです。したがって、これは使用すべきツールであり、コメントで述べられているように、OPが「第一原則」からそれを作成するという欲求に反します。それでも、アルゴリズムを自分でコーディングしたくない場合は、それが存在することを知っておくと便利です。


自家製の非SWT法

各画像のメタデータ、たとえばxmlファイルに各画像にラベル付けされている部屋の数がある場合、そのxmlファイルにアクセスして、画像に含まれるラベルの数に関するデータを取得し、それを保存できますnum_of_labelsなどの変数の番号。次に、画像を取得し、指定した設定レートで侵食するwhileループを通過させ、各ループで画像内の外部輪郭を見つけ、num_of_labelsと同じ数の外部輪郭ができたらループを停止します。次に、各輪郭の境界ボックスを見つけるだけで完了です。

# erodes image based on given kernel size (erosion = expands black areas)
def erode( img, kern_size = 3 ):
    retval, img = cv2.threshold(img, 254.0, 255.0, cv2.THRESH_BINARY) # threshold to deal with only black and white.
    kern = np.ones((kern_size,kern_size),np.uint8) # make a kernel for erosion based on given kernel size.
    eroded = cv2.erode(img, kern, 1) # erode your image to blobbify black areas
    y,x = eroded.shape # get shape of image to make a white boarder around image of 1px, to avoid problems with find contours.
    return cv2.rectangle(eroded, (0,0), (x,y), (255,255,255), 1)

# finds contours of eroded image
def prep( img, kern_size = 3 ):    
    img = erode( img, kern_size )
    retval, img = cv2.threshold(img, 200.0, 255.0, cv2.THRESH_BINARY_INV) #   invert colors for findContours
    return cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) # Find Contours of Image

# given img & number of desired blobs, returns contours of blobs.
def blobbify(img, num_of_labels, kern_size = 3, dilation_rate = 10):
    prep_img, contours, hierarchy = prep( img.copy(), kern_size ) # dilate img and check current contour count.
    while len(contours) > num_of_labels:
        kern_size += dilation_rate # add dilation_rate to kern_size to increase the blob. Remember kern_size must always be odd.
        previous = (prep_img, contours, hierarchy)
        processed_img, contours, hierarchy = prep( img.copy(), kern_size ) # dilate img and check current contour count, again.
    if len(contours) < num_of_labels:
        return (processed_img, contours, hierarchy)
    else:
        return previous

# finds bounding boxes of all contours
def bounding_box(contours):
    bBox = []
    for curve in contours:
        box = cv2.boundingRect(curve)
    bBox.append(box)
    return bBox

上記の方法で作成されたボックスには、ラベルの周りにスペースがあります。ボックスが元の画像に適用される場合、これには元のデザインの一部が含まれる場合があります。これを回避するには、新しく見つかったボックスを使用して関心領域を作成し、空白を削除します。次に、そのroiの形状を新しいボックスとして保存します。

おそらく、画像内にいくつのラベルがあるかを知る方法がないでしょう。この場合、ケースに合った最適な値を見つけて目的のBLOBを取得するまで、浸食値をいじることをお勧めします。

または、デザインを削除した後、残りのコンテンツの輪郭を見つけて、互いの距離に基づいて境界ボックスを1つの長方形に結合することもできます。

ボックスを見つけたら、元の画像に対してそれらのボックスを使用するだけで完了です。


OpenCV 3のシーンテキスト検出モジュール

あなたの質問へのコメントで述べたように、opencv 3にはシーンテキスト検出(ドキュメントテキスト検出ではない)の手段が既に存在します。バージョンを切り替えることはできませんが、同じ質問を持ち、限定されない古いopencvバージョンには、これを最後に含めることにしました。シーンテキスト検出のドキュメントは、簡単なGoogle検索で見つけることができます。

テキスト検出用のopencvモジュールには、無料のオープンソースのテキスト認識モジュールであるtessaractを実装するテキスト認識も付属しています。 tessaractの没落、したがってopencvのシーンテキスト認識モジュールは、商用アプリケーションほど洗練されておらず、使用に時間がかかることです。したがって、パフォーマンスは低下しますが、無料で使用できるため、テキスト認識も必要な場合は、お金を払わなくても最高です。

リンク:

正直なところ、テキスト検出モジュールを実装する詳細な方法を提供するために、opencvと画像処理の両方の経験と専門知識が不足しています。 SWTアルゴリズムでも同じです。過去数か月間、私はこのようなことを始めましたが、詳細がわかり次第、この回答を編集します。

38
prijatelj